为什么要使用泛型?
@Test
public void test1(){
List list = new ArrayList();
list.add(123);
list.add(456);
list.add(789);
list.add("AA");
Iterator it = list.listIterator();
while(it.hasNext()){
int num = (Integer)it.next();
System.out.println(num);
}
}
结果会有异常
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
at com.wya.j2se.fanxing.TestDemo.test1(TestDemo.java:17)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
类转型异常,因为List实例化时没有限定是哪种类型的,所以默认是Object,我们可以add任意类型的元素,但是当我们想把元素按数字类型输出时就会出现类转型异常,这时就需要泛型了。
泛型的作用:
1. 解决元素存储的安全性问题,只有指定类型才可以添加到集合中:类型安全
2. 解决获取数据元素时,不需要强制类型转换。
如何使用泛型?
interfaceList<T> 和classTestGen<K,V>
其中,T,K,V不代表值,而是表示类型。这里使用任意字母都可以。常用T表示,是Type的缩写。T只能是引用类型,不能使用基本类型。
2.泛型的实例化
List<String> strList = new ArrayList<String>();
3.自定义泛型类
public class Order<T> {
private Integer id;
private String sn;
private T t;
public Order() {
super();
// TODO Auto-generated constructor stub
}
public Order(Integer id, String sn, T t) {
super();
this.id = id;
this.sn = sn;
this.t = t;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getSn() {
return sn;
}
public void setSn(String sn) {
this.sn = sn;
}
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
}
@Test
public void test2(){
//实例化对象时指定了泛型为String类型,则Order类里所有的泛型都是String类型
//如果没有指定泛型类型,默认是Object类型
Order<String> order = new Order<String>();
order.setId(1);
order.setSn("sn123456");
order.setT("订单1");//这里就变成了String类型
}
如果定义泛型类时这么表示
public class Order<T extends Number> {
...
}
则表示泛型T必须是Number的子类,所以像String类型就不允许传进来了。
4.泛型方法
泛型方法的格式:
[访问权限] <泛型> 返回类型 方法名([泛型标识 参数名称]) 抛出的异常
public class Order<T> {
private Integer id;
private String sn;
private T t;
public Order() {
super();
// TODO Auto-generated constructor stub
}
public Order(Integer id, String sn, T t) {
super();
this.id = id;
this.sn = sn;
this.t = t;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getSn() {
return sn;
}
public void setSn(String sn) {
this.sn = sn;
}
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
/*
* 定义一个泛型方法
*/
public <E> E getE(E e){
return e;
}
}
@Test
public void test3(){
Order<String> order = new Order<String>();
//参数指定是Double类型的,所以返回值自动变成Double类型
Double value = order.getE(1.234);
System.out.println(value);//1.234
}
泛型和继承的关系
如果B是A的一个子类型(子类或者子接口),而G是具有泛型声明的类或接口,G<B>并不是G<A>的子类型!
比如:String是Object的子类,但是List<String>并不是List<Object>的子类。
@Test
public void test4(){
List<Object> list1 = null;
List<String> list2 = new ArrayList<String>();
//不能把list2赋给list1,编译错误
list1 = list2;
}
如果想可以实现把带泛型的List赋给别人,可以使用通配符?
@Test
public void test5(){
List<?> list1= null;
List<Object> list2 = new ArrayList<Object>();
List<String> list3 = new ArrayList<String>();
list1 = list2;
list1 = list3;
}
注意两点:
①读取List<?>的对象list中的元素时,永远是安全的,因为不管list的真实类型是什么,它包含的都是Object。
②写入list<?>中的元素时,不行。因为我们不知道?的元素类型,我们不能向其中添加对象。唯一的例外是null,它是所有类型的成员。
所以我们只能读取具有通配符的对象数据,不能写入。
有限制的通配符
<?>允许所有泛型的引用调用
举例:
<?extends Number> (无穷小 , Number]
只允许泛型为Number及Number子类的引用调用
<? super Number> [Number , 无穷大)
只允许泛型为Number及Number父类的引用调用
<? extends Comparable>
只允许泛型为实现Comparable接口的实现类的引用调用
@Test
public void test6(){
List<? extends Number> list1= null;
List<Integer> list2 = new ArrayList<Integer>();
List<String> list3 = new ArrayList<String>();
list1 = list2;
//编译错误String不是Number的子类
list1 = list3;
}
泛型注意事项
1.静态方法中不能使用类的泛型。
2.如果泛型类是一个接口或抽象类,则不可创建泛型类的对象。
3.不能在catch中使用泛型
4.从泛型类派生子类,泛型类型需具体化