Полиморфизм Java: Пожалуйста, помогите мне понять полиморфизм

1
class ClassA {
    String whoAmI() {
        return "ClassA";
    }
}

class ClassB extends ClassA{
    String whoAmI() {
        return "ClassB";
    }
}

class Main {

    public static void main(String[] args) {

        ClassA obj1 = new ClassA();
        ClassA obj2 = new ClassB();

        System.out.println(obj1.whoAmI()); 
        System.out.println(obj2.whoAmI());
    }
}

Вывод кода выше:

ClassA
ClassB

В вышеприведенном коде вывод выглядит так, как ожидается, что я могу увидеть методы класса "ClassB", когда я создаю ссылочную переменную класса "ClassA" и создаю экземпляр с помощью "new ClassB();", но почему это не так в случае когда я создаю ссылочную переменную интерфейса "Список" и создаю ее, используя свой класс реализации "ArrayList" (я знаю, что мы не можем напрямую создавать объекты интерфейсов)?

import java.util.ArrayList;
import java.util.List;

public class Main {

    public static void main(String[] args) {

        List objList = new ArrayList();

        objList.add("One");
        objList.add("Two");
        objList.add("Three");

        System.out.println(objList.get(1)); // Only able to call methods of interface "List", but not methods of its implementing class "ArrayList. WHY?"
    }

}

Если класс "ArrayList" реализует интерфейс "Список", то почему я не могу вызывать методы класса "ArrayList"?

Я знаю, что в моем сознании есть некоторое недоразумение о концепции полиморфизма. Пожалуйста, помогите мне разобраться в этом недоразумении!

Теги:
polymorphism
inheritance

3 ответа

2
Лучший ответ

полиморфизм имеет два понятия о методах.

перегрузка метода - где вы перегружаете/добавляете/имеете разные параметры в своем методе

например:

class ClassA {
    String whoAmI() {
        return "ClassA";
    }
}

class ClassB extends ClassA{
    // you are overloading the method whoAmI from class A
    String whoAmI(String name) {
        return "ClassB "+name;
    }
}

метод overriding - где вы переопределяете/изменяете функцию по умолчанию метода

class ClassA {
    String whoAmI() {
        return "ClassA";
    }
}

class ClassB extends ClassA{
    // override whoAmI method change function
    String whoAmI() {
        //do something
        int foo = 5 + 10;
        return "ClassB foo: "+foo;
    }
}

и в вашем вопросе

class ClassA {

    String whoAmI() {
        return "ClassA";
    }
} 

class Main {

    public static void main(String[] args) {

        Object obj1 = new ClassA();
        obj1.whoAmI(); 
    }   
}

от вашего фрагмента кода выше вы ссылаетесь объект ClassA() в качестве Object которого объект does'nt имеет whoAmI() метод. вы говорите, что obj1 - это тип объекта ClassA(), который имеет разные наборы методов.

        Object
       /
   ClassA()
       |
    method:whoAmI()

ссылаясь на иерархию классов выше. classA() имеет метод whoAmI() и Object имеет equals(), hashCode(), getClass(), etc...() когда вы расширяетесь до Object super class не наследует методы внутри child class. В вашем примере, поскольку ClassA() расширяет Object (суперкласс), Object не будет наследовать метод whoAmI() но это наоборот. ClassA() наследует методы внутри Object. и если вы ссылаетесь на свой ClassA() на Object и получаете доступ к методу внутри ClassA() вам нужно ClassA() свой Object в ClassA() чтобы сообщить компилятору, что я ClassA() метод из ClassA().

Редакция:

в вашем примере вывод не является тем же, поскольку вы указываете ссылку ClassB() на ClassA() которая переопределяет метод whoAmI();

и в вашем примере List ArrayList реализует List но переменная экземпляра - A List. см. "диаграмма ниже"

Пользовательский класс

Class A                       Class B extends A

method: whoAmI()              method override: whoAmI()
output: "i am class A"        output: "i am new class B"
                              method: fooMethod()
                              output: "my own method"

поэтому, когда вы объявляете объект Class A вы будете использовать класс методы, поля и т.д.

ClassA obj = new ClassA();

после того, как вы измените ссылочный объект на ClassB() вы теперь будете использовать метод переопределения ClassB's/различные наборы полей и т.д., но это не означает, что вы можете вызвать fooMethod() легко, потому что помните, что это все еще ClassA методы в ClassB внутри ClassA будет переопределен.

ClassA obj = new ClassB();
// override whoAmI() method changed output

но когда вы бросаете obj в ClassB() это похоже на то, что вы сообщаете компилятору, что это obj является ClassB() когда вы можете использовать fooMethod() потому что компилятор считает, что obj(casted) является ClassB

((ClassB)obj).fooMethod();

Я попытался наилучшим образом, чтобы объяснить это самым простым способом, который я знаю. cheerioo

0

Object obj1 = new ClassA();

В этой строке Object считается статическим типом переменной, а ClassA считается динамическим типом переменной.

Статические типы всегда используются, чтобы гарантировать существование поля или метода компилятором, а динамические типы - это то, что фактически используется для вызова методов при запуске программы.

Идея такова: поскольку статический тип всегда должен быть суперклассом динамического типа, статический тип используется, чтобы гарантировать, что независимо от того, какие подклассы вы используете в качестве динамического типа переменной, они всегда будут по меньшей мере поддерживать методы суперкласса. Например, каждый объект имеет метод hashCode() и метод toString(), поскольку эти методы считаются существенными для всех объектов Java. Вам всегда будет позволено называть obj1.hashCode().

Однако, поскольку класс Object не содержит whoAmI(), компилятор whoAmI() ошибку.

0

Скажем, у вас было это

Object ref;
if (new Random().nextInt(2) % 2 == 0)
    ref = new ClassA();
else
    ref = new String("whatever");

Должен ли вы ссылаться на метод whoAmI объекта, на который ссылается переменная ref? Нет. Компилятор не может постоянно знать, какие типы объектов будут храниться во время выполнения. Таким образом, методы решаются во время компиляции в зависимости от типа переменных. Тип Object не имеет метода whoAmI.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню