Java泛型

来源:互联网 发布:ubuntu双系统安装 编辑:程序博客网 时间:2024/06/03 13:06

为什么要使用泛型?

先来看一段代码
@Testpublic 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.Integerat 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. 解决获取数据元素时,不需要强制类型转换。

如何使用泛型?

1.泛型的声明

    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;}}
@Testpublic 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;}}
@Testpublic void test3(){Order<String> order = new Order<String>();//参数指定是Double类型的,所以返回值自动变成Double类型Double value = order.getE(1.234);System.out.println(value);//1.234}

泛型和继承的关系

如果BA的一个子类型(子类或者子接口),而G是具有泛型声明的类或接口,G<B>并不是G<A>的子类型!

比如:StringObject的子类,但是List<String>并不是List<Object>的子类。


@Testpublic void test4(){List<Object> list1 = null;List<String> list2 = new ArrayList<String>();//不能把list2赋给list1,编译错误list1 = list2;}

如果想可以实现把带泛型的List赋给别人,可以使用通配符?
@Testpublic 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接口的实现类的引用调用

@Testpublic 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.从泛型类派生子类,泛型类型需具体化




原创粉丝点击