Интерфейс приведения Java к классу

#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; для этого вам не нужен метод.