2012-04-19 2 views
0

У меня возник вопрос о следующем коде (это вызов динамической привязки?). Я чувствую смущение около 3 баллов.Отношение между объявленным типом и созданным типом

Во-первых, какое среднее значение переменной pq? Показывает ли pd тип данных P или Q?

Во-вторых, когда я вызываю метод pq.m (pp), почему результат будет Q :: P, но не P :: Q?

Наконец, что это означает ((P) qq) .m (qq) ;? Надеюсь, кто-то может решить мою проблему.

Результат следующий код будет
P :: Q, Q :: P, Q :: Q, R :: P, Q :: P, Q :: Q, Q :: Q

class Test { 
    public static void main(String[] args) { 
     P pp = new P();  
     Q qq = new Q(); 
     R rr = new R(); 
     P pq = qq; 
     pp.m(qq);  
     pq.m(pp); 
     pq.m(qq);   
     rr.m(pp); 
     qq.m(pq); 
     qq.m(qq); 
     ((P) qq).m(qq);  
    } 
} 
class P { 
    public void m(P p){System.out.println("P::P"); } 
    public void m(Q p){System.out.println("P::Q"); } 
    public void m(R c){System.out.println("P::R"); } 
} 
class Q extends P { 
    public void m(P p){System.out.println("Q::P"); } 
    public void m(Q p){System.out.println("Q::Q"); } 
    public void m(R c){System.out.println("Q::R"); } 
} 
class R extends Q { 
     public void m(P p){System.out.println("R::P"); } 
     public void m(Q p){System.out.println("R::Q"); } 
    public void m(R c){System.out.println("R::R"); } 
} 
+3

Нет переменной 'pd', поэтому трудно ответить на ваш первый вопрос ... –

+1

Но чтобы ответить на все ваши вопросы, вы должны прочитать о [наследование в Java] (http://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html). –

+0

где pd ... ???? –

ответ

0

P pq = qq; означает, что pq известен остальной программе как тип P. Но как создатель, вы знаете, что это действительно тип Q. Таким образом, это означает, что когда вы вызываете pq.m(), это действительно вызывает реализацию из класса Q.

Это называется переопределением метода. Поэтому, когда вы вызываете pq.m (pp), вы действительно вызываете: public void m(P p){System.out.println("Q::P");, потому что это метод из класса Q.

Если Q не имеет метода am (P), он автоматически вызовет метод суперкласса , то один из P.

((P) qq).m(qq); так же, как делают:

P pqq = (P)qq; // pqq is known as P type, but it's instance is still the original Q type 
pqq.m(qq); // Again, since pqq is truly an instance of Q, it calls Q.m(Q) 

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

Все это говорит о том, что ваш пример не очень хорошо иллюстрирует его силу. Но, к примеру, если класс Q был дополнительный метод, public void sayHello();, затем

Q q = new Q(); 
P p = new Q(); 
q.sayHello(); // This would be legal 
p.sayHello(); // This would be illegal because the compiler knows p as a declared instance of P, even though you know it's truly a Q. 
((Q)p).sayHello(); // This would be legal because you told the compiler to look at p as an instance of Q. It's called a cast. 

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

0

Запуск, я думаю, вы имеете в виду pq, а не pd. Так как Q расширяет P, Q также является P-типом. Это как сказать, что яблоко - это плод. Итак, вы берете яблоко (Q) и говорите: это плод (P). Когда вы вызываете методы pq, они будут вызывать методы из класса Q, так как pq все еще является объектом Q. В последней части, когда вы делаете ((P) qq).m(qq);, это то же самое, выполнив следующие действия:

P p = (P) qq; 
q.m(qq); 

Итак, как было сказано выше, этот код будет вызывать метод из класса Q, печать «Q :: Q»

0

Динамическое связывание и, следовательно, полиморфизм работает только для объекта слева от точки вызова метода (o.m(x) - только для o). Типы аргументов решаются статически во время компиляции. Возьмем более известную ситуацию:

class A { 
    public boolean equals(A other) { 
    System.out.println("A.equals called"); return true; 
    } 
} 

A a1 = new A(), a2 = new A(); 
Object o = a1; 
o.equals(a1); // doesn't print anything 
a1.equals(o); // doesn't print anything 
a1.equals(a2); // prints "A.equals called" 

Дело в том, что класс А не отменяет Object.equals (Object), но вместо этого просто добавляет еще один перегруженный метод А.равно (A) - и этот вызов вызывается только тогда, когда аргумент имеет объявленный тип A.

+0

извините ... i un-downvoted. я нашел ваше объяснение очень запутанным, потому что я думал, что это звучит так, как будто вы описывали C++, а не java. последний добавленный абзац улучшает ваш ответ. – stevevls