سؤال

دعنا نقول أن لدي فئة مثل هذا (وأيضًا تفترض أيضًا أن جميع المتغيرات الخاصة:

public class Item {
    private String _id = null;
    private String _name = null;
    private String _description = null;

        ...
}

الآن ، إذا كنت أرغب في إنشاء تمثيل ToString () لهذه الفئة ، فسأفعل شيئًا كهذا داخل فئة العنصر:

@Override
public String toString() {
    return (_id + " " + _name + " " + _description);
}

ولكن ماذا لو قلت 15 متغيرًا خاصًا داخل الفصل؟ هل يجب علي كتابة اسم كل متغير مثل هذا؟

من الناحية المثالية ، أود أن أتغلب على المهمة من خلال التكرار من خلال قائمة المتغيرات الخاصة في هذه الفئة وبناء تمثيل السلسلة:

@Override
public String toString() {
    ArrayList<String> members = getClass().getMembers(); //Some method like this
    String string = "";
    for(...)
        string += members[i] + " ";
}

أو ربما طريقة Tojson ، ما زلت بحاجة إلى الوصول إلى أسماء هذه المتغيرات. أي اقتراحات؟

هل كانت مفيدة؟

المحلول

يمكنك أن تفعل:

@Override
public String toString() {
  StringBuilder sb = new StringBuilder();
  sb.append(getClass().getName());
  sb.append(": ");
  for (Field f : getClass().getDeclaredFields()) {
    sb.append(f.getName());
    sb.append("=");
    sb.append(f.get(this));
    sb.append(", ");
  }
  return sb.toString();
}

لا استخدم سلسلة سلسلة لإنشاء نتيجة نهائية من 15 من أعضاء البيانات ، خاصة إذا toString() سوف يسمى كثيرا. يمكن أن يكون تجزئة الذاكرة والنفقات العامة عالية حقًا. يستخدم StringBuilder لبناء سلاسل ديناميكية كبيرة.

عادةً ما أحصل على IDE (intellij) لتوليد ببساطة toString() طرق بالنسبة لي بدلاً من استخدام انعكاس لهذا.

نهج آخر مثير للاهتمام هو استخدام التعليق التوضيحي toString من Project Lombok:

import lombok.ToString;

@ToString(excludes="id")
public class ToStringExample {
  private static final int STATIC_VAR = 10;
  private String name;
  private Shape shape = new Square(5, 10);
  private String[] tags;
  private int id;

  @ToString(callSuper=true, includeFieldNames=true)
  public static class Square extends Shape {
    private final int width, height;

    public Square(int width, int height) {
      this.width = width;
      this.height = height;
    }
  }
}

أجد أن هذا أفضل بكثير ، على سبيل المثال ، Jakarta Commons Tostring Builders لأن هذا النهج أكثر قابلية للتكوين ، كما أنه تم تصميمه في وقت الترجمة وليس وقت التشغيل.

نصائح أخرى

تحقق من واجهة برمجة التطبيقات هذه org.apache.commons.lang.builder.toStringBuilder, ، يوفر طرقًا متعددة لإنشاء انعكاس USINF toString أو بدون انعكاس. نلقي نظرة على الفئات الفرعية الأخرى كذلك.

هناك مثل هذه واجهة برمجة التطبيقات ، ويسمى انعكاس جافا

لإنجاز ما تطلبه ، يمكنك ببساطة القيام بشيء مثل:

 Class<?> cls = this.getClass();
 Field fieldlist[] = cls.getDeclaredFields();
 for (Field aFieldlist : fieldlist) {
   // build toString output with StringBuilder()
 }

يجب أن يكون هذا بالضبط ما تبحث عنه

    public String toString() {
    StringBuilder sb = new StringBuilder();
    try {
        Class c = Class.forName(this.getClass().getName());
        Method m[] = c.getDeclaredMethods();
        Object oo;

        for (int i = 0; i < m.length; i++)
            if (m[i].getName().startsWith("get")) {
                oo = m[i].invoke(this, null);
                sb.append(m[i].getName().substring(3) + ":"
                        + String.valueOf(oo) + "\n");
            }
    } catch (Throwable e) {
        System.err.println(e);
    }
    return sb.toString();
}

توفر معظم IDEs طريقة لإنشاء ملف toString الطريقة في فئة معينة.

أعطى Item الفصل مع حقول متعددة:

class Item {
    int i;
    int j;
    int k;
    int l;
    int m;
    int n;
    int o;  
}

على سبيل المثال ، في Eclipse ، قم بتنفيذ ميزة "إنشاء tostring () على Item سيقوم الفصل أعلاه بإنشاء ما يلي:

@Override
public String toString() {
    return "Item [i=" + i + ", j=" + j + ", k=" + k + ", l=" + l + ", m="
            + m + ", n=" + n + ", o=" + o + "]";
}

استخدام انعكاس من شأنه أن يسمح لطريقة برمجية لمراقبة حقول الفرد ، ولكن الانعكاس بحد ذاته عملية باهظة الثمن (قراءة: بطيئة) ، لذلك ما لم تكن مطلوبة حقًا ، باستخدام ثابت toStringالطريقة المكتوبة في وقت التشغيل ربما ستكون أكثر رغبة.

يمكنك مواجهة مشكلة السرعة. إذا كنت تستخدم التفكير ، فقد يكون بطيئًا حقًا ، بالمقارنة مع تشغيل الكود الأصلي. إذا كنت ستستخدم التفكير ، فمن المحتمل أن يكون لديك ذاكرة التخزين المؤقت للذاكرة للمتغيرات التي تتكررها.

بدءا من إجابة متوسطة جيدة, ، يمكنك استخدام هذا الرمز للحصول على تمثيل سلسلة لجميع مجالات الكائن ، حتى لو كنت خارج صفها (من الواضح أنه فقط للحقول ذات طريقة getter):

/**Gives a string representation of the fields of the object
 * @param obj the object
 * @return
 */
private static String objectToString(Object obj) {
    StringBuilder sb = new StringBuilder();
    try {
        Class c = Class.forName(obj.getClass().getName());
        Method m[] = c.getDeclaredMethods();

        Object oo;
        for (int i = 0; i < m.length; i++)
            if (m[i].getName().startsWith("get")) {
                oo = m[i].invoke(obj, null);
                sb.append(m[i].getName().substring(3) + "="
                        + String.valueOf(oo) + "\n");
            }
    } catch (Throwable e) {
        System.err.println(e);
    }
    return sb.toString();
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top