文档章节

Java泛型总结

281165273
 281165273
发布于 2013/08/21 15:02
字数 1549
阅读 81
收藏 0
1.泛型概念

泛型即参数化类型,主要作用是为了创建更加范化的代码和提供编译期类型安全。

最常见的理据就是不用等到运行期,编译期就可以确保容器类不会装入不同类型的元素,并且可以不用强制类型转换。

例子:

List<String> list=new ArrayList<String>();
list.add("ok");
list.add(Integer.valueOf("11"));//compile error
String s=list.iterator().next();
2.泛型声明

例子:

public interface List<E> {
    void add(E x);
    Iterator<E> iterator();
}

public interface Iterator<E> {
    E next();
    boolean hasNext();
}

尖括号部分形式类型参数的声明,类型参数在整个类的声明中可用,几乎是所有可是使用其他普通类型的地方。

一个泛型类型的声明只被编译一次,并且得到一个class文件,就像普通的class或者interface的声明一样。

类型参数就跟在方法或构造函数中普通的参数一样。就像一个方法有形式参数(formal value parameters)来描述它操作的参数的种类一样,一个泛型声明也有形式类型参数(formal type parameters)。当一个方法被调用,实参(actual arguments)替换形参,方法体被执行。当一个泛型声明被调用,实际类型参数(actual type arguments)取代形式类型参数。

3.泛型与继承

即泛型没有协变性

例子:

List<String> list1=new ArrayList<String>();
List<Object> list2=list1;//compile error
list2.add(1);

假设允许第2行代码,那么第三行代码将可以在一个String的集合中插入一个数字。

4.通配符

当一个方法可以处理任意类型的集合,而不关心集合中元素的类型时,使用无界通配符,collection<?>相当于各种collection的父类。

旧代码:

void printCollection(Collection c) {
       Iterator i = c.iterator();
           for (int k = 0; k < c.size(); k++) {
                  System.out.println(i.next());
         }
}

新代码:

void printCollection(Collection<Object> c) {
           for (Object e : c) {
                 System.out.println(e);
           }
}

这个方法可以处理任意集合,转换成泛型如果参数使用collection<Object>,那么方法的作用就小了,原来可以打印任意类型集合,现在只能打印collection<Object>集合了。

正确的泛型代码:

void printCollection(Collection<?> c) {
for (Object e : c) {
System.out.println(e);
}
}

但是注意,如果方法关心集合元素的类型,则需要使用有界通配符了,如下面代码:

Collection<?> c = new ArrayList<String>();
c.add(new Object()); // compile error

因为我们不知道collection里元素的类型,所有不能添加任意元素到集合,add方法有类型参数E作为集合的元素类型。我们传给add的任何参数都必须是一个未知类型的子类。因为我们不知道那是什么类型,所以我们无法传任何东西进去。唯一的例外是null,它是所有类型的成员。

另一方面,我们可以调用get()方法并使用其返回值。返回值是一个未知的类型,但是我们知道,它总是一个Object,因此把get的返回值赋值给一个Object类型的对象或者放在任何希望是Object类型的地方是安全的。

5.有界通配符

例子:&#160;

public abstract class Shape {

public abstract void draw(Canvas c);

}

public class Circle extends Shape {

private int    x, y, radius;

public void draw(Canvas c) { // ...

}

}

public class Rectangle extends Shape {

private int    x, y, width, height;

public void draw(Canvas c) {

// ...

}

}

public class Canvas {

public void draw(Shape s) {

s.draw(this);

}

public void drawAll(List<Shape> shapes) {

          for (Shape s : shapes) {

             s.draw(this);

         }

}}

&#160;

现在,类型规则导致drawAll()只能使用Shape的list来调用。它不能,比如说对List<Circle>来调用。这很不幸,因为这个方法所作的只是从这个list读取shape,因此它应该也能对List<Circle>调用。我们真正要的是这个方法能够接受一个任意种类的shape:

