jdk descargar actualizar java

descargar - java offline



Casting "con" Interface (5)

La diferencia en esta situación es, obviamente, que I es una interfaz que podría implementarse. Esto significa que, aunque B no tiene nada que ver con I , podría haber una subclase de B , que implementa la interfaz I Ilustraremos esto con un ejemplo:

interface I{} class A implements I{} class B{} class C extends B implements I{} I[] arr = new A[10]; // valid, cause A implements I B b = new C(); // Valid because C is a subclass of B arr[0] = (I) b; // This won''t produce ClassCastException at runtime, because b // contains an object at runtime, which implements I arr[0] = (I) new B(); // This will compile but will result in a ClassCastException // at runtime, cause B does not implement I

Es importante distinguir la diferencia entre tipos static y dynamic . En este caso, el tipo estático de la variable b es B , pero tiene el tipo dinámico (el tipo de tiempo de ejecución) C , donde el new B() también tiene el tipo B estático, pero el tipo dinámico también es B Y como en algunos casos una conversión de B a I no generará excepciones (como en este escenario), el compilador permite tales conversiones pero solo a un tipo de interfaz .

Ahora mira el siguiente escenario:

I[] arr = new A[10]; B b = new C(); // Valid because C is a subclass of B A a1 = (A) b; // compile time error A a2 = (A) new B(); // compile time error

¿Es posible que una subclase de B alguna vez extienda A y B al mismo tiempo? La respuesta es NO , porque está limitado a una sola clase para extender en Java (donde este no es el caso en otros lenguajes OO), por lo que el compilador lo prohíbe, ya que no hay escenarios posibles, donde esto funcionará.

Esta pregunta ya tiene una respuesta aquí:

interface I{} class A implements I{} class B{}

Primero:

I[] arr = new A[10]; arr[0] = (I) new B(); // will produce ClassCastException at runtime

Segundo: en donde si uso clase concreta

I[] arr = new A[10]; arr[0] = (A) new B(); // will produce compile-time error

¿Cuál es la diferencia si en mi primer ejemplo, (I) new B() , el compilador Java también debería producir un error de compilación?

¿No es que el compilador java debería poder distinguir que también es un "tipo inconvertible"? Especialmente cuando el nuevo operador llega de inmediato?

¿Hay alguna instancia / posibilidad de que sea posible que crear esa nueva instancia de B pueda producir un tipo convertible de tipo I?

Sé que en algún momento, el compilador de Java no debería decir inmediatamente que es un error del compilador, como cuando haces esto:

I i = (I) getContent(); // wherein getContent() will return a type of Object

Editar:

Permítame aclarar esta pregunta por qué no es un posible duplicado de esto: Convertir la referencia del tipo conocido a una interfaz fuera de la jerarquía del tipo

La intención de esta pregunta no es porque no estoy al tanto de cuál será el resultado o qué es algo malo en algo, etc.

Solo quiero saber una "explicación más detallada de una manera técnica" de por qué la JVM se comporta de esa manera o por qué Java tuvo la clase de decisión de no cometer ese tipo de escenario en un error de compilación .

Como todos sabemos, siempre es mejor encontrar "código problemático" en tiempo de compilación que en tiempo de ejecución.

Otra cosa, la respuesta que estoy buscando se encontró aquí en este hilo, no en esos "duplicados?".


La herencia de clase es una herencia única, ningún descendiente futuro puede introducir una nueva clase base, por ejemplo, en su ejemplo, ningún descendiente de B puede ser lanzado a A Pero puede introducir una nueva interfaz, es decir, un descendiente de B podría admitir I

Es una falla del compilador que no puede resolver su caso simple, pero no es un caso que pueda ver en la naturaleza. Crear y lanzar en una línea que es.

Ejemplo de por qué el compilador no puede detectar esto en un caso más complejo usando sus clases

void method(B b){ I i = (I) b; } class C extends B implements I{} // a descendent of B that introduces support for I method(new A()); //still compile time error method(new B()); //runtime exception method(new C()); //works


Las reglas para qué conversiones son legales en tiempo de compilación solo tienen en cuenta los tipos estáticos.

Cuando el compilador de Java analiza la expresión (I) new B() , ve que el tipo estático de la expresión new B() es B Podemos decir que el new B() no puede ser una instancia de I , pero las reglas de análisis en tiempo de compilación no pueden decir que el objeto no es realmente una instancia de una subclase de B que implemente I

Así, el compilador tiene que dejarlo pasar. Dependiendo de lo sofisticado que sea el compilador, podría detectar la rareza y emitir algún tipo de advertencia, pero de la misma manera que 1/0 no es un error en tiempo de compilación, esto no puede ser un error en tiempo de compilación.


Probé cuatro casos:

  1. Lanzar una clase a otra clase.
  2. Casting una clase a una interfaz.
  3. Casting de una interfaz a una clase.
  4. Casting una interfaz a otra interfaz.

El error en tiempo de compilación solo ocurre en el primer caso.

static interface I {} static interface J {} static class A {} static class B {} Object o = (B) new A(); // compile-time error Object o = (I) new A(); // runtime error Object o = (B) ((I) new A()); // runtime error Object o = (J) ((I) new A()); // runtime error

Mi conjetura es que esto sucede porque determinar si el lanzamiento tendrá éxito o no será relativamente más fácil en el primer caso, en comparación con los otros tres casos. La razón principal es que una clase solo puede extender una clase, lo que permite al compilador razonar si la conversión tendrá éxito o no. Vea estos ejemplos:

Supongamos que, además de las clases e interfaces anteriores, agrego una nueva clase:

static class C extends B implements I, J {}

Ejemplo de código que convierte una clase en una interfaz (última línea):

C c = new C(); B b = (B) c; I i = (I) b; // This is ok.

Ejemplo de código que convierte una interfaz a una clase (última línea):

C c = new C(); I i = (I) c; B b = (B) i; // This is ok.

Ejemplo de código que convierte una interfaz en otra interfaz (última línea):

C c = new C(); I i = (I) c; J j = (J) i; // This is ok.


Puede lanzar cualquier objeto a la var deseada, solo si lo hace al tipo var:

interface I{} class A implements I{} class B{} I var = (I) object; // This is always possible in compile-time, no matter the object type, because object is casted to the var type, I I var = (A) object; // Not possible in compile-time because of the difference of types

La excepción de tiempo de ejecución se produce cuando el objeto no se puede convertir, pero no se puede saber hasta el tiempo de ejecución.

A object = new A(); I var = (I) object; B anotherObject = new B(); var = (I) anotherObject;

Ambos de los anteriores funcionarán en tiempo de compilación, pero solo el primero lo hará en tiempo de ejecución, debido a la implementación de la interfaz I.