Java泛型

为什么要使用泛型?

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

如何使用泛型?

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;
	}
	
}
@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
		
	}

泛型和继承的关系

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

比如:StringObject的子类,但是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.从泛型类派生子类,泛型类型需具体化




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值