1

这是一个实际的问题,但我不确定它是否有实际的答案。如果你有一个超类,假设有 10 个子类,那么将这 10 个子类放在一个集合中的最简单方法是什么?现在(这可能是糟糕的设计),我已将它们放在超类的静态集合字段中。

然而,提出这个问题的动机是因为我获得了其中一个子类的字段之一的身份,但我需要引用同一子类中的不同字段。

例如,假设子类具有以下字段:

public class SampleSubClass extends SampleSuperClass{
...
private Object1 o_1;
private Object2 o_2;
private Object3 o_3;
...
}

在程序的其他地方,我只有 o_2 的身份,我想在 o_3 处获得。理论上,可能有比将 SampleClass 的所有实例放在某个集合中更简单的方法。例如,也许在我的梦想中,有一种软件语言,超类确实携带有关其子类的信息,而超类本身就是一个集合。

但没关系。现在对我来说,将集合放在程序中的某个位置似乎是一种好方法,即使用哈希图/哈希表,并将其用作超类的静态成员。

请告诉我有更好的方法。有没有办法通过只引用对象中的字段 B 来引用对象中的字段 A?

例如,假设我有一个 ActionPerformed 方法,它有一个包含在 ActionEvent 对象参数中的源对象。我如何找到拥有/包含该源对象的类的实例?设计这个的最佳方法是什么?

4

2 回答 2

2

给定字段引用的对象,没有本地方法可以找到字段的所有者。JVM 记录指向每个对象的引用数,以便它可以进行垃圾收集,但它不会跟踪引用的所有者。

您可以将所有字段的值存储在将Map它们映射到其所有者的 a 中:

import java.util.*;

public class Super
{
    static Map<Object, Super> owners = new IdentityHashMap<Object, Super>();
    // IdentityHashMap will not work with primitives due to autoboxing,
    // but HashMap requires all field values to have sensible implementations
    // of hashCode() and equals().

    /** Gets the owner associated with a field. */
    public static Object getOwner(Object field)
    {
        return owners.get(field);
    }

    /** Establishes ownership over a field. */
    protected void own(Object field)
    {
        owners.put(field, this);
    }

    /** Removes an ownership, but only if this is the owner. */
    protected void disown(Object field)
    {
        if (owners.get(field) == this) owners.remove(field);
    }

    /** Shorthand for disown(oldField); own(newField). */
    protected <T> T change(T oldField, T newField)
    {
        disown(oldField);
        own(newField);
        return newField;
    }
}

public class SubA extends Super
{
    protected String s;
    protected Integer i;

    public SubA(String aString, Integer anInt) { setS(aString); setI(anInt); }
    public void setS(String aString) { s = change(s, aString); }
    public void setI(Integer anInt) { i = change(i, anInt); }
    public String toString() { return "SubA(" + s + "," + i + ")"; }
}

public class SubB extends Super
{
    protected Object o;

    public SubB(Object anObject) { setO(anObject); }
    public void setO(Object anObject) { o = change(o, anObject); }
    public String toString() { return "SubB(" + o + ")"; }
}

public class Demo
{
    public static void main(String[] args)
    {
        String s1 = "String1", s2 = "String2", s3 = "String3";
        Integer i1 = 111, i2 = 222;
        Object o1 = new Object(), o2 = new Object();

        SubA a1 = new SubA(s1, i1), a2 = new SubA(s2, i2);
        SubB b = new SubB(o1);

        p("s1 owner = %s", Super.getOwner(s1)); // SubA(String1,111)
        p("s2 owner = %s", Super.getOwner(s2)); // SubB(String2,222)
        p("s3 owner = %s", Super.getOwner(s3)); // null
        p("i1 owner = %s", Super.getOwner(i1)); // SubA(String1,111)
        p("i2 owner = %s", Super.getOwner(i2)); // SubA(String2,222)
        p("o1 owner = %s", Super.getOwner(o1)); // SubB(java.lang.Object@...)
        p("o2 owner = %s", Super.getOwner(o2)); // null

        p("s1 -> s3, o1 -> o2");
        a1.setS(s3);
        b.setO(o2);

        p("s1 owner = %s", Super.getOwner(s1)); // null
        p("s3 owner = %s", Super.getOwner(s3)); // SubA(String3,111)
        p("o1 owner = %s", Super.getOwner(o1)); // null
        p("o2 owner = %s", Super.getOwner(o2)); // SubB(java.lang.Object@...)
    }

    static void p(String fmt, Object... args)
    {
        System.out.format(fmt, args);
        System.out.println();
    }
}

或者,您可以通过继承或使用包装类使字段值本身维护对其所有者的引用:

public class OwnableObject
{
    protected Object owner;

    public OwnableObject(Object anOwner) { owner = anOwner; }
    public Object getOwner() { return owner; }
    public void setOwner(Object anOwner) { owner = anOwner; }
}

public class MyString extends OwnableObject
{
    protected String str = null;

    public MyString(Object anOwner) { super(anOwner); }
    public String toString() { return str; }
    public void set(String aString) { str = aString; }
}

public class FieldWrapper<E> extends OwnableObject
{
    protected E value = null;

    public FieldWrapper(Object anOwner) { super(anOwner); }
    public E getValue() { return value; }
    public void setValue(E aValue) { value = aValue; }
}

public class Demo
{
    protected MyString s = new MyString(this);
    protected FieldWrapper<Integer> i = new FieldWrapper<Integer>(this);

    public void setS(String aString) { s.set(aString); }
    public void setI(int anInt) { i.setValue(anInt); }
    public String toString() { return "Demo(" + s + "," + i.getValue() + ")"; }

    public static void main(String[] args)
    {
        Demo d1 = new Demo();
        Demo d2 = new Demo();

        MyString f1 = d1.s;
        FieldWrapper<Integer> f2 = d1.i;
        OwnableObject f3 = d2.s;
        OwnableObject f4 = d2.i;

        d1.setS("one");
        d2.setS("two");
        d1.setI(1000);
        d2.setI(2000);

        p("f1 = %s, owner = %s", f1, f1.getOwner());
        p("f2 = %d, owner = %s", f2.getValue(), f2.getOwner());
        p("f3 = %s, owner = %s", f3, f3.getOwner());
        p("f4 = %s, owner = %s", f4, f4.getOwner());
    }

    static void p(String fmt, Object... args)
    {
        System.out.format(fmt, args);
        System.out.println();
    }
}
于 2013-06-05T05:38:41.333 回答
1

回答您的直接问题:如何轻松定义包含给定类集的集合?

public class ClassA {
    private final List<Class<? extends a>> knownSubclasses = Arrays.asList(ClassB.class, ClassC.class);
};
class ClassB extends ClassA {}
class ClassC extends ClassA {}

回答您的动机:如何在不为超类声明的情况下访问子类中的字段?

public class SomeSuperclass {
    protected Object3 getObject3() throws UnsupportedOperationException {
        throw new UnsupportedOperationException();
    }
}
public class SomeSubclass extends SomeSuperclass {
     private final Object3 object3 = null;
     @Override
     protected Object3 getObject3() { return object3; }
}

也许通过使用接口识别具有 object3 的实例

public interface MyClassWithObject3 { Object3 getObject3(); }

...
void someOperation(SomeSuperclass that) {
   if (that instanceof MyClassWithObject3) { ... }
}

您还可以使用命名属性

void someOperation(SomeSuperClass that) {
    Object3 object3 = that.getProperty("object3");
}
于 2013-06-05T00:24:38.543 回答