泛型(Generic)
所谓泛型:就是变量类型的参数法
- 泛型是JDK1.5中一个最重要的特征。通过引入泛型,我们将获得编译时类型的安全和运行时更小地抛出ClassCastExceptions的可能。
泛型之前
- 类别定义时的逻辑完全一样,只是里面成员变量的类型不同
- 如果需要多个相似的类,需要定义多个文件,不同的只是变量的类别,而逻辑是完全一样的
- 对之前代码的一些改写
例1
public class GenericFoo<T>
{
private T foo;
public T getFoo()
{
return foo;
}
public void setFoo(T foo)
{
this.foo = foo;
}
public static void main(String[] args)
{
//foo1 里面成员变量是Boolean类型
GenericFoo<Boolean> foo1 = new GenericFoo<Boolean>();
//foo1 里面成员变量是Integer类型
GenericFoo<Integer> foo2 = new GenericFoo<Integer>();
foo1.setFoo(new Boolean(false));
foo2.setFoo(new Integer(3));
Boolean b = foo1.getFoo();
Integer i = foo2.getFoo();
System.out.println(b);
System.out.println(i);
//foo1 = foo2;
GenericFoo a = new GenericFoo();
a.setFoo("hello");
String str = (String)a.getFoo();
System.out.println(str);
}
}
例2
public class Generic<T1, T2>
{
private T1 foo1;
private T2 foo2;
public T1 getFoo1()
{
return foo1;
}
public void setFoo1(T1 foo1)
{
this.foo1 = foo1;
}
public T2 getFoo2()
{
return foo2;
}
public void setFoo2(T2 foo2)
{
this.foo2 = foo2;
}
public static void main(String[] args)
{
Generic<Integer, Boolean> foo = new Generic<Integer, Boolean>();
foo.setFoo1(new Integer(-20));
foo.setFoo2(new Boolean(false));
System.out.println(foo.getFoo1());
System.out.println(foo.getFoo2());
}
使用泛型编写一个简易版AraayList
public class SimpleCollection<T>
{
private T[] objArr;
private int index = 0;
public SimpleCollection()
{
objArr = (T[])new Object[10];
}
public SimpleCollection(int capacity)
{
objArr = (T[])new Object[capacity];
}
public void add(T t)
{
objArr[index++] = t;
}
public int getLength()
{
return this.index;
}
public T get(int i)
{
return objArr[i];
}
public static void main(String[] args)
{
SimpleCollection<Integer> c = new SimpleCollection<Integer>();
for(int i = 0; i < 10; i++)
{
c.add(new Integer(i));
}
for(int i = 0; i < 10; i++)
{
Integer in = c.get(i);
System.out.println(in);
}
}
限制泛型的可用类型
- 在定义泛型类别时,预设可以使用任何的类 型来实例化泛型类型中的类型,但是如果想要限制使用泛型类别时,只能用某个特定类型或者是其子类型才能实例化该类型时,可以在定义类型时,使用extends关键字指定这个类型必须是继承某个类,或者实现某个接口
- 参见程序 ListGenericFoo.java
- 当没有指定泛型继承的类型或接口时,默认 使用T extends Object,所以默认情况下任 何类型都可以作为参数传入
- 使用<?>或是<? extends SomeClass> 的声明方式,意味著您只能通过该名称來 取得所参考实例的信息,或者是移除某些信息,但不能增加它的信息,因为只知 道当中放置的是SomeClass的子类,但不 确定是什么类的实例,编译器不让您加入 信息, 理由是,如果可以加入信息的話, 那么您就得記得取回的实例是什么类型, 然后转换为原來的类型方可进行操作,这 就失去了使用泛型的意义。
public class ListGenericFoo<T extends List<String>> {//限制的泛型时也可以有泛型
private T[] fooArray;
public T[] getFooArray() {
return fooArray;
}
public void setFooArray(T[] fooArray) {
this.fooArray = fooArray;
}
public static void main(String[] args) {
ListGenericFoo<LinkedList<String>> foo1 = new ListGenericFoo<LinkedList<String>>();
ListGenericFoo<ArrayList<String>> foo2 = new ListGenericFoo<ArrayList<String>>();
LinkedList[] linkedList = new LinkedList[10];
LinkedList<String> list = new LinkedList();
list.add("asd");
linkedList[1] = list;
foo1.setFooArray(linkedList);
ArrayList[] arrayList = new ArrayList[10];
foo2.setFooArray(arrayList);
//ListGenericFoo<HashMap> foo3 = new ListGenericFoo<HashMap>();
}
}
}
例3
public class GenericTest<T> {
private T foo;
public T getFoo() {
return foo;
}
public void setFoo(T foo) {
this.foo = foo;
}
//<T> 声明为泛型方法
public <T> Map<String, T> setFoos(T foo) {
Map<String, T> map = new HashMap<>();
map.put("cx", foo);
return map;
}
public static void main(String[] args) {
GenericTest<? extends List> ge = null;
ge = new GenericTest<ArrayList>();
ge = new GenericTest<LinkedList>();
//泛型方法 传什么T就是什么类型
Map<String, String> map = ge.setFoos("asd");
//ge = new GenericTest<HashMap>();
//泛型层次在List之上
GenericTest<? super List> ge2 = null;
ge2 = new GenericTest<Object>();
GenericTest<String> ge3 = new GenericTest<String>();
ge3.setFoo("hello world");
GenericTest<? extends Object> ge4 = ge3;
System.out.println(ge4.getFoo());
ge4.setFoo(null);
System.out.println(ge4.getFoo());
/*
此时ge4的类型约定是Object及以下此时set进去值是String类型
我们在取的时候包含Object类型,String类型是Object类型子类却
能取出来String的父类此时就需要强制类型转换就失去了泛型的意义
*/
//ge4.setFoo("welcome");
}
}