#java #class #interface #casting
#java #класс #интерфейс #Кастинг
Вопрос:
У меня есть вопрос об интерфейсе и интерфейсе реализации класса.
Это мой код:
interface iMyInterface {
public iMethod1();
}
public class cMyClass implements iMyInterface {
public iMethod1() {
// some code
}
protected iMethod2() {
// some code
}
}
Я хотел бы создать экземпляр iMyInterface
как это :
iMyInterface i = new cMyClass();
i.iMethod1();
Все в порядке, но как я могу вызвать iMethod2()
из своего экземпляра интерфейса? Это работает и безопасно:
((cMyClass)i).iMethod2();
Спасибо за помощь.
Ответ №1:
Да, это будет работать (если вы измените объявление cMyClass
на iMyInterface
implementate ), и это безопасно, если ссылка действительно ссылается на экземпляр cMyClass
.
Однако, как правило, это плохая идея. Весь смысл использования интерфейса заключается в том, чтобы иметь возможность работать с любой реализацией — это отделить абстракцию от реализации. Если вам затем потребуется конкретная реализация, вы могли бы также создать тип i
только cMyClass
для начала.
Итак, предположим, что вместо самостоятельного вызова cMyClass
конструктора вы получаете параметр метода типа iMyInterface
— это плохая идея для приведения cMyClass
в этот момент, поскольку это может быть другая реализация интерфейса.
(Отдельно следует отметить, что неплохо бы начать следовать соглашениям об именовании Java, в которых говорится, что классы и интерфейсы должны быть обработаны на языке Pascal, поэтому отбросьте префиксы c
and i
.)
Комментарии:
1. Я думаю, что, если он собирается выполнить приведение, он должен проверить приведение с
instanceof
помощью, чтобы быть в безопасности.2. @S.L.Barth: если желаемый режим сбоя в любом случае не является ClassCastException, конечно, в этом случае подойдет безусловное приведение.
3. @Jon Skeet Спасибо, я использую его сейчас, включая Method2 в интерфейсе. Извините, я забыл добавить implements IMyInterface в свой образец.
Ответ №2:
Он будет работать (при условии, что CMyClass реализует IMyInterface и вы находитесь в области действия модификатора protected), но это неправильный подход OO.
Если вы хотите использовать iMethod2, рассмотрите:
- добавление его в интерфейс
- создайте другой интерфейс, содержащий этот метод
- Используйте
cMyClass myClass = new cMyClass();
Комментарии:
1. Спасибо, я добавляю Method2 в свой интерфейс.
2. На самом деле вы хотите ограничить свой тип экземпляра наименьшим разумным интерфейсом, например
List<String> l = new ArrayList<>() ;
, если вы хотите использовать методы, специфичные для arraylist, расширяющие ваш тип переменной.
Ответ №3:
Существует еще одна альтернатива приведению интерфейса к классу. Вот пример того, как это сделать.
interface iMyInterface {
void iMethod1();
}
public class cMyClass implements iMyInterface {
private iMyInterface myInterface;
public cMyClass() {
myInterface = this;
}
public void iMethod1(){
System.out.println("Print from cMyClass iMethod1()");
}
protected void iMethod2() {
System.out.println("Print from cMyClass iMethod2()");
}
/**
* Getter so we can access to the interface methods.
* @return
*/
public iMyInterface getMyInterface() {
return myInterface;
}
}
И чтобы получить значения из вашего интерфейса, вот пример кода.
public class Main {
public static void main(String[] args) {
cMyClass myClass = new cMyClass();
myClass.getMyInterface().iMethod1();
myClass.iMethod2();
}
}
Вывод:
Печать из CMyClass iMethod1()
Печать из CMyClass iMethod2()
Я думаю, что это хороший пример того, как вы можете отделить код интерфейса от кода класса. Просто создайте экземпляр интерфейса, и каждый метод будет использоваться через getter с этим интерфейсом.
Комментарии:
1. Я знаю 4 года. Но ваш ответ ничего не дает. Вызов методов интерфейса в самом классе — это нормально. Я не знаю никакого соглашения, в котором говорилось бы вам разделить их. И если вы действительно хотите, вы можете привести неявно:
iMyInterface i = classInstance;
для этого вам не нужен метод.