- 浏览: 705961 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (272)
- Struts1.x (7)
- 事务 (2)
- Hibernate (11)
- 数据库 (14)
- JavaScript&Ajax (43)
- JSP&Servlet (2)
- Flex (1)
- 其它 (9)
- Java (22)
- 框架集成 (1)
- WebService (3)
- Tomcat (3)
- 加密和安全登录 (13)
- 基于原型的JavaScript (0)
- JavaDoc和Java编码规范 (3)
- CAS (1)
- 加密 (1)
- Axis2 (10)
- Ext2.x (3)
- SSH整合 (2)
- Ext (0)
- 正则表达式 (1)
- 设计模式 (4)
- 对象序列化技术 (3)
- CVS (2)
- Struts2 (6)
- Spring 2.x (7)
- Spring Security (2)
- Java 课程 (20)
- 程序员之死 (1)
- 软件测试 (6)
- UML (5)
- NetBeans (1)
- cxf (1)
- JMS (13)
- 设计 (5)
- ibatis2.x (3)
- Oracle (1)
- WebSphere (7)
- 概要设计 (1)
- DB2 (10)
- PowerDesigner (0)
- 软件工程 (5)
- rose (1)
- EA (1)
- LDAP (7)
- Portal&Portlet (3)
- MQ (10)
- ESB (4)
- EJB (2)
- JBoss (2)
最新评论
-
typeRos:
只有配置文件,没有代码么大神
Spring实现IBMMQ的JMS消息发布/订阅模式 -
panamera:
如果ActiveMQ服务器没有启动,这个时候消息生产者使用Jm ...
Spring JMSTemplate 与 JMS 原生API比较 -
lian819:
顶1楼, 引用文件, 配置属性, 太方便了
EXTJS 同步和异步请求 -
wilhard:
说得清楚明白
<%@ include file=""%>与<jsp:include page=""/>区别 -
刘琛颖:
总结的很好。受益了
javascript 父窗口(父页面)— 子窗口 (子页面)互相调用的方法
一、定义泛型接口、类
JDK 1.5 改写了集合框架中的全部接口和类,为这些接口、类增加了泛型支持,从而可以在声明集合变量、创建集合对象时传入类型实参。
下面是 JDK 1.5 改写后 List 接口、Iterator 接口、Map 的代码片段:
// 定义接口时制定了一个类型形参,该形参名为 E
public interface List<E>
{
// 在该接口里,E 可作为类型使用
// 下面方法可以使用 E 作为参数类型
void add(E x);
Iterator<E> iterator();
}
// 定义接口时制定了一个类型形参,该形参名为 E
public interface Iterator<E>
{
// 在该接口里 E 完全可以作为类型使用
E next();
bollean hasNext();
}
// 定义接口时制定了两个类型形参,该形参名为 K、V
public interface Map<K, V>
{
// 在该接口里 K, V 完全可以作为类型使用
Set<K> keySet();
V put(K key, V value);
}
我们可以为任何类增加泛型的声明(并不是只有集合类才可以使用泛型声明,虽然泛型是集合类的重要使用场所)。例:
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;
}
}
实例化带有泛型的 Apple 类:
二、从泛型类派生子类
当创建了带泛型声明的接口、父类之后,可以为该接口创建实现类,或者从该父类来派生子类,但是,当使用这些接口、父类时不能再包含类型形参。下面的代码是错误的:
// 定义类 A 继承 Apple 类,Apple 类不能跟类型参数
public class A extends Apple<T>{}
如果想从 Apple 类派生一个子类,可以改为如下方法:
// 使用 Apple 类时,为 T 形参传入 String 类型
public class A extends Apple<String>
当然也可以不为接口、类传入的类型参数传入实际类型,所以下面的代码也是正确的:
public class A extends Apple
如果从 Apple<String> 类派生子类,则在 Apple 类中所使用 T 类型形参的地方都将被替换成 String类型,即它的子类将会集成到 String getInfo() 和 void setInfo(String info) 两个方法,如果子类需要重新写父类的方法,必须注意到这一点。例如:
public class A1 extends Apple<String>
{
// 正确重写了父类的方法,返回值与父类 Apple<String> 的返回值完全相同
public String getInfo()
{
return "子类" + super.getInfo();
}
/*
// 下面方法是错误的,重写父类方法时返回值类型不一致
public Object getInfo()
{
return "子类";
}
*/
}
三、并不存在泛型类
我们可以把 ArrayList<String> 类当做 ArrayList 的子类,而事实上系统并没有为 ArrayList<String> 生成新的 class 文件,而且也不会把 ArrayList<String> 当成新类来处理。
例如:下面程序的打印结果是true
List<String> l1 = new ArrayList<String>();
List<Integer> l2 = new ArrayList<Integer>();
System.out.println(l1.getClass() == l2.getClass());
静态方法、静态初始化或者静态变量的声明和初始化中不允许使用类型参数。
下面程序演示了这种错误:
public class R<T>
{
// 下面程序代码错误,不能在静态属性声明中使用类型参数
static T info;
T age;
public void foo(T msg){}
// 下面代码错误,不能在静态方法声明中使用类型形参
public static void bar(T msg){}
}
由于系统中并不会真正生成泛型类,所以 instanceof 运算符后不能使用泛型类,例如下面的代码是错误的:
Collection cs = new ArrayList<String>();
// 下面代码编译时引发错误:instanceof 运算符后不能使用泛型类
if(cs instanceof List<String>){...}
四、类型通配符
如果 SubClass 是 SuperClass 的子类型(子类或者子接口),而 G 是具有泛型声明的类或者接口,那么 G<SubClass> 是 G<SuperClass> 的子类型并不成立。例如:List<String> 并不是 List<Object> 的子类。
与数组进行对比:
// 下面程序编译正常、运行正常
Number[] nums = new Integer[7];
nums[0] = 9;
System.out.println(nums[0]);
// 面程序编译正常、运行时发生 java.lang.ArrayStoreException 异常
Integer[] ints = new Integer[5];
Number[] nums2 = ints;
nums2[0] = 0.4;
System.out.println(nums2[0]);
// 下面程序发生编译异常,Type mismatch: cannot convert from List<Integer> to List<Number>
List<Integer> iList = new ArrayList<Integer>();
List<Number> nList = iList;
数组和泛型有所不同,如果 SubClass 是 SuperClass 的子类型(子类或者子接口),那么 SubClass[] 依然是 SuperClass[] 的子类;但是 G<SubClass> 不是 G<SuperClass> 的子类。
如何适用类型通配符:
为了表示各种泛型 List 的父类,我们需要使用类型通配符,类型通配符是一个问号 (?),将一个问号作为类型实参传给 List 集合,写作:List<?> (意思是未知类型元素的 List)。这个问号 (?) 被称作通配符,它的元素类型可以匹配任何类型。例如:
public void test(List<?> c)
{
...
}
现在我们可以使用任何类型的 List 来调用它,程序依然可以访问集合 c 中的元素,其类型是 Object。
这种写法适用于任何支持泛型声明的接口和类,例如:Set<?>、Collection<?>、Map<?, ?>等。
但是这种带通配符的 List 仅表示它是各种泛型 List 的父类,并不能把元素加入到其中,例如下面的代码将引发编译错误:
List<?> c = new ArrayList<String>();
// 下面程序引发编译错误
c.add(new Object());
因为我们不知道上面程序中 c 集合中的元素类型,所以不能向其中添加对象。唯一的例外是 null,它是所有引用类型的实例。例如:下面程序是正确的:
c.add(null);
五、设置类型通配符的上限
当直接使用 List<?> 这种形式时,即表明这个 List 集合是任何泛型 List 的父类。但还有一种特殊的情况,我们不想这个 List<?> 是任何泛型 List 的父类,只想表示它是某一类泛型 List 的父类。
被限制的泛型通配符如下表示:
List<? extends SuperClass>
六、设定类型形参的上限
Java 泛型不仅允许在使用通配符形参时设定类型上限,也可以在定义类型形参时设定上限,用于表示传给该类型形参的实际类型必须是上限类型,或是该上限类型的子类。例如:
import java.util.*;
public class Apple<T extends Number>
{
T col;
public static void main(String[] args)
{
Apple<Integer> ai = new Apple<Integer>();
Apple<Double> ad = new Apple<Double>();
//下面代码将引起编译异常
//因为String类型传给T形参,但String不是Number的子类型。
Apple<String> as = new Apple<String>();
}
}
有时候程序需要为类型形参设定多个上限(至多有一个父类上限,可以有多个接口上限)表明该类型形参必须是其父类的子类(包括是父类本身也行),并且实现多个上限接口。例如:
// 表明 T 类型必须是 Number 类或其子类,并必须实现 java.io.Serializable 接口
public class Apple<T extends Number & java.io.Serializable>
{
...
}
七、泛型方法
1、定义泛型方法
泛型方法的用法格式是:
修饰符 <T, S> 返回值类型 方法名(形参列表)
{
// 方法体……
}
示例:
static void fromArrayToCollection(Object[] a, Collection<Object> c)
{
for(Object o : a)
{
c.add(o);
}
}
上面的方法中形参 c 的数据类型是 Collection<Object>,因为 Collection<Object> 不是 Collection<String> 类的父类,所以这个方法的功能非常有限,它只能将 Object 数组的元素复制到 Object (Object 的子类不行) Collection 集合,及下面的代码会引发编译异常:
String[] str = {"a", "b"};
List<String> strList = new ArrayList<String>();
// Collection<String> 对象不能当成 Collection<Object> 调用,下面的代码出现编译异常
fromArrayGToCollection(str, strList);
上面方法的参数类型不可以使用 Collection<String>,那是用通配符 Collection<?> 也是不可行的,因为不能把对象放进一个未知类型的集合当中去。
使用泛型方法解决这个问题:
static <T> void fromArrayToCollection(T[] a, Collection<T> c)
{
for (T o : a)
{
c.add(o);
}
}
public static void main(String[] args)
{
Object[] oa = new Object[100];
Collection<Object> co = new ArrayList<Object>();
//下面代码中T代表Object类型
fromArrayToCollection(oa, co);
String[] sa = new String[100];
Collection<String> cs = new ArrayList<String>();
//下面代码中T代表String类型
fromArrayToCollection(sa, cs);
//下面代码中T代表Object类型
fromArrayToCollection(sa, co);
Integer[] ia = new Integer[100];
Float[] fa = new Float[100];
Number[] na = new Number[100];
Collection<Number> cn = new ArrayList<Number>();
//下面代码中T代表Number类型
fromArrayToCollection(ia, cn);
//下面代码中T代表Number类型
fromArrayToCollection(fa, cn);
//下面代码中T代表Number类型
fromArrayToCollection(na, cn);
//下面代码中T代表String类型
fromArrayToCollection(na, co);
//下面代码中T代表String类型,但na是一个Number数组,
//因为Number既不是String类型,也不是它的子类,所以出现编译错误
fromArrayToCollection(na, cs);
}
上面程序定义了一个泛型方法,该泛型方法中定义了一个 T 类型形参,这个 T 类型形参就可以在该房内当成普通类型来使用。与在接口、类中定义的类型形参不同的是,方法声明中定义的类型形参只能在方法里使用,而接口、类声明中定义的类型形参则可以住在整个接口、类中使用。
与类、接口中使用泛型参数不同的是,方法中的泛型参数无需显式传入实际类型参数,如上面程序中,当程序调用 fromArrayToCollection 时,无须在调用该方法前传入 String、Object 等类型,编译器可以根据实参推断出类型形参的值。
但是不要是编译器迷惑,例如下面的程序:
public class Test
{
// 声明一个泛型方法,该泛型方法中带一个 T 类型参数
static <T> void test(Collection<T> a, Collection<T> c)
{
// 方法体
}
public static void main(String[] args)
{
List<Object> ao = new ArrayList<Object>();
List<String> as = new ArrayList<String>();
// 下面代码将产生编译错误
test(as, ao);
}
}
上面程序中,编译器无法正确识别 T 所代表的实际类型。可以将该方法修改为下面的形式:
public class Test
{
// 声明一个泛型方法,该泛型方法中带一个 T 类型参数
static <T> void test(Collection<? extends T> a, Collection<T> c)
{
// 方法体
}
public static void main(String[] args)
{
List<Object> ao = new ArrayList<Object>();
List<String> as = new ArrayList<String>();
// 下面代码编译正常
test(as, ao);
}
}
上面代码中将方法的第一个形参类型修改为 Collection<? extends T>,这种采用类型通配符的表示方法,只要 test 方法的前一个 Collection 集合元素类型是后一个 Collection 集合元素类型的子类即可。
2、泛型方法和类型通配符的区别
JDK 中对于 Collection 接口中两个方法的定义:
public interface Collection<E>
{
boolean containsAll(Collection<?> c);
boolean addAll(Collection<? extends E> c);
}
上面两个方法都采用了类型通配符的形式,如果采用泛型方法形式来代替它们,如下所示:
public interface Collection<E>
{
boolean <T> containsAll(Collection<T> c);
boolean <T extends E> addAll(Collection<T> c);
}
上面方法使用了 <T extends E> 泛型形式,这是定义类型形参时设定上限。
3、设定通配符的下限
Java 允许设置通配符下限:<? super Type>,这个通配符表示它必须是 Type 本身,或者是 Type 的父类。示例:
public class MyUtils
{
// 下面 dest 集合元素类型必须与 src 集合元素类型相同,或是其父类
public static <T> copy(Collection<? super T> dest, Collection<T> src)
{
T last = null;
for(T ele : src)
{
last = ele;
dest.add(ele);
}
return last;
}
public static void main(String[] args)
{
List<Number> ln = new ArrayList<Number>();
List<Integer> ln = new ArrayList<Integer>();
li.add(5);
// 此处可准确的知道最后一个被复制的元素是 Integer 类型(与 src 集合元素的类型相同)
Integer last = copy(ln, li);
System.out.println(ln);
}
}
发表评论
-
java:comp/env 解释
2012-07-13 13:40 10840关于获取数据源的语法,大体有(javax.sql.D ... -
java.naming.factory.url.pkgs 的用途
2012-06-28 09:48 1760原文地址:http://blog.csdn.net/l ... -
解析 HTTP
2010-11-14 18:09 48053、HTTP 请求 客户端通过发送 HTTP 请求向服务器 ... -
Tomcat server.xml 文件
2010-11-07 17:21 1227Tomcat 服务器有一系列可配置的组件构成,这些组件 ... -
Tomcat的体系结构
2010-11-04 21:13 1483Tomcat的体系结构 Tomcat服务器是由一系列可配 ... -
第十四课时: 输入/输出1
2010-10-30 20:48 1320Java 的 IO 支持通过 java.io 包 ... -
第十七课时: 网络编程
2010-10-18 22:00 1153一. 网络编程的基础知 ... -
第十六课时: 多线程
2010-10-07 14:24 981一. 继承 Thread 类创建线程 通过继承 Thread ... -
第十四课时:输入/输出2
2010-09-05 15:54 1253... -
第十三课时:Annotation 注释
2010-08-29 15:55 1134从 JDK 5.0 开始,Java 增加了对元数据 ( ... -
第十二课时:JDBC 编程 (2)
2010-08-28 13:13 877示例: import java.sql.*; impor ... -
第十二课时:JDBC 编程 (1)
2010-08-08 15:52 2103一、SQL 语句基础 SQL 的全称是 Structured ... -
第11课时:异常处理
2010-07-25 16:51 1150一、异常处理机制 1、使用 try...catch 捕获异常 ... -
第十课时:与运行环境交互
2010-07-24 06:03 779一、与用户交互 1、使用 Scanner 获取键盘输入 获 ... -
第六课时:面向对象(5)—— 2010年05月22日
2010-07-04 13:45 990一、内部类 在某些情况下,我们把一个类放在另一个类的 ... -
第三课时:面向对象(2)
2010-05-02 23:20 1424一、成员变量与局部变量 二、类的继 ... -
第二课时:数组、面向对象(1)
2010-05-02 23:19 960一、数组 1、 ... -
第四课时:面向对象(3)
2010-05-02 23:17 903一、基本数据类型的包装类 1、 基本数据类型和包装 ... -
第一课时提纲:Java 基础(GC)
2010-03-22 23:22 1189一、Java 命名规范 1、对常量的命名规范: ...
相关推荐
【Java.SE.Lesson.4_code.rar】这个压缩包文件包含了北京圣思园Java培训课程的第四课时的源代码,主要关注的是Java Standard Edition(Java SE)的相关编程知识。Java SE是Java平台的核心,用于开发和运行桌面应用...
【Java.SE.Lesson.5_code.rar】这个压缩包文件显然包含了北京圣思园Java培训课程中的第五课时的源代码。这通常意味着我们将深入到Java编程语言的核心概念中,特别是那些在Java Standard Edition(Java SE)环境下的...
在这个特定的场景中,我们关注的是一个名为"Framework3_Aula02"的学习资源,这可能是某个课程或工作坊的第二课,主要涉及TypeScript语言的应用。 TypeScript是JavaScript的一个超集,它添加了静态类型系统、接口、...
13. **泛型**:Java泛型提高了代码的类型安全性,允许在编译时检查类型。 14. **反射**:反射机制允许程序在运行时动态获取类的信息并操作类的对象。 15. **包装类**:Java为每种原始数据类型提供了对应的包装类,...
第9章 常用类 4课时 理解Object类及其常用方法equals,hashCode和finalize等。 能够使用String,StringBuffer,StringBuilder类创建字符串对象和使用其方法,分辨不同类之间的区别。 ...
《.NET编程系列课程(5)》是一门深入探讨C#编程语言的在线讲座课程,总计30课,每节课时长达70至90分钟,确保学生能够充分理解和掌握每个主题。作为第五课,本课程继续深化了对C#语言的理解,包括实践演示DEMO和详细...
C++是一种静态类型的、编译式的、通用的、大小写敏感的、不仅支持过程化编程、数据抽象化、面向对象编程、泛型编程等多种编程范式的现代程序设计语言。由贝尔实验室的Bjarne Stroustrup于1979年开始设计并实现,并在...
【标题】"AULA22EST-TICOS" 指的可能是一场关于信息技术(TICs)的教育讲座或课程,其中"AULA"在西班牙语中是"课堂"的意思,而"22EST"可能是课程编号或者时间标记,表示第22课时。这个主题暗示我们将探讨与C#编程...
【Java编程二十五课:第九讲】 本课时主要聚焦于Java编程语言的深入学习,特别是针对Java中的核心概念和技术进行讲解。"JB_25_Lesson_09"可能涵盖了许多关键主题,包括但不限于类、对象、封装、继承、多态性等面向...