场景
1 2 3 4 C:\Users\Administrator>java -version java version "1.8.0_381" Java(TM) SE Runtime Environment (build 1.8.0_381-b09) Java HotSpot(TM) 64-Bit Server VM (build 25.381-b09, mixed mode
1 2 3 4 5 6 7 ArrayList list = new ArrayList (); list.add("aaa" ); list.add("bbb" ); list.add("ccc" ); for (int i = 0 ; i < list.size(); i++) { System.out.println((String)list.get(i)); }
但如果在添加 String 对象时,不小心添加了一个 Integer 对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import java.util.ArrayList;public class Main { public static void main (String args[]) { ArrayList list = new ArrayList <>(); list.add("aaa" ); list.add("bbb" ); list.add("ccc" ); list.add(111 ); for (int i = 0 ; i < list.size(); i++) { System.out.println((String)list.get(i)); } } }
上述代码在编译时没有报错,但在运行时却抛出了一个 ClassCastException 异常
,其原因是 Integer 对象不能强转为 String 类型
1 2 Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String at Main.main(Main.java:11)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 import java.util.ArrayList;public class Main { public static void main (String args[]) { ArrayList<String> list = new ArrayList <>(); list.add("aaa" ); list.add("bbb" ); list.add("ccc" ); list.add(111 ); for (int i = 0 ; i < list.size(); i++) { System.out.println((String)list.get(i)); } } }
泛型类
1 2 3 4 5 6 7 class 类名称 <泛型标识> { private 泛型标识 /*(成员变量类型)*/ 变量名; ..... } }
尖括号 <> 中的 泛型标识被称作是类型参数
,用于指代任何数据类型
泛型标识是任意设置的(如果你想可以设置为 Hello都行),Java 常见的泛型标识以及其代表含义如下:
1 2 3 4 5 6 T :代表一般的任何类。 E :代表 Element 元素的意思,或者 Exception 异常的意思。 K :代表 Key 的意思。 V :代表 Value 的意思,通常与 K 一起配合使用。 S :代表 Subtype 的意思,文章后面部分会讲解示意。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class Generic <T> { private T key; public Generic (T key) { this .key = key; } public T getKey () { return key; } }
泛型类中的静态方法和静态变量不可以使用泛型类所声明的类型参数
1 2 3 4 5 6 7 public class Test <T> { public static T one; public static T show (T one) { return null ; } }
而静态变量和静态方法在类加载时已经初始化,直接使用类名调用;在泛型类的类型参数未确定时,静态成员有可能被调用,因此泛型类的类型参数是不能在静态成员中使用的。
泛型类不只接受一个类型参数,它还可以接受多个类型参数
1 2 3 4 5 6 7 8 9 10 11 12 13 public class MultiType <E,T> { E value1; T value2; public E getValue1 () { return value1; } public T getValue2 () { return value2; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class Generic <T> { private T key; public Generic (T key) { this .key = key; } public T getKey () { return key; } } public class Main { public static void main (String args[]) { Generic<String> generic = new Generic <>("hello" ); System.out.println(generic.getKey()); Generic generic1 = new Generic ("word" ); System.out.println(generic1.getKey()); } }
泛型接口
1 2 3 4 5 6 7 8 9 public interface 接口名<类型参数> { ... } public interface Inter<T> { public abstract void show(T t) ; }
在泛型接口中,静态成员也不能使用泛型接口定义的类型参数
1 2 3 4 5 6 7 8 9 10 interface IUsb <U, R> { int n = 10 ; U name; R get (U u) ; void hi (R r) ; default R method (U u) { return null ; } }
定义一个接口 IA 继承了 泛型接口 IUsb,在 接口 IA 定义时必须确定泛型接口 IUsb 中的类型参数 。
1 2 3 4 interface IA extends IUsb <String, Double> { }
AA继承了IA的接口,而IA接口继承了IUsb并指定了特定的泛型参数,因此AA其实就是实现了IUsb接口的方法get和hi方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class AA implements IA { public Double get (String s) { System.out.println("AA 的Double get=" + s); return null ; } public void hi (Double d) { System.out.println("AA hi=" +d); } public void test () { System.out.println("test" ); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 public class Main { public static void main (String args[]) { AA aa = new AA (); aa.get("哈哈" ); aa.hi(10.01 ); aa.test(); } } AA 的Double get=哈哈 AA hi=10.01 test
当然也可以直接用:定义一个类 BB 实现了 泛型接口 IUsb,在 类 BB 定义时需要确定泛型接口 IUsb 中的类型参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class BB implements IUsb <Integer, Float> { @Override public Float get (Integer integer) { System.out.println("BB Float get=" + integer); return 10.11F ; } @Override public void hi (Float afloat) { System.out.println("BB hi=" +afloat); } }
定义一个类 CC 实现了 泛型接口 IUsb 时,若是没有确定泛型接口 IUsb 中的类型参数,则默认为 Object
1 2 3 4 5 6 7 8 9 10 11 12 13 public class CC implements IUsb { @Override public Object get (Object o) { System.out.println("CC object get=" + o.toString()); return null ; } @Override public void hi (Object o) { System.out.println("cc object hi=" + o.toString()); } }
定义一个类 DD 实现了 泛型接口 IUsb 时,若是没有确定泛型接口 IUsb 中的类型参数,也可以将 DD 类也定义为泛型类,其声明的类型参数必须要和接口 IUsb 中的类型参数相同
1 2 3 4 5 6 // DD 类定义为 泛型类,则不需要确定 接口的类型参数 // 但 DD 类定义的类型参数要和接口中类型参数的一致 class DD<U, R> implements IUsb<U, R> { ... }
泛型方法
当在一个方法签名中的返回值前面声明了一个 < T > 时,该方法就被声明为一个泛型方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public <类型参数> 返回类型 方法名(类型参数 变量名) { ... } public class Test<U> { // 该方法只是使用了泛型类定义的类型参数,不是泛型方法 public void testMethod(U u){ System.out.println(u); } // <T> 真正声明了下面的方法是一个泛型方法 public <T> T testMethod1(T t){ return t; } }
1 2 3 4 5 6 7 8 9 10 public class Test<T> { // 是泛型类中的普通方法 public void testMethod(T t) { System.out.println(t); } // 是一个泛型方法 public <T> T testMethod1(T t) { return t; } }
1 2 3 4 5 6 7 8 9 public class Main { public static void main(String args[]) { Test test = new Test<Integer>(); test.testMethod("112"); String tt = (String) test.testMethod1("你好"); System.out.println(tt); } }
1 2 3 4 5 6 7 8 9 10 public class Test { public void testMethod (String t) { System.out.println(t); } public <T> T testMethod1 (T t) { return t; } }
在调用泛型方法的时候,可以显式地指定类型参数,也可以不指定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 public class Test { public static <T> T add (T x, T y) { return y; } public static void main (String[] args) { int i = Test.add(1 , 2 ); Number f = Test.add(1 , 1.2 ); Object o = Test.add(1 , "asd" ); int a = Test.<Integer>add(1 , 2 ); int b = Test.<Integer>add(1 , 2.2 ); Number c = Test.<Number>add(1 , 2.2 ); } }
泛型类,在创建类的对象的时候确定类型参数的具体类型; 泛型方法,在调用方法的时候再确定类型参数的具体类型。
总结
后续还有更多高级的用法,比如类型擦除、通配符等有空继续按照此博主 内容进行学习