2014-11-28 4 views
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()); 
    } 
} 

Выход вышеуказанного кода:Java полиморфизм: Пожалуйста, помогите мне понять полиморфизм

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» реализует интерфейс «List», то почему я не могу назвать методы класса «ArrayList»?

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

ответ

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; 
    } 
} 

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

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 В КОТОРЫХ объект не имеет метода 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(), вам необходимо указать Object на номер ClassA(), чтобы сообщить компилятору, что я вызываю метод от ClassA().

EDITED:

в вашем примере выход не то же самое, потому что вы даете ссылку на 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(), однако компилятор выдаст ошибку.

0

Допустим, у вас это

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

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

Смежные вопросы