Java T扩展U的用途?
最近我遇到了一个定义与此类似的方法,我不太了解它的用法:Java T扩展U的用途?,java,generics,Java,Generics,最近我遇到了一个定义与此类似的方法,我不太了解它的用法: public static <T, U extends T> T foo(U u) { ... } 其中,T被推断为Number,U(可能)被推断为Integer。但是,当这优于此方法定义时,我无法回过头来思考: public static <T> T bar(T t) { ... } 代码仍然有效T被推断为Number或Integer(不知道在本例中,参数类型Integer是否优于呼叫站点返回类型Number
public static <T, U extends T> T foo(U u) { ... }
其中,T
被推断为Number
,U
(可能)被推断为Integer
。但是,当这优于此方法定义时,我无法回过头来思考:
public static <T> T bar(T t) { ... }
代码仍然有效T
被推断为Number
或Integer
(不知道在本例中,参数类型Integer
是否优于呼叫站点返回类型Number
)
我读过这些问题:,但我仍然不知道第一种方法有两个参数是否比第二种方法有任何优势,第二种方法只有一个泛型。我的第一个想法是:见鬼
Number n = Baz.bar(2);
将“始终”工作,因为整数扩展了数字。所以这样做没有好处。但是如果你有一个不是抽象的超类呢
然后,U extends T
允许您返回一个对象,该对象仅为超类型类的对象,而不是子类的对象
差不多
class B { }
class C extends B { }
现在,泛型方法也可以返回B的实例。如果只有一个T。。。然后该方法只能返回C的实例
换句话说,U扩展T
允许您返回B和C的实例。T
单独:仅返回C
但是当然,当你看一些特定的B和C时,上面的内容是有意义的。但是当一个方法(实际上)只是返回一个B的实例时,为什么首先需要泛型呢
所以,我同意这个问题:我也看不出这个结构的实用价值。除非一个人进入反射,但即使这样,我也看不到一个合理的设计,因为第一种方法是U扩展t
publicstatictfoo(U){…}
意味着T
和U
可以是不同的类型。即,一种类型为T
,另一种类型为U
,是T
的子类型
用你的第二个例子
公共静态T条(T T){…}
bar(T)
必须返回与参数T
相同的类型。它不能将超类类型的对象返回给参数类型。这只适用于第一个变体。当您想要返回超级类型时,这很方便;就像你在例子中展示的那样
将U
作为输入,并返回T
——这是U
的超级类型;另一种方法是T super U
——但这在java中是不合法的
这应该是我实际意思的一个例子。假设一个非常简单的类,如:
static class Holder<T> {
private final T t;
public Holder(T t) {
this.t = t;
}
public <U super T> U whenNull(U whenNull){
return t == null ? whenNull : t;
}
}
其用途是:
Holder<Number, Integer> n = new Holder<>(null);
Number num = n.whenNull(22D);
Holder n=新的Holder(空);
数字num=n.whenNull(22D);
这允许返回一个超级类型;但是看起来很奇怪。我们在类声明中添加了另一个类型
我们可以求助于:
static class Holder<T> {
private final T t;
public Holder(T t) {
this.t = t;
}
public static <U, T extends U> U whenNull(U whenNull, Holder<T> holder) {
return holder.t == null ? whenNull : holder.t;
}
}
静态类持有者{
私人期末考试;
公共持有人(T){
t=t;
}
公共静态U whenNull(U whenNull,保持架){
返回holder.t==null?whenNull:holder.t;
}
}
或者甚至将此方法设置为静态
对于现有限制,您可以尝试执行以下操作:
Optional.ofNullable(<SomeSubTypeThatIsNull>)
.orElse(<SomeSuperType>)
Optional.ofNullable()
.orElse()
我认为,实际上,只有当方法的类型参数显示为作为方法签名一部分的参数化类型的类型参数时,这才有意义
(至少,我不能很快想出一个例子,否则它真的有意义)
您链接到的问题也是如此,其中方法类型参数用作AutoBean
类中的类型参数
一个小更新: 根据问题和其他答案中的讨论,该问题的核心可能是对类型参数使用方式的误解。因此,这个问题可以被看作是一个重复的,但希望有人会认为这个答案仍然有用。 最后,使用
模式的原因可以从参数化类型的继承关系中看出,详细内容可能是。例如,为了说明最相关的一点:列表
不是列表的子类型
下面是一个例子,展示了它在哪些方面可以发挥作用。它包含了一个“琐碎”的实现,它总是能够工作(据我所知,这是没有意义的)。但是,当类型参数T
和U
也是方法参数和返回类型的类型参数时,类型界限变得相关。当T扩展U
时,可以返回一个类型,该类型的类型参数为超类型。否则,您将无法执行,如示例所示,//不起作用
:
import java.util.ArrayList;
import java.util.List;
public class SupertypeMethod {
public static void main(String[] args) {
Integer integer = null;
Number number = null;
List<Number> numberList = null;
List<Integer> integerList = null;
// Always works:
integer = fooTrivial(integer);
number = fooTrivial(number);
number = fooTrivial(integer);
numberList = withList(numberList);
//numberList = withList(integerList); // Does not work
// Both work:
numberList = withListAndBound(numberList);
numberList = withListAndBound(integerList);
}
public static <T, U extends T> T fooTrivial(U u) {
return u;
}
public static <T, U extends T> List<T> withListAndBound(List<U> u) {
List<T> result = new ArrayList<T>();
result.add(u.get(0));
return result;
}
public static <T> List<T> withList(List<T> u) {
List<T> result = new ArrayList<T>();
result.add(u.get(0));
return result;
}
}
import java.util.ArrayList;
导入java.util.List;
公共类超类型方法{
公共静态void main(字符串[]args){
整数=空;
数字=空;
List numberList=null;
List integerList=null;
//始终有效:
整数=英尺数(整数);
数字=英尺数(数字);
数字=英尺数(整数);
numberList=withList(numberList);
//numberList=withList(integerList);//不起作用
//这两项工作:
numberList=withListAndBound(numberList);
numberList=WithListandBund(整数列表);
}
公共静态T英尺(U){
返回u;
}
带ListAndBound的公共静态列表(列表u){
列表结果=新建ArrayList();
结果。添加(u.get(0));
返回结果;
}
公共静态列表withList(列表u){
列表结果=新建ArrayList();
结果。添加(u.ge
static class Holder<T> {
private final T t;
public Holder(T t) {
this.t = t;
}
public static <U, T extends U> U whenNull(U whenNull, Holder<T> holder) {
return holder.t == null ? whenNull : holder.t;
}
}
Optional.ofNullable(<SomeSubTypeThatIsNull>)
.orElse(<SomeSuperType>)
import java.util.ArrayList;
import java.util.List;
public class SupertypeMethod {
public static void main(String[] args) {
Integer integer = null;
Number number = null;
List<Number> numberList = null;
List<Integer> integerList = null;
// Always works:
integer = fooTrivial(integer);
number = fooTrivial(number);
number = fooTrivial(integer);
numberList = withList(numberList);
//numberList = withList(integerList); // Does not work
// Both work:
numberList = withListAndBound(numberList);
numberList = withListAndBound(integerList);
}
public static <T, U extends T> T fooTrivial(U u) {
return u;
}
public static <T, U extends T> List<T> withListAndBound(List<U> u) {
List<T> result = new ArrayList<T>();
result.add(u.get(0));
return result;
}
public static <T> List<T> withList(List<T> u) {
List<T> result = new ArrayList<T>();
result.add(u.get(0));
return result;
}
}