Java泛型(1)基础部分、 Type Parameter、Type Argument、parameterized type 、raw type 等
1.官方文档
|
https://docs.oracle.com/javase/tutorial/java/generics/index.html |
|
https://docs.oracle.com/javase/tutorial/java/generics/types.html |
|
https://docs.oracle.com/javase/tutorial/java/generics/rawTypes.html https://docs.oracle.com/javase/specs/jls/se17/html/jls-4.html#jls-4.8 |
|
https://docs.oracle.com/javase/tutorial/java/generics/genTypeInference.html |
2.用泛型的好处
- Stronger type checks at compile time.
A Java compiler applies strong type checking to generic code and issues errors if the code violates type safety. Fixing compile-time errors is easier than fixing runtime errors, which can be difficult to find. - Elimination of casts.
The following code snippet without generics requires casting:List list = new ArrayList(); list.add("hello"); String s = (String) list.get(0);
List<String> list = new ArrayList<String>(); list.add("hello"); String s = list.get(0); // no cast
- Enabling programmers to implement generic algorithms.
By using generics, programmers can implement generic algorithms that work on collections of different types, can be customized, and are type safe and easier to read.
3.泛型中的类型名词
3.1 Generic Type : 泛型类型
以通过参数传递类型形式定义的类或者接口,如下面的GenericClass和GenericInterface都是泛型类型。
interface GenericInterface<T,U,V> { }
class GenericClass <T,U,V> { }
3.2 Type Parameter (Type Variable) : 类型形参(类型变量)
上述代码中的 T、U、V 就是类型形参,也叫类型变量。
以下类型可以作为类型形参:[ 类,接口,数组,其它类型变量 ] 。
类型形参的命名习惯(非强制)如下:
- E - Element (used extensively by the Java Collections Framework)
- K - Key
- N - Number
- T - Type
- V - Value
- S,U,V etc. - 2nd, 3rd, 4th types
3.3 Type Argument : 类型实参
传递给类型形参的实际参数就是类型实参。
- 在声明时 Foo<T> 中的T就是类型形参
- 在定义时 Foo<String> 中的 String 就是类型实参.
3.4 parameterized type : 参数化类型
类型 + <泛型形参> 组合 就是参数化类型,如:List<String> 。它可以作为泛型实参,如:
class A<T> { }
//class B<N,A<N> > { } //error
class C<P> { }
class D<P extends A<P>> { }
public class ParameterizedTypes {
@Test
public void main(){
A<Integer> ai = new A<>();
C<A<Float>> ca = new C<>();
}
}
3.5 Raw Type : 泛型生类型
在java官方文档中,有两处关于 Raw Type的介绍:
第1处:
https://docs.oracle.com/javase/tutorial/java/generics/rawTypes.html
第2处:
https://docs.oracle.com/javase/specs/jls/se17/html/jls-4.html#jls-4.8
总结如下:
- 泛型类型在定义且未指定泛型实参时,这个类型就是raw type
- 数组类型对应的元素类型是raw type
- 非泛型类型不是Raw Type
示例:
class Ra <T>{ public void fun(T t){} } //只是个泛型类型声明
class Rb { public void fun( ){} } //只是个类声明
public class RawTypes {
@Test
public void testRawType(){
Ra<Integer> rai = new Ra<>(); //Ra<Integer> is parameterized type
Ra ra = rai ; //Ra is a raw type of Ra<T>
Ra<String> ras = new Ra() ; //warning,unchecked assignment,Ra is a raw type of Ra<T>,
ra.fun("test") ; //warning,unchecked call
}
}
其中第9、10行产生警告,原因是编译器在执行泛型擦除的时候无法得到类型的确定信息,从而无法安全擦除。
可以使用-Xlint:-unchecked flag 和 @SuppressWarnings("unchecked") 关闭这个警告。
4.泛型函数
4.1 约定
- [ 构造函数、普通函数、静态函数 ] 可以使用泛型。
- 泛型形参的个数可为多个
- 泛型形参支持通配符类型
4.2 示例
class M1 {
public <T> M1(T m) { System.out.println("M1::constructor") ; }
public void foo() { System.out.println("M1::foo") ; }
}
public class Methods {
public Methods() { System.out.println("constructor") ;}
//public <T> Methods(T t) { System.out.println("con(" + t.getClass().getSimpleName() + ")") ;}
public <K,V> void fun(K k,V v) { System.out.println("fun(" + k.getClass().getSimpleName() + ")") ;}
public static <K> void foo(K k) { System.out.println("foo(" + k.getClass().getSimpleName() + ")") ;}
//public <T> static void foo(){} //error ,<T>在 static后面,返回值前面。
@Test
public void test_generic_method1(){
Methods obj = new Methods() ; //constructor
obj.<Integer,Double>fun(1,2.0) ; //fun(Integer)
obj.<Float,Byte>fun(1f, (byte) 0b1) ; //fun(Float)
obj.fun("s","") ; //fun(String)
obj.foo(1) ; //foo(Integer)
Methods.<String>foo("ok") ; //foo(String)
M1 m = new M1(3) ; //构造泛型函数
m.foo() ;
}
public <T extends Number> void f2(T t) {}
public void f3(Collection<? super Number> t){}
@Test
public void test_generic_method2(){
Methods obj = new Methods() ; //constructor
obj.<Integer>f2(1);
obj.f2(3f);
//obj.<String>f2("error"); //error
obj.f3(new ArrayList<Object>());
//obj.f3(new ArrayList<Integer>()); //error
}
}
输出结果为:
constructor
constructor
fun(Integer)
fun(Float)
fun(String)
foo(Integer)
foo(String)
M1::constructor
M1::foo
4.3 泛型类的泛型构造函数
/**
* 泛型类的构造函数为泛型
*/
@Test
public void test_generic_constructor1(){
class Vector <T> {
Object mObject;
<U> Vector(U u){
mObject = u;
}
}
Object obj = new Vector<Integer>("hello");
Vector<Float> fv = new Vector<>("hi") ;
Vector<Byte> vt = new Vector("yes") ;
}
4.4 普通类的泛型构造函数
/**
* 普通类的构造函数为泛型。
*/
@Test
public void test_generic_constructor2(){
class V2{
Object mObject;
<U> V2(U u){
mObject = u;
}
}
//Object obj2 = new V2<String>("1") ;
V2 fv2 = new V2(33f) ;
V2 vt2 = new V2("yes") ;
}