Существует множество объявлений println(...)
в классе PrintStream
(тип System.out
).
Два из них:
void println(String x)
void println(Object x)
Когда вы вызываете println((A)b)
, компилятор выбирает println(Object)
, потому что A
не String
(или любой другой тип, поддерживаемый println
). Когда вы вызываете println(b.toString())
, компилятор выбирает println(String)
, потому что вы передаете строку.
В вашем случае приведение b
к A
не имеет никакого эффекта, так как println () не имеет объявления ни для типов A, ни для B. Но приведение все равно произойдет (потому что вы просили об этом), или, может быть, этого не произойдет, потому что компилятор оптимизирует его, так как знает, что оно избыточно и не может дать сбой и не имеет никакого эффекта.
Не идиоматично писать:
A a2 = (A)b;
, поскольку это избыточно, поскольку B является подклассом A. Возможно, компилятор оптимизирует преобразование (что является операцией во время выполнения для проверки , принадлежит ли объект определенному типу , никогда не меняй его тип).
После создания объекта типа B его тип никогда не изменяется . Это всегда B:
class B extends/implements A {...}
B b = new B(); // construct a B
A a = b; // assign a B to an A variable, it's superclass
A a = (A) b // as above including check to see that b is an A (redundant, may be optimised away).
B b = a; // Syntax error, won't compile
B b = (B) a // Will check whether a is of type B then assign to variable b
В последнем случае, поскольку B
является подклассом A
, может случиться так, что a содержит экземпляр B
и приведение будет успешным. Или может случиться так, что a содержит экземпляр некоторого другого класса, который расширяет / реализует / равен A
и не является B
, и вы получите ClassCastException
.
Таким образом, поскольку объект типа B всегда сохраняет свою идентичность (это "B" -ness), то любые (instance-) методы, вызываемые для этого объекта, всегда будут вызывать реализацию B независимо от того, была ли переменная, через которую вы обращаетесь к объекту, объявлен как A или B.
Помните, что вы можете вызывать только те методы, которые объявлены в классе, для которого определена переменная.
Так, например, если B объявляет метод b_only()
, то компилятор не позволит вам написать a.b_only()
; Вы могли бы написать ((B)a).b_only()
хотя.