Я ищу объяснение следующего поведения:
- У меня есть 6 классов: {a.A, b.B, c.C, a.D, b.E, c.F}, у каждого из которых есть видимый для пакета метод m(), который записывает имя класса.
- У меня есть класс a.Main с методом main, который выполняет некоторое тестирование этих классов.
- Вывод не соответствует правилам наследования.
Вот классы:
package a;
public class A {
void m() { System.out.println("A"); }
}
// ------
package b;
import a.A;
public class B extends A {
void m() { System.out.println("B"); }
}
// ------
package c;
import b.B;
public class C extends B {
void m() { System.out.println("C"); }
}
// ------
package a;
import c.C;
public class D extends C {
void m() { System.out.println("D"); }
}
// ------
package b;
import a.D;
public class E extends D {
void m() { System.out.println("E"); }
}
// ------
package c;
import b.E;
public class F extends E {
void m() { System.out.println("F"); }
}
Основной класс находится в package a
:
package a;
import b.B;
import b.E;
import c.C;
import c.F;
public class Main {
public static void main(String[] args) {
A a = new A();
B b = new B();
C c = new C();
D d = new D();
E e = new E();
F f = new F();
System.out.println("((A)a).m();"); ((A)a).m();
System.out.println("((A)b).m();"); ((A)b).m();
System.out.println("((A)c).m();"); ((A)c).m();
System.out.println("((A)d).m();"); ((A)d).m();
System.out.println("((A)e).m();"); ((A)e).m();
System.out.println("((A)f).m();"); ((A)f).m();
System.out.println("((D)d).m();"); ((D)d).m();
System.out.println("((D)e).m();"); ((D)e).m();
System.out.println("((D)f).m();"); ((D)f).m();
}
}
А вот и вывод:
((A)a).m();
A
((A)b).m();
A
((A)c).m();
A
((A)d).m();
D
((A)e).m();
E
((A)f).m();
F
((D)d).m();
D
((D)e).m();
D
((D)f).m();
D
А вот и мои вопросы:
1) Я понимаю, что D.m()
скрывает A.m()
, но приведение к A
должно раскрывать скрытый метод m()
, это правда? Или D.m()
переопределяет A.m()
, несмотря на то, что B.m()
и C.m()
разрывает цепочку наследования?
((A)d).m();
D
2) Еще хуже, следующий код показывает переопределение, почему?
((A)e).m();
E
((A)f).m();
F
И почему бы не в этой части:
((A)a).m();
A
((A)b).m();
A
((A)c).m();
A
а этот?
((D)d).m();
D
((D)e).m();
D
((D)f).m();
D
Я использую OpenJDK javac 11.0.2.
ОБНОВЛЕНИЕ: На первый вопрос отвечает Как переопределить метод с областью видимости по умолчанию (пакет)?
Метод экземпляра mD, объявленный или унаследованный классом D, переопределяет из D другой метод mA, объявленный в классе A, если все следующее верно:
- A является суперклассом D.
- D не наследует мА (потому что пересекает границы пакета)
- Подпись mD является подписью (§8.4.2) подписи mA.
- Одно из следующего верно: [...]
- mA объявляется с доступом к пакету в том же пакете, что и D (в этом случае), и либо D объявляет mD, либо mA является членом прямого суперкласса D. [...]
НО: второй вопрос до сих пор не решен.