Java泛型编程是JDK1.5版本后引入的!
一.泛型的优点
(1)类型安全
通过知道使用泛型定义的变量的类型限制,编译器可以更有效地提高Java程序的类型安全。
(2)消除强制类型转换
消除源代码中的许多强制类型转换。这使得代码更加可读,并且减少了出错机会。所有的强制转换都是自动和隐式的。
(3)提高性能。
在泛型的实现中,编译器将强制类型转换插入生成的字节码中,但是更多类型信息可用于编译器这一事实,为未来版本的 JVM 的优化带来了可能。
二.泛型使用的注意事项
(1)泛型的类型参数只能是类类型(包括自定义类),不能是简单类型。
(2)泛型的类型参数可以有多个。
(3)不能对确切的泛型类型使用instanceof操作。如下面的操作是非法的,编译时会出错。
- if(ex_num instanceof FX<Number>){
- }
- List<String>[] aa = new List<String>[5]; // Not really allowed.
- Object o = aa;
- Object[] oa = (Object[]) o;
- List<Integer> li = new ArrayList<Integer>();
- li.add(new Integer(3));
- oa[1] = li; // Unsound, but passes run time store check
- String s = lsa[1].get(0); // Run-time error: ClassCastException.
这种情况下,由于JVM泛型的擦除机制,在运行时JVM是不知道泛型信息的,所以可以给oa[1]赋上一个ArrayList<Integer>而不会出现异常,但是在取出数据的时候却要做一次类型转换,所以就会出现ClassCastException,如果可以进行泛型数组的声明,上面说的这种情况在编译期将不会出现任何的警告和错误,只有在运行时才会出错。
下面采用通配符的方式是被允许的:
- List<?>[] aa= new List<?>[5]; // OK, array of unbounded wildcard type.
- Object o = aa;
- Object[] oa = (Object[]) o;
- List<Integer> li = new ArrayList<Integer>();
- li.add(new Integer(3));
- oa[1] = li; // Correct.
- Integer i = (Integer) lsa[1].get(0); // OK
三.自定义泛型
3.1 泛型类 T
import java.util.List;
/**
* 泛型类
* @author Administrator
*
* @param <T>
*/
//我们常见的如T、E、K、V等形式的参数常用于表示泛型形参,由于接收来自外部使用时候传入的类型实参。
public class Student<T> { //T代表是任意类型!
private T data; //data类型由T指定[即:由外部指定 ]
public T getData() { //返回值的类型由外部决定
return data;
}
public void setData(T data) {// 设置的类型也由外部决定
this.data = data;
}
/**
* 构造方法
* @param data
*/
public Student(T data) {
super();
this.data = data;
}
public Student() {
super();
// TODO Auto-generated constructor stub
}
}
测试类
public class TestStudent {
public static void main(String[] args) {
Student<String> stu = new Student<String>();// data类型为String类型
stu.setData("mike"); // 设置字符串
System.out.println(stu.getData().length()); // 获得字符串长度
// method_1();
// method_2();
method_3();
}
private static void method_3() {
//类型通配符
Student<String> ints = new Student<String>("QQ");
Student<Object> floats = new Student<Object>(new Date());
getData3(ints);
getData3(floats);
}
private static void method_2() {
//类型通配符
Student<Number> ints = new Student<Number>(10);
Student<Float> floats = new Student<Float>(20.5f);
getData2(ints);
getData2(floats);
}
private static void method_1() {
//类型通配符
Student<Number> ints = new Student<Number>(10);
Student<Float> floats = new Student<Float>(20.5f);
getData1(ints);
// getData1(floats); //发生异常
}
public static void getData1(Student<Number> data) {//只能接收Number
System.out.println("data :" + data.getData());
}
public static void getData2(Student<? extends Number> data) {//只能接收Number及其Number的子类
System.out.println("data :" + data.getData());
}
public static void getData3(Student<? super String> data) {// 只能接收String或Object类型的泛型
System.out.println("data :" + data.getData());
}
}
注意:<T extends Number> 表示 T 只接受 Number 及其子类,传入其他类型的数据会报错。这里的限定使用关键字 extends,后面可以是类也可以是接口。但这里的 extends 已经不是继承的含义了,应该理解为 T 是继承自 Number 类的类型,或者 T 是实现了 XX 接口的类型。
3.2 泛型类 <K,V>/**
* 泛型类
* @author Administrator
*
* @param <K>
* @param <V>
*/
public class City<K, V> { //指定了两个泛型类型
private K key; //key类型由外部决定
private V value; //value类型由外部决定
public K getKey() {
return key;
}
public void setKey(K key) {
this.key = key;
}
public V getValue() {
return value;
}
public void setValue(V value) {
this.value = value;
}
public City(K key, V value) {
super();
this.key = key;
this.value = value;
}
public City() {
super();
// TODO Auto-generated constructor stub
}
}
测试类
public static void main(String[] args) {
// key-value
City<String, Integer> city = new City<String, Integer>("John", 20);
System.out.println(city.getKey() + ":" + city.getValue());
}
3.3 泛型接口
/**
* 泛型接口
*
* @author Administrator
*
* @param <T>
*/
public interface Animal<T> {
T eat(); // 抽象方法返回值就是泛型类型
}
/**
* 定义泛型接口的子类
*
* @author Administrator
*
* @param <T>
*/
class Cat<T> implements Animal<T> {
private T property; // 定义属性
public T getProperty() {
return property;
}
public void setProperty(T property) {
this.property = property;
}
/**
* 通过构造方法设置属性内容
* @param property
*/
public Cat(T property) {
super();
this.property = property;
}
/**
* 重写这个方法
*/
@Override
public T eat() {
// TODO Auto-generated method stub
return this.property;
}
}
测试类
public static void main(String[] args) {
Cat<String> cat = new Cat<String>("加菲猫");
System.out.println(cat.eat() + "~~~吃鱼!");
}
3.4 泛型方法
/**
* 泛型方法
*
* @author Administrator
*
*/
public class Bear {
public <T> T get(T t) { // 可以接收任意类型的数据
return t;
}
public static void main(String[] args) {
Bear bear = new Bear();
//T :接收任意类型的数据
System.out.println(bear.get("大白熊")); //字符串
System.out.println(bear.get(100.56)); //浮点型
System.out.println(bear.get(true)); //布尔型
}
}
3.5 泛型数组
public static void main(String[] args) {
// 声明数组
Integer arr[] = add1(11, 22, 33, 44, 55);
add2(arr);
}
public static <T> T[] add1(T... arg) { // 接收可变参数
return arg; // 返回泛型数组
}
public static <T> void add2(T...arg) { // 接收可变参数
System.out.print("接收泛型数组:");
for (T t : arg) {
System.out.print(t + "\t");
}
System.out.println();
}