java 带有 newInstance 的泛型类型参数
java generic type parameter with newInstance
我不确定为什么 Java 要求我将 makeInstance 方法的 return 转换为 T?我究竟做错了什么?有没有更好的方法来完成这个?
public class Scratch {
public <T extends Base> T freshen(T instance) {
//why do I need to cast this to T
return makeInstance(instance.getClass());
}
public <T extends Base> T makeInstance(Class<T> type) {
try {
return type.newInstance();
} catch (InstantiationException ex) {
Logger.getLogger(Scratch.class.getName()).log(Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
Logger.getLogger(Scratch.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
public static final class Base {
}
}
Java 想要你转换结果的原因是 T
return 从 makeInstance
方法编辑的不能保证与 [=11= 相同] 的 freshen
方法。原因是getClass()
没有returnClass<T>
。相反,它 returns Class<? extends X>
,其中 X
是 instance
静态类型的擦除,即 Object
。这就是编译器的推理链停止的地方:它无法从该调用中推断出 return 类型将是 T
,需要您进行转换。
转换实例的替代方法是转换 class,如下所示:
return makeInstance((Class<T>)instance.getClass());
您可以使用以下方法解决此问题。
public class Scratch<T extends Base> {
public T freshen(T instance) {
// No need to cast this to T
return makeInstance(instance.getClass());
}
public T makeInstance(Class<T> type) {
try {
return type.newInstance();
} catch (InstantiationException ex) {
Logger.getLogger(Scratch.class.getName()).log(Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
Logger.getLogger(Scratch.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
public static final class Base {
}
}
希望对您有所帮助。
问题的根本原因是 "type erasure":当 Java 编译器编译 freshen()
方法的主体时,它实际上用其上层替换了 T
类型绑定,即:Base
.
所以这是编译器正在做的推理:
- instance
是 Base
类型(如我所说,T
已替换为 Base
)
- .getClass()
在类型为 Base
的变量上调用,因此此调用的 return 值为 Class<? extends Base
>
- 因此,从编译器的角度来看,传递给 makeInstance()
的参数属于 Class<? extends Base>
类型。因此 makeInstance()
里面的 T
也是 Base
=> 方法 returns Base
我不确定为什么 Java 要求我将 makeInstance 方法的 return 转换为 T?我究竟做错了什么?有没有更好的方法来完成这个?
public class Scratch {
public <T extends Base> T freshen(T instance) {
//why do I need to cast this to T
return makeInstance(instance.getClass());
}
public <T extends Base> T makeInstance(Class<T> type) {
try {
return type.newInstance();
} catch (InstantiationException ex) {
Logger.getLogger(Scratch.class.getName()).log(Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
Logger.getLogger(Scratch.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
public static final class Base {
}
}
Java 想要你转换结果的原因是 T
return 从 makeInstance
方法编辑的不能保证与 [=11= 相同] 的 freshen
方法。原因是getClass()
没有returnClass<T>
。相反,它 returns Class<? extends X>
,其中 X
是 instance
静态类型的擦除,即 Object
。这就是编译器的推理链停止的地方:它无法从该调用中推断出 return 类型将是 T
,需要您进行转换。
转换实例的替代方法是转换 class,如下所示:
return makeInstance((Class<T>)instance.getClass());
您可以使用以下方法解决此问题。
public class Scratch<T extends Base> {
public T freshen(T instance) {
// No need to cast this to T
return makeInstance(instance.getClass());
}
public T makeInstance(Class<T> type) {
try {
return type.newInstance();
} catch (InstantiationException ex) {
Logger.getLogger(Scratch.class.getName()).log(Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
Logger.getLogger(Scratch.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
public static final class Base {
}
}
希望对您有所帮助。
问题的根本原因是 "type erasure":当 Java 编译器编译 freshen()
方法的主体时,它实际上用其上层替换了 T
类型绑定,即:Base
.
所以这是编译器正在做的推理:
- instance
是 Base
类型(如我所说,T
已替换为 Base
)
- .getClass()
在类型为 Base
的变量上调用,因此此调用的 return 值为 Class<? extends Base
>
- 因此,从编译器的角度来看,传递给 makeInstance()
的参数属于 Class<? extends Base>
类型。因此 makeInstance()
里面的 T
也是 Base
=> 方法 returns Base