泛型

泛型

泛型的好处:安全、避免类型转换

泛型的使用形式有两种:泛型类/泛型接口、泛型方法

一、泛型类

语法格式

[修饰符] class 类名<泛型形参列表>{
}
[修饰符] interface 类名<泛型形参列表>{
}
public interface Collection<E>  //<E>就是泛型形参列表
public class ArrayList<E>       //<E>就是泛型形参列表
public class HashMap<K,V>	   //<K,V>就是泛型形参列表

要求:泛型是针对引用数据类型的,不能是各种基本数据类型。

public class UDFGeneric {
	public static void main(String[] args) {
		//语文老师
		Student<String> chinese = new Student<String>();
		
		//数学老师
		Student<Double> math = new Student<Double>();
		
		//英语老师
		Student<Character> english = new Student<Character>();
	}
	
}

/*
* 定义一个特殊的学生类,学生类包含两个属性:姓名、成绩
* 此时成绩的情况很复杂
* 语文老师表示学生时,成绩等级为:优秀、良好、及格、不及格
* 数学老师表示学生时,成绩为98.5,96.5....
* 英语老师在表示学生时,成绩为ABCD
*/

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;
	}
	
}

如何为泛型类、泛型接口指定泛型实参?

  • 创建泛型类的对象时
Student<String> chinese = new Student<String>();
  • 继承泛型类时可以指定泛型实参
  • 实现泛型接口时可以指定泛型实参
class ChineseStudent extends Student<String>{
}
class Employee implements Comparable<Employee>{
	private int id;
	private String name;
	public Employee(int id, String name) {
		super();
		this.id = id;
		this.name = name;
	}
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	@Override
	public String toString() {
		return "Employee [id=" + id + ", name=" + name + "]";
	}
	@Override
	public int compareTo(Employee o) {
		return this.id - o.id;
	}
	
}

泛型类或泛型接口上的<泛型形参>这个类型可以用在哪些地方?

  • 可以用于属性、方法的数据形参、局部变量的类型
  • 不能用于静态成员(因为静态成员可以通过类名调用,但是泛型在很多时候必须在实例化的时候指定)
class MyClass<T>{
	private T t;  //用于当作属性的数据类型

	public MyClass(T t) { //用于当作方法的数据形参的类型
		super();
		this.t = t;
	}
	//可以用于返回值的类型
	public T getT() {
		return t;
	}

	public void setT(T t) {
		this.t = t;
	}

	@Override
	public String toString() {
		return "MyClass [t=" + t + "]";
	}
	
	public void test() {
		T t; //可以用于局部变量的类型
	}
}

泛型类或泛型接口的泛型形参,可以设定上限

<T extends 上限> //T的类型实参只能是上限本身或者上限子类
<T extends 上限1 & 上限2 &上限3 .....>

如果在使用泛型类或者泛型接口时没有指定泛型实参,会怎么样?

这种现象为泛型被擦除。泛型被擦除后,泛型形参被解析为泛型形参的第一个上限类型。

  • 如果没有指定泛型形参上限,按Object处理
  • 如果制定了泛型形参的上限,就按照上限处理
  • 如果有多个上限,按照最左边的第一个上限处理

在这里必须说明泛型形参有多个上限的情况

//T的实参要求,同时是Number的子类,还要实现Comparable和Serializable接口
class AClass<T extends Number & Comparable & Serializable>{
}

二、泛型方法

什么情况需要声明泛型方法?

  • 如果某个静态方法想要使用泛型,需要单独设计

    例如:java.util.Arrays数组工具类

    public static <T> List<T> asList(T... a)
    
  • 如果泛型类型或者泛型接口上的泛型形参不适用于某一个方法(可以是静态的,也可以非静态),那么这个方法可以单独设计泛型

    例如:java.util.Collection<E>

    public abstract <T> T[] toArray(T[] a)
    

泛型方法的语法格式

[修饰符] <泛型形参列表> 返回值类型 方法名([数据形参列表])

泛型方法的<泛型形参列表>这个类型就用于当前方法的形参类型、返回值类型、局部变量,和其他方法无关

泛型方法的类型形参什么时候指定类型实参

当调用方法时,编译器会根据方法的实参的类型,来确定泛型的实参类型。

List<Integer> asList = Arrays.asList(1,2,3,4,5);//根据1,2,3,4,5,可以确定是Integer类型

泛型方法的<泛型形参列表>中也可以指定上限

public <T extends Number> void test(T t){}

三、通配符

通配符:wildcard

形式

<?>  //代表可以是任意类型
<? extends 上限>   //?代表是上限或者上限的子类
<? super 下限>   //?代表是下限或者下限的父类

什么情况下使用通配符

/*
声明一个方法,这个方法可以用于遍历所有Collection系列的集合,此时因为Collection是一个泛型接口,Collection<E>,如果不指定<E>的具体类型,会报警告,对于这种情况,有两种选择,(一)抑制警告;(二)用?来表示任意类型
*/
public void print(Collection<?> c){
    for (Object object : c){
        System.out.println(object);
    }
}
public void print(Collection<Object> c){
    for (Object object : c){
        System.out.println(object);
    }
}
print(Collection<String> c);//这是错误的,一定会报错

Object可以接受任意类型对象,但是不代表Collection<Object>可以接收任意泛型实参的集合。

ArrayList<Object> obj = new ArrayList<String>;
//这是绝对错误的写法,这不是多态,这是乱写

所以通配符在某种意义上实现了泛型的多态

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值