Можно ли вызвать методы подклассов над объектом суперкласса?

Животное - это суперкласс собаки и у собаки есть метод, называемый корой

public void bark()
{
    System.out.println("woof");
}

Рассмотрим следующее:

Animal a = new Dog();
if (a instanceof Dog){
    a.bark();
}

Что произойдет?

  • присвоение не разрешено
  • разрешен вызов коры и во время выполнения печатается "woof"
  • вызов коры разрешен, но ничего не печатается
  • вызов коры вызывает ошибку времени компиляции
  • вызов коры приводит к ошибке времени выполнения

Я сказал 2, когда мы проверяем, является ли объект собакой; поскольку собака - это класс с методом коры в нем, если это тогда мы называем это, которое будет распечатываться: s

Мое понимание здесь верно?

Ответы

Ответ 1

Это не будет компилироваться, так как у Animal нет метода, называемого bark. Подумайте об этом так, все собаки - животные, но не все животные - собаки. Все собаки лают, но не все животные коры.

Ответ 2

нет - ответ:

4) вызов коры вызывает ошибку времени компиляции

метод bark не определяется как метод для назначенного типа Animal, что, следовательно, приводит к проблеме времени компиляции; это можно решить путем кастинга;

((Dog)a).bark();

Ответ 3

Ключ находится в следующей строке:

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

Это 4. Вы не можете спросить общий Animal - это то, что ваш код говорит, что это - лаять. Потому что вы так же легко сказали

Animal a = new Cat();

и линия коры не знает, что вы этого не сделали.

Ответ 5

Если идея заключается в том, чтобы напечатать метод подкласса из объекта суперкласса, это будет работать:

Вместо Animal a = new Dog(); if (a instanceof Dog){ a.bark(); } измените на

Animal a = new Dog();

if (a instanceof Dog){ 
    Dog d = (Dog) a; 
    d.bark();
}  

Это возвращает суперкласс обратно в подкласс и печатает его. хотя его плохой дизайн, его единственный способ узнать, какой объект класса ребенка он указывает на динамически.

Ответ 6

В Head First Java они используют очень хорошую аналогию с ТВ-пультом для ссылки, а ваш телевизор - как объект, в котором ссылка указывает на. Если у вашего пульта есть только кнопки (методы) для включения, выключения, канала вверх и вниз, а также громкость вверх и вниз, не имеет значения, какие интересные функции у вашего телевизора. Вы все еще можете делать только эти незначительные вещи с вашего пульта. Вы не можете отключить телевизор, например, если пульт не имеет кнопки отключения звука.

Ссылка на животное знает только о методах животных. Не имеет значения, какие другие методы имеет базовый объект, вы не можете получить к ним доступ из справочника животных.

Ответ 7

FYI, это не очень хороший дизайн.

Почти каждый раз, когда у вас есть код этой формы:

if (x instanceof SomeClass)
{
   x.SomeMethod();
}

вы злоупотребляете системой типов. Это не способ использования классов, это не способ записи поддерживаемого объектно-ориентированного кода. Это хрупкое. Это свернулось. Это плохо.

Вы можете создавать методы шаблонов в базовом классе, но они должны вызывать методы, которые существуют в базовом классе и переопределяются в подклассах.

Ответ 8

В 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. Он записывает первую строку на консоль. У собаки есть метод коры, поэтому суперкласс называет его. Он записывает вторую строку на консоль.

Ответ 9

"Я сказал 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: "вызов коры вызывает ошибку времени компиляции"

Надеюсь, это поможет.