- 浏览: 216818 次
- 性别:
- 来自: 北京
文章分类
泛型的本质是类型参数化,所谓类型参数化是指被声明的数据类型是可以改变的,由实际参数来决定。
通常情况下实际参数的值决定了形式参数的值,而类型参数化是实际参数的类型决定了形式参数的类型。
泛型使用场景一。
Integer max(Integer a, Integer b){
return a>b?a:b;
}
该方法比较的是2个Integer类型,如果要比较Double类型,难道又要写一个同样的方法,只是参数变成了Double吗,如果有一种机制,不必先确定a、b的类型,直到调用的时候再指定就好了。这样代码就能够重用了,这时泛型出现了。
当然5.0之前很多人会把参数定义成Object类型来解决。
泛型实例一
public class Generic<T>{
private T obj;
public Generic(T t){//构造方法不指定泛型
obj = t;
}
public T getObj(){
return obj;
}
}
调用
main{
Generic<Integer> generic = new Generic<Integer>(100);
generic .getObj();
Generic<String> genericString = new Generic<String>("100");
genericString .getObj();
}
T是类型参数的名称,这个名称用来作为传递给Generic实际类型的占位符
类型参数的声明必须放到<>中,如 Class<T>
Generic使用了类型参数,因此Generic也叫泛型类。也被称作参数化泛型。
这里定义的obj的类型T,T是一个占位符,需要等到类对象实例化后才能确定obj的类型。
T还可以被作为返回类型
因为obj是T类型,因此getObj返回类型必须也是T。
综合上面:T是一个数据类型说明,可以用来说明任何实例方法中的局部变量,类的成员变量,方法的形式参数,以及方法的返回值
泛型的一个好处就是会检查类型,因此可以保住类型的安全。
带2个类型参数的泛型类
实例:
public class TwoGeneric(K,V){
//使用K,V
}
有界类型
当需要对泛型参数做约束时,使用有界泛型。
如
public class Generic<T extends Number>{//继承接口也要使用extends
}
表示实例话泛型类时,泛型参数必须是Number接口的子类。
通配符参数
Stats <T>类的void doSomething(Stats <T> ob)//对于这样的类型有一个弊端,当实例化Stats <T>时要求调用方法也要使用相同的类型才行,都是T,如果使用void doSomething(Stats <U> ob),编译会不通过,因为不存在一个U参数类型的泛型类。就像不能写成Class<U>一样,Class使用的是T的参数类型。
这时可以使用通配符。
如:
void doSomething(Stats <?> ob)//表示ob可以是任意参数类型的Stats 类。
这里?有一个默认的上届就是实现Number接口,如果想要改变这种上届可以定义方法为
Stats <? extends Integer> ob
但是无法改编成
Stats <? extends String> ob
因为通配符无法将上届改变成超出泛型类声明时的范围。
注意:
class Stats<? extends Number>{……}
通配符是声明泛型类的变量的,不能创建泛型类。
泛型方法
泛型方法:如果一个方法被声明成泛型方法,那它将有一个或是多个类型参数,不过与泛型类不同,它只能在它所修饰的方法中使用。
泛型方法的创建方式如下:
[访问权限修饰符] [static] [final] <类型参数列表> 返回值类型 方法名([形式参数列表])
● 访问权限修饰符(包括private、public、protected)、static和final都必须写在类型参数列表的前面。
● 返回值类型必须写在类型参数表的后面。
● 泛型方法可以写在一个泛型类中,也可以写在一个普通类中。由于在泛型类中的任何方法,本质上都是泛型方法,所以在实际使用中,很少会在泛型类中再用上面的形式来定义泛型方法。
● 类型参数可以用在方法体中修饰局部变量,也可以用在方法的参数表中,修饰形式参数。
● 泛型方法可以是实例方法或是静态方法。类型参数可以使用在静态方法中,这是与泛型类的重要区别。
使用一个泛型方法通常有两种形式:
<对象名|类名>.<实际类型>方法名(实际参数表);
和:
[对象名|类名].方法名(实际参数表);
如果是在类的内部调用,且采用第二种形式,则前缀都可以省略。
使用实例:
泛型方法定义在普通的类中
public class demoGenMethods{
//定义泛型方法,有一个形式参数用类型参数T来定义
public static <T> void showGenMsg(T ob, int n){<T>表示类型参数列表
T localOb = ob; //局部变量也可以用类型参数T来定义
System.out.println(localOb.getClass().getName());
}
public static <T> void showGenMsg(T ob){
System.out.println(ob.getClass().getName());
}
public static void main(String args[]){
String str = "parameter";
Integer k = new Integer(123);
//用两种不同的方法调用泛型方法
demoGenMethods.<Integer>showGenMsg(k,1);
showGenMsg(str);
}
}
注意泛型方法必须定义类是上面的<T>,起到定义的作用,如果不写会报不识别的类型错误。
所以:
public <T> void get(T obj){
return ;
}
是正确的写法。
如果泛型方法定义在泛型类中,则泛型方法不能是静态的。
调用方式
demoGenMethods.<Integer>showGenMsg(k,1);
注意必须带类名demoGenMethods,因为是静态方法。
调用方式有两种:
demoGenMethods.<Integer>showGenMsg(k,1);
showGenMsg(str);
因为因为传入了一个实际参数,因为形式参数也是使用泛型类型,所以可以使用第二种调用方法就能识别出来泛型类型是什么类型。
<T>的定义可以用于返回值、形式参数、或是方法的局部变量
如
public <T> void get(T obj){
T a ;
return ;
}
如果:
public <T> void doSomething(){
T ob;
……
}
调用它的时候,根本就没有实际参数,所以编译器无法知道T的实际类型,这种情况下,就必须使用第一种形式。
即,demoGenMethods.<Integer>showGenMsg(k,1);
泛型接口
定义形式:interface 接口名<类型参数表>
接口:
interface MinMax<T extends Comparable<T>>{
T min();
T max();
}
注意到Comparable本身也是一个泛型类,它是由系统定义在类库中的
实现类:
class MyClass<T extends Comparable<T>> implements MinMax<T>{
}
接口泛型:
它实现类的类型参数T必须和要实现的接口中的声明完全一样
如果一个类实现了一个泛型接口,则此类也是泛型类。否则,它无法接受传递给接口的类型参数
如果实现的是泛型接口的特定类型
如:class MyClass implements MinMax<Integer>
目的就是要想办法传递给接口,若是不能传递给接口,就要接口实现接口时直接指定出类型。
泛型类的继承
以泛型类为父类
泛型类继承实例:
定义父类
public class superGen<T> { }
接下来定义它的一个子类:
public class derivedGen <T> extends superGen<T>{}
这两个类型参数必须用相同的标识符T。这意味着传递给derivedGen的实际类型也会传递给superGen
derivedGen<Integer> number = new derivedGen<Integer>(100);
将Integer作为类型参数传递给derivedGen,再由它传递给superGen,因此,后者的成员ob也是Integer类型。
当然,derivedGen中也可以使用T,还可以增加自己需要的类型参数。下面这个程序展示了一个更为复杂的derivedGen类。
public class derivedGen <T, U> extends superGen<T>{
}
以非泛型类为父类
public class derivedNonGen<T> extends nonGen{}
if (iob instanceof Generic)
会返回true
if (iob instanceof Generic<?>)
也会返回true
尖括号中只能写通配符“?”,而不能写Integer之类确定的类型。实际上在测试时,“?”会被忽略。
<?super T>表示的是下限是T,也就是他能存放的是T或者是T的超类。
而list.add所添加的对象是list泛型中的类或是子类
通常情况下实际参数的值决定了形式参数的值,而类型参数化是实际参数的类型决定了形式参数的类型。
泛型使用场景一。
Integer max(Integer a, Integer b){
return a>b?a:b;
}
该方法比较的是2个Integer类型,如果要比较Double类型,难道又要写一个同样的方法,只是参数变成了Double吗,如果有一种机制,不必先确定a、b的类型,直到调用的时候再指定就好了。这样代码就能够重用了,这时泛型出现了。
当然5.0之前很多人会把参数定义成Object类型来解决。
泛型实例一
public class Generic<T>{
private T obj;
public Generic(T t){//构造方法不指定泛型
obj = t;
}
public T getObj(){
return obj;
}
}
调用
main{
Generic<Integer> generic = new Generic<Integer>(100);
generic .getObj();
Generic<String> genericString = new Generic<String>("100");
genericString .getObj();
}
T是类型参数的名称,这个名称用来作为传递给Generic实际类型的占位符
类型参数的声明必须放到<>中,如 Class<T>
Generic使用了类型参数,因此Generic也叫泛型类。也被称作参数化泛型。
这里定义的obj的类型T,T是一个占位符,需要等到类对象实例化后才能确定obj的类型。
T还可以被作为返回类型
因为obj是T类型,因此getObj返回类型必须也是T。
综合上面:T是一个数据类型说明,可以用来说明任何实例方法中的局部变量,类的成员变量,方法的形式参数,以及方法的返回值
泛型的一个好处就是会检查类型,因此可以保住类型的安全。
带2个类型参数的泛型类
实例:
public class TwoGeneric(K,V){
//使用K,V
}
有界类型
当需要对泛型参数做约束时,使用有界泛型。
如
public class Generic<T extends Number>{//继承接口也要使用extends
}
表示实例话泛型类时,泛型参数必须是Number接口的子类。
通配符参数
Stats <T>类的void doSomething(Stats <T> ob)//对于这样的类型有一个弊端,当实例化Stats <T>时要求调用方法也要使用相同的类型才行,都是T,如果使用void doSomething(Stats <U> ob),编译会不通过,因为不存在一个U参数类型的泛型类。就像不能写成Class<U>一样,Class使用的是T的参数类型。
这时可以使用通配符。
如:
void doSomething(Stats <?> ob)//表示ob可以是任意参数类型的Stats 类。
这里?有一个默认的上届就是实现Number接口,如果想要改变这种上届可以定义方法为
Stats <? extends Integer> ob
但是无法改编成
Stats <? extends String> ob
因为通配符无法将上届改变成超出泛型类声明时的范围。
注意:
class Stats<? extends Number>{……}
通配符是声明泛型类的变量的,不能创建泛型类。
泛型方法
泛型方法:如果一个方法被声明成泛型方法,那它将有一个或是多个类型参数,不过与泛型类不同,它只能在它所修饰的方法中使用。
泛型方法的创建方式如下:
[访问权限修饰符] [static] [final] <类型参数列表> 返回值类型 方法名([形式参数列表])
● 访问权限修饰符(包括private、public、protected)、static和final都必须写在类型参数列表的前面。
● 返回值类型必须写在类型参数表的后面。
● 泛型方法可以写在一个泛型类中,也可以写在一个普通类中。由于在泛型类中的任何方法,本质上都是泛型方法,所以在实际使用中,很少会在泛型类中再用上面的形式来定义泛型方法。
● 类型参数可以用在方法体中修饰局部变量,也可以用在方法的参数表中,修饰形式参数。
● 泛型方法可以是实例方法或是静态方法。类型参数可以使用在静态方法中,这是与泛型类的重要区别。
使用一个泛型方法通常有两种形式:
<对象名|类名>.<实际类型>方法名(实际参数表);
和:
[对象名|类名].方法名(实际参数表);
如果是在类的内部调用,且采用第二种形式,则前缀都可以省略。
使用实例:
泛型方法定义在普通的类中
public class demoGenMethods{
//定义泛型方法,有一个形式参数用类型参数T来定义
public static <T> void showGenMsg(T ob, int n){<T>表示类型参数列表
T localOb = ob; //局部变量也可以用类型参数T来定义
System.out.println(localOb.getClass().getName());
}
public static <T> void showGenMsg(T ob){
System.out.println(ob.getClass().getName());
}
public static void main(String args[]){
String str = "parameter";
Integer k = new Integer(123);
//用两种不同的方法调用泛型方法
demoGenMethods.<Integer>showGenMsg(k,1);
showGenMsg(str);
}
}
注意泛型方法必须定义类是上面的<T>,起到定义的作用,如果不写会报不识别的类型错误。
所以:
public <T> void get(T obj){
return ;
}
是正确的写法。
如果泛型方法定义在泛型类中,则泛型方法不能是静态的。
调用方式
demoGenMethods.<Integer>showGenMsg(k,1);
注意必须带类名demoGenMethods,因为是静态方法。
调用方式有两种:
demoGenMethods.<Integer>showGenMsg(k,1);
showGenMsg(str);
因为因为传入了一个实际参数,因为形式参数也是使用泛型类型,所以可以使用第二种调用方法就能识别出来泛型类型是什么类型。
<T>的定义可以用于返回值、形式参数、或是方法的局部变量
如
public <T> void get(T obj){
T a ;
return ;
}
如果:
public <T> void doSomething(){
T ob;
……
}
调用它的时候,根本就没有实际参数,所以编译器无法知道T的实际类型,这种情况下,就必须使用第一种形式。
即,demoGenMethods.<Integer>showGenMsg(k,1);
泛型接口
定义形式:interface 接口名<类型参数表>
接口:
interface MinMax<T extends Comparable<T>>{
T min();
T max();
}
注意到Comparable本身也是一个泛型类,它是由系统定义在类库中的
实现类:
class MyClass<T extends Comparable<T>> implements MinMax<T>{
}
接口泛型:
它实现类的类型参数T必须和要实现的接口中的声明完全一样
如果一个类实现了一个泛型接口,则此类也是泛型类。否则,它无法接受传递给接口的类型参数
如果实现的是泛型接口的特定类型
如:class MyClass implements MinMax<Integer>
目的就是要想办法传递给接口,若是不能传递给接口,就要接口实现接口时直接指定出类型。
泛型类的继承
以泛型类为父类
泛型类继承实例:
定义父类
public class superGen<T> { }
接下来定义它的一个子类:
public class derivedGen <T> extends superGen<T>{}
这两个类型参数必须用相同的标识符T。这意味着传递给derivedGen的实际类型也会传递给superGen
derivedGen<Integer> number = new derivedGen<Integer>(100);
将Integer作为类型参数传递给derivedGen,再由它传递给superGen,因此,后者的成员ob也是Integer类型。
当然,derivedGen中也可以使用T,还可以增加自己需要的类型参数。下面这个程序展示了一个更为复杂的derivedGen类。
public class derivedGen <T, U> extends superGen<T>{
}
以非泛型类为父类
public class derivedNonGen<T> extends nonGen{}
if (iob instanceof Generic)
会返回true
if (iob instanceof Generic<?>)
也会返回true
尖括号中只能写通配符“?”,而不能写Integer之类确定的类型。实际上在测试时,“?”会被忽略。
<?super T>表示的是下限是T,也就是他能存放的是T或者是T的超类。
而list.add所添加的对象是list泛型中的类或是子类
发表评论
-
JVM启动时指定-Dfile.encoding="UTF8"的作用
2013-10-17 13:50 2413简单来说就是指定JVM默认的编码方式 java io中很多方法 ... -
java多线程 小记
2012-04-15 14:49 0thread join的方法 http://blog.csdn ... -
浅析多线程
2012-04-08 22:35 0线程组 线程是被 ... -
多线程意外中断处理
2012-04-08 20:54 0本文转自:http://peirenlei.iteye.com ... -
多线程项目学习
2012-04-08 20:35 0线程组的作用: ThreadGroup类中的某些方法,可以对线 ... -
java 静态成员变量的内存分配
2012-04-06 10:28 0静态成员变量是属于类变量,即当JVM加载class文件到虚拟机 ... -
深度克隆与浅克隆
2012-04-05 16:31 1179要想实现某个对象的克隆需要该对象实现java.lang.Clo ... -
修改图片大小并添加水印
2012-03-29 13:47 1330import java.awt.*; import java. ... -
JVM的内存分配
2012-03-16 10:06 0Java里的堆(heap)栈(stack)和方法区(metho ... -
HashMap添加数据的过程
2012-03-14 22:18 7140当添加的元素的key为null ... -
几种classloader的加载范围
2012-02-28 12:43 1379Bootstrap class loader:最顶级的clas ... -
利用正则表达式获取网页中多处重复出现的标签数据
2012-02-21 11:21 2741public static void main(String[ ... -
标准的URLConnection请求
2012-01-13 16:39 0只写了主要的代码 URL url = new URL(urlS ... -
常用的ClassLoader的加载范围
2012-01-13 13:53 1440WebAppClassLoader装载器装作文件的范围: 会加 ... -
ClassLoader.getSystemClassLoader().loadClass()和Class.forName()的区别
2012-01-13 13:08 0class A { static { System.ou ... -
httpClient超时解决办法
2012-01-12 16:47 0DefaultHttpClient: 请求超时 httpcli ... -
项目中的使用技巧小记
2012-01-10 21:11 618实现数据在多线程之间的共享: 因为线程的成员变量是各个该线程实 ... -
ThreadLocal
2012-01-10 08:55 1452ThreadLocal是实现线程范围内的数据共享,即不同线程获 ... -
线程加锁优化
2012-01-08 13:19 0实际上,在某些classes中,这种instance方法的同步 ... -
实现多线程使用继承Thread类和Runnable的原因
2012-01-03 15:09 1407我们都知道实现多线程的两种方式,一种是继承Thread类,另一 ...
相关推荐
《JAVA程序员面试之葵花宝典》是一本集大成的面试指南,旨在帮助JAVA开发者在面试中展现出全面而深入的技能。这份资料涵盖了JAVA语言的核心概念,是每一位JAVA程序员在求职路上的重要参考资料。 首先,基础语法是...
【Java程序员面试之葵花宝典】主要涵盖了Java编程的核心概念和面试常见问题。以下是针对这些知识点的详细解析: 1. **面向对象的特征** - **抽象**:抽象是对象设计的基础,它关注对象的主要功能,忽略不重要的...
标题"2016年面试葵花宝典500家公司面试题打包.rar"表明这是一个集合了2016年度500家公司的面试问题的资源包,主要针对的是IT行业的面试准备,特别是对于C++编程语言的理解和应用。"葵花宝典"常常被用来形容具有指导...
《Java面试葵花宝典》是一本专门为Java开发者准备的面试指南,涵盖了广泛的Java基础知识、框架原理以及架构设计等内容,旨在帮助求职者在面试中展现出扎实的技术功底和深入的理解能力。以下是对其中可能涉及的知识点...
// 泛型类型的具体实现 } ``` #### 11. .NET Remoting 与 Web Service - **Remoting**:是一种跨进程、跨计算机边界调用对象的技术。它可以用于构建分布式应用程序,类似于 COM+ 或 DCOM。 - **Web Service**:...
【JAVA葵花宝典】 在Java编程中,掌握面向对象的四大特征——抽象、继承、封装和多态性,是成为一名优秀程序员的基础。这四个概念构成了Java类和对象的核心。 1. 抽象:抽象是忽略一个主题中与当前目标无关的细节...
《程序员面试之葵花宝典》是一本针对程序员面试精心编撰的指南,它涵盖了广泛且常见的面试题目,旨在帮助程序员在编程技能方面进行全面的提升。这本书不仅包含了问题,还提供了详细的答案,使得读者能够在实践中学习...
《JAVA面试葵花宝典》是一份专门为Java开发者准备的面试指南,涵盖了Java语言的核心概念、进阶技术、设计模式以及面试常见问题等关键知识点。这份文档旨在帮助求职者全面了解和掌握Java技术栈,以便在面试中展现出...
《Delphi之未经证实的葵花宝典2.7》是一部专为Delphi初学者编写的教程资料,它深入浅出地介绍了这个强大的面向对象的Windows应用程序开发工具。Delphi,源自Borland公司,现在由Embarcadero Technologies持有,以其...
Java面试题大全——葵花宝典与面试编程 在Java开发者的职业生涯中,面试是必不可少的一环,尤其对于初入职场或寻求职业发展的毕业生来说,准备充分的面试题集至关重要。"java面试题大全-葵花宝典和面试编程"正是...
《C#葵花宝典》是一本专注于C#编程语言的学习资源集合,旨在提升学习者在算法和逻辑思维方面的能力。这份压缩包包含了丰富的练习题目,涵盖了C#的基础语法、面向对象编程、数据结构与算法等多个核心领域。下面将详细...
以上只是JAVA编程学习的一部分内容,实际的《葵花宝典》可能还涵盖了反射、注解、枚举、泛型、并发编程、网络编程等多个主题,每一方面都值得深入研究。通过这个资源包,初学者可以系统地学习JAVA,提升编程能力,更...
《葵花宝典(JAVA)》是一份专为Java开发者准备的面试题锦囊,它涵盖了Java编程语言的各个方面,旨在帮助求职者在面试中展现出扎实的理论基础和实践经验。以下将详细介绍这份文档中可能涉及的关键知识点: 1. **基础...
5. "java葵花宝典5.doc"可能讲解了Java的泛型、枚举、Lambda表达式以及函数式编程,这些都是Java 5及以后版本的重要特性。 此外,这些文档可能还会包含实际项目中的应用示例,帮助读者将理论知识转化为实践能力。...
Java葵花宝典是程序员面试和学习Java编程的重要参考资料,涵盖了Java的核心概念和技术。以下是根据文档部分内容提炼出的关键知识点: 1. **面向对象的特征**: - **抽象**:抽象是忽略不重要的细节,专注于核心...
本版本只是一个预览版,增加了一些新的技巧,还有很多没有整理(包括manusoft、千中元的专栏没有添加...所以未来只会少量添加非常好及系统的技巧,主要重点将放在整理系统设计,设计模式,OOP及泛型编程思想方面的知识
《Java软件开发面试宝典-葵花宝典》是一本专为编程爱好者和对Java概念不熟悉的人士设计的面试指南。它旨在帮助读者更好地理解和掌握Java编程语言的关键概念,以便在面试中表现出色。以下将详细介绍Java软件开发中的...