英文:
Get subclass back when stored as superclass
问题
// 以下是翻译后的内容:
我已经试了几个小时,但始终无法解决这个问题。
基本上,我有一个类 `A`,还有一个扩展了 `A` 的类 `B`。`A` 有一个字符串字段 "name",还有另一个字段 "id",类 `B` 在实例化时会修改 `name`。然后将 `B` 以 `A` 的形式存储,唯一将 `A` 类与 `B` 类关联的是 "id" 字段。
我需要一种方法,从 `A` 类中获取 `B` 类已更改的 "name"。
以下是代码示例:
```java
class A {
public String name = "test";
public String id = "A_ID";
public A(String id) {
if (id.equals("B_ID")) {
// 如何在不实例化 B 的情况下获取 B 类的 name 字段
}
}
}
class B extends A {
{
name = "test1";
id = "B_ID";
}
}
以下是我尝试过的方法:
class A {
public static Map<String, Class<? extends A>> REGISTRY = new HashMap<>();
public String name = "test";
public String id = "A_ID"; // 当更改时为 B_ID
public Object getField(String key) {
Field field = REGISTRY.get(this.id).getSuperclass().getDeclaredField(key);
return field.get(this); // <- 问题出在这里
}
}
class B extends A {
static {
REGISTRY.put("B_ID", B.class);
}
public B() {
name = "test1";
id = "B_ID";
}
}
我的解决方案存在问题,将 this
传递给 field.get(this)
会返回当前 A 对象的字段,而我们已经拥有这些字段了。我需要从 B
获取在实例化时 B
类所更改的字段,但是当实例化 B
时会多次调用 getField
,从而导致无限循环,我需要一种在不实例化 B
的情况下从 B
获取字段的方法。
我尝试过将 A
强制转换为 B
,但会导致 ClassCastException。
抱歉这很令人困惑,我无法发送整个类,因为它实际上有 1000 多行,但基本上 ID 字段是与 A 一起存储且在 B 中保留的唯一数据,我需要一种在不实例化 B 的情况下获取来自 B 的字段的方法。
编辑:我认为我的示例可能会令人困惑,以下是 pkm 回答仍然存在问题的示例:
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
class A {
public static Map<String, Class<? extends A>> REGISTRY = new HashMap<>();
public String name = "test";
public String id; // 当更改时为 B_ID
public A(String id) {
this.id = id;
this.getField("name"); // 应该输出 test1
}
public Object getField(String key) throws NoSuchFieldException, SecurityException,
IllegalArgumentException, IllegalAccessException {
Field field = REGISTRY.get(this.id).getSuperclass().getDeclaredField(key);
return field.get(this); // <- 问题仍然存在,仍然返回 "test"
}
}
class B extends A {
static {
REGISTRY.put("B_ID", B.class);
}
public B() {
super("B_ID");
name = "test1";
}
}
public class main {
public static void main(String[] args) throws NoSuchFieldException, SecurityException,
IllegalArgumentException, IllegalAccessException {
new B(); // 更新注册表
A a = new A("B_ID");
System.out.println(a.id); //--》输出:B_ID
System.out.println(a.getField("name")); //--》输出:test,应该是 test1
}
}
英文:
So I've been trying to fix this for a few hours now, to no avail.
Basically, I have class A
, and class B
which extends A
. A
has a string field "name", and another field "id", class B
changes name
when instantiated. B
is then later stored as A
, and the only thing identifying that A
class to the B
class is the "id" field.
I need a way to get the changed "name" that the B class has, from the A class.
Here's a code example:
class A {
public String name = "test";
public String id = "A_ID";
public A(String id) {
if (id.equals("B_ID") {
// how would I get the name field of the B class, without instantiating B
}
}
}
class B extends A {
{
name = "test1";
id = "B_ID";
}
}
And here's what I've tried:
class A {
public static Map<String, Class<? extends A>> REGISTRY = new HashMap<>();
public String name = "test";
public String id = "A_ID"; // is B_ID when changed
public Object getField(String key) {
Field field = REGISTRY.get(this.id).getSuperclass().getDeclaredField(key);
return field.get(this); // <- the issue
}
}
class B extends A {
static {
REGISTRY.put("B_ID", B.class);
}
public B() {
name = "test1";
id = "B_ID";
}
}
Here's the problem with my solution, passing this
to field.get(this)
returns the fields of the current A object, which is what we already have. I need the fields that B
changes when instantiated, but when B
gets instantiated it calls getField
a few times, which then causes a perpetual loop, I need a way to get the fields from B
without instantiating B
.
I've tried casting A
to B
but that causes a ClassCastException.
Sorry that this is confusing, I can't send the entire class as it's literally 1k+ lines, but basically the ID field is the only data stored with A that remains from B, and I need a way to get the fields from B without instantiating it
EDIT: I think my example was confusing, here's an example of how pkm's answer still presents the issue.
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
class A {
public static Map<String, Class<? extends A>> REGISTRY = new HashMap<>();
public String name = "test";
public String id; // is B_ID when changed
public A(String id) {
this.id = id;
this.getField("name") // should output test1
}
public Object getField(String key) throws NoSuchFieldException, SecurityException,
IllegalArgumentException, IllegalAccessException {
Field field = REGISTRY.get(this.id).getSuperclass().getDeclaredField(key);
return field.get(this); // <- the issue, still returns "test"
}
}
class B extends A {
static {
REGISTRY.put("B_ID", B.class);
}
public B() {
super("B_ID");
name = "test1";
}
}
public class main {
public static void main(String[] args) throws NoSuchFieldException, SecurityException,
IllegalArgumentException, IllegalAccessException {
new B(); // To update the registry
A a = new A("B_ID");
System.out.println(a.id); //--> output: B_ID
System.out.println(a.getField("name")); //--> output: test, should be test1
}
}
答案1
得分: 0
这是修正后的代码:
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
class A {
public static Map<String, Class<? extends A>> REGISTRY = new HashMap<>();
public String name = "test";
public String id = "A_ID"; // 当更改时变为 B_ID
public Object getField(String key) throws NoSuchFieldException, SecurityException,
IllegalArgumentException, IllegalAccessException {
Field field = REGISTRY.get(this.id).getSuperclass().getDeclaredField(key);
return field.get(this); // <- 存在问题的地方
}
}
class B extends A {
static {
REGISTRY.put("B_ID", B.class);
}
public B() {
name = "test1";
id = "B_ID";
}
}
public class Test {
public static void main(String[] args) throws NoSuchFieldException, SecurityException,
IllegalArgumentException, IllegalAccessException {
A a = new B();
System.out.println(a.name); //---> 输出: test1
System.out.println(a.getField("id")); //---> 输出: B_ID
}
}
根据您的陈述:我需要一种从 A 类获取 B 类已更改的 "name" 的方法。
已经正确实现,B_ID。
英文:
Here is the corrected code:
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
class A {
public static Map<String, Class<? extends A>> REGISTRY = new HashMap<>();
public String name = "test";
public String id = "A_ID"; // is B_ID when changed
public Object getField(String key) throws NoSuchFieldException, SecurityException,
IllegalArgumentException, IllegalAccessException {
Field field = REGISTRY.get(this.id).getSuperclass().getDeclaredField(key);
return field.get(this); // <- the issue
}
}
class B extends A {
static {
REGISTRY.put("B_ID", B.class);
}
public B() {
name = "test1";
id = "B_ID";
}
}
public class Test {
public static void main(String[] args) throws NoSuchFieldException, SecurityException,
IllegalArgumentException, IllegalAccessException {
A a = new B();
System.out.println(a.name); //--> output: test1
System.out.println(a.getField("id")); //--> output: B_ID
}
}
As per your statement: I need a way to get the changed "name" that the B class has, from the A class.
It'a achieved correctly, B_ID.
答案2
得分: 0
已通过将注册表从Class<? extends A>
更改为A
来修复此问题,然后注册B
的新实例。我认为这可能会在将来引起问题,我一直在避免这样做,但目前可以解决。
英文:
Fixed this by changing the registry from Class<? extends A>
to just A
, and then registering a new instance of B
. I think it might lead to issues down the road and I was avoiding doing this but it works for now.
专注分享java语言的经验与见解,让所有开发者获益!
评论