metodos - pila generica java
¿Para qué sirven los constructores genéricos en Java? (5)
Como todos saben, puedes tener una clase genérica en Java usando argumentos de tipo:
class Foo<T> {
T tee;
Foo(T tee) {
this.tee = tee;
}
}
Pero también puede tener constructores genéricos, es decir, constructores que reciben explícitamente sus propios argumentos de tipo genérico, por ejemplo:
class Bar {
<U> Bar(U you) {
// Why!?
}
}
Estoy luchando por entender el caso de uso. ¿Qué me permite esta característica?
¿Qué me permite esta característica?
Hay al menos tres cosas que te permite hacer y que de otro modo no podrías hacer:
expresar relaciones entre los tipos de argumentos, por ejemplo:
class Bar { <T> Bar(T object, Class<T> type) { // ''type'' must represent a class to which ''object'' is assignable, // albeit not necessarily ''object''''s exact class. // ... } }
<retirado>
Como observó primero @Lino, le permite expresar que los argumentos deben ser compatibles con una combinación de dos o más tipos no relacionados (lo que puede tener sentido cuando todos, pero a lo sumo uno, son tipos de interfaz). Vea la respuesta de Lino para un ejemplo.
Debido a que ese tipo genérico no vinculado se borra a Object
, sería lo mismo que pasar Object
en su constructor:
public class Foo {
Object o;
public Foo(Object o) {
this.o = o;
}
}
... pero como pasar un Object
blanco, a menos que esté haciendo algo inteligente , esto tiene poco valor práctico.
Verá beneficios y gana si transfiere genéricos encuadernados en su lugar, lo que significa que realmente puede tener garantías en torno al tipo que le importa.
public class Foo<T extends Collection<?>> {
T collection;
public Foo(T collection) {
this.collection = collection;
}
}
Efectivamente, se trata más de flexibilidad que de ser algo revolucionario. Si desea la flexibilidad para pasar en una categoría específica de tipos, entonces usted tiene el poder para hacerlo aquí. Si no lo hace , entonces no hay nada malo con las clases estándar. Simplemente está aquí para su conveniencia, y dado que el borrado de tipo sigue siendo una cosa, un genérico no vinculado es el mismo (y tiene la misma utilidad) que pasar Object
.
El caso de uso en el que estoy pensando podría ser que algunos quieren un Objeto que hereda de 2 Tipos. Ej. Implementa 2 interfaces
:
public class Foo {
public <T extends Bar & Baz> Foo(T barAndBaz){
barAndBaz.barMethod();
barAndBaz.bazMethod();
}
}
Aunque nunca lo he usado en producción.
En realidad, este constructor
class Bar {
<U> Bar(U you) {
// Why!?
}
}
es solo como un método genérico . Tendría mucho más sentido si tuviera varios argumentos de constructor como este:
class Bar {
<U> Bar(U you, U me) {
// Why!?
}
}
Entonces podría hacer cumplir la restricción, que tienen el mismo tiempo con el compilador. Sin hacer que U sea genérico para toda la clase.
Está claro en el ejemplo que proporcionaste que U
no juega ningún papel en el constructor de la clase, ya que efectivamente se convierte en un Object
en tiempo de ejecución:
class Bar {
<U> Bar(U you) {
// Why!?
}
}
Pero digamos que quería que mi constructor solo aceptara tipos que extienden alguna otra clase o interfaz, como se ve a continuación:
class Foo<T extends Baz> {
<U extends Bar> Foo(U u) {
// I must be a Bar!
}
}
Observe que la clase ya tiene un tipo genérico diferente en uso; esto le permite utilizar un tipo genérico separado, no relacionado a la definición de la clase.
Por supuesto, nunca he usado algo como esto, y nunca lo he visto en uso, ¡pero es posible!