Phản ánh chung nhận giá trị trường


132

Tôi đang cố gắng để nhận được giá trị trường thông qua sự phản ánh. Vấn đề là tôi không biết loại trường và phải quyết định nó trong khi nhận giá trị.

Mã này dẫn đến ngoại lệ này:

Không thể đặt trường java.lang.String com .... fieldName thành 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);

Tôi đã cố gắng để đúc, nhưng tôi nhận được lỗi biên dịch:

field.get((targetType)objectValue)

hoặc là

targetType objectValue = targetType.newInstance();

Tôi có thể làm cái này như thế nào?


4
Nhìn vào API , đối số field.get()nên là object, không objectValue.
akaIDIOT

Câu trả lời:


144

Giống như đã trả lời trước, bạn nên sử dụng:

Object value = field.get(objectInstance);

Một cách khác, đôi khi được ưa thích hơn, là gọi getter một cách linh hoạt. mã ví dụ:

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;
}

Cũng lưu ý rằng khi lớp của bạn kế thừa từ một lớp khác, bạn cần xác định đệ quy Trường. ví dụ, để tìm nạp tất cả các Trường của một lớp nhất định;

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

1
có vẻ như không chính xác rằng bạn cần phải lặp đi lặp lại qua các siêu lớp. C.getFields () hoặc c.getField () sẽ tự động tìm kiếm trường trên mỗi giao diện hiện thực và đệ quy thông qua tất cả các siêu lớp. Vậy là đủ để chuyển sang getX từ getDeclaredX.
Przemysław adyński

3
Thật vậy, thường trình getFields () sẽ cho phép bạn tìm nạp các trường cho tất cả các siêu lớp và giao diện, nhưng chỉ các lớp công khai. Thông thường, các trường được đặt ở chế độ riêng tư / được bảo vệ và được hiển thị thông qua getters / setters.
Marius

@Marius, tôi có thể biết gói là BaseValidationObjectgì không?
randytan

@Randytan, nó chứa trong kho mã riêng của tôi, bạn có thể thay thế nó bằng Object. Điều tương tự cũng áp dụng cho các cuộc gọi Logger tĩnh, thay thế chúng bằng logger (ví dụ) của riêng bạn.
Marius

@Marius objectlớp không có phương pháp getMethods(). Có lời khuyên nào không?
randytan

127

Bạn nên truyền đối tượng để lấy phương thức của trường , vì vậy

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

6
Bạn có biết lý do tại sao đối tượng phải được sử dụng trong trường.get (đối tượng) - chính trường đó xuất phát từ đối tượng đó, tại sao nó lại cần nó!?
serup

18
@serup Không, đối tượng Trường đến từ đối tượng Class, không có kết nối với thể hiện thực của bạn. ( object.getClass()sẽ trả lại cho bạn đối tượng Class này)
Dmitry Spikhalskiy

1
objecttrong đoạn trích không được xác định để người đọc không thể hiểu cách sử dụng nó.
Ghilteras

@Ghilteras trong trường hợp đó, họ chưa nên sử dụng phản xạ và nhận được một số kỹ năng cơ bản trước tiên. Sự phản chiếu là một chủ đề đủ nâng cao để không giải thích rằng một biến objectcó nghĩa là đối tượng / đối tượng mục tiêu mà chúng ta làm việc cùng. Tôi nghĩ rằng độc giả thực sự hoàn toàn ổn với objectcâu trả lời này là gì .
Dmitry Spikhalskiy

@RajanPrasad Không thực sự. Có một đối tượng trong câu hỏi có tên 'đối tượng'. Các đối tượng khác có tên khác. Câu trả lời là chính xác và phù hợp cho các câu hỏi và cho các tên được sử dụng trong câu hỏi để làm cho mọi thứ rõ ràng nhất có thể. Nếu nó không hiệu quả với bạn - tôi không biết làm thế nào để nó rõ ràng hơn và bạn nên thử các câu trả lời khác hoặc có thể tránh phản xạ chưa.
Dmitry Spikhalskiy

19

Tôi sử dụng các phản xạ trong triển khai toString () của lớp ưu tiên của tôi để xem các thành viên và giá trị của lớp (gỡ lỗi đơn giản và nhanh chóng).

Mã đơn giản hóa tôi đang sử dụng:

@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();
}

Tôi hy vọng rằng nó sẽ giúp được ai đó, vì tôi cũng đã tìm kiếm.


12

Mặc dù tôi không thực sự rõ ràng với những gì bạn đang cố gắng đạt được, tôi đã phát hiện ra một lỗi rõ ràng trong mã của bạn: Field.get()mong muốn đối tượng chứa trường làm đối số, không phải giá trị (có thể) của trường đó. Vì vậy, bạn nên có field.get(object).

Vì bạn dường như đang tìm kiếm giá trị trường, bạn có thể có được giá trị đó như sau:

Object objectValue = field.get(object);

Không cần khởi tạo loại trường và tạo một số giá trị trống / mặc định; hoặc có thể có một cái gì đó tôi đã bỏ lỡ.


2
objectkhông được xác định, độc giả không thể hiểu làm thế nào để áp dụng câu trả lời.
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

Bạn đang gọi get với đối số sai.

Nó nên là:

Object value = field.get(object);

2
objectkhông được xác định, độc giả không thể hiểu cách áp dụng ví dụ trong câu trả lời
Ghilteras

2

Tôi đăng giải pháp của mình trong Kotlin, nhưng nó cũng có thể hoạt động với các đối tượng java. Tôi tạo một phần mở rộng hàm để bất kỳ đối tượng nào cũng có thể sử dụng hàm này.

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)
}}

Hãy xem trang web này: https://www.geekforgeek.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));
`
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.