2016-08-12 2 views
1

У меня есть класс Context. Он должен быть передан и использован в другом конструкторе класса - называется, скажем, менеджером. Но переменная контекста должна быть также реализацией MyInterface, которая обязывает реализовать requireMethod(). Поэтому я хотел бы быть что-то вроде:Параметр метода - одновременно требует как класс, так и интерфейс

class Manager { 
    Manager(Context context) { 
     context.doSomeStandardContextStuff(); 
     if (context instanceof MyInterface) { 
      context.requiredMethod() 
     } 
    } 
} 

Однако составитель и IDE сказать мне, что requiredMethod() не может быть решена.

Итак, я обязан решить эту проблему, чтобы создать «искусственный» другой класс, который простирается от класса Context и реализует MyInterface - только для того, чтобы использовать его как один объект в конструкторе выше? Или есть лучшее решение для этого?

Редактировать: Хорошо, спасибо вам, ребята, за очень интересную дискуссию и помощь в изучении новых вещей.

Чтобы увидеть код работает с кастинг на интерфейсной подход, смотрите здесь (легко собрать и запустить онлайн): http://www.tutorialspoint.com/compile_java_online.php?PID=0Bw_CjBb95KQMekxoTU4zV0JFVms

+1

try: ((MyInterface) context) .requiredMethod() – ByeBye

+2

В вашем операторе 'if' вы можете гарантировать, что' context' является 'MyInterface', поэтому просто добавьте его:' ((MyInterface) context) .requiredMethod() ' – Zircon

+0

Не могли бы вы переопределить' doSomeStandardContextStuff() 'на этом объекте, чтобы он дополнительно вызывал' requiredMethod() 'изнутри? Ваш пример довольно загадочный, поэтому я не уверен, что он подойдет. – 4castle

ответ

2

Проверяется, если переменная является экземпляром типа во время выполнения:

if (context instanceof MyInterface) 

Но это не разрешает переменную этого типа во время компиляции. Чтобы сделать это, вы можете бросить его:

if (context instanceof MyInterface) { 
    ((MyInterface)context).requiredMethod() 
} 
+0

Ничего себе, это действительно работает. Не знал, что Java может отнести класс к интерфейсу, который находится за пределами определенной иерархии классов. Thx много, не нужно создавать «класс мусора» на Java. – forsberg

+0

@forsberg: Технически вы можете * попробовать * отличать любые типы ссылок, независимо от их полиморфного отношения или его отсутствия. Если переменная этого типа во время выполнения, все будет хорошо. – David

+0

Это скомпилируется, но если вы прочтете новые комментарии OP, это не решит проблему дизайна. Оператор 'instanceof' никогда не будет' true', так как у них нет классов, которые расширяют оба. – 4castle

4

Вы можете сделать конструктор родовое, и имеют двойной тип, связанный:

<T extends Context & MyInterface> Manager(T context) { 
    context.doSomeStandardContextStuff(); 
    context.requiredMethod(); 
} 

Это избавляет от необходимости бросить совсем.


Однако вы также можете указать тип реализации. т.е .:

class Implementation extends Context implements MyInterace {...} 
Manager(Implementation i) {...} 

Или, в случае, у вас есть несколько реализаций, создать общую супертип:

abstract class Union extends Context implements MyInterface {} 
class Implementation extends Union {...} 
Manager(Union u) {...} 

Union был бы фиктивным классом, но все равно был бы более эффективным, чем общая версия.

Поскольку общая версия стирается, чтобы Context в качестве параметра, и должна быть брошена (за кадром), чтобы MyInterface каждый раз, когда вы хотите вызвать метод из MyInterface.

+0

Мне нравится подход с ограниченным типом, потому что он дает вам безопасность типа (вы получаете ошибку компиляции при попытке передать объект, который не реализует интерфейс) и очищает код, когда вам не нужно выполнять операции типа- Кастинг. –

+0

Интересно, спасибо. – forsberg

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