- 浏览: 484478 次
- 性别:
- 来自: 大连
文章分类
最新评论
-
龘龘龘:
TrueBrian 写道有个问题,Sample 1中,为了控制 ...
What's New on Java 7 Phaser -
龘龘龘:
楼主总结的不错。
What's New on Java 7 Phaser -
TrueBrian:
有个问题,Sample 1中,为了控制线程的启动时机,博主实际 ...
What's New on Java 7 Phaser -
liguanqun811:
不知道楼主是否对zookeeper实现的分布式锁进行过性能测试 ...
Distributed Lock -
hobitton:
mysql的get lock有版本限制,否则get lock可 ...
Distributed Lock
4 泛型和继承
首先考虑如下代码:
public class Base { private String id; public String getName() { return "Base"; } public final String getId() { return id; } public final void setId(String id) { this.id = id; } }
public class Derived extends Base { public String getName() { return "Derived"; } public static void main(String args[]) { // Base base = new Base(); Derived derived = new Derived(); List<Base> list = new ArrayList<Base>(); list.add(base); list.add(derived); // List<Derived> list2 = new ArrayList<Derived>(); List<Base> list3 = list2; // Type mismatch: cannot convert from List<Derived> to List<Base> // List list4 = list2; list4.add(new Integer(1)); for(Object o : list4) { System.out.println(o); } try { for(Base b : list2) { System.out.println(b); // Runtime Exception } } catch(ClassCastException e) { e.printStackTrace(); } // List<?> list5 = list2; } }
泛型类可以继承或者实现其它泛型类或接口,例如ArrayList<T>实现了List<T>接口。因此ArrayList<Base>可以被转换成List<Base>,此外向List<Base>中添加base和derived也是合法的。
但是将list2赋值给list3会导致编译错误,就像关于继承的那个经典问题一样:苹果可以是水果的子类,但是能够装苹果的袋子不是能够装水果的袋子的子类。将list2赋值给list4是合法的,但是如果向list4中添加一个Integer对象,那么在访问list2的时候会导致运行时异常。
list5使用了通配符,这在稍后会介绍。
5 通配符
在引入泛型之前,遍历Collection的方法通常如下:
public static void visit(Collection c) { for(Iterator iter = c.iterator(); iter.hasNext(); ) { System.out.println(iter.next()); } } public static void main(String args[]) { List list = new ArrayList(); list.add("1"); visit(list); }
使用泛型后,可以写成:
public static void visit(Collection<Object> c) { for(Object o : c) { System.out.println(o); } } public static void main(String args[]) { List<String> list = new ArrayList(); list.add("1"); visit(list); // The method visit(Collection<Object>) in the type Test is not applicable for the argument (List<String>) }
由于List<String>并不是Collection<Object>的子类(Collection<Object>并不是所有类型的集合的父类型),因此调用visit(list)会造成编译错误。为了解决这个问题,Java泛型引入了通配符“?”。Collection<?>是所有类型的集合的父类型,叫做“未知集合”。
需要注意的是,向“未知集合”中添加对象不是类型安全的,这会导致编译错误,唯一例外的是null。此外从“未知集合”中获得的对象的类型也只能是Object类型。例如:
Collection<?> c = new ArrayList<String>(); c.add("1"); // The method add(capture#1-of ?) in the type Collectoin<capture#1 of ?> is not applicable for the arguments (String) c.add(null); Object o = c.get(0);
5.1 有界通配符
5.1.1 上界
可以使用extends为通配符限定上界,例如以下代码中限定了通配符的上界是Base类:
public static void visit(Collection<? extends Base> c) { for(Base b : c) { System.out.println(b); } } public static void main(String args[]) { List<Base> list = new ArrayList<Base>(); list.add(new Base()); list.add(new Derived()); visit(list); }
在visit方法中,同样不能向c中添加非null对象。例如以下代码会造成编译错误:
public static void visit(Collection<? extends Base> c) { c.add(new Derived()); // The method add(capture#1-of ? extends Base) in the type Collection<capture#1 -of ? extends Base> is not applicable for the arguments(Derived) }
有时也可以不使用通配符而达到相同的目的,例如:
public static <T> void copy(List<T> dest, list< ? extends T> src) { ... } public static <T, S extends T> void copy(List<T> dest, List<S> src) { ... }
5.1.2 下界
可以使用super为通配符限定下界,考虑以下代码:
public class Derived extends Base implements Comparable<Object> { public int compareTo(Object obj) { return System.identityHashCode(this) - System.identityHashCode(obj); } public static <T extends Comparable<T>> T max(Collection<T> c) { return Collections.max(c); } public static void main(String args[]) { List<Derived> list = new ArrayList<Derived>(); list.add(new Derived()); Derived.max(list); // Bound mismatch: The generic method max(Collection<T>) of type Derived is not applicable for the arguments (List<Derived>). The inferred type Derived is not a valid substitute for the bounded parameter <T extends Comparable<T>> } }
以上的max方法中限定了T类型必须实现了Comparable<T>接口,那么在main方法中以list为参数调用max方法会导致编译错误,这是因为Derived类没有实现Comparable<Derived>接口。这样的限制有些严格,如果将max方法改成如下方式,可以带来更大的灵活性。
public static <T extends Comparable<? super T>> T max(Collection<T> c) { return Collections.max(c); }
以下的代码虽然没有太大的意义,但是需要注意的是,在print方法中,p.setFirst()方法和p.setSecond()方法的参数类型为T,但是p.getFirst()方法和p.getSecond()方法的返回值类型只能是Object型。
public class Pair<T> { // private T first; private T second; public Pair(T first, T second) { this.first = first; this.second = second; } public T getFirst() { return first; } public void setFirst(T first) { this.first = first; } public T getSecond() { return second; } public void setSecond(T second) { this.second = second; } public void print(Pair<? super T> p) { Object first = p.getFirst(); Object second = p.getSecond(); System.out.println("first: " + first + ", second: " + second); } public static void main(String args[]) { Pair<Derived> p1 = new Pair<Derived>(new Derived(), new Derived()); Pair<Base> p2 = new Pair<Base>(new Base(), new Base()); p1.print(p2); } }
5.2 通配符捕获
考虑为Pair类编写一个方法,用于交换first和second。由于通配符不是变量类型,那么如下的写法是非法的:
? t = p.getFirst();
此外,以下的写法也会导致编译错误:
public static void swap(Pair<?> p) { Object first = p.getFirst(); p.setFirst(p.getSecond()); // The method setFirst(captur#4-of ?) in the type Pair<capture#4-of ?> is not applicable for the arguments (capture#5-of ?) p.setSecond(first); // The method setFirst(captur#6-of ?) in the type Pair<capture#6-of ?> is not applicable for the arguments (Object) }
可以通过一个额外的泛型方法中的类型参数来捕获通配符,例如:
public static void swap(Pair<?> p) { doSwap(p); } private static <T> void doSwap(Pair<T> p) { T first = p.getFirst(); p.setFirst(p.getSecond()); p.setSecond(first); }
6 泛型和反射
Class类是泛型的,而且实现了java.lang.reflect.Type接口。Class类没有公共构造方法。Class对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的。Class类的newInstance方法通过默认的构造函数返回类型为T的对象。例如:
public static <T> Pair<T> make(Class<T> c) throws InstantiationException, IllegalAccessException { return new Pair<T>(c.newInstance(), c.newInstance()); } Pair<String> ps = Pair.make(String.class);
接口 TypeVariable<D extends GenericDeclaration>,ParameterizedType, WildcardType,GenericArrayType继承自Type,用于通过反射获得泛型类型的信息(尽管进行了擦除)。
TypeVariable 表示各种类型变量。其getName()方法返回在源码中声明的变量名;getBounds()方法返回类型变量上边界Type对象数组;getGenericDeclaration()返回GenericDeclaration对象,以表示声明此类型变量的一般声明。
ParameterizedType 表示参数化类型,例如Collection<String>。其getRawType()返回原始类型,也就是声明此类型的类或接口;getActualTypeArguments()方法返回表示此类型实际类型参数的 Type对象数组。
WildcardType 表示一个通配符类型表达式,如 ?、? extends Number 或 ? super Integer。getLowerBounds()方法返回类型变量下边界Type对象数组;getUpperBounds()方法返回类型变量上边界Type对象数组。
GenericArrayType 表示一种数组类型,其组件类型为参数化类型或类型变量。getGenericComponentType() 返回此数组的元素类型的Type对象。
关于以上接口的详细文档,请参考Javadoc。以下是一个简单的例子,用于获得类型变量的Class类型:
import java.lang.reflect.ParameterizedType; public abstract class GenericBase<T extends Comparable<? super T>> { // private Class<T> clazz; @SuppressWarnings("unchecked") public GenericBase() { ParameterizedType pt = (ParameterizedType)getClass().getGenericSuperclass(); clazz = (Class<T>)pt.getActualTypeArguments()[0]; } public Class<T> getClazz() { return clazz; } public void setClazz(Class<T> clazz) { this.clazz = clazz; } } public class GenericDerived extends GenericBase<String> { public static void main(String args[]) { GenericDerived gd = new GenericDerived(); System.out.println(gd.getClazz()); } }
评论
Object oa[] = new Integer[5];
oa[0] = new Object();
以上代码会导致异常,也就是说在对你说:
java认为Integer数组是一个Object数组(可以通过编译),但尝试把它当成Object数组使用是个错误(抛出运行时异常)。就抱错的时机来说,我更倾向于编译时错误。
协变问题了, 数组是协变的, 但泛型不是
一个Integer数组可以是一个Number数组, 但一个List<Integer>不是List<Number>
协变和非协变都有优缺点, 比如泛型重载, 虽然java的泛型是可擦除的
发表评论
-
Understanding the Hash Array Mapped Trie
2012-03-30 10:36 0mark -
A Hierarchical CLH Queue Lock
2012-01-14 19:01 2152A Hierarchical CLH Queue Lock ( ... -
Inside AbstractQueuedSynchronizer (4)
2012-01-08 17:06 3528Inside AbstractQueuedSynchroniz ... -
Inside AbstractQueuedSynchronizer (3)
2012-01-07 23:37 4756Inside AbstractQueuedSynchroniz ... -
Inside AbstractQueuedSynchronizer (2)
2012-01-07 17:54 6371Inside AbstractQueuedSynchroniz ... -
Inside AbstractQueuedSynchronizer (1)
2012-01-06 11:04 7953Inside AbstractQueuedSynchroniz ... -
Code Optimization
2011-10-14 00:11 1613当前开发人员在进行编码的时候,可能很少关注纯粹代码级别的优化了 ... -
Distributed Lock
2011-08-02 22:02 92171 Overview 在分布式系统中,通常会 ... -
What's New on Java 7 Phaser
2011-07-29 10:15 82871 Overview Java 7的并 ... -
Sequantial Lock in Java
2011-06-07 17:00 22231 Overview Linux内核中常见的同步机 ... -
Feature or issue?
2011-04-26 22:23 121以下代码中,为何CglibTest.intercept ... -
Bloom Filter
2010-10-19 00:41 50811 Overview Bloom filt ... -
Inside java.lang.Enum
2010-08-04 15:40 64831 Introduction to enum J ... -
Open Addressing
2010-07-07 17:59 34821 Overview Open addressi ... -
JLine
2010-06-17 09:11 11014Overview JLine 是一个用来处理控 ... -
ID Generator
2010-06-14 14:45 1685关于ID Generator,想 ... -
inotify-java
2009-07-22 22:58 83151 Overview 最近公 ... -
Perf4J
2009-06-11 23:13 84941 Overview Perf4j是一个用于计算 ... -
Progress Estimator
2009-02-22 19:37 1539Jakarta Commons Cookbook这本书 ... -
jManage
2008-12-22 00:40 39591 Overview 由于项目需要, 笔者开发了一个 ...
相关推荐
在Java编程语言中,泛型(Generic)是一个强大的特性,它允许我们在编译时检查类型安全,并且可以消除运行时的类型转换。泛型引入的主要目的是提高代码的重用性、安全性和效率,同时减少类型转换的繁琐工作。这篇...
标题中的“Java Generic 介绍”涵盖了泛型的基本概念、使用方式以及其背后的原理。以下是对这一主题的详细阐述: 1. **泛型的基本概念**:泛型是Java中的一种模板类或接口,它允许开发者在定义类、接口和方法时使用...
Java1.5泛型指南中文版(Java1.5 GenericTutorial)
标题中的"Generic_MT4_java_generic_mt4_"暗示了一个与MetaTrader 4 (MT4)交易平台相关的编程项目,可能是一个自定义的智能交易系统(Expert Advisor,EA)或指标,使用了Java语言,并且具有通用性。这个“Generic_...
Generic Variance java 源码
Generic Stack java 源码
在《java-generic.rar》压缩包中包含的《java generic.pdf》文件,很可能是详细阐述了以下几个关于Java泛型的核心知识点: 1. **类型参数化**:泛型的核心在于类型参数化,这使得我们可以在定义类、接口和方法时...
本文将深入探讨Java中的浅复制和深复制,并以Android为背景,结合具体的实例讲解如何实现Java泛型深拷贝。 首先,我们要理解浅复制和深复制的概念。浅复制(Shallow Copy)是指创建一个新的对象,然后将原对象引用...
"Generic22BW.zip"是一个压缩包文件,其命名方式暗示它可能是一个通用或标准的软件版本,"BW"可能是“Black and White”或者“Basic Version”的缩写,表明这可能是一个简化版或黑白主题的版本。从标签"Generic22...
### Java泛型编程详解 #### 引言 Java 5引入了多项语言级别的扩展功能,其中最为重要的一项就是泛型(Generics)的引入。本文档旨在为读者介绍Java中的泛型概念及其用法。 如果你熟悉其他语言如C++中的模板...
11.4java-泛型(Generic)
genArr = (Generic[]) new Generic[2]; System.out.println(genArr); } } ``` 这段代码展示了创建泛型数组时可能遇到的问题。尽管 `genArr` 被声明为 `Generic[]` 类型,但在运行时,其实际类型仍然是 `Object[]...
**Wsdl2Java客户端生成工具详解** 在Java WebService开发中,`Wsdl2Java`是一个非常实用的工具,主要用于根据WSDL(Web Services Description Language)文件自动生成对应的Java客户端代码。这极大地简化了开发过程...
java高手真经 全光盘源代码 打包rar 第1部分(2个程序包) HelloWorld.zip 01.Java入门样例Hello...javageneric.zip 27.Java泛型编程 javaannotation.zip 28.Java注释符编程 javafeature.zip 29.Java5.0语言新特性
标签:apache、velocity、tools、generic、jar包、java、中英对照文档; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码和结构保持不变,注释和说明...
该文件里包含两个.jar包: collections-generic-4.01.jar和looks-2.1.4.jar, 引入collections-generic-4.01.jar: 右击工程--》Build path ——》Add External JAR-->选中collections-generic-4.01.jar --》OK 在源...