Java中的泛型方法

Java中的泛型方法

 

       泛型是什么意思在这就不多说了,而Java中泛型类的定义也比较简单,例如:public class Test<T>{}。这样就定义了一个泛型类Test,在实例化该类时,必须指明泛型T的具体类型,例如:Test<Object> t = new Test<Object>();,指明泛型T的类型为Object。

       但是Java中的泛型方法就比较复杂了。

       泛型类,是在实例化类的时候指明泛型的具体类型;泛型方法,是在调用方法的时候指明泛型的具体类型。

 

       定义泛型方法语法格式如下:

      

       调用泛型方法语法格式如下:

 

       说明一下,定义泛型方法时,必须在返回值前边加一个<T>,来声明这是一个泛型方法,持有一个泛型T,然后才可以用泛型T作为方法的返回值。

       Class<T>的作用就是指明泛型的具体类型,而Class<T>类型的变量c,可以用来创建泛型类的对象。

       为什么要用变量c来创建对象呢?既然是泛型方法,就代表着我们不知道具体的类型是什么,也不知道构造方法如何,因此没有办法去new一个对象,但可以利用变量c的newInstance方法去创建对象,也就是利用反射创建对象。

       泛型方法要求的参数是Class<T>类型,而Class.forName()方法的返回值也是Class<T>,因此可以用Class.forName()作为参数。其中,forName()方法中的参数是何种类型,返回的Class<T>就是何种类型。在本例中,forName()方法中传入的是User类的完整路径,因此返回的是Class<User>类型的对象,因此调用泛型方法时,变量c的类型就是Class<User>,因此泛型方法中的泛型T就被指明为User,因此变量obj的类型为User。

       当然,泛型方法不是仅仅可以有一个参数Class<T>,可以根据需要添加其他参数。

       为什么要使用泛型方法呢?因为泛型类要在实例化的时候就指明类型,如果想换一种类型,不得不重新new一次,可能不够灵活;而泛型方法可以在调用的时候指明类型,更加灵活。

 

 

http://wwwiteye.iteye.com/blog/1849917

泛型接口

泛型也可以应用于接口,例如生成器,一种专门负责创建对象的类。这其实是工厂方法设计模式的一种应用。不过使用生成器创建对象时,不需要参数。而工厂方法一般是需要参数的。

Java代码  收藏代码
  1. package tik4.generic;  
  2.   
  3. public interface Generator<T> {  
  4.     T next();  
  5. }  

 一个Fibonacci数列实现