public void drawAll(List<? extends Shape> shapes) { //..}

这里有一处很小但是很重要的不同:我们把类型 List<Shape> 替换成了 List<? extends Shape>。现在drawAll()可以接受任何Shape的子类的List,所以我们可以对List<Circle>进行调用。

List<? extends Shape>是有限制通配符的一个例子。这里?代表一个未知的类型,就像我们前面看到的通配符一样。但是,在这里,我们知道这个未知的类型实际上是Shape的一个子类(它可以是Shape本身或者Shape的子类而不必是extends自Shape)。我们说Shape是这个通配符的上限(upper bound)。

像平常一样,要得到使用通配符的灵活性有些代价。这个代价是,现在像shapes中写入是非法的。比如下面的代码是不允许的:

public void addRectangle(List<? extends Shape> shapes) {

shapes.add(0, new Rectangle()); // compile-time error!

}

你应该能够指出为什么上面的代码是不允许的。因为shapes.add的第二个参数类型是? extends Shape ——一个Shape未知的子类。因此我们不知道这个类型是什么,我们不知道它是不是Rectangle的父类;它可能是也可能不是一个父类,所以这里传递一个Rectangle不安全。

而正好相反的是下限通配符,? super TestObject——一个TestObject未知的超类,因此我们可以将TestObject及其子类安全的放入集合,而当我们从集合中取出元素时,我们无法知道究竟是哪个父类,因此赋值是不安全的。

public class TestObject {

}

public class TestObject1 extends TestObject {

}

	

public void addTestObject(List<? super TestObject> list) {

          list.add(new TestObject1());

          TestObject to=list.get(0);//compile error

}

关于GET和SET原则

如果方法传入的泛型是生产者,即将实例加入到当前容器类,则用?extends,如果是从当前容器类消费实例,放入参数传入的容器类,则用?super

关于自限定

Enum<E extends Enum<E>>

用于限定继承关系A extends Enum<A>

并且会限制重载,方法的参数类型会协变,使得子类中不能即含有基类型参数的方法,又含有子类型参数的方法,而如果不是自限定的,则可以重载

泛型的重载还有一个特殊的地方,可以用方法返回值来确定重载的版本

© 著作权归作者所有

共有 人打赏支持
上一篇: JAVA基础小结
下一篇: spring aop
281165273
粉丝 4
博文 64
码字总数 35522
作品 0
武汉
程序员
私信 提问
【J2SE】JAVA语法糖之-伪泛型

JAVA语法糖之-伪泛型 泛型即参数化类型 首先看一个泛型例子: public static void main(String[] args) {List<String> strList = new ArrayList<String>();strList.add("generic test!");fo......

磊神Ray
2011/09/28
0
0
Java 8新特性探究(六)泛型的目标类型推断

简单理解泛型 泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。通俗点将就是“类型的变量”。这种类型变量可以用在类、接口和方法的创建中。...

OSC闲人
2013/12/14
0
3
Java 泛型详解-绝对是对泛型方法讲解最详细的,没有之一

对java的泛型特性的了解仅限于表面的浅浅一层,直到在学习设计模式时发现有不了解的用法,才想起详细的记录一下。 本文参考java 泛型详解、Java中的泛型方法、 java泛型详解 1 概述 泛型在j...

hensemlee
09/23
0
0
Java泛型简明教程

本文是从 Java Generics Quick Tutorial 这篇文章翻译而来。 泛型是Java SE 5.0中引入的一项特征,自从这项语言特征出现多年来,我相信,几乎所有的Java程序员不仅听说过,而且使用过它。关于...

老枪
2011/06/03
383
1
Java语言学习(十一):枚举类型和泛型

Java中一个重要的类型:枚举,它可以用来表示一组取值范围固定的变量,使用 enum 关键字定义枚举类型,其中元素不能重复,通常大写表示。利用Java的反射机制,可以在运行时分析类,如查看枚举...

海岸线的曙光
07/18
0
0

没有更多内容

加载失败,请刷新页面

加载更多

HashTable和Vector为什么逐渐被废弃

HashTable,不允许键值为null,还一个就是put方法使用sychronized方法进行线程同步,单线程无需同步,多线程可用concurren包的类型。 如编程思想里面说的作为工具类,封闭性做的不好没有一个...

noob_chr
昨天
0
0
Win10 下安装Win7双系统

很多人买了预装64位Win8/8.1的电脑后想重装(或者再安装一个)Win7系统,但是折腾半天发现以前的方法根本不奏效。这是因为预装Win8/8.1的电脑统一采用了UEFI+GPT引导模式,传统的BIOS(Legacy...

yaly
昨天
1
0

中国龙-扬科
昨天
1
0
假若明天来临——《AI.未来》读后感3900字

假若明天来临——《AI.未来》读后感3900字: 你有没有想过,如果有一天你被确诊为癌症患者,你会做些什么?你有没有想过,在你百年之后,你希望你的墓碑上刻写着什么内容? 在我翻开李开复老...

原创小博客
昨天
1
0
tomcat线程模型

Connector结构 BIO模式 NIO模式

grace_233
昨天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部