12.Java 泛型(自定义泛型类、自定义泛型接口、自定义泛型方法、泛型的继承与通配符)
一、泛型引入
1、为什么需要泛型
传统方式存在的问题
-
不能对加入到集合中的数据类型进行约束
-
遍历时,需要进行类型转换
泛型的理解与好处
-
编译时能检查添加元素的类型
-
能减少类型转换的次数
2、泛型初体验
(1)说明
- 这里以 Dog 类为例
ArrayList<Dog> list = new ArrayList<Dog>();
-
不使用泛型:放入集合时,Dog 类型会先转换为 Object 类型,取出时,需要转换为 Dog 类型
-
使用泛型:放入集合和取出时,不需要进行类型转换
(2)演示
package com.my.test;
import java.util.ArrayList;
import java.util.Iterator;
public class GenericTest {
public static void main(String[] args) {
ArrayList<Dog> list = new ArrayList<>();
list.add(new Dog("小黄", 2));
list.add(new Dog("小汪", 3));
list.add(new Dog("小多", 4));
System.out.println("========== 增强 for 循环遍历 ==========");
for (Dog dog : list) {
System.out.println(dog);
}
System.out.println("========== 迭代器循环遍历 ==========");
Iterator<Dog> iterator = list.iterator();
while (iterator.hasNext()) {
Dog dog = iterator.next();
System.out.println(dog);
}
}
}
class Dog {
String name;
int age;
public Dog(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
- 输出结果
========== 增强 for 循环遍历 ==========
Dog{name='小黄', age=2}
Dog{name='小汪', age=3}
Dog{name='小多', age=4}
========== 迭代器循环遍历 ==========
Dog{name='小黄', age=2}
Dog{name='小汪', age=3}
Dog{name='小多', age=4}
3、泛型概述
-
在类声明或实例化时制定好需要的具体类型
-
可以保证在编译时没有警告,运行时就不会产生 ClassCastException(类型转换异常)
-
通过标识表示类中某个属性的类型,某个方法的参数类型或返回值类型
4、泛型语法
- 自定义泛型类
class 【类名】 <T> {}
- 自定义泛型接口
class 【接口名】 <T> {}
- 自定泛型方法
【修饰符】 <T> 【返回数据类型】 【方法名】(【参数列表】) {}
5、注意事项
-
T 表示类型(Type 的缩写,也可以为 K、V 等),且必须是引用类型
-
指定泛型具体类型后,可以传入该类型或者其子类类型
-
泛型的简写
// 完整写法
ArrayList<Dog> list = new ArrayList<Dog>();
// 简写
ArrayList<Dog> list = new ArrayList<>();
- 这样写 ArrayList<> list = new ArrayList<>();,默认指定泛型具体类型为 Object 类型
二、自定义泛型类
1、基本介绍
class 【类名】 <T> {}
2、注意事项
- 普通成员可以使用泛型
T t;
- 使用泛型的数组不能初始化,因为不能确定 T 的类型,无法开辟空间,在指定泛型的具体类型后才能初始化
// 错误写法
T arr[] = new T[];
-
静态成员不能使用泛型,因为静态成员与类相关,类加载时,静态成员无法确定泛型的具体类型,无法完成初始化
-
泛型的具体类型在创建对象时确定
-
创建对象时,没有指定泛型的具体类型,默认为 Object 类型
3、演示
- CustomGenericsClassTest.java
package com.my.test;
public class CustomGenericsClassTest {
public static void main(String[] args) {
Person<String> person1 = new Person<>("jack");
Person<Integer> person2 = new Person<>(10);
person1.show();
person2.show();
}
}
class Person<T> {
T t;
public Person(T t) {
this.t = t;
}
public void show() {
System.out.println(this.t);
}
}
- 输出结果
jack
10
三、自定义泛型接口
1、基本介绍
class 【接口名】 <T> {}
2、注意事项
-
接口中静态成员不能使用泛型
-
接口的泛型的具体类型,在继承接口或实现接口时确定
-
没有指定泛型的具体类型,默认为 Object 类型
3、演示
- CustomGenericInterfaceTest.java
package com.my.test;
public class CustomGenericInterfaceTest {
public static void main(String[] args) {
new Student().show("jack");
}
}
class Student implements Person<String> {
@Override
public void show(String s) {
System.out.println(s);
}
}
interface Person<T> {
public void show(T t);
}
- 输出结果
jack
四、自定义泛型方法
1、基本介绍
【修饰符】 <T> 【返回数据类型】 【方法名】(【参数列表】) {}
2、注意事项
-
泛型方法可以定义在普通类和泛型类中
-
当泛型方法被调用时,泛型的具体类型被确定
-
public void method(T t) {} 不是泛型方法,而是使用了泛型
3、演示
- CustomGenericMethodTest.java
package com.my.test;
public class CustomGenericMethodTest {
public static void main(String[] args) {
Cat<String> cat = new Cat<>();
cat.show(10, "tom");
}
}
class Cat<K> {
public<T> void show(T t, K k) {
System.out.println(t.getClass());
System.out.println(k.getClass());
}
}
- 输出结果
class java.lang.Integer
class java.lang.String
五、泛型的继承与通配符
1、基本介绍
- 泛型不具备继承性
// 错误写法
List<Object> list1 = new ArrayList<String>();
-
<?>:支持任意类型
-
<? extends A>:支持 A 类以及 A 类的子类,规定了泛型的上限
-
<? super A>:支持 A 类以及 A 类的父类,规定了泛型的下限
2、演示
- GenericExtends.java
package com.my.test;
import java.util.ArrayList;
import java.util.List;
public class GenericExtends {
public static void main(String[] args) {
List<Object> list1 = new ArrayList<>();
List<String> list2 = new ArrayList<>();
List<AA> list3 = new ArrayList<>();
List<BB> list4 = new ArrayList<>();
List<CC> list5 = new ArrayList<>();
printList1(list1);
printList1(list2);
printList1(list3);
printList1(list4);
printList1(list5);
// printList2(list1); // ×
// printList2(list2); // ×
printList2(list3);
printList2(list4);
printList2(list5);
printList3(list1);
// printList3(list2); // ×
printList3(list3);
// printList3(list4); // ×
// printList3(list5); // ×
}
public static void printList1(List<?> list) {
for (Object o : list) {
System.out.println(o);
}
}
public static void printList2(List<? extends AA> list) {
for (Object o : list) {
System.out.println(o);
}
}
public static void printList3(List<? super AA> list) {
for (Object o : list) {
System.out.println(o);
}
}
}
class AA {}
class BB extends AA {}
class CC extends BB {}
原文地址:https://blog.csdn.net/weixin_52173250/article/details/144273035
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!