如何扩展由另一个类实例化的java类?

时间:2009-04-30 00:44:49

标签: java inheritance

给定两个java类A和B,其中A通常通过B实例化,例如:

    A myA = B.createA();

我可以创建A的子类(让我们称之为SubA)并以某种方式让它由B.createA()方法实例化吗?

(请注意,我无法修改A和B ....)

我知道并非A的所有实例都是SubA的实例,因此我不能这样做:

    SubA mySubA = B.createA();

同样,我也不能这样投:

    SubA mySubA = (SubA) (B.createA());

出于同样的原因 - 它将获得ClassCastException。

我是否密集并忘记了一些基本的东西,或者没有办法做到这一点?

(后期补充:我很抱歉,我应该提到A和B各有大约50种方法,我想要做的就是给SubA添加一个属性,以及一个getter和一个setter。我我真的不想实现所有50个A的方法来调用超类对象中的相应方法。)

4 个答案:

答案 0 :(得分:3)

这通常通过代理完成:

class SubA extends A {
    private A proxiedClass;

    public SubA(A a) {
        proxiedClass = a;
    }

    public int anyMethodInA() {
        return proxiedClass.anyMethodInA();
    }
}

...

SubA mySubA = new SubA(B.createA());

手动执行此操作相当冗长,因此大多数人使用某种AOP库(如AspectJ)来拦截他们感兴趣的方法调用。

答案 1 :(得分:3)

听起来您真正喜欢的是修改原始AB的行为。在这种情况下,您可以尝试扩展这两个类(其中B的扩展名纯粹是为了指定一个稍微不同的工厂方法来创建SubA)。

class SubA extends A {
    /** This is the one special aspect of SubA justifying a sub-class.
        Using double purely as an example. */
    private double specialProperty;

    public double getSpecialProperty() { return specialProperty; }
    public void setSpecialProperty(double newSP) { specialProperty = newSP; }

    public SubA() {
        super();
        // Important differences between SubAs and As go here....
        // If there aren't any others, you don't need this constructor.
    }

    // NOTE: you don't have to do anything else with the other methods of
    // A.  You just inherit those.
}

class SubB extends B {
    // Purely for the purposes of a slightly different factory method
    public A createA() {
        return new SubA();
    }

    // Or if you need a static method 
    // (this is usually instead of the first choice)
    public static A createA() {
        return new SubA();
    }
}

请注意,此时,您可以创建一个SubB工厂对象,并使其看起来像原始B,如下所示:

B myNewB = new SubB();
A myA = myNewB.createA();

或者,如果您使用的是静态工厂,那么它就不是那么接近匹配(但它很接近)。

A myA = SubB.createA();

现在,如果你真的需要对子属性做一些事情,你可以通过子界面访问它。即,如果你像这样创建对象:

SubA mySubA = SubB.createA();
mySubA.setSpecialProperty(3.14);
double special = mySubA.getSpecialProperty();

编辑以讨论“延迟添加”:

此时,您的SubA对象应该正是您想要的。它将从父级(A)继承50个方法,您可以将其他属性添加到子级,以及getter和setter。我改变了上面的代码来说明我的意思。

答案 2 :(得分:1)

你可以在它周围创建一个包装器,SubA有一个以A为参数的构造函数。

像这样:

SubA mySubA = new SubA(B.createA());

由于SubA的所有实例都是A的实例,您可以将其分配给现有的A变量并覆盖任何必要的方法。

A myA = new SubA(B.createA());

我想不出任何其他干净的方式。

答案 3 :(得分:1)

如果您只是想在没有面向对象的情况下向A添加字段(例如更改行为),则可以将其添加为“外部字段”。使用WeakHashMapA的实例映射到字段值(只要字段值不直接或间接引用A,或者您将拥有对象生命周期争用问题):

private static final Map<A,FieldType> map =
    new java.util.WeakHashMap<A,FieldType>(); // thread-safe from 1.6, IIRC

public static FieldType getField(A a) {
    return map.get(a);
}
public static void setField(A a, FieldType value) {
    map.set(a, value);
}

我们真的应该使用WeakIdentityHashMap,但它在Java库中不存在!