一、
1、泛型类 语法:类名<T> 如 Info<T> ,其中Info是定义的一个类,T代表一个类型名称。表示这个Info类里面的所有成员的类型为T。注意:这里的T是一个通用的类型,泛指的。具体是什么类型是在该Info类被实例化时决定的,因为在实例化时必须指定T真正代表的类型。
还可以定义含有多个类型的泛型类,如 Info<T1,T2>
2、限制泛型可用类型 语法: 类名<T extends otherClass> 其中otherClass是指某个类或接口。
3、使用泛型类型通配符 语法:类名<? extends otherClass> 其中otherClass是指某个类或接口。
4、泛型要求能包容的是对象类型,而基本类型在java里不属于对象。但是基本类型都有其包装类型,也就是对象类型:
关于基本类型和包装类型的链接:http://blog.csdn.net/u013003837/article/details/31420343
List<int> list=new ArrayList<int>();//这里,这样是错误的
list.add(0);
list.add(1);
如果想存放基本类型就用其包装类型去实现功能:
List<Integer> list=new ArrayList<Integer>();//这样就正确了
list.add(0);
list.add(1);
二、
在编写程序时,经常遇到两个模块的功能非常相似,其中一个是处理int数据,另一个是处理string数据,或者其他自定义的数据类型,但我们没有办法,只能分别写多个方法处理每个数据类型,因为方法的参数类型不同。使用泛型就可以在方法中传入通用的数据类型,来解决写多个不同数据类型方法的问题。如下只能处理int数据类型。
public class Tack{
private int[] m_item;
public int Pop(){...}
public void Push(int item){...}
public Tack(int i)
{
this.m_item = new int[i];
}
}
当需要处理string类型时,把int改成string这样做本身没有任何问题。那么我们可以用一个通用的数据类型object来实现。
public class Tack{
private object[] m_item;
public object Pop(){...}
public void Push(object item){...}
public Tack(int i)
{
this.m_item = new[i];
}
}
上面的写法可以接收任何数据类型,但存在缺陷,主要表现在
(1)当Tack处理值类型时,会出现装箱、折箱操作,这将在托管堆上分配和回收大量的变量,若数据量大,则性能损失非常严重。
(2)在处理引用类型时,虽然没有装箱和折箱操作,但将用到数据类型的强制转换操作,增加处理器的负担。
(3)在数据类型的强制转换上还有更严重的问题。
那我们可以引入泛型,可以解决这些问题。泛型是使用一个通用的数据类型T来代替object,在类实例化时必须要指定T的类型,运行时(Runtime)自动编译为本地代码,运行效率和代码质量都有很大提高,并且保证数据类型安全。
使用泛型来重写上面的程序,用一个通用的数据类型T来作为一个占位符,等待在实例化时用一个实际的类型来代替。
public class Tack<T>{
private T[] m_item;
public T Pop(){...}
public void Push(T item){...}
public Tack(int i)
{
this.m_item = new T[i];
}
}
这个类的调用方法:
//实例化只能保存int类型的类
Stack<int> a = new Stack<int>(100);
a.Push(10);
a.Push("8888"); //这一行编译不通过,因为类a只接收int类型的数据
int x = a.Pop();
//实例化只能保存string类型的类
Stack<string> b = new Stack<string>(100);
b.Push(10);//这一行编译不通过,因为类b只接收string类型的数据
b.Push("8888");
string y = b.Pop();
这个类和object实现的类有截然不同的区别:
1.他是类型安全的。实例化了int类型的栈,就不能处理string类型的数据,其他数据类型也一样。
2.无需装箱和折箱。这个类在实例化时,按照所传入的数据类型生成本地代码,本地代码数据类型已确定,所以无需装箱和折箱。
3.无需类型转换。
三、AnyClass.java
package Test5;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;
/*
* 使用泛型实例化常用集合类
*/
public class AnyClass {
public static void main(String[] args) {
//定义ArrayList容器,设置容器内的值类型为Integer
ArrayList<Integer> a=new ArrayList<Integer>();
//为容器添加新值
a.add(1);
for(int i=0;i<a.size();i++){
System.out.println("获取ArrayList容器的值:"+a.get(i));
}
//定义HashMap容器,设置容器的键名与键值类型分别为Integer与String型
Map<Integer,String> m=new HashMap<Integer,String>();
for(int i=0;i<5;i++){
//为容器填充键名与键值
m.put(i, "成员"+i);
}
for(int i=0;i<m.size();i++){
//根据键名获取键值
System.out.println("获取Map容器的值"+m.get(i));
}
//定义Vector容器,使容器中的内容为String类型
Vector<String> v=new Vector<String>();
for(int i=0;i<8;i++){
//为Vector容器添加内容
v.addElement("成员"+i);
}
for(int i=0;i<v.size();i++){
System.out.println("获取Vector容器的值"+v.get(i));
}
}
}
程序运行结果:
四、泛型高级用法---限制泛型可用类型
LimitClass.java
package Test5;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
/*
* 泛型的高级用法:1、限制泛型可用类型 。2、使用类型通配符。
* 这里讲解限制泛型可用类型,语法:class 类名称<T extends anyClass>
* 其中anyClass指某个接口或类。使用限制泛型后,泛型类的类型必须实现或继承了anyClass这个接口或类。需要注意的是
* 无论anyClass是接口还是类,在进行泛型限制时都必须使用extends关键字。
*/
//定义LimitClass类,在该类中限制泛型类型。这样就规定了泛型T必须是一个实现了List接口的类。并且这个List也可以后加括号指明类型,如List<String>等。当没有指定泛型继承的类型或接口时,默认使用T extends Object,所以默认情况下任何类型都可以作为参数传入。
public class LimitClass<T extends List> {
//实例化已经实现List接口的类
LimitClass<ArrayList> lca=new LimitClass<ArrayList>();
//实例化已经实现List接口的类
LimitClass<LinkedList> lcl=new LimitClass<LinkedList>();
//这句是错误的。因为HashMap没有实现List()接口,所以不能实例化HashMap类型的泛型对象
LimitClass<HashMap> lch=new LimitClass<HashMap>();
}
五、泛型高级用法---使用类型通配符
1、<? extends SomeClass>是一个限界通配符(bounded wildcard),?代表了一个未知的类型,并且它是SomeClass的子类,也可以是SomeClass本身。这里面SomeClass是统配符的上界(upper bound of the wildcard),通配符所代表的其实是一组类型,但具体的类型是未知的。相应的也有限定下界的,使用关键字super。
也可以限制引用指向某个类或接口的继承层次之上的类或接口:
//引用指向继承层次之上
GenericFoo<? super List> ge= null;
ge = new GenericFoo<Object>();
2、类型统配声明
//此时foo1只能接受GenericFoo<Integer>类型的实例,foo2只能接受GenericFoo<Boolean>类型的实例
GenericFoo<Integer> foo1 = null;
GenericFoo<Boolean> foo2 = null;
如果希望有一个变量foo可以指向下面所有的实例:
//foo = new GenericFoo<ArrayList>();
//foo = new GenericFoo<LinkedList>();
可以这样声明:
GenericFoo<? extends List> foo = null;
foo = new GenericFoo<ArrayList>();
foo = new GenericFoo<LinkedList>();
注意:这种形式不同于前面的限制泛型可用类型时提到的形式。
前面提到的形式是在声明泛型的类的时候限制了可以用的泛型类型,而现在这种形式是在使用的时候限制了引用的类型,使得引用指向继承了某一个类或接口的类型。
如果该应用指向其他类型,则会编译报错:
//Error:Type mismatch
foo = new GenericFoo<HashMap>();
3、使用<?>或是<? extends SomeClass>的声明方式,意味着您只能通过该名称来取得所参考的实例的信息,或者是移除某些信息,但不能增加或者改写它的信息。因为只知道当中放置的是SomeClass的子类,但不确定是什么类的实例,编译器不让您加入信息,理由是,如果可以加入信息的话,那么您就得记得取回的是什么类型的实例,然后转换为原来的类型方可进行操作,这样就失去了使用泛型的意义。
另,GenericFoo<? extends Object>等价于GenericFoo<?>,但是它们与GenericFoo<Object>不同,因为GenericFoo<Object>限定了类型为Object。
4、泛型类要注意:
1) 在定义一个泛型类的时候,在 “<>”之间定义形式类型参数,例如:“class TestGen<K,V>”,其中“K” , “V”不代表值,而是表示类型。
2) 实例化泛型对象的时候,一定要在类名后面指定类型参数的值(类型),一共要有两次书写。例如:
TestGen<String,String> t=new TestGen<String,String>();
3) 泛型中<K extends Object>,extends并不代表继承,它是类型范围限制
六、
1、普通泛型
1.1 GenericsDemo06.java
package generic;
/*
* 普通泛型
* 在JDK1.5版本以后,提出了泛型机制。语法为:类名<T>
*/
//定义类Point,T代表一个类型的名称。总起来 Point<T>就叫泛型类
class Point<T>{ //定义泛型类Point<T>
private T var ; //定义泛型成员变量 var
public T getVar(){ //设置getXXX()方法, 返回值的类型由调用者决定
return var ;
}
public void setVar(T var){ //设置setXXX()方法, 设置的类型也由调用者决定
this.var = var ;
}
};
//定义类GenericsDemo06
public class GenericsDemo06{
public static void main(String args[]){
//实例化一个String型的Point对象,即Point中值的类型为String
Point<String> p = new Point<String>() ;
p.setVar("it") ;// 设置字符串
System.out.println(p.getVar().length()) ;// 取得字符串的长度
}
};
程序结果如下:
1.2 GenericsDemo09.java
package generic;
/*
* 在定义泛型类时可以声明多个类型
*/
//定义类Notepad,在该类中定义了两个类型K、V。这样就是定义了一个含有多个类型的泛型类
class Notepad<K,V>{ //定义泛型类Notepad<K,V>
private K key ; //定义泛型成员变量key
private V value ; //定义泛型成员变量value
public K getKey(){
return this.key ;
}
public V getValue(){
return this.value ;
}
public void setKey(K key){
this.key = key ;
}
public void setValue(V value){
this.value = value ;
}
};
public class GenericsDemo09{
public static void main(String args[]){
//实例化第一个类型为String、第二个类型为Integer的Notepad对象,即Notepad中值的类型分别为String和Integer
Notepad<String,Integer> t = null ;
t = new Notepad<String,Integer>() ; // 里面的key为String类型,value为Integer类型
t.setKey("汤姆") ; // 设置第一个内容
t.setValue(20) ; // 设置第二个内容
System.out.print("姓名;" + t.getKey()) ; // 取得信息
System.out.print(",年龄;" + t.getValue()) ; // 取得信息
}
};
程序运行结果如下:
2、通配符
GenericsDemo14.java
package generic;
//定义一个类名为Info,类型为T的泛型类Info<T>
class Info<T>{
private T var ; //定义泛型成员变量var
public void setVar(T var){
this.var = var ;
}
public T getVar(){
return this.var ;
}
//定义普通方法
public String toString(){ // 直接打印
return this.var.toString() ;
}
};
public class GenericsDemo14{
public static void main(String args[]){
//实例化类型为String的Info对象
Info<String> i = new Info<String>() ;//使用String为泛型类型
i.setVar("it") ;// 设置内容
fun(i) ;
}
//1、这里我们放在方法的参数中,fun方法的形参类型为Info<?>
//2、Info<? extends Object>等价于Info<?>,它们表示可以将Info实例化为Object及以下的子类类型,称为向下限制。
//是使用了通配符"?"和extends关键字在创建一个泛型类对象时限制这个泛型类的类型实现某个接口或继承某个类。
public static void fun(Info<?> temp){ // 可以接收任意的泛型对象
System.out.println("内容:" + temp) ;
}
}
程序运行结果如下:
3、受限泛型
3.1 GenericsDemo17.java
package generic;
//定义泛型类Infos<T>
class Infos<T>{
private T var ; //定义泛型变量 var
public void setVar(T var){ //4 6
this.var = var ;
}
public T getVar(){
return this.var ;
}
public String toString(){ //9 12 直接打印
return this.var.toString() ;
}
};
public class GenericsDemo17{
public static void main(String args[]){
//实例化类型为Ingeger的对象
Infos<Integer> i1 = new Infos<Integer>() ; //1 声明Integer的泛型对象
//实例化类型为Float的对象
Infos<Float> i2 = new Infos<Float>() ; //2 声明Float的泛型对象
i1.setVar(30) ; //3 设置整数,自动装箱
i2.setVar(30.1f) ; //5 设置小数,自动装箱
//调用同类中的静态方法fun,直接调用就可。需要传递参数
fun(i1) ; //7
fun(i2) ; //10
}
//在方法参数中定义了受限泛型,该类型为:只能是Number及其Number的子类
public static void fun(Infos<? extends Number> temp){ // 只能接收Number及其Number的子类
System.out.print(temp + "、") ; //8 11
}
};
上面程序中红颜色标注了执行顺序
程序运行结果如下:
3.2 GenericsDemo21.java
package generic;
class Infon<T>{
private T var ; // 定义泛型变量
public void setVar(T var){
this.var = var ;
}
public T getVar(){
return this.var ;
}
public String toString(){ // 直接打印
return this.var.toString() ;
}
};
public class GenericsDemo21{
public static void main(String args[]){
Infon<String> i1 = new Infon<String>() ; // 声明String的泛型对象
Infon<Object> i2 = new Infon<Object>() ; // 声明Object的泛型对象
i1.setVar("hello") ;
i2.setVar(new Object()) ;
fun(i1) ;
fun(i2) ;
}
public static void fun(Infon<? super String> temp){ // 只能接收String或Object类型的泛型
System.out.print(temp + "、") ;
}
};
程序运行结果如下:
4、泛型无法向上转型
GenericsDemo23.java
package generic;
class Infom<T>{
private T var ; // 定义泛型变量
public void setVar(T var){
this.var = var ;
}
public T getVar(){
return this.var ;
}
public String toString(){ // 直接打印
return this.var.toString() ;
}
};
public class GenericsDemo23{
public static void main(String args[]){
Infom<String> i1 = new Infom<String>() ; // 泛型类型为String
Infom<Object> i2 = new Infom<Object>();
i2 = i1 ; //这句会出错 incompatible types
}
};
程序运行结果如下:
5、泛型接口
GenericsDemo24.java
package generic;
//在接口上定义泛型
interface Infoo<T>{ // 在接口上定义泛型
public T getVar() ; // 定义抽象方法,抽象方法的返回值就是泛型类型
}
class InfoImpl<T> implements Infoo<T>{ // 定义泛型接口的子类
private T var ; // 定义属性
public InfoImpl(T var){ // 通过构造方法设置属性内容
this.setVar(var) ;
}
public void setVar(T var){
this.var = var ;
}
public T getVar(){
return this.var ;
}
};
public class GenericsDemo24{
public static void main(String arsg[]){
// 通过子类实例化对象 ,父类引用指向子类对象
Infoo<String> i = new InfoImpl<String>("汤姆") ;
System.out.println("内容:" + i.getVar()) ;
}
}
程序运行结果如下:
GenericsDemo25.java
package generic;
//在接口上定义泛型
interface Infoc<T>{ // 在接口上定义泛型
public T getVar() ; // 定义抽象方法,抽象方法的返回值就是泛型类型
}
class InfoImpls implements Infoc<String>{ // 定义泛型接口的子类
private String var ; // 定义属性
public InfoImpls(String var){ // 通过构造方法设置属性内容
this.setVar(var) ;
}
public void setVar(String var){
this.var = var ;
}
public String getVar(){
return this.var ;
}
};
public class GenericsDemo25{
public static void main(String arsg[]){
// 通过子类实例化对象
Infoc i = new InfoImpls("汤姆") ;
System.out.println("内容:" + i.getVar()) ;
}
};
程序运行结果如下:
6、泛型方法
Java代码
class Demo{
public <T> T fun(T t){ // 可以接收任意类型的数据
return t ; // 直接把参数返回
}
};
public class GenericsDemo26{
public static void main(String args[]){
Demo d = new Demo() ; // 实例化Demo对象
String str = d.fun("汤姆") ; // 传递字符串
int i = d.fun(30) ; // 传递数字,自动装箱
System.out.println(str) ; // 输出内容
System.out.println(i) ; // 输出内容
}
};
7、通过泛型方法返回泛型类型实例
Java代码
class Info<T extends Number>{ // 指定上限,只能是数字类型
private T var ; // 此类型由外部决定
public T getVar(){
return this.var ;
}
public void setVar(T var){
this.var = var ;
}
public String toString(){ // 覆写Object类中的toString()方法
return this.var.toString() ;
}
};
public class GenericsDemo27{
public static void main(String args[]){
Info<Integer> i = fun(30) ;
System.out.println(i.getVar()) ;
}
public static <T extends Number> Info<T> fun(T param){//方法中传入或返回的泛型类型由调用方法时所设置的参数类型决定
Info<T> temp = new Info<T>() ; // 根据传入的数据类型实例化Info
temp.setVar(param) ; // 将传递的内容设置到Info对象的var属性之中
return temp ; // 返回实例化对象
}
};
8、使用泛型统一传入的参数类型
Java代码
class Info<T>{ // 指定上限,只能是数字类型
private T var ; // 此类型由外部决定
public T getVar(){
return this.var ;
}
public void setVar(T var){
this.var = var ;
}
public String toString(){ // 覆写Object类中的toString()方法
return this.var.toString() ;
}
};
public class GenericsDemo28{
public static void main(String args[]){
Info<String> i1 = new Info<String>() ;
Info<String> i2 = new Info<String>() ;
i1.setVar("HELLO") ; // 设置内容
i2.setVar("汤姆") ; // 设置内容
add(i1,i2) ;
}
public static <T> void add(Info<T> i1,Info<T> i2){
System.out.println(i1.getVar() + " " + i2.getVar()) ;
}
};
9、泛型数组
Java代码
public class GenericsDemo30{
public static void main(String args[]){
Integer i[] = fun1(1,2,3,4,5,6) ; // 返回泛型数组
fun2(i) ;
}
public static <T> T[] fun1(T...arg){ // 接收可变参数
return arg ; // 返回泛型数组
}
public static <T> void fun2(T param[]){ // 输出
System.out.print("接收泛型数组:") ;
for(T t:param){
System.out.print(t + "、") ;
}
}
};
10、泛型的嵌套设置
Java代码
class Info<T,V>{ // 接收两个泛型类型
private T var ;
private V value ;
public Info(T var,V value){
this.setVar(var) ;
this.setValue(value) ;
}
public void setVar(T var){
this.var = var ;
}
public void setValue(V value){
this.value = value ;
}
public T getVar(){
return this.var ;
}
public V getValue(){
return this.value ;
}
};
class Demo<S>{
private S info ;
public Demo(S info){
this.setInfo(info) ;
}
public void setInfo(S info){
this.info = info ;
}
public S getInfo(){
return this.info ;
}
};
public class GenericsDemo31{
public static void main(String args[]){
Demo<Info<String,Integer>> d = null ; // 将Info作为Demo的泛型类型
Info<String,Integer> i = null ; // Info指定两个泛型类型
i = new Info<String,Integer>("汤姆",30) ; // 实例化Info对象
d = new Demo<Info<String,Integer>>(i) ; // 在Demo类中设置Info类的对象
System.out.println("内容一:" + d.getInfo().getVar()) ;
System.out.println("内容二:" + d.getInfo().getValue()) ;
}
};