`

java泛型总结

    博客分类:
  • 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。

分享到:
评论

相关推荐

    很好的Java泛型的总结

    Java泛型机制详解 Java泛型是Java语言中的一种机制,用于在编译期检查类型安全。Java泛型的出现解决了Java早期版本中类型安全检查的缺陷。Java泛型的好处是可以在编译期检查类型安全,避免了运行时的...

    Java泛型总结(2)进阶篇

    Java泛型是Java SE 5.0引入的一个重要特性,极大地提高了代码的类型安全性和重用性。在本文中,我们将深入探讨Java泛型的进阶概念,包括通配符、边界、类型擦除以及在实际开发中的应用。 1. 通配符 通配符在Java...

    java泛型总结.docx

    以下是对Java泛型的详细解释: 1. **泛型类型**:泛型类型允许我们在定义类、接口或集合时引入类型参数。比如`List&lt;String&gt;`就是一个泛型类型,其中String是类型参数,代表了列表中的元素类型。这样,当我们将字符...

    思维导图之Java泛型详解

    思维导图之Java泛型详解

    Java 泛型总结(一):基本用法与类型擦除

    "Java 泛型总结(一):基本用法与类型擦除" Java 泛型是 Java 语言中的一种强大功能,它可以使代码更加简洁、安全。下面是对 Java 泛型的基本用法和类型擦除机制的介绍。 泛型的基本用法 ------------- 泛型是...

    java泛型技术之发展

    总结,Java泛型技术的发展极大地提升了Java编程的效率和安全性。它通过编译时检查和类型安全保证,帮助开发者编写出更加健壮和易于维护的代码。理解并熟练掌握Java泛型,是每一个Java开发者必备的技能。

    java 泛型方法使用示例

    下面我们将深入探讨Java泛型方法的概念、语法以及使用示例。 **一、泛型方法概念** 泛型方法是一种具有类型参数的方法,这些类型参数可以在方法声明时指定,并在方法体内部使用。与类的泛型类似,它们提供了编译时...

    Java 泛型总结(二):泛型与数组

    Java 泛型总结(二):泛型与数组 Java 中泛型数组的关系确实有些复杂,不允许直接创建泛型数组,本文将分析其中的原因,并总结一些创建泛型数组的方式。 首先,让我们看看数组和泛型的关系。数组相比于 Java ...

    Java泛型编程最全总结

    Java泛型是Java编程语言中的一个关键特性,它在2004年随着JDK 5.0的发布被引入,极大地增强了代码的类型安全性和重用性。泛型允许我们在编写类、接口和方法时指定参数化类型,使得代码在编译时期就能捕获类型错误,...

    Java 泛型总结(三):通配符的使用

    Java 泛型总结(三):通配符的使用 通配符是 Java 泛型中一个重要的概念,它允许我们在泛型中实现向上转型,解决了泛型不支持协变的问题。本文将详细介绍通配符的使用和原理。 在 Java 中,数组是协变的,这意味...

    java 泛型的使用 详细讲解

    ### Java泛型的使用详细讲解 #### 一、引言 在Java开发中,泛型是一种重要的语言特性,它能够帮助开发者在不增加代码量的情况下处理多种数据类型,同时还能保持代码的清晰度和可读性。本文将详细介绍Java泛型的...

    Java 泛型总结及详解

    通过理解和掌握Java泛型,开发者可以在编写代码时得到更多编译器的帮助,增强程序的类型安全性,同时降低运行时异常的风险,提高代码质量。在实际开发中,合理使用泛型可以显著提升代码的可读性、可维护性和效率。

    Java泛型类型擦除后的补偿

    总结来说,Java泛型的类型擦除虽然在运行时消除了类型信息,但通过编译时的类型检查、桥接方法、通配符等补偿机制,仍然实现了强大的类型安全和便利性。开发者应理解这些补偿机制,以便更好地利用Java泛型进行类型...

    全面总结Java泛型--实例

    标题与描述均提到了“全面总结Java泛型--实例”,这表明文章旨在深入解析Java泛型的概念,并通过具体示例来展示其应用。Java泛型是Java编程语言的一个强大特性,它允许在编译时检查类型安全,并且所有的强制转换都是...

    全面总结Java泛型

    Java 泛型是 Java 编程语言中一个强大的特性,它允许在类、接口和方法中使用类型参数,从而增加了代码的复用性和安全性。在本文中,我们将深入探讨 Java 泛型的各种方面。 首先,普通泛型允许我们在定义类时引入一...

    Java泛型与容器详细笔记.pdf (带书签)

    总结来说,Java泛型与容器详细笔记提供了关于如何使用Java中的泛型和容器类的深入理解,涵盖了Java集合框架的核心组件,泛型的类型安全机制,以及一些提高开发效率的第三方库。文档通过实例代码展示了如何在实际项目...

Global site tag (gtag.js) - Google Analytics