泛型
**泛型用在何处:**当我们在声明类或接口时,类或接口中定义某个成员时,该成员有些类型是不确定的,而这个类型在使用这个类或接口时可以确定,那么我们可以使用泛型。
**泛型的好处:**可以有效的避免强转
泛型如何使用:
使用的类或者接口或者方法已经定义好泛型,我们才可以用!
在使用该内容的时候,指定其具体类型:
在实例化对象的时候,等号左侧的泛型需要指定,等号右侧可以省略
泛型的具体类型不能是基本数据类型,只能是引用数据类型
泛型是不存在多态的
语法格式:(重点)
【修饰符】 class 类名<类型变量列表>{
}
【修饰符】 interface 接口名<类型变量列表>{
}
//尖括号中写任意字母(大小写都OK[一般用大写字母])例如:<T,E,B,C>
/*
泛型在类体中:
作为属性的类型
作为方法的形参
作为方法的返回值类型
特殊:
静态的资源不能使用泛型
泛型不能够创建数组
使用:直接实例化其对象
在实例化对象的时候指定泛型的具体类型
将其作为父类、父接口
在继承的时候,就可以确定父级中的泛型类型
class Sub extends Student<String,Double>
在继承的时候,无法确定父级中的泛型类型,需要实例化子类对象的时候在确定
class Sub<T,H,A> extends Student<T,H>{
*/
注意:
- <类型变量列表>:可以是一个或多个类型变量,一般都是使用单个的大写字母表示。例如:、<K,V>等。
- <类型变量列表>中的类型变量不能用于静态成员上。
示例代码:
例如:我们要声明一个学生类,该学生包含姓名、成绩,而此时学生的成绩类型不确定,为什么呢,因为,语文老师希望成绩是“优秀”、“良好”、“及格”、“不及格”,数学老师希望成绩是89.5, 65.0,英语老师希望成绩是’A’,‘B’,‘C’,‘D’,‘E’。那么我们在设计这个学生类时,就可以使用泛型。
public class Student<T>{
private String name;
private T score;
public Student() {
super();
}
public Student(String name, T score) {
super();
this.name = name;
this.score = score;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public T getScore() {
return score;
}
public void setScore(T score) {
this.score = score;
}
@Override
public String toString() {
return "姓名:" + name + ", 成绩:" + score;
}
}
使用泛型类与泛型接口
(1)实际类型参数必须是引用数据类型,不能是基本数据类型
(2)在创建类的对象时指定类型变量对应的实际类型参数
(2)在创建类的对象时指定类型变量对应的实际类型参数
public class TestGeneric{
public static void main(String[] args) {
//语文老师使用时:
Student<String> stu1 = new Student<String>("张三", "良好");
//数学老师使用时:
//Student<double> stu2 = new Student<double>("张三", 90.5);//错误,必须是引用数据类型
Student<Double> stu2 = new Student<Double>("张三", 90.5);
//英语老师使用时:
Student<Character> stu3 = new Student<Character>("张三", 'C');
//错误的指定
//Student<Object> stu = new Student<String>();//错误的
}
}
JDK1.7支持简写形式:Student stu1 = new Student<>(“张三”, “良好”);
指定泛型实参时,必须左右两边一致,不存在多态现象
(3)在继承参数化的类或实现参数接口时,指定类型变量对应的实际类型参数
class ChineseStudent extends Student<String>{
public ChineseStudent() {
super();
}
public ChineseStudent(String name, String score) {
super(name, score);
}
}
public class TestGeneric{
public static void main(String[] args) {
//语文老师使用时:
ChineseStudent stu = new ChineseStudent("张三", "良好");
}
}
类型变量的上限(全部限制)
当在声明类型变量时,如果不希望这个类型变量代表任意引用数据类型,而是某个系列的引用数据类型,那么可以设定类型变量的上限。
目的 :缩小泛型具体类型的范围
语法格式:
<T extends 类、接口>
或者
<类型变量 extends 上限>
如果有多个上限
<类型变量 extends 上限1 & 上限2>
如果多个上限中有类有接口,那么只能有一个类,而且必须写在最左边。接口的话,可以多个。
如果在声明<类型变量>时没有指定上限,默认上限是java.lang.Object。
注意:
泛型的上限可以设置两个类吗?不可以
泛型的上限可以设置两个接口吗? 可以
泛型的上限可以同时有类和接口吗? 可以(类必须在首位)
泛型擦除
会发生泛型擦除,自动按照最左边的第一个上限处理。如果没有指定上限,上限即为Object。
如果泛型有上限,就以上限为准
自定义泛型方法
语法: 方法修饰符 <T,E…>
语法格式:
【修饰符】 <类型变量列表> 返回值类型 方法名(【形参列表】)【throws 异常列表】{
//...
}
- <类型变量列表>:可以是一个或多个类型变量,一般都是使用单个的大写字母表示。例如:、<K,V>等。
- <类型变量>同样也可以指定上限
类型通配符
<?>任意类型(局部限制)
<?> 任意类型(兼容各个版本)
<? extends 上限> 设置上限 (大)
<? super 下限> 设置下限 (小)