Ответ 1
Это не будет компилироваться, так как у Animal нет метода, называемого bark. Подумайте об этом так, все собаки - животные, но не все животные - собаки. Все собаки лают, но не все животные коры.
Животное - это суперкласс собаки и у собаки есть метод, называемый корой
public void bark()
{
System.out.println("woof");
}
Рассмотрим следующее:
Animal a = new Dog();
if (a instanceof Dog){
a.bark();
}
Что произойдет?
Я сказал 2, когда мы проверяем, является ли объект собакой; поскольку собака - это класс с методом коры в нем, если это тогда мы называем это, которое будет распечатываться: s
Мое понимание здесь верно?
Это не будет компилироваться, так как у Animal нет метода, называемого bark. Подумайте об этом так, все собаки - животные, но не все животные - собаки. Все собаки лают, но не все животные коры.
нет - ответ:
4) вызов коры вызывает ошибку времени компиляции
метод bark не определяется как метод для назначенного типа Animal, что, следовательно, приводит к проблеме времени компиляции; это можно решить путем кастинга;
((Dog)a).bark();
Ключ находится в следующей строке:
Animal a = new Dog();
Хотя был создан новый экземпляр Dog
, его ссылка на a
, которая объявлена как тип Animal
. Поэтому любые ссылки на a
делают new Dog
обрабатываемым как Animal
.
Следовательно, если Animal
не имеет метода bark
, следующая строка вызовет ошибку компилятора:
a.bark();
Даже если a
проверен, является ли это экземпляром Dog
, а a instanceof Dog
фактически вернет true
, переменная a
все еще имеет тип Animal
, поэтому блок внутри оператора if
все еще обрабатывает a
как Animal
.
Это особенность статически типизированных языков, где переменным присваивается тип раньше времени и проверяется во время компиляции, чтобы увидеть, что типы совпадают. Если этот код был выполнен на динамически типизированном языке, где типы проверяются во время выполнения, может быть разрешено следующее:
var a = new Dog();
if (a instanceof Dog)
a.bark();
a.bark()
гарантируется только для выполнения, когда экземпляр является Dog
, поэтому вызов bark
всегда будет работать. Однако Java является статически типизированным языком, поэтому этот тип кода не разрешен.
Это 4. Вы не можете спросить общий Animal - это то, что ваш код говорит, что это - лаять. Потому что вы так же легко сказали
Animal a = new Cat();
и линия коры не знает, что вы этого не сделали.
Если идея заключается в том, чтобы напечатать метод подкласса из объекта суперкласса, это будет работать:
Вместо Animal a = new Dog(); if (a instanceof Dog){ a.bark(); }
измените на
Animal a = new Dog();
if (a instanceof Dog){
Dog d = (Dog) a;
d.bark();
}
Это возвращает суперкласс обратно в подкласс и печатает его. хотя его плохой дизайн, его единственный способ узнать, какой объект класса ребенка он указывает на динамически.
В Head First Java они используют очень хорошую аналогию с ТВ-пультом для ссылки, а ваш телевизор - как объект, в котором ссылка указывает на. Если у вашего пульта есть только кнопки (методы) для включения, выключения, канала вверх и вниз, а также громкость вверх и вниз, не имеет значения, какие интересные функции у вашего телевизора. Вы все еще можете делать только эти незначительные вещи с вашего пульта. Вы не можете отключить телевизор, например, если пульт не имеет кнопки отключения звука.
Ссылка на животное знает только о методах животных. Не имеет значения, какие другие методы имеет базовый объект, вы не можете получить к ним доступ из справочника животных.
FYI, это не очень хороший дизайн.
Почти каждый раз, когда у вас есть код этой формы:
if (x instanceof SomeClass)
{
x.SomeMethod();
}
вы злоупотребляете системой типов. Это не способ использования классов, это не способ записи поддерживаемого объектно-ориентированного кода. Это хрупкое. Это свернулось. Это плохо.
Вы можете создавать методы шаблонов в базовом классе, но они должны вызывать методы, которые существуют в базовом классе и переопределяются в подклассах.
В java (только на языке, который я знаю) вы можете создать пустой метод и вызвать его в суперклассе. Затем вы можете переопределить его в подклассе, чтобы делать все, что захотите. Таким образом суперкласс вызывает метод подкласса.
public class Test {
public static void main(String[] args){
Snake S = new Snake();
Dog d = new Dog();
}
}
class Animal{ //Super Class
public Animal(){
bark(); //calls bark when a new animal is created
}
public void bark(){
System.out.println("this animal can't bark");
}
}
class Dog extends Animal{ //Subclass 1
@Override
public void bark(){
System.out.println("Woof");
}
}
class Snake extends Animal{//Subclass 2
public void tss(){
}
}
Этот код вызывает объект Snake, затем вызывает объект Dog. Он записывает это на консоль:
this animal can't bark
Woof
У Snake нет метода коры, поэтому вызывается метод super class. Он записывает первую строку на консоль. У собаки есть метод коры, поэтому суперкласс называет его. Он записывает вторую строку на консоль.
"Я сказал 2, когда мы проверяем, является ли объект собакой, поскольку собака - это класс с методом коры в нем, если это тогда мы называем это, которое будет распечатываться: s"
Ваше обоснование правильное, но это не так, как оно работает.
Java - это статический типизированный язык, который означает, что действительность методов, на которые объект может отвечать, проверяется в время компиляции.
Вы можете подумать, что проверка:
if( a instanceof Dog )
Сделал бы, но на самом деле это не так. То, что делает компилятор, проверяется на "интерфейс" объявленного типа (Animal в этом случае). "Интерфейс" состоит из методов, объявленных в классе Animal.
Если метод bark() не определен в суперклассе Animal, компилятор говорит: "Эй, это не сработает".
Это полезно, потому что "иногда" мы делаем опечатки во время кодирования (например, вместо ввода barck())
Если компилятор не предупредит нас об этом, вам придется найти его в "runtime" и не всегда с ясным сообщением (например, javascript в IE говорит что-то вроде "неожиданного объекта" )
Тем не менее, статический типизированный язык, такой как java, позволяет принудительно вызвать вызов. В этом случае используется оператор "cast" ()
Подобно этому
1. Animal a = new Dog();
2. if (a instanceof Dog){
3. Dog imADog = ( Dog ) a;
4. imADog.bark();
5. }
В строке 3 вы "бросаете" на тип "Собака", чтобы компилятор мог проверить, является ли кость допустимым сообщением.
Это инструкция для компилятора: "Эй, я программист здесь, я знаю, что я делаю". И компилятор, проверяет, хорошо, собака, может получить сообщение bark(), продолжить. Тем не менее, если во время выполнения животное не является собакой, исключение во время выполнения повысит.
Литой может также быть сокращенно:
if( a instanceof Dog ) {
((Dog)a).bark();
}
Это будет работать.
Итак, правильный ответ 4: "вызов коры вызывает ошибку времени компиляции"
Надеюсь, это поможет.