Java_如何编写自己的泛型类

泛型

泛型,即参数化类型,类似于方法中将变量参数化,泛型是将原来定义的具体的类型参数化。

使用泛型的需求

Java中为什么要使用泛型,是因为泛型使用起来非常之方便,泛型类/方法针对于面向复用的开发。当我们想让一个类/方法同时适配于多种数据类型,这将大大省去我们编写重复代码的时间。

举一个常见的例子说明:

List<Integer> ilist = new ArrayList<Integer>();
List<String>  slist = new ArrayList<String>();

其中List接口以及类ArrayList均使用了泛型,从而可以构造出接收以类型Integer, String为参数的list;
所以下面的add操作中可以用不同类型的变量作为参数(用泛型可以省去重载方法的开销):

ilist.add(1);
ilist.add(2);
System.out.println(ilist);
slist.add("a");
slist.add("b");
System.out.println(slist);

分别输出为[1, 2] [a, b]

泛型应用场景

在这里插入图片描述
可以看到,除了部分底层的实现类,上层的类/抽象类/接口基本都是用泛型实现的,用泛型实现能够很好地进行复用,比如这里的L可以是Employee,Course,Process,从而派生出三个具体子类DutyIntervalSet,CourseIntervalSet,ProcessIntervalSet。

下面我们将以上图为例介绍如何编写一个自己的泛型类。

如何编写自己的泛型类

我们以MultiIntervalSet为例进行分析:
编写面向泛型的类时需要注意以下几点:
①泛型类的声明:需要在类名后加上<L>

public class MultiIntervalSet<L> implements IMultiIntervalSet<L>

②需要用到泛型的地方,全部用L代替

protected final Set<L> elabel = new HashSet<>();
protected final Map<L, List<Interval>> emap = new HashMap<>();

③只能对定义为泛型的变量做一些通用的操作
对于一个L label的泛型变量label,可以对它进行list.add(label),set.contains(label)等操作,由于它在具体传入的时候已经变成了一个具体的类。但是想要显式地调用它自己的方法只能调用如下几种(此时感觉label就是一个原始的Object类):
在这里插入图片描述
要小心,不要代入某个具体的类型,调用它特有的方法;
所以这也是泛型的一个局限性,对于通用的操作可以复用,但如果要用到某个具体类的方法,则不能将该类型作为参数传递。

④泛型类中可以有非泛型方法,也可以有非泛型的成员变量。
这点很好理解,泛型类中不一定每个方法都需要用到泛型,用到泛型时才是泛型方法;同时泛型类中当然也可以有具体类型的成员变量。

protected final Set<L> elabel = new HashSet<>();
protected final Map<L, List<Interval>> emap = new HashMap<>();
protected Interval duration;

最后给出一个泛型方法的例子
public boolean remove(L label) {
    
    
		if(!elabel.contains(label)) return false;
		else {
    
    
			emap.remove(label);
			elabel.remove(label);
			checkRep();
			return true;
		}
	}

总结

总之,写泛型类的时候要保持平常心,将L当作一个普通的类型去编写代码,开始时不要因为觉得L的写法陌生,而不敢对它进行操作,或者不愿意自定义泛型类/方法。


补充介绍:类型通配符

类型通配符一般是使用?代替具体的类型参数。例如 List<?> 在逻辑上是List<String>,List<Integer> 等所有List<具体类型实参>的父类。
①在某些情况下,我们必须使用到类型通配符,否则静态编译时会报错:
比如:重写equals函数时用到instanceof运算符

@Override public boolean equals(Object obj) {
    
    
    	if(obj instanceof Edge<L>) {
    
    
			Edge<L> e = (Edge<L>)obj;
		//...后续逻辑省略	

编译报错:Cannot perform instanceof check against parameterized type Edge. Use the form Edge<?> instead since further generic type information will be erased at runtime

修改为下图所示,编译通过。

if(obj instanceof Edge<?>) {
    
    
			Edge<?> e = (Edge<?>)obj;

②类型通配符还可以用于特定的情形
比如限定类型的上/下限:

List<? extends Number>
限定接收类型的上限为Number,接受Number及其下层子类类型

List<? super Number>
限定接收类型的下限为Number,接受Number及其三层父类类型,如 Object 类型的实例。

猜你喜欢

转载自blog.csdn.net/weixin_45577864/article/details/118520924