Damn Vegetables
Damn Vegetables

Reputation: 12464

Java, can I apply an arbitrary interface to an existing class?

If two classes have some methods of exact same signature, but those methods are not inherited, is there any way to define an interface with the common methods and point both instances of the two classes using the same interface?

For example, suppose a class Cat has boolean isAlive() and another class Dog has boolean isAlive() but Cat and Dog has no common ancestor other than Object and boolean isAlive() is not an inherited method. I cannot modify Cat or Dog because they were written by others. Can I arbitrarily create an interface like that and use it to point a Cat or a Dog?

interface lovable
{
    boolean isAlive();
}

void main()
{
    lovable thing = new Cat(); <-- any syntax to achieve this?
    love(thing);
}

void love(lovable thing)
{
    if (thing.isAlive())
        System.out.println("Aww.");
    else
        System.out.println("Eww.");
}

Upvotes: 5

Views: 5015

Answers (3)

Aleksei Shestakov
Aleksei Shestakov

Reputation: 2538

You can create Proxy object as was mentioned in Can you force a java object into implementing an interface at runtime? :

public interface Loveable {
    boolean isAlive();
}

public static class Cat {
    boolean isAlive() {
        return true;
    }
}

public static class Dog {
    boolean isAlive() {
        return false;
    }
}

public static <T> T getWrapper(final Object obj, final Class<T> intface) {
    InvocationHandler invocationHandler = new InvocationHandler() {
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            return obj.getClass().getDeclaredMethod(method.getName(), method.getParameterTypes()).invoke(obj, args);
        }
    };
    return (T) Proxy.newProxyInstance(obj.getClass().getClassLoader(), new Class[]{intface}, invocationHandler);
}

public static void main(String[] args) throws Exception {
    System.out.println(getWrapper(new Cat(), Loveable.class).isAlive());
    System.out.println(getWrapper(new Dog(), Loveable.class).isAlive());
}

Upvotes: 7

Eugene Kirin
Eugene Kirin

Reputation: 578

You can't because your types (Cat, Dog) have to implement your interface. How ever you have 2 solutions if this classes from some lib. The first to use wrapper as was mentioned and the second to use reflection. I suppose the lib www.eclipse.org/aspectj could help you to implement this with minimal afforts.

Upvotes: 0

Ken Bekov
Ken Bekov

Reputation: 14015

If you create it by yourself:

public interface Lovable{
    boolean isAlive();
}

public class LovableCat extends Cat implements Lovable{

}

public static void main() {
    Lovable thing = new LovableCat();
    love(thing);
}

If returned from somewhere else:

public interface Lovable{
    boolean isAlive();
}

public class LovableCat implements Lovable{

    private Cat cat;

    public LovableCat(Cat cat){
       this.cat = cat;
    }

    public boolean isAlive(){
       return cat.isAlive();
    }
}

public static void main() {
    Lovable thing = new LovableCat(cat);
    love(thing);
}

Upvotes: 5

Related Questions