web-dev-qa-db-fra.com

Java transtypage en interfaces

Quelqu'un peut-il m'expliquer comment le compilateur ne se plaint pas dans le premier casting, mais se plaint dans le second?

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 !!
     }
}
73
geo

Lorsque vous lancez o1 et o3 avec (I2), vous dites au compilateur que la classe de l'objet est en fait une sous-classe de son type déclaré, et que cette sous-classe implémente I2.

La classe Integer est final, donc o3 ne peut pas être une instance d'une sous-classe de Integer: le compilateur sait que vous mentez. C1 n'est cependant pas définitif, donc o1 pourrait être une instance d'un sous-type de C1 qui implémente I2.

Si tu fais C1 final, le compilateur se plaindra aussi:

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
     }
}
145
WilQu

Selon JLS chapitre 5

5.5.1. Type de référence Coulée

Étant donné un type de référence au moment de la compilation S (source) et un type de référence au moment de la compilation T (cible), une conversion de transtypage existe de S vers T si aucune erreur au moment de la compilation ne se produit en raison des règles suivantes. Si T est un type d'interface:

Si S n'est pas une classe finale (§8.1.1), alors, s'il existe un supertype X de T, et un supertype Y de S, tels que X et Y sont tous les deux des types paramétrés distinctement prouvés, et que les effacements de X et Y sont identiques, une erreur de compilation se produit.

Sinon, la distribution est toujours légale au moment de la compilation (car même si S n'implémente pas T, une sous-classe de S pourrait).

Si S est une classe finale (§8.1.1), alors S doit implémenter T, sinon une erreur de compilation se produit.

35
maba

En effet, la classe Integer est finale et C1 n'est pas. Ainsi, un objet Integer ne peut pas implémenter I2, alors qu'un objet C1 le pourrait s'il s'agit d'une instance d'une sous-classe de C1 qui implémente I2.

23
Etienne Miret

Selon JLS 5.5.1 - Casting du type de référence , la ou les règles s'appliquent:

  • Si T est un type de classe, alors | S | <: | T |, ou | T | <: | S |. Sinon, une erreur de compilation se produit.

    I2 y = (I2)o3; //compiler complains here !!

Dans ce cas, un Integer et I2 sont sans aucun lien , donc une erreur de compilation se produit. De plus, comme Integer est final, il n'y a pas de relation entre Integer et I2.

I2 et I1 peut être lié car les deux sont une interface marqueur (il n'y a pas de contrat).

Quant au code compilé, la règle suit:

  • Si S n'est pas une classe finale (§8.1.1), alors, s'il existe un supertype X de T, et un supertype Y de S, de sorte que X et Y sont tous les deux distinctement prouvés types paramétrés et que les effacements de X et Y sont les mêmes, une erreur de compilation se produit.

S est o1 et T est I2.

J'espère que cela t'aides.

15
Buhake Sindi