Кастинг Java в интерфейсах
может кто-нибудь объяснить мне, как компилятор не жалуется в первом кастинге, но жалуется во втором?
interface I1 { }
interface I2 { }
class C1 implements I1 { }
class C2 implements I2 { }
public class Test{
public static void main(){
C1 o1 = new C1();
C2 o2 = new C2();
Integer o3 = new Integer(4);
I2 x = (I2)o1; //compiler does not complain
I2 y = (I2)o3; //compiler complains here !!
}
}
4 ответа:
когда вы разыгрываете
o1
иo3
С(I2)
, вы говорите компилятору, что класс объекта на самом деле является подклассом его объявленного типа, и что этот подкласс реализуетI2
.The
Integer
класс финал, так чтоo3
не может быть экземпляром подклассаInteger
: компилятор знает, что вы лжете.C1
однако не является окончательным, такo1
может быть экземпляром подтипаC1
, который реализуетI2
.если вы
C1
final, компилятор тоже будет жаловаться:interface I1 { } interface I2 { } final class C1 implements I1 { } class C2 implements I2 { } public class Test{ public static void main(){ C1 o1 = new C1(); C2 o2 = new C2(); Integer o3 = new Integer(4); I2 y = (I2)o3; //compiler complains here !! I2 x = (I2)o1; //compiler complains too } }
по данным JLS Глава 5
5.5.1. Литье Ссылочного Типа
учитывая тип ссылки времени компиляции S (Источник) и тип ссылки времени компиляции T (цель), преобразование приведения существует от S до T, если ошибки времени компиляции не происходят из-за следующих правил. Если T-Тип интерфейса:
Если S не является конечным классом (§8.1.1), то, если существует супертип X из T и супертип Y из S, такой, что и X и Y являются доказуемо различными параметризованными типами, и что стирания X и Y одинаковы, возникает ошибка времени компиляции.
в противном случае приведение всегда является законным во время компиляции (потому что даже если S не реализует T, подкласс S может быть).
Если S является конечным классом (§8.1.1), то S должен реализовать T, или возникает ошибка времени компиляции.
это потому, что класс
Integer
является окончательной иC1
нет. Таким образом, целочисленный объект не может реализовать I2, в то время как объект C1 может, если он является экземпляром подкласса C1, который реализует I2.
по данным JLS 5.5.1-литье ссылочного типа правило(ы) применения:
если T является типом класса, то либо |s| <:>
I2 y = (I2)o3; //compiler complains here !!
в данном случае, an
Integer
иI2
are связаны в любом случае, поэтому возникает ошибка времени компиляции. Кроме того, потому чтоInteger
иfinal
, нет никакой связи междуInteger
иI2
.
I2
иI1
может быть связано из-за того, что оба являются интерфейсом маркера (нет контракта).что касается скомпилированного кода, то правило следующее:
- если S не является конечным классом (§8.1.1), то, если существует супертип X из T и супертип Y из S, такой, что оба X и Y являются доказуемо различными параметризованными типами и что стирания X и Y одинаковы, Ошибка времени компиляции происходит.
S
иo1
иT
иI2
.надеюсь, что это помогает.