循序渐进理解泛型的通配符

一 泛型方法的应用

1 代码示例

import java.util.Vector;

public class RandomGenerObject {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		Vector<Integer> v = new Vector<Integer>();
		Vector<Object> v1 = new Vector<Object>();
		//radomMeth(v);             //a处代码
		radomMeth(v1);

	}

	public static void radomMeth(Vector<Object> vector) {
		vector.add("cjg"); //b处代码
		vector.add(156);   //c处代码
		for (Object obj : vector) {
			System.out.println(obj);
		}
	}

}

2 运行结果

cjg
156

3 代码解析

  • 在radomMeth()方法中,对于Vector<Object>泛型,实现了可以向该参数中添加任意类型的对象,例如b处代码和c处代码,这是因为任何对象的基类都是Object类型,所以任何类型的对象都可以自动转换成Object类型。
  • 在具体调用radomMeth()方法时,只要传入的参数为Object类型泛型对象,才会正确运行。如果是其他类型的泛型对象,则会编译出错。这是因为参数化类型无继承性特性。如果把a处代码的注释去掉,就会提示编译出错。

二 泛型通配符的应用

1 代码示例

import java.util.Vector;

public class RandomGener {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		Vector<Integer> v = new Vector<Integer>();
		v.add(1);
		v.add(2);
		radomMeth(v);
		
		Vector<Object> v1 = new Vector<Object>();
		v1.add("aa");
		v1.add(2.2);
		radomMeth(v1);
	}

	public static void radomMeth(Vector<?> vector) {
		// vector.add("1");      //a处代码
		System.out.println("输出" + vector + "各个成员----------");
		for (Object obj : vector) {
			System.out.println(obj);
		}
		System.out.println("对象的大小" + vector.size());
	}

}

2 运行结果

输出[1, 2]各个成员----------
1
2
对象的大小2
输出[aa, 2.2]各个成员----------
aa
2.2
对象的大小2

3 代码解析

  • 在radomMeth()方法中,通过“?”标识实现接受任何类型参数的方法,即在具体调用该方法时,传入的对象可以是任意类型,例如Integer类型的对象v和Object类型的对象v1。
  • 在radomMeth()方法中,虽然可以接受任意类型的参数,但是具体接受什么类型只有在具体调用方法时才能确定。因此在调用a处代码时,会编译报错。可是如果调用与参数类型无关的方法size(),则不会编译报错。

三 通配符的上限和下限的应用

1 代码示例

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

public class IntegrationGener {

	public static void main(String[] args) {
		List<Number> listNums = new ArrayList<Number>();
		listNums.add(1);
		listNums.add(1.23);

		List<Integer> listInteger = new ArrayList<Integer>();
		List<? extends Number> listNums2 = listInteger;
		List<? super Integer> listNums3 = listInteger;
		listNums3.add(7);
		listNums3.add(null);
		System.out.println("listNums3中的元素" + listNums3.get(0));
		System.out.println("listNums3中的元素个数" + listNums3.size());
		System.out.println("listNums2中的元素" + listNums2.get(0));
		System.out.println("listNums2中的元素个数" + listNums2.size());
		listNums3.add(null);
		System.out.println("listNums3中的元素个数" + listNums3.size());
		System.out.println("listNums2中的元素个数" + listNums2.size());
		
		List<Number> listNums1 = new ArrayList<Number>();
		List<? super Integer> listNums4 = listNums1;
		listNums4.add(6);
	}
}

2 运行结果

listNums3中的元素7
listNums3中的元素个数2
listNums2中的元素7
listNums2中的元素个数2
listNums3中的元素个数3
listNums2中的元素个数3

3 代码解析

  • 为了解决泛型参数类型无继承性,出现了extends和super标识符号。List<? extends Number> listNums2表示listNums2对象可以被Number类型的任何子类型对象(List<Integer> listInteger)赋值。List<? super Integer> listNums3表示listNums3对象可以被Integer类型的任何父类(listNums1)或Interger类型对象(listInteger)赋值。
  • 一条比较通用的原则是,如果要向列表中添加元素则用<? super T>,如果要从列表中获取元素则用<? extends T>,如果既要获取又要添加则不使用通配符。
一 泛型方法的应用 1 代码示例
import java.util.Vector;

public class RandomGenerObject {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		Vector<Integer> v = new Vector<Integer>();
		Vector<Object> v1 = new Vector<Object>();
		//radomMeth(v);             //a处代码
		radomMeth(v1);

	}

	public static void radomMeth(Vector<Object> vector) {
		vector.add("cjg"); //b处代码
		vector.add(156);   //c处代码
		for (Object obj : vector) {
			System.out.println(obj);
		}
	}

}
2 运行结果 cjg
156 3 代码解析
  • 在radomMeth()方法中,对于Vector<Object>泛型,实现了可以向该参数中添加任意类型的对象,例如b处代码和c处代码,这是因为任何对象的基类都是Object类型,所以任何类型的对象都可以自动转换成Object类型。
  • 在具体调用radomMeth()方法时,只要传入的参数为Object类型泛型对象,才会正确运行。如果是其他类型的泛型对象,则会编译出错。这是因为参数化类型无继承性特性。如果把a处代码的注释去掉,就会提示编译出错。

猜你喜欢

转载自cakin24.iteye.com/blog/2324638