Java泛型 发表于 2021-03-24 | 更新于 2021-03-24
总字数: 2.4k | 阅读时长: 10分钟 | 阅读量:
泛型 概述 Java 泛型是 JavaSE1.5 中引入的一个新特性,其本质是参数化类型,也就是说所操作的数据类型被指定为一个参数(type parameter)这种参数类型在定义的时候是宽泛的,而在使用的时候是确定的。可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。
泛型的优点 1 2 3 4 1、提高了程序的安全性(类型安全) 2、提高了程序的可扩展性、可重用性 3、将运行期遇到的问题转移到了编译期 4、省去了类型强转的麻烦(Object类对象)
泛型格式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 泛型标识符:<自定义无意义英文大写单字母占位符> 常用格式: <T> Type <E> Element <K> Key <V> Value 泛型类:把泛型定义在类上 格式:class 类名<泛型类型1,…> 【注意】泛型类型必须是引用类型 泛型方法:把泛型定义在方法上 格式:public <泛型类型> 返回类型 方法名(泛型类型 .) 泛型接口:把泛型定义在接口上 格式:public interface 接口名<泛型类型1…>
泛型方法 案例代码 1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class GenericityMethodDemo { public static void main (String[] args) { System.out.println(getData(100 )); System.out.println(getData("Java" )); System.out.println(getData('A' )); System.out.println(getData(false )); } public static <T> T getData (T t) { return t; } }
案例代码 2
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 public class GenericityMethodDemo2 { public static void main (String[] args) { Integer[] intArr = {1 , 2 , 3 }; String[] stringArr = {"4" , "5" , "6" }; Student[] students = {new Student("张三" , 1 ), new Student("李四" , 2 ), new Student("王五" , 3 )}; printArray(intArr); printArray(stringArr); printArray(students); } public static <T> void printArray (T[] t) { for (int i = 0 ; i < t.length; i++) { System.out.println(t[i]); } } }
【注意】
1 2 3 4 5 1、要求形式参数列表中必须有一个参数是当前自定义泛型,因为需要通过参数来约束当前方法运行过程中泛型对应的具体数据类型是哪一个 2、返回值类型可以使用自定义泛型,而且是被形式参数列表中传入的泛型对应具体的数据类型控制 3、方法体内也可以使用自定义泛型,同时也是被参数当中泛型对应具体数据类型约束监控
泛型类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class GenericityClassDemo { public static void main (String[] args) { Number<Integer> num1 = new Number<Integer>(100 ); Number<String> num2 = new Number<String>("100" ); System.out.println(num1.getT()); System.out.println(num2.getT()); } } class Number <T > { private T t; }
【注意】
1 2 3 4 5 1、类内可以直接使用对应的类名声明泛型 2、类内使用的泛型具体数据类型是在创建当前类对象时约束 3、在创建当前类对象时没有约束泛型对应的具体数据类型,那么所有使用到泛型的位置都是Object类型,有悖于泛型使用原则 4、如果类声明过了泛型,那么类中所有使用此泛型的方法都同时被声明,即无法使用其他类型 5、泛型类中定义的静态方法不能直接使用类声明的泛型,因为泛型需要在创建对象时声明,而静态方法在类加载时就加载完成,此时泛型还没有声明。如果静态方法想要使用泛型,只能自己声明自己使用
泛型接口
案例代码 1
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 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 interface USB {}class Mouse implements USB {}class Keyboard implements USB {}interface PC <T > { T use (T t) ; } class MyPC <T > implements PC <T > { @Override public T use (T t) { return t; } } class YourPC implements PC <Mouse > { @Override public Mouse use (Mouse t) { return t; } } public class GenericityInterfaceDemo { public static void main (String[] args) { MyPC<Keyboard> myPC = new MyPC<Keyboard>(); Keyboard keyboard = myPC.use(new Keyboard()); System.out.println(keyboard); System.out.println("-----------------" ); YourPC yourPC = new YourPC(); Mouse mouse = yourPC.use(new Mouse()); System.out.println(mouse); } }
案例代码 2
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 34 35 36 37 38 39 40 interface Comparable <T > { public abstract int compareTo (T t) ; } class Father implements Comparable <Father > { private String name; private int age; @Override public int compareTo (Father f) { return this .age - f.age; } } public class GenericityInterfaceDemo { public static void main (String[] args) { Father father1 = new Father("小明父亲" , 30 ); Father father2 = new Father("小红父亲" , 29 ); if (father1.compareTo(father2) < 0 ) { System.out.println("小红父亲年长:" + father2.getAge()); } else { System.out.println("小明父亲年长:" + father1.getAge()); } } }
【注意】
1 2 1、接口中的成员变量不能使用泛型,因为static、final 2、泛型接口的实现类可以指定泛型的类型,也可以不指定,如果在实现类中明确了数据类型,创建对象时就不需要再进行明确
泛型通配符 在泛型中,? 表示未知类型,被称为通配符。通配符可以在各种情况下使用:可以作为形式参数、成员变量、局部变量的类型,也可以作为返回值类型。但是,通配符不能用于泛型方法调用、泛型类实例创建对象或者父类的类型实际参数
表示全部类型,类似 Object。区别于 T,T 只是占位符,而 ?是数据类型
【使用场景】
1 2 3 1、当一个方法可以用Object类提供的功能来实现时,泛型通配符是使用的 2、若代码使用了泛型类中的方法,而这些方法又是不依赖于参数化类型的,可以使用泛型通配符
案例代码
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 class Grade <T > { private T t; public void show () { System.out.println("show" + this ); } } class School { public void showGrade (Grade<?> grade) { grade.show(); } } public class GenericityWildCardDemo { public static void main (String[] args) { School school = new School(); school.showGrade(new Grade<Student>(new Student())); school.showGrade(new Grade<Teacher>(new Teacher())); } }
泛型上限 表示以 T 为父类的所有子类(包括父类)
泛型下限 表示以 E 为子类的所有父类(包括子类)
案例代码
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 class School { public void showGrade (Grade<?> grade) { grade.show(); } public void showExtends (Grade<? extends Person> grade) { System.out.println(grade); } public void showSuper (Grade<? super Person> grade) { System.out.println(grade); } } public class GenericityWildCardDemo { public static void main (String[] args) { School school = new School(); school.showGrade(new Grade<Student>(new Student())); school.showGrade(new Grade<Teacher>(new Teacher())); school.showExtends(new Grade<Student>()); school.showSuper(new Grade<Object>()); } }
泛型推断 JDK1.7 新特性,可以省略实例化对象时尖括号内的类型
案例代码
1 2 3 4 5 6 7 8 9 public class GenericityInferDemo { public static void main (String[] args) { Grade<Student> grade = new Grade<>(); Student student = grade.getT(); } }
总结 1、泛型就是泛化的类型,本质是参数化类型,是 jdk1.5 引入的新特性,用在类、接口和方法上,即泛型类,泛型接口和泛型方法
2、为了解决利用继承 Object 来实现通用性导致的强制类型转换和可能发生的类型转换异常的问题。
3、泛型的好处是确保了编译时期的类型安全,和避免了强制类型转换的麻烦
4、缺陷是因为泛型使用了类型擦除机制,jvm 运行之前会将泛型信息擦除掉,这样做是为了兼容 jdk1.5 之前的代码,但是也会导致通过反射可以跳过泛型的问题,因为运行期间并没有泛型的限制
5、泛型通配符?代表任意类型,泛型上限<? extends T>,泛型下限<? super T>
6、jdk1.7 新特性泛型推断,声明变量时定义过泛型得话,在实例化对象时可以省略类型,但是还要加<>,否则还是原类型
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 闲花博客 | Lu's Blog