java泛型(一)--泛型的简单介绍以及常用情况

一.泛型的基本概念

泛型是JavaSE5引入的一个新概念,实现了参数化类型的概念,并且使代码可以应用于多种类型。

在日常编写程序时,我们都会很注重“泛化”,像多态其实就是一种类型的泛化,将子类的对象赋给父类的引用获得更好的泛化特性,将方法的参数类型设置为父类以获得泛化特性等等......  同样,为类声明出接口,而后对接口进行操作同样也可以获得很好的泛化特性。但是上述的方法都有一定的局限性,那就是继承与实现。继承引起了类与类之间的强耦合关系,实现接口又可能会实现一些不需要的接口。我们想去实现代码能应用于一个“不具体的类型”,而不是具体的类与接口。泛型的出现很好的帮我们实现了这一点!


二.泛型的简单使用

1.泛型与容器类的联合使用

考虑一种情况,我们需要实现一个自己的容器类,这个类仅仅持有一个对象的引用(假设持有的对象是字符串),在JavaSE5之前,我们可以编写出如下代码:

package com.fsc.generic;

public class MyHolder {
	private String s;
	public MyHolder(String s){
		this.s = s;
	}
	public String getS() {
		return s;
	}
	public void setS(String s) {
		this.s = s;
	}
}
代码很简单,也实现了持有一个对象。但是如果除了需要持有字符串外还要持有其他类呢?难道要再写一个MyHolder2类么?在泛型出现以前我们可以编写如下代码:

package com.fsc.generic;

public class MyHolder {
	private Object obj;
	public MyHolder(Object obj){
		this.obj = obj;
	}
	public Object getObj() {
		return obj;
	}
	public void setObj(String obj) {
		this.obj = obj;
	}
}
来看一下使用的情况:

MyHolder holderForString = new MyHolder("A String");
String s = (String) holderForString.getObj();
需要对返回的数据进行强制转换,并且很容易出现问题,若我们将返回值转化为Integer,那么在运行期就会出现ClassCastException。


与上述代码类似,在JavaSE5以前的集合类就是用Object的数组来储存数据,每次我们向里面添加什么对象都不予以限制,在返回时需要程序员手动通过强制转换来还原对象。问题在于编译器无法得到对象的实际类型,如果我传入了一个String对象,而在返回时将其返回成Integer的话,运行期的虚拟机就会很不客气的抛出一个ClassCastException,就像这样:

ArrayList list = new ArrayList();
list.add("123");
list.add(1);
Integer i = (Integer) list.get(0);

而泛型的作用就是将异常转移到编译器,下面是添加了泛型后的程序:

ArrayList<String> list = new ArrayList<String>();
list.add("123");
//list.add(1);   不允许向集合添加非String类型的对象
		
String s = list.get(0);
编译器阻止了我们添加不正确的对象,也不需要我们手动进行转型,极大的避免了上述情形的发生。


2.泛型实现元组

很多时候我们希望retrue可以返回多个对象,在这种情况下一般就是创建一个类,让它持有需要返回的对象。考虑这样一种情况,我们需要返回非常多组(假设每组中有两个对象)数据,我们就需要为这些对象创建很多的类。有了泛型,我们就能很好的解决这个问题。

public class TwoTuple<A,B> {
	public final A first;
	public final B second;
	
	public TwoTuple(A first, B second){
		this.first = first;
		this.second = second;
	}
	
	@Override
	public String toString() {
		return "first: "+ first+"  second: "+second;
	}
}

需要返回数据时我们只需要返回一个元组即可。


三.泛型的定义规则

1.泛型类的定义

在前面实现了MyHolder类,现在我们将其定义为泛型类:

package com.fsc.generic;

public class MyHolder<T> {
	private T t;
	public MyHolder(T t){
		this.t = t;
	}
	public T getT() {
		return t;
	}
	public void setT(T t) {
		this.t = t;
	}
}

仅仅需要在类名后面加上<T>即可,而后可以在类中使用T,不过只能将其作为一种类型参数来使用,而不能当做是一个真正的类。具体原因会在下面的文章中介绍。


2.泛型接口的定义

<span style="font-size:18px;color:#000000;">public interface GenericInterface<T>{
	public T get();
}</span>
可以看到和类的定义方式基本相同。

3.泛型方法的定义

public class GenericMethod {
	public static <T> void f(T x){
	}
	public <T> void g(T x){
		
	}
}
泛型方法的定义比较特殊,它不需要将泛型作用在整个类上。 是否拥有泛型方法,与其所在的类是否是泛型没有关系。在Thingking in java一书中给出了指导原则: 如果泛型方法可以取代对整个类进行泛化时,就应该只使用泛型方法。对于静态的(static)方法,其无法访问泛型类的类型参数(T),所以如果要在static方法中使用类型参数,那么就必须要使用泛型方法。


针对泛型方法的类型参数推断

在使用泛型类时,如果我们需要创建一个对象,就需要制定类型参数的值,像这样:

ArrayList<String> list = new ArrayList<String>();

new ArrayList<String>()中的类型参数String是没有意义的(在JavaSE7中已经可以使用<>不写参数来创建对象了),在使用泛型方法的时候,我们可以不用写明参数类型,编译器会自动为我们找出类型,示例中使用的方法为上面实现的GenericMethod.class:

f("123");
f(1);
f(1.0);
编译器自动为我们找出了类型,我们可以和调用正常的方法一样调用f().






下一篇文章中将详细说明泛型的擦除,边界,通配符等一些问题。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值