java基础之 泛型

泛型类

容器类应该算得上最具重用性的类库之一。

  1.  
    public class Container{
  2.  
    private String key;
  3.  
    private String value;
  4.  
    public Container(String k,String v){
  5.  
    key=k;
  6.  
    value=v;
  7.  
    }
  8.  
    public String getKey(){
  9.  
    return key;
  10.  
    }
  11.  
    public Stirng setKey(){
  12.  
    this.key=key;
  13.  
    }
  14.  
    public String getValue(){
  15.  
    return value;
  16.  
    }
  17.  
    public String setValue(){
  18.  
    this.value=value;
  19.  
    }
  20.  
    }

Container类保存了一对key-value键值对,但类型是死定的,也就是说如果我要创建一个键值对String-integer类型的,当前这个Container是做不到的,必须在定义。

  1.  
    public class Container<k,V>{
  2.  
    private k key;
  3.  
    private V value;
  4.  
    public Container(K k,V v){
  5.  
    key=k;
  6.  
    value=v;
  7.  
    }
  8.  
    public K getkey(){
  9.  
    return key;
  10.  
    }
  11.  
    public V getValue(){
  12.  
    return value
  13.  
    }
  14.  
    public void setKey(){
  15.  
    this.key=key;
  16.  
    }
  17.  
    public void setValue(){
  18.  
    this.value=value;
  19.  
    }
  20.  
    }

在编译器,是无法知道K和V具体是什么类型,只有在运行时才会真正根据类型来构造和分配内存。可以看一下现在Container类对于不同类型的支持情况。

  1.  
    public class Main{
  2.  
    public static void main(String[] args){
  3.  
    Container<String,String> c1=new Container<String ,String>("name","hansheng");
  4.  
    Container<String,Integer> c2=new Container<String,Integer>("age",22);
  5.  
    Container<Double,Double> c3=new Container<Double,Double>(1.1,1.3);
  6.  
    System.out.println(c1.getKey() + " : " + c1.getValue());
  7.  
    System.out.println(c2.getKey() + " : " + c2.getValue());
  8.  
    System.out.println(c3.getKey() + " : " + c3.getValue());
  9.  
    }
  10.  
    }

泛型接口

在泛型接口中,生成器是一个很好的理解

  1.  
    public interface Generator<T>{
  2.  
    public T next();
  3.  
    }
  4.  
    //然后定义这个生成器类来实现这个接口
  5.  
    public class FruitGenerator implements Generator<String>{
  6.  
    private String[] fruits=new String[]{"Apple","Banana","Pear"};
  7.  
    @Override
  8.  
    public String next(){
  9.  
    Ramdom rand=new Random();
  10.  
    return fruits[rand.nextInt(3)];
  11.  
    }
  12.  
    }

泛型方法

一个基本原则是:无论何时,只要你能做到,你就应该尽量使用泛型方法。也就是说,如果使用泛型方法可以取代将整个类型化,那么应该有限使用泛型方法。

  1.  
    public class Main{
  2.  
    public static <T> void out(T,t){
  3.  
    System.out.println(t);
  4.  
    }
  5.  
    public static void main(String[] args){
  6.  
    out("hansheng");
  7.  
    out(123);
  8.  
    }
  9.  
    }

可以看到方法的参数彻底泛型化了,这个过程设计到编译器的类型推到和自动打包,也就是原来需要我们自己对类型进行的判断和处理,现在编译器帮我们做了。这样在定义方法的时候不必考虑以后到底需要处理哪些类型的参数,大大增加了编程的灵活性。
再看一个泛型方法和可变参数的例子:

  1.  
    public class Main {
  2.  
     
  3.  
    public static <T> void out(T... args) {
  4.  
    for (T t : args) {
  5.  
    System.out.println(t);
  6.  
    }
  7.  
    }
  8.  
     
  9.  
    public static void main(String[] args) {
  10.  
    out("finding", 123, 11.11, true);
  11.  
    }
  12.  
    }

泛型接口实现的方式

  1.  
    interface Info<T>{
  2.  
    public T getVar();
  3.  
    }
  4.  
    class InfoImpl<T> implements Info<T>T{
  5.  
    private T var;
  6.  
    public InfoImpl(T var){
  7.  
    this.setVar(var);
  8.  
    }
  9.  
    public void setVar(R var){
  10.  
    this.var=var;
  11.  
    }
  12.  
    public T getVar(){
  13.  
    return this.var;
  14.  
    }
  15.  
    }
  16.  
    public class Test{
  17.  
    public static void main(String args){
  18.  
    Info<String> i=null;
  19.  
    i=new InfoImpl<String>("hansheng");
  20.  
    System.out.println("content"+i.getVar);
  21.  
    }
  22.  
    }

类型擦除

  1.  
    Class c1=new ArrayList<Integer>().getClass();
  2.  
    Class c2=new ArrayList<String>().getClass();
  3.  
    System.out.println(c1==c2);

显然在平时使用中,ArrayList<Integer>()和new ArrayList<String>()是完全不同的类型,但是在这里,程序却的的确确会输出true

通过上面的例子可以证明,在编译之后程序会采取去泛型化的措施。也就是说Java中的泛型,只在编译阶段有效。在编译过程中,正确检验泛型结果后,会将泛型的相关信息擦出,并且在对象进入和离开方法的边界处添加类型检查和类型转换的方法。也就是说,泛型信息不会进入到运行时阶段。

对此总结成一句话:泛型类型在逻辑上看以看成是多个不同的类型,实际上都是相同的基本类型。

限制泛型可用类型

如果想限制使用泛型类别时,只能用某个特定类型或者是其子类型才能实例化该类型时,可以在定义类型时,使用extends关键字指定这个类型必须是继承某个类,或者实现某个接口,也可以是这个类或接口本身。

  1.  
    public class ListGenerator<T extends List>
  2.  
    {
  3.  
    private T[] fooArray;
  4.  
    public T[] getfooArray(){
  5.  
    return fooArray;
  6.  
    }
  7.  
    public void setFooArray(T[] fooArray){
  8.  
    this.fooArray=fooArray;
  9.  
    }
  10.  
    public static void main(String[] args){
  11.  
    ListGenerator<LinkedList> foo1=new ListGenerator<LinkedList>();
  12.  
    ListGenerator<ArrayList> foo2=new ListGenerator<ArrayList>();
  13.  
    Link[] linkedLists=new LinkedList[10];
  14.  
    foo1.setFooArray(linkedLists);
  15.  
    ArrayList[] arrayLists=new ArrayList[10];
  16.  
    foo2.setFooArray(arrayLists);
  17.  
    }
  18.  
    }

类声明中:public class ListGenerator<T extends List>这样就规定了T必须是一个List继承系中的类,即实现了List接口的类。

当不使用泛型时,比如那些声明时带有<T>的集合类型,如果使用时没有指定类型,泛型类别为Object.

<T extends SomeClass>是一个限定通配符,?代表了一个未知的类型,并且是它SomeClass的子类,也可以SomeClass本身。



文/hansheng(简书作者)
原文链接:http://www.jianshu.com/p/a1214460f109
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
posted @ 2018-11-29 11:53  heroinss  阅读(160)  评论(0编辑  收藏  举报