2016-02-26 2 views
0

Если у двух классов есть методы точной такой же подписи, но эти методы не наследуются, есть ли способ определить интерфейс с общими методами и указать оба экземпляра этих двух классов с использованием одного и того же интерфейса?Java, могу ли я применить произвольный интерфейс к существующему классу?

Например, предположим, что класс Cat имеет boolean isAlive() и другой класс Dog имеет boolean isAlive() но Cat и Dog не имеет общего предка, кроме Object и boolean isAlive() не является унаследованный метод. Я не могу изменить Cat или Dog, потому что они были написаны другими. Могу ли я произвольно создать такой интерфейс и использовать его, чтобы указать Cat или 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."); 
} 
+0

'class Cat реализует привлекательные' – QBrute

+3

http://stackoverflow.com/questions/5196941/can-you-force-a-java-object-into-implementing-an-interface-at-runtime –

+1

@QBrute to cite OP: «Я не могу изменить Cat или Dog, потому что они были написаны другими». так что это не представляется возможным/выполнимым. – Thomas

ответ

1

Вы можете создать объект Proxy, как было упомянуто в 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()); 
} 
+0

Благодарим вас за подробный пример. Хотя это может быть сложнее, чем я думал, это, безусловно, показало мне интересную возможность, на которую способен Java. –

+0

Можем ли мы обобщить 'Loveable' в getWrapper(), чтобы мы могли повторно использовать его для других интерфейсов? –

+0

Да, обновил мой ответ. –

3

Если вы создаете его сами:

public interface Lovable{ 
    boolean isAlive(); 
} 

public class LovableCat extends Cat implements Lovable{ 

} 

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

Если вернулся откуда-то еще:

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

Любопытный: Почему бы не «публичный класс LovableCat расширяет Cat реализует Lovable'? – bradimus

+0

Хорошая идея. Но в любом случае вам нужно реализовать 'isLovable();' –

+0

@bradimus Извините, я только что протестировал, и вы правы! Он работает правильно .... –

0

Вы не можете, потому что ваши типы (кошки, собаки) должны реализовать интерфейс. Как бы то ни было, у вас есть 2 решения, если эти классы из какой-либо библиотеки. Первый, чтобы использовать обертку, как было упомянуто, а второе - использовать отражение. Я полагаю, что lib www.eclipse.org/aspectj может помочь вам реализовать это с минимальными затратами.

Смежные вопросы