การสะท้อนทั่วไปรับค่าฟิลด์


132

ฉันพยายามรับค่าฟิลด์ผ่านการสะท้อน ปัญหาคือฉันไม่ทราบประเภทช่องและต้องตัดสินใจขณะรับค่า

รหัสนี้มีผลกับข้อยกเว้นนี้:

ไม่สามารถตั้งค่า java.lang.String field com .... fieldName เป็น java.lang.String

Field field = object.getClass().getDeclaredField(fieldName);
field.setAccessible(true);

Class<?> targetType = field.getType();
Object objectValue = targetType.newInstance();

Object value = field.get(objectValue);

ฉันพยายามแคสต์ แต่พบข้อผิดพลาดในการคอมไพล์:

field.get((targetType)objectValue)

หรือ

targetType objectValue = targetType.newInstance();

ฉันจะทำเช่นนี้ได้อย่างไร?


4
มองไปที่APIอาร์กิวเมนต์ที่จะfield.get()ควรจะเป็นไม่ได้object objectValue
akaIDIOT

คำตอบ:


144

เช่นเดียวกับคำตอบก่อนหน้านี้คุณควรใช้:

Object value = field.get(objectInstance);

อีกวิธีหนึ่งซึ่งบางครั้งเป็นที่ต้องการคือเรียก getter แบบไดนามิก โค้ดตัวอย่าง:

public static Object runGetter(Field field, BaseValidationObject o)
{
    // MZ: Find the correct method
    for (Method method : o.getMethods())
    {
        if ((method.getName().startsWith("get")) && (method.getName().length() == (field.getName().length() + 3)))
        {
            if (method.getName().toLowerCase().endsWith(field.getName().toLowerCase()))
            {
                // MZ: Method found, run it
                try
                {
                    return method.invoke(o);
                }
                catch (IllegalAccessException e)
                {
                    Logger.fatal("Could not determine method: " + method.getName());
                }
                catch (InvocationTargetException e)
                {
                    Logger.fatal("Could not determine method: " + method.getName());
                }

            }
        }
    }


    return null;
}

โปรดทราบว่าเมื่อคลาสของคุณสืบทอดมาจากคลาสอื่นคุณจะต้องกำหนดฟิลด์ซ้ำ ตัวอย่างเช่นเพื่อดึงฟิลด์ทั้งหมดของคลาสที่กำหนด

    for (Class<?> c = someClass; c != null; c = c.getSuperclass())
    {
        Field[] fields = c.getDeclaredFields();
        for (Field classField : fields)
        {
            result.add(classField);
        }
    }

1
ดูเหมือนจะไม่เป็นความจริงอย่างแน่นอนที่คุณต้องทำซ้ำผ่านชั้นเรียนพิเศษด้วยตัวเอง c.getFields () หรือ c.getField () จะค้นหาฟิลด์โดยอัตโนมัติบนอินเทอร์เฟซการใช้งานแต่ละรายการและเรียกซ้ำผ่านซูเปอร์คลาสทั้งหมด ดังนั้นแค่เปลี่ยนไปใช้ getX จาก getDeclaredX ก็เพียงพอแล้ว
PrzemysławŁadyński

3
อันที่จริงรูทีน getFields () จะช่วยให้คุณสามารถดึงฟิลด์สำหรับซุปเปอร์คลาสและอินเทอร์เฟซทั้งหมดได้ แต่เฉพาะแบบสาธารณะเท่านั้น โดยปกติเขตข้อมูลจะถูกทำให้เป็นส่วนตัว / มีการป้องกันและถูกเปิดเผยผ่าน getters / setters
Marius

@ มาริอุสฉันขอทราบได้ไหมว่าแพ็คเกจคือBaseValidationObjectอะไร?
randytan

@Randytan ซึ่งมีอยู่ในที่เก็บรหัสส่วนตัวของฉันคุณสามารถแทนที่ด้วย Object เช่นเดียวกับการเรียก Logger แบบคงที่แทนที่ด้วยคนตัดไม้ของคุณเอง (อินสแตนซ์)
Marius

@Marius ชั้นไม่ได้มีวิธีการobject getMethods()คำแนะนำใด ๆ ?
randytan

127

คุณควรส่งวัตถุเพื่อรับเมธอดของฟิลด์ดังนั้น

  Field field = object.getClass().getDeclaredField(fieldName);    
  field.setAccessible(true);
  Object value = field.get(object);

6
คุณรู้หรือไม่ว่าทำไมต้องใช้ object ใน field.get (object) - field นั้นมาจาก object นั้นทำไมมันถึงต้องการมันอีก!?
serup

19
@serup ไม่ใช่วัตถุฟิลด์มาจากคลาสอ็อบเจ็กต์ซึ่งไม่มีการเชื่อมต่อกับอินสแตนซ์จริงของคุณ ( object.getClass()จะส่งคืนวัตถุคลาสนี้ให้คุณ)
Dmitry Spikhalskiy

1
objectไม่ได้กำหนดไว้ในตัวอย่างข้อมูลดังนั้นผู้อ่านจึงไม่เข้าใจวิธีใช้
Ghilteras