Java代码  收藏代码
  1. package tik4.generic;  
  2.   
  3. public class Fibonacci implements Generator<Integer> {  
  4.     private int count;  
  5.   
  6.     // 参数类型用Integer,使用int将不能编译  
  7.     // public int next() {  
  8.     // return 0;  
  9.     // }  
  10.     public Integer next() {  
  11.         return fib(count++);  
  12.     }  
  13.   
  14.     private int fib(int n) {  
  15.         if (n < 2return 1;  
  16.         return fib(n - 2) + fib(n - 1);  
  17.     }  
  18.   
  19.     public static void main(String[] args) {  
  20.         Fibonacci gen = new Fibonacci();  
  21.         for (int i = 0; i <= 17; i++)  
  22.             System.out.print(gen.next() + " ");  
  23.     }  
  24.     /* 
  25.      * Output: 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 
  26.      */  
  27. }  

 

泛型方法

可以在类中包含参数化方法,而这个方法所在的类可以是泛型类,也可以不是泛型类。是否拥有泛型方法,和所在的类是否泛型没有关系。泛型方法使得该方法能够独立于类而产生变化。以下是一个基本原则:如果泛型方法可以取代整个类的泛型化,就应该只使用泛型方法。另外,对于一个static方法而言,无法访问泛型

类的参数类型,所以static方法需要使用泛型能力,就必须成为泛型方法

Java代码  收藏代码
  1. package tik4.generic;  
  2.   
  3. public class GenericMothod {  
  4.     public <T,M,N> void getTType(T t,M m,N n){  
  5.         /* 
  6.          * 传入int,long ,double等基本类型时,自动打包机制 
  7.          * 会将基本类型包装成相应的对象 
  8.          */  
  9.         System.out.println(t.getClass().getName());  
  10.         System.out.println(m.getClass().getName());  
  11.         System.out.println(n.getClass().getName());  
  12.     }  
  13.     public static void main(String[] args) {  
  14.         //泛型类在创建对象时必须指定参数类型,而泛型方法则不需要在创建对象时指定参数类型T  
  15.         GenericMothod gm = new GenericMothod();  
  16.         gm.getTType(""11.0);  
  17.         gm.getTType(1.0F, 'c', gm);  
  18.     }/* 
  19.      *Output:  
  20.     java.lang.String 
  21.     java.lang.Integer 
  22.     java.lang.Double 
  23.     java.lang.Float 
  24.     java.lang.Character 
  25.     tik4.generic.GenericMothod 
  26.     */  
  27. }  

 

利用参数类型推断

问题:很烦这种写法是不是,老子在声明变量的的时候已经指明了参数类型,为毛还要在初始化对象时再指定?

Java代码  收藏代码
  1. Map<Integer, List<? extends Set<String>>> map =   
  2.     new HashMap<Integer, List<? extends Set<String>>>();  

解决:搞一个工具类

Java代码  收藏代码
  1. package tik4.generic;  
  2.   
  3. import java.util.HashMap;  
  4. import java.util.List;  
  5. import java.util.Map;  
  6. import java.util.Set;  
  7.   
  8. public class New {  
  9.     public static <K, V> Map<K, V> hashMap() {  
  10.         return new HashMap<K, V>();  
  11.     }  
  12.   
  13.     public static void main(String[] args) {  
  14.         Map<Integer, List<? extends Set<String>>> map = New.hashMap();  
  15.     }  
  16. }  

 注意:

类型推断只对赋值操作有效,其他时候不起作用。如果你使用泛型方法调用的结果(例如:New.hashMap())作为参数,传递给其他方法,此时编译器不会执行类型推断。编译器认为,调用泛型方法之后,其返回值被赋给一个Object类型的变量。上代码:

Java代码  收藏代码
  1. package tik4.generic;  
  2.   
  3. import java.util.List;  
  4. import java.util.Map;  
  5. import java.util.Set;  
  6.   
  7. public class LimitsOfInference {  
  8.     static void f(Map<Integer, List<? extends Set<String>>> map){};  
  9.     public static void main(String[] args) {  
  10.         /* 
  11.          * the mothed f(Map<Integer, List<? extends Set<String>>> 
  12.          * is not applicable for arguments (Map<Object,Object>) 
  13.          * 不能编译 
  14.          */  
  15. //      f(New.hashMap());  
  16.     }  
  17. }  
 
显示类型说明?? think in java4中是这么写的,但是我的机器上不能编译,难道书上是在扯淡

 在泛型方法中,可以显示的指定参数类型。在 点操作符 和 方法名之间插入尖括号,然后将类型置于括号内。如果是在定义该方法的类的内部,则在点操作符之前使用this关键字如果使用static方法,必须在点操作符之前加上类名。这种语法,可以解决LimitsOfInference.java中的问题。

Java代码  收藏代码
  1. package tik4.generic;  
  2.   
  3. import java.util.List;  
  4. import java.util.Map;  
  5. import java.util.Set;  
  6.   
  7. public class ExplicitTypeSpecification {  
  8.     static void f(Map<Integer, String> map){};  
  9.       
  10.     public static void main(String[] args) {  
  11.                 //java 5和java6 中均不能编译。  
  12.         f(New.<Map<Integer, String>>hashMap());   
  13.     }  
  14. }  

 

 泛型推导在java7中已经实现了。

Java代码  收藏代码
  1. List<String> list = new ArrayList<>();  

     因为编译器可以从前面(List)推断出推断出类型参数,所以后面的ArrayList之后可以不用写泛型参数了,只用一对空着的尖括号就行。当然,你必须带着”菱形”<>,否则会有警告的。 

     Java SE7 只支持有限的类型推断:只有构造器的参数化类型在上下文中被显著的声明了,你才可以使用类型推断,否则不行。 看代码:

Java代码  收藏代码
  1. List<String> list = new ArrayList<>();  
  2. list.add("A");  
  3.   
  4. //这个不行  
  5. list.addAll(new ArrayList<>());  
  6.   
  7. // 这个可以  
  8. List<? extends String> list2 = new ArrayList<>();  
  9. list.addAll(list2);  




Java泛型--泛型应用--泛型接口、泛型方法、泛型数组、泛型嵌套

1、泛型接口

1.1泛型接口的基本概念

1.2泛型接口实现的两种方式

定义子类:在子类的定义上也声明泛型类型
interface Info<T>{		// 在接口上定义泛型
	public T getVar() ;	// 定义抽象方法,抽象方法的返回值就是泛型类型
}
class InfoImpl<T> implements Info<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[]){
		Info<String> i = null;		// 声明接口对象
		i = new InfoImpl<String>("李兴华") ;	// 通过子类实例化对象
		System.out.println("内容:" + i.getVar()) ;
	}
};
如果现在实现接口的子类不想使用泛型声明,则在实现接口的时候直接指定好其具体的操作类型即可:
interface Info<T>{		// 在接口上定义泛型
	public T getVar() ;	// 定义抽象方法,抽象方法的返回值就是泛型类型
}
class InfoImpl implements Info<String>{	// 定义泛型接口的子类
	private String var ;				// 定义属性
	public InfoImpl(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[]){
		Info i = null;		// 声明接口对象
		i = new InfoImpl("李兴华") ;	// 通过子类实例化对象
		System.out.println("内容:" + i.getVar()) ;
	}
};

2、泛型方法

2.1定义泛型方法

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) ;		// 输出内容
	}
};

2.2通过泛型方法返回泛型类的实例

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 ;	// 返回实例化对象
	}
};

2.3使用泛型统一传入参数的类型

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()) ;
	}
};
如果add方法中两个泛型的类型不统一,则编译会出错。
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 GenericsDemo29{
	public static void main(String args[]){
		Info<Integer> i1 = new Info<Integer>() ;
		Info<String> i2 = new Info<String>() ;
		i1.setVar(30) ;		// 设置内容
		i2.setVar("李兴华") ;		// 设置内容
		add(i1,i2) ;
	}
	public static <T> void add(Info<T> i1,Info<T> i2){
		System.out.println(i1.getVar() + " " + i2.getVar()) ;
	}
};

3、泛型数组

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 + "、") ;
		}
	}
};

4、泛型的嵌套设置

Demo类中的info属性是Info类的这种属性,Info类本身需要两个泛型。
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()) ;
	}
};
 
posted @ 2016-03-15 01:06  标准小兵  阅读(2290)  评论(0编辑  收藏  举报