泛型

  • 为什么要有泛型
  一般的类和方法,只能使用具体的类型,要么是基础类型,要么是自定义的类型。如果要编写可以应用于多种类型的代码,这种刻板的限制对代码的束缚就会很大。
  例如,声明一个自定义类型,继承要求类型必须继承某父类,接口要求类型必须实现某一接口。所以,为了编写更加通用的代码,使代码能够应用于“某种不确定的类型”,JavaSE5后引入了泛型。
  • 什么是泛型
  泛型实现了参数化类型的概念,术语的意思是“适用于很多很多的类型”,把类型当做一个参数,在具体编程时指定,不指定默认Object。泛型在编程语言出现时,最后的目的是希望类或方法能够具备最广泛的表达能力。具体实现:解耦类或方法与所使用的类型关系的约束。
      疑问:java并没有那么高的实现,与C++的泛型相比,存在很多弊端。
 泛型最引人注目的引用就是集合类,泛型的主要目的之一就是用来指定容器要持有的类型的对象,而且有编译器来保证类型的正确性,可在编译期排错,保证运行期效率

参数类型与Object类:参数类型可在具体编码时,指定某一个具体类型。Object已经是一个具体类型了,需要强制转换为需要的类型

    List<T> list = new ArrayList<T>();
    List list = new ArrayList();//默认T为Object,使用Object,不利于编译期保证类型,后面取值也强转,可能会出错,降低运行期效率。
    ...

  元组:将一组对象打包成一个单一对象,这个容器允许读取其中的元素,不允许向其中存放新的对象。

public class TwoTuple<A,B>{//参数类型A、B可随意注入不同类型的对象
    public final A a;
    public final B b;
    public TwoTuple(A a,B b){
        this.a = a;
        this.b = b;
    }
}

 注:基本类型无法做参数类型,也就是必须使用Integer,Long等

  • 泛型类与泛型方法

泛型方法所在类可以是泛型类也可以不是泛型类。无论何时,只要你能做到,你就应该尽量使用泛型方法。

public class GenericMethods{
    
    public <T> void f(T x){
        System.out.println(x.getClass().getName());
    }        

    public static void main(String[] s){
        GenericMethods gm = new GenericMethods();
        gm.f(1);//java.lang.Integer
        gm.f("1");//java.lang.String
        gm.f(1L);//java.lang.Long
    }

}        

 

对于一个static的方法而言,无法访问泛型类的类型参数,所以static方法需要使用泛型能力,就必须使其成为泛型方法
当使用泛型类时,必须创建对象的时候指定类型参数的值,而使用泛型方法的时候,通常不比指明参数类型类型,因为编译器会为我们找到具体的类型。这叫类型参数推断
运用泛型的类型参数推断可以,避免一些重复代码。
HashMap<? extends Object> map = New.map();
  •  泛型的擦除
public class ErasedTypeEquivalence{
    public static void main(String s[]){
        Class class1 = new ArrayList<String>().getClass();
        Class class2 = new ArrayList<Integer>().getClass();
        System.out.println(class1 == class2);//true        
    }    
}

ArrayList<String>与ArrayList<Integer>是同一种类型。在泛型代码内部,无法获取有关泛型参数类型的任何信息。

ArrayList<String>与ArrayList<Integer>被擦除成ArrayList,String及Integer被擦除成Object。

当你编写代码的时候,你时刻要提醒自己,你只是看起来好像拥有有关参数的类型信息而已,可以理解为编译器知道String类型,但是运行期虚拟机不知道,认为是Object。

 

public class Erased<T>{
    private final int SIZE = 100;
    public static void main(String[] s){
        if(s instanceof T){}//error
        T var = new T();//error
        T[] array = new T[SIZE];//error
        T[] araat = (T) new Object[SIZE];//unchecked warning
    }
}

 

 

class Building{}
class House extends Building{}
public class ClassTypeCapture<T>{
    Class<T> kind;
    public ClassTypeCapture(Class<T> kind){
        this.kind = kind;
    }
    
    public boolean f(Object obj){
        return kind.isInstance(obj);
    }
    
    public static void main(String s[]){
        ClassTypeCapture ctc1 = new ClassTypeCapture<Building>(Building.class);
        System.out.println(ctc1.f(new Building()));
        System.out.println(ctc1.f(new House()));
        ClassTypeCapture ctc2 = new ClassTypeCapture<House>(House.class);
        System.out.println(ctc2.f(new Building()));
        System.out.println(ctc2.f(new House()));
    }
}

 

泛型的通配符
public class Test{
    public static void main(String[] s){
        Fruit[] fruit = new Apple[10];
        fruit[0] = new Apple();
        fruit[1] = new Fushishan();
        try{
            fruit[0] = new Fruit();
        }catch(Exception e){
            System.out.println(e);
        }
        try{
            fruit[0] = new Orange();
        }catch(Exception e){
            System.out.println(e);
        }
    }
}

class Fruit{}
class Apple extends Fruit{}
class Orange extends Fruit{}
class Fushishan extends Apple{}

 

posted on 2018-07-06 16:25  FFStayF  阅读(162)  评论(0编辑  收藏  举报