2016-07-17 4 views
2

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

public class ClassA { 
    public void stampa(ClassA p) { 
     System.out.println("AAA"); 
    } 
} 
public class ClassB extends ClassA { 
    public void stampa(ClassB p) { 
     System.out.println("BBB"); 
    } 
    public void stampa(ClassA p) { 
     System.out.println("AAA/BBB"); 
    } 
} 
public class ClassC extends ClassA { 
    public void stampa(ClassC p) { 
     System.out.println("CCC"); 
    } 
    public void stampa(ClassA p) { 
     System.out.println("AAA/CCC"); 
    } 
} 

И главное, что выглядит эта

public static void main(String[] args) { 
    ClassA a1, a2; 
    ClassB b1; 
    ClassC c1; 
    a1 = new ClassB(); 
    b1 = new ClassB(); 
    c1 = new ClassC(); 
    a2 = new ClassC(); 
    b1.stampa(b1);//BBB 
    a1.stampa(b1);//AAA/BBB 
    b1.stampa(c1);//AAA/BBB 
    c1.stampa(c1);//CCC 
    c1.stampa(a1);//AAA/CCC 
    a2.stampa(c1);//AAA/CCC 
} 

У меня трудно понять, почему результат для a1.stampa (b1); «AAA/BBB», а не «BBB». Как я понял из наследования, статическим типом a1 во время компиляции является ClassB, поэтому я искал метод «штамп» в ClassB, а для параметра метода статический тип тоже ClassB, поэтому я выберу первый штамповый метод класса В.

То же самое происходит и при попытке понять результат a2.stampa (c1); который является «AAA/CCC», а не «CCC».

Может кто-нибудь, пожалуйста, помогите мне понять, что я делаю неправильно?

ответ

1

Вопрос заключается в том, что следующий

public class ClassB extends ClassA { 
    public void stampa(ClassB p) { 

не наиважнейшая это

public class ClassA { 
    public void stampa(ClassA p) { 

Это перегрузки вместо этого ...

Это означает, что дополнительная метод, а не переопределение, и к нему можно получить доступ только через b1.stampa(b1);.

0

Это проблема, связанная с перегрузкой и полиморфизмом.

ClassA a1; 
ClassB b1; 
... 
a1.stampa(b1); 

Компилятор может только определить тип два параметра и имя функции вызываются при компиляции (из-за полиморфизм).

so "a1.stampa (b1);" make compile find stampa с типом параметра ClassB в ClassA, но ClassA не выполняет эту функцию, поэтому параметр понижается в должности, компилирует find stampa с типом параметра ClassA в ClassA. Эта функция существует, поэтому запись компилятора в этой строке требует вызова функции с именем stampa и типом параметра ClassA.

При запуске программы a1 фактически является объектом ClassB, этот объект перезаписывает функцию с именем stampa и типом параметра ClassA. Поэтому конечный результат - «AAA/BBB».

Просто помните, что перегрузка происходит во время компиляции, а полиморфизм происходит во время выполнения.

Пожалуйста, проигнорируйте мой сломанный английский.

0

Речь идет о разнице между переопределением и перегрузка методов.

Методы имеют signature, определенные именем метода и типами параметров, но не именами параметров или типом возвращаемого значения.

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

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

Компилятор Java определяет , который метод для вызова во время компиляции, то есть используемая подпись метода. Фактический метод с этой сигнатурой, подлежащей вызову, определяется в времени выполнения, в зависимости от фактического класса объекта, на который делается ссылка.

Так, в время компиляции для a1.stampa(b1) компилятор просматривает все stampa на классе ClassA (потому что a1 имеет тип ClassA), и находит только один такой метод, с подписью stampa(ClassA).

В время выполнения, объект ссылается a1 фактически ClassB, поэтому ClassB.stampa(ClassA) называется, так как ClassB был переопределен метод из ClassA.

ClassB.stampa(ClassA) затем печатает AAA/BBB.

0

По моим сведениям, результат для a1.stampa (b1); это «AAA/BBB», а не «BBB», потому что, когда вы передаете b1 в штамп(), он будет передаваться по типу суперкласса и потому, что у вас есть перегруженный метод суперкласса, а при выполнении перегруженных методов всегда применяются методы подкласса, поэтому подкласс метод выполняется вместо суперкласса.

0

Это время выполнения Полиморфизм, которая решается с помощью методов переопределенных. Прежде всего, вы не можете даже ожидать, что a1.stampa(b1); вызовет метод, который не переопределяет метод родительского класса (который в вашем случае имеет значение public void stampa(ClassB)). Этот метод никогда не будет вызван из вашего вызова, поскольку он не переопределяет родительский класс метод.

Теперь причина, почему public void stampa(ClassA p) вызывается происходит потому, что во время выполнения родительского класса ссылочных переменная a1 относится к объекту ClassB .so, метод, который переопределяет метод родительского класса вызывается.

То же самое относится и к вашей другой проблеме.

Для лучшего понимания полиморфизма времени выполнения вы можете обратиться к https://docs.oracle.com/javase/tutorial/java/IandI/polymorphism.html