Question

Given two java classes, A and B, where A is usually instantiated via B, such as:

    A myA = B.createA();

Can I create a subclass of A (let's call it SubA) and somehow have it be instantiated by the B.createA() method?

(Note that I cannot modify A and B....)

I know that not all instances of A are instances of SubA, thus I cannot do this:

    SubA mySubA = B.createA();

Similarly, I cannot cast it like this either:

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

for the same reason -- it will get a ClassCastException.

Am I being dense and forgetting something fundamental, or is there no way to do this?

(Late addition: I'm so sorry, I should have mentioned that A and B have roughly 50 methods each, and all I want to do is add a single property to SubA, along with a getter and a setter. I'd really rather not implement all 50 of A's methods to invoke the corresponding method in the superclass's object.)

Was it helpful?

Solution

It sounds like like what you'd really like is to modify the behavior of both the original A and B. In that case, you could try extending both classes (where the extension of B is purely to specify a slightly different factory method for creating SubAs).

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();
    }
}

Note that at this point, you could create one of your SubB factory objects and make it look like the original B like so:

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

Or, if you're using the static factory instead, it isn't quite as close a match (but it's close).

A myA = SubB.createA();

Now, if you really need to do something with the sub-property, you'll have access to it via the child interface. I.e., if you create the object like so:

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

Edit to discuss "Late addition":

At this point, your SubA object should be exactly what you want. It will inherit the 50 methods from the parent (A) and you can add your additional property to the child, plus the getter and setter. I changed the code above to illustrate what I mean.

OTHER TIPS

This is usually done via a proxy:

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());

Doing this manually is rather verbose, so most people use some kind of a AOP library (like AspectJ) to only intercept method calls they are interested in.

You could create a wrapper around it, with SubA having a constructor that takes A as the parameter.

Like this:

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

Since all instances of SubA are instances of A, you could then assign it to your existing A variable and override any necessary methods.

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

I can't think of any other clean way of doing it.

If you are just wanting to add a field to A without object oriented such as changing behaviour, you could add it as an "external field". Use a WeakHashMap to map from instance of A onto the field value (just so long as the field value doesn't directly or indirectly reference A or you'll have an object life time contention issue):

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);
}

Really we should be using WeakIdentityHashMap, but it doesn't exist in the Java library!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top