java泛型--泛型的简单介绍以及常用情况
Posted 加冰雪碧
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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().
下一篇文章中将详细说明泛型的擦除,边界,通配符等一些问题。
以上是关于java泛型--泛型的简单介绍以及常用情况的主要内容,如果未能解决你的问题,请参考以下文章