JAVA 泛型浅谈(1)

java泛型应用是java核心基础之一,从java 5开始引进泛型。如果你曾经使用过java Collection(如List/ Map),那你已经算是接触过泛型了。


一、为什么要使用泛型?

先通过一段小程序来了解:

import java.util.ArrayList;
import java.util.List;

public class GenericTest {

    public static void main (String[] args) {
        List list = new ArrayList(); // (1)
        //List<String> list = new ArrayList<String> (); // (2) 
        list.add("xiaoming");
        list.add("xiaohong");
        list.add(100); // (3)

        System.out.println(); 
        for (int i = 0; i < list.size(); i++) {   
            String name = (String) list.get(i); // (4)
            System.out.println("#" + i + " name: " + name);
        } 
    }   
}

代码中(1) 处创建了 list 对象, 并向其添加两个字符串以及一个Integer元素.  List 里默认存储的是Object对象,因此编译可以通过.

(4)处依次取出list 中的每个元素,随后并打印.

运行结果:

#0 name: xiaoming
#1 name: xiaohong
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
 at GenericTest.main(GenericTest.java:15)

可见, 运行时,在取出第三个元素100 时,抛出类型转换错误,即把Integer 类型强制转换成String.

这是因为在(1) 处定义的List 没有限定其类型,导致 list.get(int i) 取出的元素也是Object类型,强制转换为String,忽略了 list[2] 存储的是Integer, 在运行时其也是Integer类型。

那有没有办法确保list存储的是确定的同一类型,以保证在编译阶段就可以检查,避免在运行时刻抛出类型转换异常?

答案就是使用泛型,限定list 对象所能存储的类型.

 
二、什么是泛型

泛型,即"参数化"类型.  对于泛型类,可以简单地理解为一个类中有不确定的类型,需在创建该类的对象时为其指定确定的类型.

因而,在编译阶段的时候,可以做类型检查.

类比函数中的实参(注意非形参)

同样是上面的代码,注释 (1) 处, 使用(2) 创建List 对象。 则可以发现在编译阶段(3)处会有编译错误如下:

The method add(int, String) in the type List<String> is not applicable for the arguments (int)

即你定义的是 List <String> ,  已经限定了其只能容纳String类型的元素.

在(4) 处无需再做类型转换, 可改为:  String name = list.get(i); // (4)

因此,泛型可以在提供代码复用性的同时,提供类型检查,减少了数据的类型转换,从而保证了类型安全。


三、泛型的命名规范

从上面的List <String> 已经知道泛型的语法,List<E> 则为泛型类的表示方法,用尖括号即大写字母表示。泛型的命名规范则如下:
E — Element,常用在java Collection里,如:List<E>,Iterator<E>,Set<E>
K,V — Key,Value,代表Map的键值对
N — Number,数字
T — Type,类型,如String,Integer等等
S,U,V etc. - 2nd, 3rd, 4th 类型,和T的用法一样

四、泛型的种类?

泛型,可以分为泛型类、泛型接口、泛型方法,

再通过一个简单的例子加深对泛型的理解

import java.util.ArrayList;
import java.util.List;

public class GenericTest2 {
	
	public static void main (String[] args) {
		Information<String> name = new Information<String> ("Petter");
		Information<Integer> age = new Information<Integer> (10);
		
		System.out.println( "name.getClass(): " + name.getClass());
		System.out.println( "age.getClass(): " + age.getClass());
		System.out.println( "name.getClass() == age.getClass() : " + (name.getClass() == age.getClass()));
	}

}

class Information<T> {
	private T data;
	
	public Information() {
	}
	
	public Information(T data) {
		this.data = data;
	}
	
	public T getData(){
		return data;
	}	
}

定义了一个Information 泛型类,<T> 表示其拥有 “不定”类型T,  在创建该类的对象时,需要传递确定的"类型实参", 如String、Integer等基本类型,以及自定义的类型.

其成员变量data 是T类型的,getData() 则为泛型方法, 返回的类型是T类型。

在Main 函数中创建了两个对象, 分别传递String/Integer 作为类型实参, 并传递对应类型的data 值。

然后打印两个的类名, 可以看出都为Information,  即实际上在内存中仍为同一类型。可以理解为,在逻辑上是不同的类型,因为其拥有不同类型的T.

关于泛型接口,后续再谈.






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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值