泛型程序设计

泛型介绍

泛型程序设计(Generic programming):可以被很多不同的类型的对象所重用。比那些直接使用Object变量,然后强制类型的转换的代码具有更好的安全性和可读性。

使用类型参数(type parameters)可以将需要使用的类型,提前声明。如:

ArrayList<String> list = new ArrayList<String>();

使用类型参数可以告知这个类适用于什么类型,当调用对应的get()方法的时候,不需要进行强制类型转换,编译器本身就知道其对应的类型。

当实现一个泛型的时候非常不容易,因为你需要知道这个这个类对应的所有用途及其类型,所以java提供了通配符类型,来解决这个问题。

定义简单泛型类

泛型类,就是指具有一个或者多个类型变量,也就是说这个类适应这几种类型。

使用类型变量T,用<>括起来,放在类名后面。这个泛型可以有多个类型变量,如<T,U>

可以使用类定义的类型变量指定类中属性和方法的类型。

public class Pari<T> {

    private T first;
    private T second;
    
    public Pari(){
        first = null;
        second = null;
    }
    public Pari(T first,T second){
        this.first = first;
        this.second = second;
    }
    
    public T getFirst(){
        return first;
    }
    
    public T getSecond(){
        return second;
    }
    
    public void setFirst(T value){
        first = value;
    }
    public void setSecond(T value){
        second = value;
    }
}


其实泛型类可以看做是普通类的工厂。

泛型方法

泛型方法既可以在普通类中,也可以在泛型类中,定义方式是在方法名前加<T> T,说明该方法是泛型方法

public static <T> T getText(T param){
		return param;
	}

类型变量的限定

有的时候,比如对于特定的方法执行特定的操作,但是该操作不适用于一些类型,这时可以对类型变量T设置限定,可以使其集成特别的类或者接口(没错,在这里对于接口也是使用继承,因为使用extends更加接近子类的意思),一个类型变量或通配符可以有多个限定

比如:T extends Comparable & Srializable

	public static <T extends Comparable> Pari<T> getMinMax(T[] word){
		
		if(word == null || word.length == 0)
			return null;
		T min = word[0];
		T max = word[0];
		for(int i=1;i<word.length;i++){
			if(word[i].compareTo(max) > 0)
				max = word[i];
			if(word[i].compareTo(min) < 0)
				min = word[i];
		}
		return new Pari<T>(min,max);
	}

注意:

JVM中没有泛型,只有普通的类和方法

所有的类型参数都是用他们的限定类型转换(如果没有类型参数,则使用Object类型),这个过程称为擦除(erased),擦除类型变量,并替换为限定类型

有时为保持类型安全性,需要插入强制类型转换


约束和局限性

不能用基本类型实例化类型参数

不能用类型参数代替基本类型:因此Pari<double>是错误的,需要使用pari<Double>,原因是类型擦除,擦除之后为Object类型,object类型并不能存储double值

类型查询只适用于基本类型

虚拟机中的对象总有一个特定的非泛型类型。因此,所有类型查询只产生原始类型。

如:if(a instanceof Pari<T>)是错误的,因为只能查询原始类型,即Pari

又如:

Pari<String> pari1 = ...

Pari<Employee> pari2 =...

if (pari1.getClass() == pari2.getClass())返回true,因为两次getClass()都是返回Pari.class

不能创建参数化类型数组

不能实例化参数类型数组

Pari<Sting>[] table = new Pari<String>[10];

因为当类型擦除后,为Pari[]类型,即可以转化为Object[]类型,这时候如果 table[0] = new Pari<Employee>();这时候就会抛出ArrayStoreException异常,所以,不允许创建参数类型数组。但是可以声明。如果想要实现可以使用通配类型数组然后进行强制类型转换

Pari<String>[] table = (Pari<String>[]) new Pari<?>[10];

不能实例化类型变量

new T()或者T.class这些都是非法的,因为类型擦除后为new Object(),这并不是想要的。

public Pari(){
     first = new T();
     second = new T();
}

但是可以通过反射调用Class.newInstance方法构造

public static<T> Pari<T> makePari(Class<T> c){
     return new Pari<>(c.newInstance(),c.newInstance())
}

泛型类的静态上下文中类型无效

public static class Singleton<T>{
     public static T s1;
     public static getS1(){
         return  s1 
     }
}
注意只是在静态类中不可以使用,普通类中可以使用。

不能抛出或捕获泛型类的实例

public class Problem<T> extends Exception{}是不对的。但是可以在异常规范中使用类型变量,意思就是可以在抛出异常的方法中使用类型变量 


泛型类继承规则

泛型类允许继承或者扩展其他的泛型类,如ArrayList<T>类实现List<T>接口,即一个ArrayList<Manager>可以被转换为List<Manger>。

但是ArrayList<Manager>不能够实现ArrayList<Employee>或List<Employee>。

所以记住,泛型的继承实现,需要保证其类型参数的一致。


通配符类型

固定的泛型类型系统,存在很多的局限性,为了解决这一点,引入了:通配符类型。

带有子类型的限定

Pari<? extends Employee>
表示任何泛型Pari类型,他的类型参数是Employee的子类,如Pari<Manager>,当使用了通配符泛型,就可以将Pari<Manager>,给以这个Pari<? extends Employee>参数的函数了。

通配符的超类型限定

通配符限定与类型变量限定十分类似,但是可以指定一个超类型限定。

? super Manager

这个通配符限定了Manager的所有的超类,这与上面讲的通配符继承恰恰相反,这时候Pari<Employee> 或者Pari<Object>可以实现或者继承Pari<? super Manager>

带有超类型限定的通配符可以向泛型对象写入,带有子类型限定的通配符可以从泛型对象读取。

需要注意,通配符不是类型变量,不能像之前的泛型类型参数一样定义变量或者方法

? t = p.getFirst()这是错误的。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值