java泛型总结

泛型(generic):是指参数化类型的能力。可以定义泛型类和泛型方法,随后编译器会用具体的类型来替换它。

 

使用泛型的主要优点是,能够在编译时而不是在运行时检测出错误。比如:

public interface Comparable {                      public interface Comparable<T> {     

public int compareTo(Object o);                    public int compareTo(T o);

}                                                                   }

         a)在jdk1.5之前                                                b)在jdk1.5

这里的<T>表示形式泛型类型,随后可以用一个具体的类型代替。替换泛型类型称为泛型实例化。

Comparable c = new Date();                                   Comparable<Date> c = new Date();

    System.out.println(c.compareTo("color"));               System.out.println(c.compareTo("color"));

          c)在jdk1.5之前                                                d)在jdk1.5

c中的代码可以通过编译,但是在运行时会报一个类型转换异常,因为Date不能和一个String做比较。

d中的代码在编译时就会报错,因为传递给compateTo方法的必须是一个Date类型。

 

 

1、定义泛型类和接口

public class GenericStack<E> {
	private ArrayList<E> list = new ArrayList<E>();
	
	public int getSize() {
		return list.size();
	}
	
	public E peek() {
		return list.get(getSize() - 1);
	}
	
	public void push(E o) {
		list.add(o);
	}
	
	public E pop() {
		E o = list.get(getSize() - 1);
		list.remove(getSize() - 1);
		return o;
	}
	
	public boolean isEmpty() {
		return list.isEmpty();
	}
}

 

 

 

2、泛型方法

public class GenericMethod {
	public static <E> void print(E[] array) {
		for(E o : array) {
			System.out.println(o);
		}
	}
	
	public static void main(String[] args) {
		Integer[] integer = {1, 2, 3, 4};
		String[] string = {"a", "b", "c", "d"};
		
		print(integer);
		print(string);
	}
}

 

 

3、泛型类型在逻辑上看以看成是多个不同的类型,实际上都是相同的基本类型。

实例:

public class LinkedStack<T> {
	private class Node {
		T item;
		Node next;

		Node() {
			item = null;
			next = null;
		}

		Node(T item, Node next) {
			this.item = item;
			this.next = next;
		}

		boolean end() {
			return item == null && next == null;
		}
	}

	private Node top = new Node(); // End sentinel

	public void push(T item) {
		top = new Node(item, top);
	}

	public T pop() {
		T result = top.item;
		if (!top.end())
			top = top.next;
		return result;
	}

	public static void main(String[] args) {
		LinkedStack<Number> lss1 = new LinkedStack<Number>();
		LinkedStack<Integer> lss2 = new LinkedStack<Integer>();
		System.out.println(lss1.getClass());
		System.out.println(lss2.getClass());
	}
}

 

输出结果:

class generic.LinkedStack

class generic.LinkedStack

true

由此,我们发现,在使用泛型类时,虽然传入了不同的泛型实参,但并没有真正意义上生成不同的类型,传入不同泛型实参的泛型类在内存上只有一个,即还是原来的最基本的类型(本实例中为LinkedStack),当然,在逻辑上我们可以理解成多个不同的泛型类型。

究其原因,在于Java中的泛型这一概念提出的目的,导致其只是作用于代码编译阶段,在编译过程中,对于正确检验泛型结果后,会将泛型的相关信息擦出,也就是说,成功编译过后的class文件中是不包含任何泛型信息的。泛型信息不会进入到运行时阶段。

 

 

4、类型通配符

接着上面的示例探讨,从上面的示例我们知道LinkedStack<Number>和LinkedStack<Integer>都是LinkedStack类型,那么在逻辑上LinkedStack<Number>和LinkedStack<Integer>是否可以看成具有父子关系的类呢?

public static void main(String[] args) {

LinkedStack<Number> lss1 = new LinkedStack<Number>();

LinkedStack<Integer> lss2 = new LinkedStack<Integer>();

getDate(lss1);

getDate(lss2);

}

 

public static void getDate(LinkedStack<Number> data) {

System.out.println(data.getClass());

}

代码中的getDate(lss2);这一行编译错误。The method getDate(LinkedStack<Number>) in the type LinkedStack<T> is not applicable for the arguments (LinkedStack<Integer>)

因此,在逻辑上LinkedStack<Number>不能视为LinkedStack<Integer>的父类。

 

那么怎么解决这种问题呢?在这里java提供了通配符类型,类型通配符一般用?表示。

public static void main(String[] args) {

LinkedStack<Number> lss1 = new LinkedStack<Number>();

LinkedStack<Integer> lss2 = new LinkedStack<Integer>();

getDate(lss1);

getDate(lss2);

}

 

public static void getDate(LinkedStack<?> data) {

System.out.println(data.getClass());

}

当用了通配符之后,错误就没有了,代码可以正确运行。

 

有时候,我们还可能听到类型通配符上限和类型通配符下限。具体有是怎么样的呢?

在上面的例子中,如果需要定义一个功能类似于getData()的方法,但对类型实参又有进一步的限制:只能是Number类及其子类。此时,需要用到类型通配符上限。

public static void main(String[] args) {

LinkedStack<Number> lss1 = new LinkedStack<Number>();

LinkedStack<Integer> lss2 = new LinkedStack<Integer>();

LinkedStack<String> lss3 = new LinkedStack<String>();

getDate(lss1);

getDate(lss2);

getDate(lss3);

}

 

public static void getDate(LinkedStack<? extends Number> data) {

System.out.println(data.getClass());

}

此时,显然,在代码getDate(lss3);处调用将出现错误提示。

类型通配符上限通过形如LinkedStack<? extends Number>形式定义,相对应的,类型通配符下限为Box<? super Number>形式,其含义与类型通配符上限正好相反,在此不作过多阐述了。

 

 

5、消除泛型和对泛型的限制

泛型是通过一种称为类型消除的方法来实现的。编译器使用泛型信息来编译代码,但是随后会消除它。因此,泛型信息在运行时是不可见的。

泛型存在于编译时。一旦编译器确定泛型类型时安全使用的,就会将它转换为原始类型。

示例:

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

    last.add("test");                                                  转换为:   last.add("test");

String str = list.get(0);                                                             String str = (String)list.get(0);

 

public static void getDate(T[] data) {                                       public static void getDate(Object[] data) {

    System.out.println(data.length);                        转换为:    System.out.println(data.length);  

}                                                                                              }

 

对泛型的限制

1.不能使用new E()

E e = new E();这是错误的,因为运行时,E不可用

 

2.不能使用new E[]

E[] e = new E[2];这是错误的

规避方法

E[] e = (E())new Object[2];

也不能使用泛型类型创建数组

ArrayList<String> list = new ArrayList<String>[10];

规避方法

ArrayList<String> list = (ArrayList<String>)new ArrayList[10];

 

3.在静态环境下不允许类的参数是泛型类型

泛型类的静态变量,静态方法和初始化语句中引用泛型类型参数是非法的。

public void Test<E> {

public static void m(E 0) { //非法

}

 

public static E o; //非法

 

static {

E o;//非法

}

}

 

4、异常不能是泛型的

泛型类不能继承Throwable。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值