Java泛型的使用

在通常的时候,一般的类和方法,只能使用具体的类型:要么是基本类型,要么是自定义的类型,如果可以应用于多种类型的代码,那么就要用到泛型.

泛型的概念:参数化类型 使代码可以应用于多种类型。

1.1简单的泛型

   有许多的原因促成了泛型的出现,而最引人注目的一个原因就是为了创造容器类.容器就事存放要使用对象的地方,数组也是如此,不过与简单的数组相比容器显得更灵活一些,具有更多的功能。

class holder2{
	private Object a;
	public holder2(Object a){this.a=a;}
	public void set (Object a){this.a=a;}
	public Object get(){return a;}
	
}
public class main {
	public static void main(String[] args) {
		// TODO 自动生成方法存根
		holder2 h2=new holder2(new String());
		String str=(String)h2.get();
		h2.set(1);
		System.out.println(h2.get().toString());
		//hoder2可以存储任何类型对象
	}
}

与其使用object,我们程序员更新欢暂时不指定类型,而是稍后再决定具体使用什么类型,要达到这个目的,需要使用类型参数,用尖括号括住,放在类名后面,然后再使用这个类的时候,再用实际的类型替换此类参型参数。

2.2利用泛型return返回多个对象

   仅一次方法调用就可以返回多个对象,你应该经常需要这样的功能吧?可是return语句只允许返回单个对象,但是有了泛型咱们就能够一次性的解决这个问题,以后再也不用在这个问题上浪费时间了。

   这个概念称为元祖(tuple),它是将一组对象直接打包存储于其中的一个单一对象,这个容器对象允许读取器中元素,但是不允许向其中存放新的对象(这个概念也称为数据传递对象或信使)

class TwoTuple<A,B>{
	public final A first;
	public final B second;
	public TwoTuple(A a,B b){first =a;second=b;}
	public String toString(){
		return "("+first+"."+second+")";
	}
}
public class tempalte{
	public static void main(String[] args){
		TwoTuple<String, Integer> tt=new TwoTuple<String,Integer>("hello",100);
		System.out.println(tt);
		
	}
}

我们利用构造器捕获了要存储的对象,而ToString事一个便利函数,用来显示列表中的值。

你也许会想,这不是违反了Java编程的安全性能原则了吗?first和second应该生命为private,然后提供GetFirst(),GetSecond()之类的访问方法才对啊。客户端程序可以读取first和 second对象,然后可以随心所欲地使用这两个对象,但是却无法将其的值赋予first或second.因为final声明了他们,而且这种格式更简洁了.

2.3 泛型方法

   到目前为止我们看到的泛型,都是应用于整个类上。但同样可以在类中包含参数化的方法,而这个方法所在的类可以是泛型类,也可以不是泛型类,也就是说,是否拥有泛型方法,与其所在的类是否是泛型没有关系.

   泛型方法使得该方法能够独立于类而产生变化。以下是一个基本的指导原则:无论何时,只要你能做到,你就应该尽量使用泛型方法,也就是说,如果使用泛型方法可以取代将整个类泛型化,那么就应该只使用泛型方法,因为它可以使事情更清楚明白。另外对于一个static的方法而言,无法访问泛型的类型参数,所以,如果static方法需要使用泛型能力,就必须使其成为泛型方法.

   要定义泛型方法,只需将泛型参数列表置于返回值之前

public class GenericMethods {

	/**
	 * @param args
	 */
	public <T> void f(T x){
		System.out.println(x.getClass().getName());
	}
	public static void main(String[] args) {
		// TODO 自动生成方法存根
		GenericMethods gm=new GenericMethods();
		gm.f(" ");
		gm.f(11);
		gm.f(11.1);

	}

}
Output :
        java.lang.String
java.lang.Integer
java.lang.Double

总结: GenericMethods类并不是参数化的,尽管这个类和其内部的方法可以被同时参数化,但是在这个例子中,只有方法f()拥有类型参数。这是由该方法的返回类型前面的类型参数列表指明的。

注意: 当使用泛型类时,必须在创建对象的事后指定类型参数的值,而使用泛型方法的时候,通常不必知名参数类型,因为编译器会为我们找出具体的类型。这称为类型参数推断。因此,我们可以像调用普通方法一样调用f(),而且就好象是f()被无限次地重载。它甚至可以接受本类做为它自己的类型参数.

2.3.1 多参数泛型方法

修改GenericMethods类,使f()方法可以接受三个类型各不相同的参数.

public class GenericMethods {

	/**
	 * @param args
	 */
	public <T,F,X> void f(T t,F f,X x){
		System.out.println(t.getClass().getName());
		System.out.println(f.getClass().getName());
		System.out.println(x.getClass().getName());
	}
	public static void main(String[] args) {
		// TODO 自动生成方法存根
		GenericMethods gm=new GenericMethods();
//		gm.f(" ",1,"aa");
	//	gm.f(11,1,"bb");
		//gm.f(11.1,"aa");
		gm.f(" ", "a", 11);
		gm.f(" ", "a", 11.1);

	}

}
Output :
java.lang.String
java.lang.String
java.lang.Integer
java.lang.String
java.lang.String
java.lang.Double

2.4深入泛型

当你开始更深入地钻研泛型时,会发现有大量的东西最初看起来没有什么意义,例如:尽管可以声明ArrayList.class ,但是不能声明成为ArrayList<Integer>.class

import java.util.ArrayList;


public class My {
	public static void main(String[] args){
		Class c1=new ArrayList<String>().getClass();
		Class c2=new ArrayList<Integer>().getClass();
		System.out.println(c1==c2);
	}

}
Output “true”

//类Class 的实例表示当前运行的Java应用程序中的类和接口。每个数组也属于一个class,被映射为一个Class对象,被所有有着相同元素和数字大小的数组共享。简单Java类型(booleanbytecharshort、 intlongfloatdouble)和关键字void也能表示为Class对象。

ArrayList<String>,和ArrayList<Integer>很容易被认为是不同的类型,不同的类型在行为方面肯定不同,例如,如果尝试着将一个Integer放入ArrayList<String>,所得到的行为(将失败)与把一个Integer放入ArrayList<Integer>(将成功)所得到的行为完全不同。但是上面的程序会认为它们是相同的类型.

残酷的现实就是如此,再泛型的代码内部,无法获得任何有关泛型参数类型的信息。

Java泛型事使用擦除来实现的,这意味当你在使用泛型时,任何具体的类型信息都被擦除了,你唯一知道的就是你在使用一个对象,因此List<String>和List<Integer>在运行时事实上相同的类型,这两种形式都被擦除称它们“原生”类型,即List.

2.4 泛型出现的各类问题

2.41任何基本类型都不能作为类型参数.

不能创建ArratList<int>之类的,解决之道是使用基本类型的包装器以及Java SE5的自动包装机制,并将基本类型int应用于这个容器,那么你将发现自动包装机制将自动地实现int到Integer的双向转换,所以  这几乎就像有一个ArratList<int>一样.

2.42 重载

public class My<W,T> {

void f(List<t> v);

void f(List<w> v);

}

由于擦除的原因,重载方法将产生相同的类型签名.

于此不同的是,当被擦除的参数不能产生唯一的参数列表,必须提供明显有区别的方法名。

public class My<W,T> {

void f1(List<t> v);

void f2(List<w> v);

 

}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

时间辜负了谁

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值