Кастинг 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 70

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.

надеюсь, что это помогает.