为何静态泛型方法的单个参数化类型可接受两种不同类型?兼析与非静态泛型方法的差异
静态泛型方法与非静态泛型方法的行为差异解析
先看你给出的代码示例:
class MyGeneric <T> { void method(T t1, T t2){} } class App{ static <T> void smethod(T t1, T t2){} //Java will infer the most specific supertype of the arguments passed in public static void main(String[] args){ MyGeneric<String> mg = new MyGeneric<>(); //! mg.method("hello", 123);// understandable smethod("hello", 123);// not understandable } }
1. 非静态泛型方法的行为
MyGeneric类的method是非静态泛型方法,它的泛型参数T是类级别的泛型参数。当你创建MyGeneric<String>实例时,这个T就被固定为String类型了——整个实例的所有非静态方法都会沿用这个T的类型。
所以调用mg.method("hello", 123)时,第一个参数是String,第二个是Integer,和已经确定的T=String不匹配,编译器自然报错,这部分你已经理解了。
2. 静态泛型方法的行为
App类的smethod是静态泛型方法,它的<T>是方法自己的泛型参数,和类的泛型(这里App没有类级泛型)完全无关。静态方法不属于任何实例,因此也无法使用类级别的泛型参数——它的泛型参数是独立的,每次调用都会重新推断。
Java编译器调用静态泛型方法时,会根据传入的参数自动推断出最具体的共同超类型作为T的类型。比如你传入String和Integer,它们的共同超类型包括Object、Serializable、Comparable<?>,编译器会选最具体的那个(这里实际是Serializable,字节码擦除后会用Object)。只要两个参数都能向上转型为这个推断出的T,调用就合法。所以smethod("hello", 123)能通过编译,因为String和Integer都可以被当作Serializable(或Object)处理。
3. 行为差异的根本原因
- 非静态泛型方法的泛型参数绑定到类的实例:实例创建时就确定了
T的类型,后续所有该实例的非静态方法调用都必须遵循这个类型。 - 静态泛型方法的泛型参数绑定到方法调用:每次调用都会根据传入的参数重新推断
T的类型,不受类(或实例)的泛型约束,只要参数能统一到某个共同超类型即可。
内容的提问来源于stack exchange,提问作者Squared
相关产品推荐
相关产品推荐

