泛型的深入研究

一 泛型定义

        允许在定义类、接口、方法时指定类型形参,这个类型形参在将在声明变量、创建对象、调用方法时时动态确定(即传入实际的类型参数,也可称为类型实参)。JDK1.5改写了集合框架中的全部接口和类,为这些接口、类增加了泛型支持,从而可以在声明集合变量、创建集合对象时传入类型实参。

二 泛型实质

        允许在定义接口、类时声明类型形参,类型形参在整个接口,类体内可当成类型使用,几乎所有可使用普通类型的地方都可以使用这种类型形参。例如:使用List类型时,如果为E形参传入String类型的实参,则产生一个新的类型:List<String>类型,可以把List<String>想象成E被全部替换成String的特殊List子接口。

三 类的泛型声明

1 代码示例

public class Apple<T>
{
	// 使用T类型形参定义实例变量
	private T info;
	public Apple(){}
	// 下面方法中使用T类型形参来定义构造器
	public Apple(T info)
	{
		this.info = info;
	}
	public void setInfo(T info)
	{
		this.info = info;
	}
	public T getInfo()
	{
		return this.info;
	}
	public static void main(String[] args)
	{
		// 由于传给T形参的是String,所以构造器参数只能是String
		Apple<String> a1 = new Apple<>("苹果");
		System.out.println(a1.getInfo());
		// 由于传给T形参的是Double,所以构造器参数只能是Double或double
		Apple<Double> a2 = new Apple<>(5.67);
		System.out.println(a2.getInfo());
	}
}

2 运行结果

苹果

5.67

3 代码分析

上面程序在定义了一个带泛型声明Apple<T>类,使用Apple<T>类就可为T类型形参传入实际类型,这样就可以生成Apple<String>、Apple<Double>形式的多个逻辑子类(物理上并不存在)。

四 泛型类派生子类

1 当从泛型类派生子类的时,不能再包括类型形参。

   public class A extends Apple<T>{}  这种定义是错误的。

2 定义类、接口、方法时可以声明类型形参,但使用类型,接口,方法时应该为类型形参传入实际的类型。

   public class A extends Apple<String>{}  这种定义是正确的。

3 调用方法时必须为所有的数据传入值,但使用类、接口时,也可以不为类型形参传入实际的类型参数。

   public class A extends Apple{}  这种定义是正确的。

4 从泛型类派生子类举例——传入实际类型参数。

public class A1 extends Apple<String>
{
	// 正确重写了父类的方法,返回值
	// 与父类Apple<String>的返回值完全相同
	public String getInfo()
	{
		return "子类" + super.getInfo();
	}
	/*
	// 下面方法是错误的,重写父类方法时返回值类型不一致
	public Object getInfo()
	{
		return "子类";
	}
	*/
}

5 从泛型类派生子类举例——不传入实际类型参数。

public class A2 extends Apple
{
	// 重写父类的方法
	public String getInfo()
	{
		// super.getInfo()方法返回值是Object类型,
		// 所以加toString()才返回String类型
		return super.getInfo().toString();
	}
}

五 泛型的错误用法

1 不能在静态变量声明中使用类型形参。

   static T info; //错误的

2 不能在静态方法中使用类型形参。

   public static void bar(T msg)   //错误的

3 instanceof运算符后不能使用泛型。

   if(cs instanceof java.util.ArrayList<string>)        //错误的

猜你喜欢

转载自cakin24.iteye.com/blog/2324603