@Ghilteras ในกรณีนั้นพวกเขาไม่ควรใช้การสะท้อนและรับทักษะพื้นฐานก่อน 🤷🏻‍♂️ การสะท้อนกลับเป็นหัวข้อขั้นสูงเพียงพอที่จะไม่อธิบายว่าตัวแปรobjectหมายถึงวัตถุ / อินสแตนซ์เป้าหมายของเราที่เราทำงานด้วย ฉันคิดว่าผู้อ่านเข้าใจดีกับสิ่งที่อยู่objectในคำตอบนี้
Dmitry Spikhalskiy

@RajanPrasad ไม่ได้จริงๆ มีวัตถุชิ้นเดียวในคำถามที่มีชื่อ "วัตถุ" วัตถุอื่นมีชื่ออื่น คำตอบนั้นแม่นยำและเหมาะสำหรับคำถามและสำหรับชื่อที่ใช้ในคำถามเพื่อให้สิ่งต่างๆชัดเจนที่สุด หากไม่ได้ผลสำหรับคุณ - ฉันไม่รู้ว่าจะทำอย่างไรให้ชัดเจนยิ่งขึ้นและคุณควรลองใช้คำตอบอื่น ๆ หรืออาจหลีกเลี่ยงการไตร่ตรอง
Dmitry Spikhalskiy

19

ฉันใช้การสะท้อนในการใช้ toString () ของคลาสความชอบของฉันเพื่อดูสมาชิกคลาสและค่าต่างๆ (การดีบักแบบง่ายและรวดเร็ว)

รหัสแบบง่ายที่ฉันใช้:

@Override
public String toString() {
    StringBuilder sb = new StringBuilder();

    Class<?> thisClass = null;
    try {
        thisClass = Class.forName(this.getClass().getName());

        Field[] aClassFields = thisClass.getDeclaredFields();
        sb.append(this.getClass().getSimpleName() + " [ ");
        for(Field f : aClassFields){
            String fName = f.getName();
            sb.append("(" + f.getType() + ") " + fName + " = " + f.get(this) + ", ");
        }
        sb.append("]");
    } catch (Exception e) {
        e.printStackTrace();
    }

    return sb.toString();
}

ฉันหวังว่ามันจะช่วยใครบางคนเพราะฉันก็ค้นหาเช่นกัน


12

แม้ว่าจะไม่ชัดเจนสำหรับฉันว่าคุณกำลังพยายามบรรลุอะไร แต่ฉันก็พบข้อผิดพลาดที่ชัดเจนในโค้ดของคุณ: Field.get()คาดว่าออบเจ็กต์ที่มีฟิลด์เป็นอาร์กิวเมนต์ไม่ใช่ค่า (เป็นไปได้) ของฟิลด์นั้น field.get(object)ดังนั้นคุณควรจะมี

เนื่องจากดูเหมือนว่าคุณกำลังมองหาค่าฟิลด์คุณสามารถรับได้ดังนี้:

Object objectValue = field.get(object);

ไม่จำเป็นต้องสร้างอินสแตนซ์ประเภทฟิลด์และสร้างค่าว่าง / ค่าเริ่มต้น หรืออาจจะมีบางอย่างที่ฉันพลาดไป


2
objectไม่ได้กำหนดไว้ผู้อ่านไม่เข้าใจวิธีใช้คำตอบ
Ghilteras

10
 Integer typeValue = 0;
 try {
     Class<Types> types = Types.class;
     java.lang.reflect.Field field = types.getDeclaredField("Type");
     field.setAccessible(true);
     Object value = field.get(types);
     typeValue = (Integer) value;
 } catch (Exception e) {
     e.printStackTrace();
 }

4

คุณกำลังโทรหาข้อโต้แย้งที่ไม่ถูกต้อง

มันควรจะเป็น:

Object value = field.get(object);

2
objectไม่ได้กำหนดไว้ผู้อ่านไม่เข้าใจวิธีใช้ตัวอย่างในคำตอบ
Ghilteras

2

ฉันโพสต์วิธีแก้ปัญหาของฉันใน Kotlin แต่มันสามารถทำงานกับวัตถุ java ได้เช่นกัน ฉันสร้างส่วนขยายฟังก์ชันเพื่อให้วัตถุใด ๆ สามารถใช้ฟังก์ชันนี้ได้

fun Any.iterateOverComponents() {

val fields = this.javaClass.declaredFields

fields.forEachIndexed { i, field ->

    fields[i].isAccessible = true
    // get value of the fields
    val value = fields[i].get(this)

    // print result
    Log.w("Msg", "Value of Field "
            + fields[i].name
            + " is " + value)
}}

ดูที่หน้าเว็บนี้: https://www.geeksforgeeks.org/field-get-method-in-java-with-examples/


1
    ` 
//Here is the example I used for get the field name also the field value
//Hope This will help to someone
TestModel model = new TestModel ("MyDate", "MyTime", "OUT");
//Get All the fields of the class
 Field[] fields = model.getClass().getDeclaredFields();
//If the field is private make the field to accessible true
fields[0].setAccessible(true);
//Get the field name
  System.out.println(fields[0].getName());
//Get the field value
System.out.println(fields[0].get(model));
`
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.