如何使用反射获取对象字段的对象引用?

时间:2021-08-25 21:22:18

Note: Every time I go to type up this question, I think I see something, but it never pans out, so for the third or fourth time.

注:每次我去键入这个问题时,我想我看到了一些东西,但它从来没有出现过,所以在第三或第四次。

Synopsis: I am trying to serialize an object that inherits from the base Response class using the Response class, of which the subclass may have non-primitive field types.

概要:我正在尝试使用Response类对继承自基响应类的对象进行序列化,其中的子类可能具有非基元字段类型。

The code is as such (warning: large and not elegant), ordered from the specific class (SpecificResponse), as extended from a common class (CommonResponse), which is a concrete implementation of the abstract class (Response), driven by a test program (Program).

代码是这样的(警告:大而不优雅),来自特定类(特异响应),从公共类(CommonResponse)扩展而来,后者是抽象类(响应)的具体实现,由测试程序(程序)驱动。

// SpecificResponse.java
package com.jdgj.thinking;

public final class SpecificResponse extends CommonResponse {
    public String hell;
    public int trike;
    public short tail;
    public SpecificResponse() {
        super();
    }
}

SpecifcResponse extends CommonResponse:

SpecifcResponse CommonResponse延伸:

// CommonResponse.java
package com.jdgj.thinking;

public class CommonResponse extends Response {
    public int thing2;
    public Value value;
    @Override
    protected void initialize() {
        System.out.println("hello!");
        value = new Value();
    }
}

For testing purposes, I just made a simple Value object:

为了测试目的,我做了一个简单的Value对象:

// Value.java
package com.jdgj.thinking;

public class Value {
    public int five;
}

And, that which does a lot of work, and also the foundation for CommonResponse, the Response class:

做了很多工作,也是CommonResponse课程的基础,Response类:

// Response.java
package com.jdgj.thinking;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;

public abstract class Response {
    public static Class<?> fromClassSignature(List<String> signature) throws IllegalArgumentException, IllegalStateException, ClassNotFoundException {
        if (signature == null || signature.size() == 0) {
            throw new IllegalArgumentException("Null or empty Response class signature.");
        }
        String lastClassName = null;
        for (String line : signature) {
            if (line.startsWith("class:")) {
                lastClassName = line.split(":")[1];
            }
        }
        if (lastClassName == null) {
            throw new IllegalStateException("Could not find the Response class name.");
        }
        Class<?> c = Class.forName(lastClassName);
        lastClassName = null;
        Class<?> sc = c.getSuperclass();
        while (sc != null && !sc.equals(Response.class)) {
            sc = sc.getSuperclass();
        }
        if (sc != null) {
            sc = null;
            return c;
        } else {
            return null;
        }
    }
    protected abstract void initialize();
    private String getFieldSignature(Field field) {
        return "field:" + field.getName() + "|" + field.getType().getCanonicalName();
    }
    private List<String> serializeObject(Class<?> c, Object o) {
        List<String> serialization = new ArrayList<String>(0);
        serialization.add("class:" + c.getName());
        for (Field f : c.getDeclaredFields()) {
            if (!f.isSynthetic() && Modifier.isPublic(f.getModifiers())) {
                StringBuilder sb = new StringBuilder(getFieldSignature(f));
                Class<?> t = f.getType();
                Object value = null;
                try {
                    value = f.get(o);
                    System.out.println(f.getName() + "=" + value);
                    if (t.isPrimitive() || t.equals(String.class)) {
                        sb.append("`" +  value.toString() + "");
                    }
                } catch (NullPointerException e) {
                    if (t.isPrimitive() || t.equals(String.class)) {
                        sb.append("`");
                    } else {
                        System.out.println("UNEXPECTED NULL POINTER EXCEPTION");
                    }
                } catch (IllegalArgumentException e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                } catch (IllegalAccessException e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                } finally {
                    serialization.add(sb.toString());
                    if (value != null) {
                        if (!(t.isPrimitive() || t.equals(String.class))) {
                            serialization.addAll(serializeObject(t, value));
                        }
                    }
                }
                sb = null;
                t = null;
            }
        }
        return serialization;
    }
    private List<String> describeClass(Class<?> c) {
        List<String> description = new ArrayList<String>(0);
        description.add("class:" + c.getName());
        for (Field f : c.getDeclaredFields()) {
            if (!f.isSynthetic() && Modifier.isPublic(f.getModifiers())) {
                description.add(getFieldSignature(f));
                Class<?> t = f.getType();
                if (!(t.isPrimitive() || t.equals(String.class))) {
                    description.addAll(describeClass(t));
                }
                t = null;
            }
        }
        return description;
    }
    public final List<String> getSerializedObject() {
        Class<?> c = getClass();
        List<String> object = new ArrayList<String>(0);
        while (c != null && !c.equals(Response.class)) {
            object.addAll(0, serializeObject(c, this));
            c = c.getSuperclass();
        }
        c = null;
        return object;
    }
    public final List<String> getClassSignature() {
        Class<?> c = getClass();
        List<String> signature = new ArrayList<String>(0);
        while (c != null && !c.equals(Response.class)) {
            signature.addAll(0, describeClass(c));
            c = c.getSuperclass();
        }
        c = null;
        return signature;
    }
}

