Java泛型使用示例整理
目标
Java泛型编程是JDK1.5版本后引入的。泛型让编程人员能够使用类型抽象,通常用于集合里面。本文旨在整理一些泛型的用法。
用法
泛型分两部分。一部分是泛型类和方法的定义。另一部分是泛型类和方法的使用。
定义篇
类定义时,使用泛型
在定义类的时候,我们可以使用泛型。如下代码:
class Demo <T> { T field; public void setFiled(T field) { this.field = field; } public T getField() { return field; } } public class Test { public static void main (String[] args) throws java.lang.Exception { Demo<String> demo = new Demo<String>(); demo.setFiled("www.bo56.com"); System.out.println(demo.getField()); } }
类名后面增加
无参数方法定义时,使用泛型
无论在泛型类,还是普通类中,我们都可以再方法中使用泛型。
import java.util.ArrayList; import java.util.List; class Demo { public <T> List<T> newArrayList() { return new ArrayList<T>(); } } public class Test { public static void main (String[] args) throws java.lang.Exception { Demo demo = new Demo(); List<String> list = demo.newArrayList(); list.add("www.bo56.com"); list.add("bo56.com"); //list.add(1); 报错。只能添加String for (String str:list) { System.out.println(str); } } }
方法的返回值前面,修饰符后面增加
没有参数的泛型方法,类型的确定,是根据等号左边的类型推导泛型的最终类型。
有参数方法定义时,使用泛型
class Demo { public <T> void showClass(T t) { System.out.println(t.getClass()); } } public class Test { public static void main (String[] args) throws java.lang.Exception { Demo demo = new Demo(); demo.showClass("123"); demo.showClass(123); } }
有参数的泛型方法,类型的确定,是根据参数类型自动推导。
方法定义时,使用通配符 ?
import java.util.ArrayList; import java.util.List; class Demo { public void show(List<?> list) { list.add(null); //list.add(123); 编译错误 for (Object object:list) { System.out.println(object); } } } public class Test { public static void main (String[] args) throws java.lang.Exception { Demo demo = new Demo(); List<String> listStr = new ArrayList<String>(); listStr.add("abc"); demo.show(listStr); List<Long> listLong = new ArrayList<Long>(); listLong.add(123L); demo.show(listLong); } }
1、只能往集合中add null。
2、因为集合中的类型不确定。因此,为了安全,转换为Object。
类或者方法定义时,使用通配符
class Demo { public <T extends Number> void showClass(T t) { System.out.println(t.getClass()); } } public class Test { public static void main (String[] args) throws java.lang.Exception { Demo demo = new Demo(); demo.showClass(123); demo.showClass(123f); demo.showClass(123L); // demo.showClass("123"); 有错误 参数的类型,只能是 Number类型或者其子类 } }
使用篇
指定固定的类型
import java.util.ArrayList; import java.util.List; public class Test { public static void main (String[] args) throws java.lang.Exception { List<Long> list = new ArrayList<Long>(); //List<Number> listN = new ArrayList<Long>(); 编译错误。List<Number> 并不是 ArrayList<Long> 的父类。 } }
如果变量声明时,为泛型指定的类型为固定类型。如List
对于泛型来说,Long是Number的子类。但是,List
使用通配符 ?
import java.util.ArrayList; import java.util.List; class Food {} class Fruit extends Food {} class Apple extends Fruit {} public class Test { public static void main (String[] args) throws java.lang.Exception { List<?> list = new ArrayList<Fruit>(); //list.add(new Food()); 编译错误 //list.add(new Fruit()); 编译错误 //list.add(new Apple()); 编译错误 list.add(null); //Food food = list.get(0); //Fruit fruit = list.get(0); //Apple apple = list.get(0); Object object = list.get(0); } }
1、只能添加null。
2、获取的值只能赋值给Object类型。
因为通配符?表示该集合存储的元素类型未知,可以是任何类型。往集合中加入元素需要是一个未知元素类型的子类型,正因为该集合存储的元素类型未知,所以我们没法向该集合中添加任何元素。唯一的例外是null,因为null是所有类型的子类型,所以尽管元素类型不知道,但是null一定是它的子类型。
使用上界通配符 extends Fruit>
import java.util.ArrayList; import java.util.List; class Food {} class Fruit extends Food {} class Apple extends Fruit {} public class Test { public static void main (String[] args) throws java.lang.Exception { List<? extends Fruit> list = new ArrayList<Fruit>(); // List<? extends Fruit> listA = new ArrayList<Food>(); 编译错误。不能为父类。 List<? extends Fruit> listN = new ArrayList<Apple>(); listN.add(null); //listN.add(123); 不能add Fruit fruit = listN.get(0); Food food = listN.get(0); //Apple apple = listN.get(0); 编译错误。get获取的值,只能给父类 listN.remove(0); } }
上界通配符,一般用于读取的场景。
1、为泛型指定的类型只能是Fruit类型或者其子类。
2、只能为其列表添加null。
3、get方法获取的值只能赋值给Fruit类或者其超类。
使用下界通配符 super Fruit>
import java.util.ArrayList; import java.util.List; class Food {} class Fruit extends Food {} class Apple extends Fruit {} public class Test { public static void main (String[] args) throws java.lang.Exception { List<? super Fruit> list = new ArrayList<Fruit>(); List<? super Fruit> listA = new ArrayList<Food>(); //List<? super Fruit> listN = new ArrayList<Apple>(); 编译错误,不能为子类 listA.add(new Fruit()); //listA.add(new Food()); 编译错误,不能为父类。 listA.add(new Apple()); Object object = listA.get(0); //Fruit fruit = listA.get(0);编译错误。 //Food food = listA.get(0);编译错误。 //Apple apple = listA.get(0); 编译错误。 } }
下界通配符,一般用于写入的场景。
1、为泛型指定的类型必须为Fruit,或者其超类。
2、可以为其列表添加任意Fruit类型,或者其子类。
3、get方法获取的类型,只能赋值给Object类型。
边界通配符总结
边界通配符总结
如果你想从一个数据类型里获取数据,使用 ? extends 通配符
如果你想把对象写入一个数据结构里,使用 ? super 通配符
如果你既想存,又想取,那就别用通配符。
注意
泛型类型是被所有调用共享的
import java.util.ArrayList; import java.util.List; public class Test { public static void main (String[] args) throws java.lang.Exception { List<String>l1 = new ArrayList<String>(); List<Integer>l2 = new ArrayList<Integer>(); System.out.println(l1.getClass() == l2.getClass()); //True } }
所有泛型类的实例都共享同一个运行时类,类型参数信息会在编译时被擦除。因此考虑如下代码,虽然ArrayList
instanceof
import java.util.ArrayList; import java.util.Collection; public class Test { public static void main (String[] args) throws java.lang.Exception { Collection cs = new ArrayList<String>(); if (cs instanceof Collection<String>){}// compile error.如果改成instanceof Collection<?>则不会出错。 } }
不能对确切的泛型类型使用instanceOf操作。如下面的操作是非法的,编译时会出错。
泛型数组问题
import java.util.ArrayList; import java.util.List; public class Test { public static void main (String[] args) throws java.lang.Exception { List<String>[] lsa = new ArrayList<String>[10]; //compile error. } }
不能创建一个确切泛型类型的数组。
import java.util.ArrayList; import java.util.List; public class Test { public static void main (String[] args) throws java.lang.Exception { List<?>[] lsa = new ArrayList<?>[10]; // ok, array of unbounded wildcard type } }
能创建带通配符的泛型数组.
参考
http://qiemengdao.iteye.com/blog/1525624
http://www.cnblogs.com/iyangyuan/archive/2013/04/09/3011274.html
技术交流
原文链接:Java泛型使用示例整理,转载请注明来源!