乐博娱乐»Java WEB»泛型的意义和作用是啥?

泛型的意义和作用是啥?

来源:hexter 宣布时间:2017-06-03 阅读次数:乐博

  简朴的说,意义和作用有:

  类型的参数化,就是可以把类型像要领的参数那样通报。这一点意义特殊。

  泛型使编译器可以在编译期间对类型进行检查以提高类型宁静,淘汰运行时由于工具类型不匹配引发的异常。

  泛型要领,算法的复用。蛮神奇的。

乐博

  想要理解为什么引入泛型,就要知道没有泛型的麻烦。

  我们知道现在的程序乐博娱乐开发都是面向工具了,所以程序里会有许多各种类型的工具,工具多了肯定需要有某种类型的容器来装。所以就有了一些容器类型,好比数组、ArrayList、HashMap、TreeSet等。

  对于数组,我们知道需要在使用时指定数组装的工具类型,如:

Animal animal[];

Dog dog[];

  而对于荟萃类型容器如ArrayList、HashMap、TreeSet等,它们不光是容器,还提供了一些要领对容器内工具的操作要领,如get,set,sort。这个时候就需要知道容器内放的是什么类型的工具,才气return或set。

  正因为程序乐博娱乐开发人员可能把任何类型的工具放进荟萃容器,所以这些容器在设计的时候只能默认设计成装Object类型工具。因为Java里Object是根类。

  所以容器就成了类似这个样子:

public class ListContainer {

private Object obj;

public Object getObj() {

return obj;

}

public void setObj(Object obj) {

this.obj = obj;

}

}

  这样的话,凭据多态,容器就能装任何类型的工具了。不外,取出工具时则需求进行强制类型转换,转换成实际的类型。但这样会有许多类型不宁静问题,为什么呢?因为编译器没法帮助做类型检查,导致代码在运行时易于泛起ClassCastException异常。因此,类型宁静问题只能由程序员自己来把关了,记着各种类型,制止类型转换错误。

ListContainer myContainer = new ListContainer();

myContainer.setObj("123");

ArrayList objectList = new ArrayList();

objectList.add(myContainer);

//下面这句编译时无异常,运行时会ClassCastException异常

Integer myStr = (Integer) ((ListContainer)objectList.get(0)).getObj();

//下面这句ok

String myStr = (String) ((ListContainer)objectList.get(0)).getObj();

  泛型进场:类型的参数化

  利用泛型,重新设计:

public class ListContainer<T> {

private T t;

public T getObj() {

return t;

}

public void setObj(T t) {

this.t= t;

}

}

  这里<T>的T的类型的参数,具体T指代什么类型,是String照旧Animal照旧Dog类型此处不管,而在程序员乐博娱乐开发时使用到ListContainer时再指定,如:

ListContainer<Dog> myCon=new ListContainer<Dog>();

  这种情况下,编译器就知道ListContainer容器是放Dog类型工具的。并进行类型宁静检查。

myCon.setObj(new Dog())//ok

myCon.setObj(“123”);//编译时提醒类型错误

  这样设计的容器在使用时编译器就可以帮助做很大一部门的类型宁静检查事情了,这就制止了许多运行时的ClassCastException异常,程序员也无需记着各种工具的类型和担忧类型匹配问题了。同时大部门情况下也不用做类型强制转换事情了。

ListContainer<String> myContainer = new ListContainer<String>();

myContainer.setObj("123");

myContainer.setObj(new Dog());//编译器就提醒类型异常

ArrayList objectList<ListContainer> = new ArrayList<ListContainer>();

objectList.add(myContainer);

Integer myStr = (objectList.get(0)).getObj(); //编译时提醒类型异常

String myStr = (objectList.get(0)).getObj();

  虽然泛型的<>里也可以放多个参数,如:

public class MultiContainer<T,S> {

private T t;

private S s;

...

MultiContainer<String,Dog> multicon=new MultiContainer<String,Dog>();

  有界泛型

  看看这个泛型和多态的问题,Dog,Cat是Animal的子类:

public void killAll(ArrayList<Animal> animals){...};//Animal容器

...

ArrayList<Animal> animals=new ArrayList<Animal>();

animals.add(new Dog());

animals.add(new Cat());

killAll(animals);//这里ok

ArrayList<Dog> dogs=new ArrayList<Dog>();//Dog是Animal的子类

dogs.add(new Dog());

dogs.add(new Dog());

killAll(dogs);//这里编译不通过

  在这里看上去似乎多态不行了。

  这里就要用到有界泛型:

  在使用泛型时,我们会有这种需求:需要指定泛型的类型规模。有界类型就是在类型参数部门指定extends或super要害字,这里的extends也含有implements的功效,划分用上限或下限来限制类型规模,从而限制泛型的类型界限。例如:

<T extends Animal>//限定T是Animal的子类

<T super Dog >//限定T是Dog的超类

  那么上面那个多态问题就酿成:

public void killAll(ArrayList<T extends Animal> animals){...};

  解决了。

<T extends Object&Comparable&Serializable>

  多个限定时我们可以使用&来进行支解,这时要害词只能使用extends。与多重继续类似,这里只有一个类其他都是接口。

  泛型要领

  有时,我们设计的要领可能其参数类型是不限定的。这种场景如果用重载要领的方式来做的话,算法重复,不是最好的方案。此时泛型要领就可以解决此类问题。

  如Calculator的add要领:

public static <N extends Number> double add(N a, N b){

double sum = 0;

sum = a.doubleValue() + b.doubleValue();

return sum;

}

  如果用重载来做的话,要许多重复代码了。