These classes are driven by a 'dev-test' program for now:

这些类目前由一个“开发测试”程序驱动:

// Program.java
import com.jdgj.thinking.Response;
import com.jdgj.thinking.SpecificResponse;

public class Program {
    private static void printClassSignature(Response response) {
        for (String line : response.getClassSignature()) {
            System.out.println(line);
        }
    }
    private static void printSerializedObject(Response response) {
        for (String line : response.getSerializedObject()) {
            System.out.println(line);
        }
    }
    public static void main(String[] args) {
        String CN_SPECRSP = "com.jdgj.thinking.SpecificResponse";
        Class<?> response = null;
        try {
            response = Response.fromClassSignature(new SpecificResponse().getClassSignature());
        } catch (IllegalArgumentException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        } catch (IllegalStateException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        } catch (ClassNotFoundException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        } finally {
            if (response != null) {
                System.out.println("Expected: " + CN_SPECRSP + "; Actually: " + response.getCanonicalName());
                Response rsp = null;
                try {
                    rsp = (Response)response.newInstance();
                } catch (InstantiationException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } finally {
                    if (rsp != null) {
                        //printClassSignature(rsp);
                        printSerializedObject(rsp);
                        rsp = null;
                    }
                }
                response = null;
            }
        }
    }
}

Here's the output:

输出:

Expected: com.jdgj.thinking.SpecificResponse; Actually: com.jdgj.thinking.SpecificResponse
hell=null
trike=0
tail=0
thing2=0
value=null
class:com.jdgj.thinking.CommonResponse
field:thing2|int`0
field:value|com.jdgj.thinking.Value
class:com.jdgj.thinking.SpecificResponse
field:hell|java.lang.String`
field:trike|int`0
field:tail|short`0

Why does value report null?

为什么value report null?

In both not having and having a constructor defined in CommonResponse to initialize the Value instance, it's still shown as null. If I uncomment the Program.getClassSignature method, the code delves into the Value object to get the five field:

在这两种方法中,都没有定义一个构造函数来初始化值实例,它仍然显示为空。如果我取消对程序的评论。getClassSignature方法,代码深入到Value对象中,得到5个字段:

Expected: com.jdgj.thinking.SpecificResponse; Actually: com.jdgj.thinking.SpecificResponse
class:com.jdgj.thinking.CommonResponse
field:thing2|int
field:value|com.jdgj.thinking.Value
class:com.jdgj.thinking.Value
field:five|int
class:com.jdgj.thinking.SpecificResponse
field:hell|java.lang.String
field:trike|int
field:tail|short
hell=null
trike=0
tail=0
thing2=0
value=null
class:com.jdgj.thinking.CommonResponse
field:thing2|int`0
field:value|com.jdgj.thinking.Value
class:com.jdgj.thinking.SpecificResponse
field:hell|java.lang.String`
field:trike|int`0
field:tail|short`0

I feel as if I've exhausted my Google-fu, and I feel like I'm missing something just.. blatantly obvious, but I cannot think of the reason, or the right query to ask Google. Everyone keeps providing ways to get primitive fields, but that is not what I am seeking. I therefore submit to the guidance of SO.

我觉得我的谷歌功夫已经用完了,我觉得我错过了一些东西。显而易见,但我想不出原因,也想不出问谷歌的正确查询。每个人都在不断地提供获取原始字段的方法,但这不是我想要的。因此,我服从于SO的指导。

1 个解决方案

#1


0  

As Holger said you never initialize that field. You have a initialize() method to do it, but never invoke it. Of course if you call getClassSignature() you get info about your field, actually it's there; you got a field named value of type com.jdgj.thinking.Value in your class, but it never has been instantiated, so that field value is null.

正如霍尔格所说,你从来没有初始化那个字段。您有一个initialize()方法来实现它,但是永远不要调用它。当然,如果你调用getClassSignature()你会得到关于你的字段的信息,实际上它就在那里;你得到一个名为type com.jdgj.thinking的字段。类中的值,但从未实例化过,因此字段值为null。

#1


0  

As Holger said you never initialize that field. You have a initialize() method to do it, but never invoke it. Of course if you call getClassSignature() you get info about your field, actually it's there; you got a field named value of type com.jdgj.thinking.Value in your class, but it never has been instantiated, so that field value is null.

正如霍尔格所说,你从来没有初始化那个字段。您有一个initialize()方法来实现它,但是永远不要调用它。当然,如果你调用getClassSignature()你会得到关于你的字段的信息,实际上它就在那里;你得到一个名为type com.jdgj.thinking的字段。类中的值,但从未实例化过,因此字段值为null。