package com.test.lambda;
import java.util.function.Supplier;
class Document {
void printAuthor() {
System.out.println("Document-Author");
}
}
class RFP extends Document {
@Override
void printAuthor() {
System.out.println("RFP-Author");
}
}
public class TestLambda1 {
public static void function21() {
Supplier<Document> s1 = Document::new; // working
Supplier<Document> s2 = RFP::new; // (1)
Supplier<? extends Document> s3 = Document::new; // working
Supplier<? extends Document> s4 = RFP::new; // working
Supplier<? super Document> s5 = Document::new; // working
Supplier<? super Document> s6 = RFP::new; // (2)
Supplier<? super RFP> s7 = Document::new; // (3)
Supplier<? super RFP> s8 = RFP::new; // working
}
public static void main(String[] args) throws Exception {
function21();
}
}
Problema en (1) (2) y (3) es que, debería funcionar como java 1,7 (1): debe dar error como único tipo de documento debe ser aceptado. (2): se debe dar error como único tipo súper del documento debe ser aceptado. (3): se debe trabajar como Super de RFP puede contener objeto de documento. Diferencia entre <? Super T> y <? se extiende T> en Java
Es raro que insistir en “que debería funcionar como java 1.7”, cuando en Java 1,7 resp. Java 7 no hubo referencias de métodos en absoluto.
Cuando se escribe una declaración como
Supplier<Document> s2 = RFP::new;
Usted tiene que hacer una distinción entre el tipo de la variable, el tipo de la función, y la ejecución real. Usted puede escribir el equivalente
Supplier<Document> s2 = new Supplier<Document>() {
public Document get() {
return new RFP();
}
}; // (1)
debido a los tipos de retorno covariantes, también se puede escribir
Supplier<Document> s2 = new Supplier<Document>() {
public RFP get() {
return new RFP();
}
}; // (1)
Por lo que el tipo de la variable coincide con el tipo de la función, mientras que la aplicación devuelve una instancia de un tipo más específico.
Cuando escribes
Supplier<? extends Document> s3 = Document::new; // working
Supplier<? extends Document> s4 = RFP::new; // working
Supplier<? super Document> s5 = Document::new; // working
Supplier<? super Document> s6 = RFP::new; // (2)
el tipo de la función será diferente. No se puede escribir new Supplier<? extends Document>() { … }
ni new Supplier<? super Document>() { … }
por lo que el compilador inferir un tipo que puede ser instanciada, que simplemente es el tipo de tipo de destino sin ? extends
o ? super
. Por lo que es equivalente a
Supplier<? extends Document> s3 = (Supplier<Document>)Document::new; // working
Supplier<? extends Document> s4 = (Supplier<Document>)RFP::new; // working
Supplier<? super Document> s5 = (Supplier<Document>)Document::new; // working
Supplier<? super Document> s6 = (Supplier<Document>)RFP::new; // (2) just like (1)
los cuales son ejemplificaciones válidos (como en el primer bloque), seguido de las asignaciones legales.
El problema con
Supplier<? super RFP> s7 = Document::new; // (3)
mentiras exactamente en la lógica de inferencia de tipos descritos anteriormente. La inferencia de tipos utilizará el tipo sin ? super
, y (Supplier<RFP>)Document::new
no es válido. Así que aquí, tenemos que proporcionar un tipo explícito para que sea válida:
Supplier<? super RFP> s7 = (Supplier<Document>)Document::new; // (3)
que sigue el mismo patrón que el segundo bloque.
No se puede poner en práctica una Supplier<? super RFP>
. Se puede implementar como un proveedor Supplier<Document>
que es asignable a Supplier<? super RFP>
. Cuando el tipo de objetivo tiene comodines, la estrategia que acaba de botar el comodines a menudo ayuda, pero a veces no lo hace.