泛型
1.概述
1.1 概念
泛型:泛型实质就是使程序员定义安全的类型。在泛型之前,Java也提供了对Object的引用“任意化”操作,这种任意化操作就是对Object引用进行“向下转型”以及“向下转型”操作,但某些强制类型转换的错误也许不会被编译器捕捉,而在运行后出现异常,可见强制类型转换存在安全隐患,所以便有了泛型的出现。
1.2 “向上转型”与“向下转型”
如下代码:
public class Test {
//定义Object类型的成员变量
private Object obj;
//设置相应的get方法
public Object getObj() {
return obj;
}
//设置相应的set方法
public void setObj(Object obj) {
this.obj = obj;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Test test = new Test();
//向上自动转型
test.setObj(new String("12366"));
System.out.println(test.getObj());
test.setObj(new Boolean(true));
System.out.println(test.getObj());
test.setObj(new Float(65.3));
//向下强制转型
Float f = (Float)(test.getObj());
System.out.println(f);
}
}
胡志平
65.3
上例中:
Set方法均为向上转型,基本上不会出什么问题,而在Float f = (Float)(test.getObj())中很可能会出现异常,如果用错类型test.getObj的实际内容为String的话,就会出现ClassCastException异常。
“向下转型”操作容易出现异常,泛型机制有效地解决了这一问题。
2.定义泛型类
2.1 格式
类名<T>
其中T代表了一个类型的名称。
用上面的例子来表示这个泛型
//定义成泛型类
public class OverClass<T> {
//定义泛型成员变量
private T over;
//设置封装方法
public T getOver() {
return over;
}
public void setOver(T over) {
this.over = over;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
//实例化一个Boolean型对象
OverClass<Boolean>over1 = new OverClass<Boolean>();
//实例化一个Float型对象
OverClass<Float>over2 = new OverClass<Float>();
//设置over的值,不需要进行类型转换
over1.setOver(true);
over2.setOver(4125.4f);
//直接输出属性值,不需要类型转换
Boolean b = over1.getOver();
Float f = over2.getOver();
System.out.println(b);
System.out.println(f);
}
}
输出:
True
4125.4
2.2 知识点
1.在定义类时,在类名后添加了一个<T>语句,这就是泛型机制。可以将OverClass类称为泛型类,同时返回和接受的参数使用T这个类型。
2.使用泛型这种形式将不会发生ClassCastException异常,因为编译器中就可以检查类型匹配是否正确。
3.在定义泛型类时,一般将类型名称使用T来表达,而容器的元素使用使用E来表达,具体的设置。
2.3 泛型的常规用法
1.定义泛型类时,可以声明多个类型。语法如下
MutiOverClass<T1,T2>
MutiOverClass:泛型类名称
T1、T2是可能被定义的类型。这样在实例化指定类型的对象就可以指定多个类型。如,
MutiOverClass<Boolean,Float> = newMutiOverClass<Boolean,Float>();
2.定义泛型类型时声明数组类型
定义泛型时也可以声明数组类型,如下实例中定义泛型时便声明了数组类型。
public class ArrayClass<T> {
//定义泛型数组
private T[]array;
//get与set方法
public T[] getArray() {
return array;
}
public void setArray(T[] array) {
this.array = array;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
ArrayClass<String> ac = new ArrayClass<String>();
String[]array={"成员1","成员2","成员3","成员4","成员5"};
//调用set方法,将数组放进泛型中去
ac.setArray(array);
for(int i = 0 ;i < ac.getArray().length ; i ++){
//调用getArray方法循环输出数组
System.out.print(ac.getArray()[i] + " ");
}
}
}
输出:
成员1 成员2 成员3 成员4 成员5
注:可以在使用泛型机制时声明一个数组,但是不可以使用泛型来建立数组的实例如
private T [] ar = new T[10]; //无法创建T的通用数组
3.集合类声明容器的元素
可以使用K和V两个字符代表容器中的键值与键值相对应的实际值。
import java.util.HashMap;
import java.util.Map;
public class MutiOverClass<K,V> {
//定义一个集合HashMap实例
private Map<K,V> map = new HashMap<K,V>();
//设置put方法,将对应的键值与键名存入集合对象
public void put(K k , V v){
map.put(k, v);
}
public V get(K k){
//根据键名获取键值
return map.get(k);
}
public static void main(String [] args){
//实例化泛型类对象
MutiOverClass<Integer,String> mo = new MutiOverClass<Integer,String>();
for(int i = 0 ; i < 5 ; i ++){
//根据集合的长度循环将键名与具体值放入集合中
mo.put(i, "我是集合成员" + (i+1));
}
for(int i = 0 ; i < mo.map.size() ; i ++){
//调用get()方法获取集合中的值
System.out.println(mo.get(i));
}
}
}
输出:
我是集合成员1
我是集合成员2
我是集合成员3
我是集合成员4
我是集合成员5
上例中的定义泛型类属于多此一举,因为在Java中集合框架已经被泛型化了,可以直接在主方法中直接使用“public Map<K,V>map = newHashMap<K,V>()”语句创建实例。如
public static void main(String[] args) {
// TODO Auto-generated method stub
Map<Integer,String>map = new HashMap<Integer,String>();
for(int i = 0 ; i < 5 ; i ++){
map.put(i, "成员变量" + (i +1));
}
for(int i = 0 ; i < map.size() ; i ++){
System.out.println(map.get(i));
}
}
}
输出:
我是集合成员1
我是集合成员2
我是集合成员3
我是集合成员4
我是集合成员5
常用的被泛型化的集合类
如下代码演示各个集合的使用方式
public class MutiOverClass2 {
public static void main(String[] args) {
// TODO Auto-generated method stub
//定义ArrayList、Map、Vector的容器,各个窗口的值类型都是String
ArrayList<String>al = new ArrayList<String>();
Map<Integer,String>map = new HashMap<Integer,String>();
Vector <String>vector = new Vector<String>();
//为各个容器添加内容
for(int i = 0 ; i < 5 ; i ++){
al.add("ArrayList" + (i +1));
map.put(i, "Map成员变量" + (i +1));
vector.addElement("Vector成员" + (i + 1));
}
//输出容器中的内容
for(int i = 0 ; i < 5 ; i ++){
System.out.println( al.get(i) + "\t" + map.get(i) + "\t" + vector.get(i));
}
}
}
输出:
ArrayList1 Map成员变量1 Vector成员1
ArrayList2 Map成员变量2 Vector成员2
ArrayList3 Map成员变量3 Vector成员3
ArrayList4 Map成员变量4 Vector成员4
ArrayList5 Map成员变量5 Vector成员5
3.泛型的高级用法
3.1 泛型的高级用法包括限制泛型可用类型和使用类型通配符等
1.限制泛型可用类型
默认可以使用任何类型来实例化一个泛型类对象,但Java中也可对泛型实例的类型作出限制。
语法:class 类名称<T extends anyClass>
其中,anyClass是指某个接口或类
使用泛型限制后,泛型类的类型必须是实现或继承了anyClass这个接口或类。无论anyClass是接口还是类,在进行泛型限制时,都必须使用extends关键字。
如下代码:
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
//限制泛型的类型
public class LimitClass<T extends List> {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
//可以实例化已经实现List接口的类
LimitClass<ArrayList> al = new LimitClass<ArrayList>();
LimitClass<LinkedList> ll = new LimitClass<LinkedList>();
LimitClass<HashMap> hm = new LimitClass<HashMap>();
}
}
注意到可以实例化已经实现List接口的类,但是HashMap却会报如下错误
当没有使用extends关键字作限制时,默认Object类下的所有子类都可以实例化泛型类对象。所以。。。
2.使用类型通配符
在泛型机制中,提供了类型通配符,其主要作用是在创建一个泛型类对象时限制这个泛型类的类型实现或继承某个接口或类的子类。要声明这样一个对象可以使用”?”通配符来表示,同时依然使用extends关键字来对泛型加以限制。
语法格式:
泛型类型名称<? Extends List> a = null;
其中<? ExtendsList>表示类型未知,当需要使用该泛型对象时,可以单独实例化。如下
A<? extends List> a = null;
a = new A<ArrayList>();
a = new A<LinkedList>();
类型通配符也可以放在方法的参数中。如下代码
public void doSomething(A<?extends List> a){
}
在上述代码中,定义方法有效地限制了传入doSomething()方法的参数类型。
注:通配符“?”不明确的意思,可以放任意集合,但不能与类型有关的操作,如.size()、get()等与类型无关的操作倒是可以用。当然也有A<?>这种形式实例化泛型类对象,表示任意类型对象。
List<String>l1 = new ArrayList<String>();
L1.add(“成员”);
List<?>l2 = l1;
System.ut.println(i2.get(0));//获得集合中第一个值
L1.set(0,”成员变更”);没有使用通配符的对象调用set方法
L2.set(0,”成员变更”); //错误不能被调用
----------- android培训、java培训、java学习型技术博客、期待与您交流! ------------