以超类形式存储时获取子类返回

huangapple 未分类评论44阅读模式
英文:

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 = &quot;test&quot;;
	public String id = &quot;A_ID&quot;;
	
	public A(String id) {
		if (id.equals(&quot;B_ID&quot;) {
			// how would I get the name field of the B class, without instantiating B
		}
	}
}
class B extends A {
	{
		name = &quot;test1&quot;;
		id = &quot;B_ID&quot;;
	}
}

And here's what I've tried:

class A {
	public static Map&lt;String, Class&lt;? extends A&gt;&gt; REGISTRY = new HashMap&lt;&gt;();
	
	public String name = &quot;test&quot;;
    public String id = &quot;A_ID&quot;; // is B_ID when changed
	
	public Object getField(String key) {
		Field field = REGISTRY.get(this.id).getSuperclass().getDeclaredField(key);
        return field.get(this); // &lt;- the issue
	}
}
class B extends A {
	static {
		REGISTRY.put(&quot;B_ID&quot;, B.class);
	}
    public B() {
		name = &quot;test1&quot;;
        id = &quot;B_ID&quot;;
    }

}

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&lt;String, Class&lt;? extends A&gt;&gt; REGISTRY = new HashMap&lt;&gt;();

    public String name = &quot;test&quot;;
    public String id; // is B_ID when changed

    public A(String id) {
        this.id = id;
        this.getField(&quot;name&quot;) // 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); // &lt;- the issue, still returns &quot;test&quot;
    }
}


class B extends A {
    static {
        REGISTRY.put(&quot;B_ID&quot;, B.class);
    }

    public B() {
        super(&quot;B_ID&quot;);
        name = &quot;test1&quot;;
    }
}

public class main {

    public static void main(String[] args) throws NoSuchFieldException, SecurityException,
            IllegalArgumentException, IllegalAccessException {
        new B(); // To update the registry
        A a = new A(&quot;B_ID&quot;);
        System.out.println(a.id);                //--&gt; output: B_ID
        System.out.println(a.getField(&quot;name&quot;));      //--&gt; 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&lt;String, Class&lt;? extends A&gt;&gt; REGISTRY = new HashMap&lt;&gt;();

  public String name = &quot;test&quot;;
  public String id = &quot;A_ID&quot;; // 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); // &lt;- the issue
  }
}


class B extends A {
  static {
    REGISTRY.put(&quot;B_ID&quot;, B.class);
  }

  public B() {
    name = &quot;test1&quot;;
    id = &quot;B_ID&quot;;
  }

}


public class Test {
  public static void main(String[] args) throws NoSuchFieldException, SecurityException,
      IllegalArgumentException, IllegalAccessException {
    A a = new B();
    System.out.println(a.name);                //--&gt; output: test1
    System.out.println(a.getField(&quot;id&quot;));      //--&gt; output: B_ID
  }
}

As per your statement: I need a way to get the changed &quot;name&quot; that the B class has, from the A class. It'a achieved correctly, B_ID.

答案2

得分: 0

已通过将注册表从Class&lt;? extends A&gt;更改为A来修复此问题,然后注册B的新实例。我认为这可能会在将来引起问题,我一直在避免这样做,但目前可以解决。

英文:

Fixed this by changing the registry from Class&lt;? extends A&gt; 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.

huangapple
  • 本文由 发表于 2020年7月24日 22:03:01
  • 转载请务必保留本文链接:https://java.coder-hub.com/63075205.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定