泛型
***泛型(generic)***的本质是类型参数化,解决不确定具体对象类型的问题。
泛型可以定义在类、接口、方法中,编译器通过识别尖括号和尖括号内的字母来解析泛型。在泛型的定义中我们通常用:E代表Element,用于集合元素,T代表the Type of object,表示某一个类,K代表Key、V代表value,用于键值对元素。
我们来一个例子瞅瞅:
public class Generic<E> {
private E foo;
public E getFoo(){
return foo;
}
public void setFoo(E foo) {
this.foo = foo;
}
public static void main(String []args){
Generic<Boolean> generic1=new Generic<>();
Generic<Integer> generic2=new Generic<>();
generic1.setFoo(new Boolean(false));
generic2.setFoo(new Integer(14));
Boolean i=generic1.getFoo();
Integer s=generic2.getFoo();
System.out.println(i);
System.out.println(s);
}
}
看了例子我们可以总结出:
①尖括号的每一个元素都指代一种未命名的类型。
②尖括号的位置非常讲究,必须在类名之后或者返回值之前。
③泛型在定义处只具备执行Object方法的例子的能力。
④对于编译后的字节码指令,并没有花头花脑的方法签名,充分说明泛型只是一种编写代码的语法检查。
public class GenericFoo<T1,T2> {
private T1 foo1;
private T2 foo2;
public T2 getFoo2() {
return foo2;
}
public void setFoo2(T2 foo2) {
this.foo2 = foo2;
}
public T1 getFoo1() {
return foo1;
}
public void setFoo1(T1 foo1) {
this.foo1 = foo1;
}
public static void main(String[]args){
GenericFoo<Integer,Boolean> generic=new GenericFoo<Integer,Boolean>();
generic.setFoo1(-20);
generic.setFoo2(false);
System.out.println(generic.getFoo1());
System.out.println(generic.getFoo2());
}
}
用泛型来定义一个数组:
public class Generic1<T> {
private T [] Array;
public T[] getArray() {
return Array;
}
public void setArray(T[] array) {
Array = array;
}
public static void main(String[]args){
Generic1<String> g=new Generic1<>();
String[] str= {"hello", "wrold","!"};
g.setArray(str);
String[] str1=null;
str1=g.getArray();
for (int i=0;i<str.length;i++){
System.out.print(str1[i]+" " );
}
}
}
在定义泛型类别的时候,预设可以使用任何的类型来实例化泛型类型中的类型,但是如果想要限制使用泛型类别时,只能用某个特定类型或者是其子类才能实例化该类型时,可以在定义类型时,使用extends关键字指定这个类型必须是继承某个类,或者实现某个接口。
import java.util.ArrayList;
import java.util.LinkedList;
public class List<E extends java.util.List<String>> {
private E[] fooArray;
public E[] getFooArray() {
return fooArray;
}
public void setFooArray(E[] fooArray) {
this.fooArray = fooArray;
}
public static void main(String[]args){
List<LinkedList<String>> foo1=new List<>();
List<ArrayList<String>> foo2=new List<>();
LinkedList[] linkedLists=new LinkedList[10];
foo1.setFooArray(linkedLists);
ArrayList[] arrayLists=new ArrayList[10];
foo2.setFooArray(arrayLists);
}
}
当没有指定泛型继承的类型或接口时,默认使用T extends Object,所以默认情况下任何类型都可以作为参数传入
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public class GenericTest <T>{
private T foo;
public T getFoo() {
return foo;
}
public void setFoo(T foo) {
this.foo = foo;
}
public static void main(String[]args){
GenericTest<?extends List> ge=null;
ge=new GenericTest<ArrayList>();
ge=new GenericTest<LinkedList>();
GenericTest<? super List> ge2=null;
ge2=new GenericTest<Object>();
GenericTest<String> ge3=new GenericTest<>();
ge3.setFoo("hello world");
GenericTest<? extends Object> ge4=ge3;
System.out.println(ge4.getFoo());
}
}
使用<?>或是<? extends SomeClass> 的声明方式,?代表一个通配符,意味着你只能通过该名称来取得所参数考实例的信息,或是移除某些信息,但是不能增加它的信息,因为只知道当中放置的是SomeClass的子类,但是不确定是什么类的实例,编译器不让你加入信息,理由是,如果可以加入信息的话,那么你就得取回的实例是什么类型,然后转换为原来的类型方可进行操作,这就失去了使用泛型的意义。