学习笔记之JavaSE(38)--泛型

今天学习的内容是泛型


一、泛型的意义

泛型意味着“类型安全”,它实现了参数化类型的概念。实际上泛型就是将运行时可能发生的问题放到编译期解决。比如:在泛型出现之前,任意类型的引用都可以存储进集合,并被向上转型为Object类型,取出的引用仍旧是Object类型,如果想要操作它就必须对其进行强制类型转换,这就存在了安全隐患!这是由于集合中可能存在不同类型的引用,强制转换就可能会发生ClassCastException。但如果使用泛型,编译器就知道集合中存储的一定是泛型类型或其子类/实现类的引用(多态与泛型并不冲突),并被向上转型为泛型类型,取出的一定是该泛型类型的引用,这时候就不用再对其进行强制类型转换,解决了类型安全问题。其实这么做就相当于将类型参数化:此集合只存储此类型或其子类/实现类的引用,不接收其他类型的引用。程序示例:

public class Test70 {

	@SuppressWarnings({ "rawtypes", "unchecked" })
	public static void main(String[] args) {

		// 不使用泛型,会有安全隐患
		ArrayList list_1 = new ArrayList();
		list_1.add("a");// String类型的对象
		list_1.add(1);// Integer类型的对象
		Iterator it_1 = list_1.iterator();
		while (it_1.hasNext()) {
			try {
				String str = (String) it_1.next();// ClassCastException
				System.out.println(str);
			} catch (ClassCastException e) {
				e.printStackTrace();
			}
		}

		// 如果使用泛型,可以避免安全隐患
		ArrayList<String> list_2 = new ArrayList<>();
		list_2.add("a");
		// !list_2.add(1);
		Iterator<String> it_2 = list_2.iterator();
		while(it_2.hasNext()){
			String str = it_2.next();
			System.out.println(str);
		}
	}
}

注意:编译器生成的字节码文件中是不带有泛型的,这个称为泛型的擦除,这么做的目的主要是为了兼容JDK1.4的类加载器。相应的,JVM在运行时可以通过获取元素的类型,自动进行类型转换动作,这成为泛型的补偿


二、自定义泛型

泛型使用最多的就是在集合类中,不过我们也可以自定义泛型。比如当类中要操作的引用类型不确定时,可以自定义泛型类;当方法中要操作的引用的类型不确定时,可以自定义泛型方法;除此之外,也可以自定义泛型接口。示例程序:

public class Test72 {

	public static void main(String[] args) {

		// 使用自定义泛型类
		Tool<String> tool_str = new Tool<>();
		Tool<Integer> tool_int = new Tool<>();
		tool_str.setTool("a");
		tool_int.setTool(1);
		tool_str.print("b");// b
		// ! tool_str.print(2); 如果方法使用的是类定义的泛型,必须按照类定义的泛型传参
		tool_int.print(2);// 2
		// ! tool_int.print("b"); 如果方法使用的是类定义的泛型,必须按照类定义的泛型传参
		System.out.println(tool_str.getTool());// a
		System.out.println(tool_int.getTool());// 1

		// 使用自定义泛型方法,可以传入任何参数
		tool_str.myPrint("a");// a
		tool_str.myPrint(1);// 1
		tool_int.myPrint("a");// a
		tool_int.myPrint(1);// 1
		Tool.myShow("a");// a
		Tool.myShow(1);// 1
	}
}

// 自定义泛型类,使用场景:当类中要操作的引用的类型不确定时
class Tool<T> {

	private T tool;

	public T getTool() {
		return tool;
	}

	public void setTool(T tool) {
		this.tool = tool;
	}

	public void print(T tool) {
		System.out.println(tool);
	}

	// 自定义泛型方法,使用场景:当方法中要操作的引用的类型不确定时
	public <E> void myPrint(E e) {
		System.out.println(e);
	}

	// 注意静态方法只能自定义泛型,不能使用类定义的泛型
	public static <E> void myShow(E a) {
		System.out.println(a);
	}
}

//自定义泛型接口
interface Inter<T>{
	void show(T t);
	<E> void myShow(E e);
}

class InterImpl_1 implements Inter<String>{

	@Override
	public void show(String t) {
	}

	@Override
	public <E> void myShow(E e) {
	}
}

class Interimpl_2<T> implements Inter<T>{

	@Override
	public void show(T t) {
	}

	@Override
	public <E> void myShow(E e) {
	}
	
}

三、泛型与集合

之前学习多态时,我们知道泛型参数不支持多态,也就是List<Fu> list = new ArrayList<Zi>();是不被允许的;同理,如果方法的参数是List<Fu>类型,ArrayList<Zi>也不能作为参数传入方法。这主要是出于安全考虑,因为在方法内部有可能把另一个子类参数的引用存储进集合,这就会出现错误!这种问题的解决方法有两种:

  1. 修饰符 <T> 返回值类型 方法名(Collection<T> c){} 或者修饰符 <T extends X> 返回值类型 方法名(Collection<T> c){}
  2. 方法名(Collection<?> c){} 、方法名(Collection<? extends X> c){}或方法名(Collection<? super X> c){}
这两种方法功能相同,但通常使用第二种方法,因为这种方法不仅书写简便,而且一目了然。其中<? extends X>和<T extends X>叫做向上限定,也就是传进方法的只能是存储该类型或其子类/实现类的集合;而<? super X>叫做向下限定,也就是传进方法的只能是存储该类型或其父类的集合那么这两种方法到底是如何解决问题的呢?答案是当方法带有<T>或<?>声明时, 只能对 传入的集合进行获取和删除操作,不能对其进行添加和修改。示例程序:
public class Test71 {

	public static void main(String[] args) {
		// 泛型基本用法,使用String类集合
		ArrayList<String> al_1 = new ArrayList<>();
		al_1.add("a");
		al_1.add("s");
		al_1.add("fd");
		al_1.add("gsd");
		System.out.println("--------------泛型基本用法,使用String类集合----------------");
		printCollection_1(al_1);
		printCollection_2(al_1);
		// !printCollection_3(al_1);
		// !printCollection_4(al_1);
		// !printCollection_5(al_1);
		//!printCollection_6(al_1);

		// 泛型基本用法,使用Person类集合
		TreeSet<Person> ts = new TreeSet<>();// 也可以使用比较器排序
		ts.add(new Person("sf", 27));
		ts.add(new Person("fab", 21));
		ts.add(new Person("xc", 24));
		ts.add(new Person("popo", 23));
		System.out.println("\n\n--------------泛型基本用法,使用Person类集合----------------");
		printCollection_1(ts);
		printCollection_2(ts);
		printCollection_3(ts);
		printCollection_4(ts);
		printCollection_5(ts);
		printCollection_6(ts);

		// 向上限定的用法
		ArrayList<Student> al_2 = new ArrayList<>();
		al_2.add(new Student("a", 13));
		al_2.add(new Student("asfda", 12));
		al_2.add(new Student("asdf", 13));
		al_2.add(new Student("fda", 11));
		System.out.println("\n\n--------------向上限定的用法----------------");
		printCollection_1(al_2);
		printCollection_2(al_2);
		// !printCollection_3(al_2);
		printCollection_4(al_2);
		printCollection_5(al_2);
		//!printCollection_6(al_2);

		// 向下限定的用法
		ArrayList<Organism> al_3 = new ArrayList<>();
		al_3.add(new Organism());
		al_3.add(new Organism());
		al_3.add(new Organism());
		al_3.add(new Organism());
		System.out.println("\n\n--------------向下限定的用法----------------");
		printCollection_1(al_3);
		printCollection_2(al_3);
		//!printCollection_3(al_3);
		//!printCollection_4(al_3);
		//!printCollection_5(al_3);
		printCollection_6(al_3);
	}

	// 使用自定义泛型(可以接收存储任何对象的集合)
	public static <T> void printCollection_1(Collection<T> ts) {
		System.out.println("使用自定义泛型:");
		// !ts.add(new Worker("k", 12));
		//ts.clear();只能获取或删除,不能添加
		Iterator<T> it = ts.iterator();
		while (it.hasNext()) {
			T t = it.next();
			System.out.print(t);
		}
	}

	// 使用类型通配符(可以接收存储任何对象的集合)
	public static void printCollection_2(Collection<?> ts) {
		System.out.println("\n使用类型通配符:");
		// !ts.add(new Worker("k", 12));
		//ts.clear();只能获取或删除,不能添加
		Iterator<?> it = ts.iterator();
		while (it.hasNext()) {
			System.out.print(it.next());
		}
	}

	// 使用确定类型(只能接收存储Person对象的集合)
	public static void printCollection_3(Collection<Person> ts) {
		System.out.println("\n使用确定泛型:");
		ts.add(new Worker("k", 12));// 如果能传入Student的集合,这里就会出现错误的!所以编译不会通过!
		Iterator<Person> it = ts.iterator();
		while (it.hasNext()) {
			Person p = it.next();
			System.out.print(p);
		}
	}

	// 向上限定,使用自定义泛型(只能接收存储Person对象、Person子类对象或Person实现类的集合)
	public static <T extends Person> void printCollection_4(Collection<T> ts) {
		System.out.println("\n向上限定,使用自定义泛型:");
		// !ts.add(new Worker("k", 12));
		//ts.clear();只能获取或删除,不能添加
		Iterator<T> it = ts.iterator();
		while (it.hasNext()) {
			Person p = it.next();
			System.out.print(p);
		}
	}

	// 向上限定,使用类型通配符(只能接收存储Person对象、Person子类对象或Person实现类对象的集合)
	public static void printCollection_5(Collection<? extends Person> ts) {
		System.out.println("\n向上限定,使用类型通配符:");
		// !ts.add(new Worker("k", 12));
		//ts.clear();只能获取或删除,不能添加
		Iterator<? extends Person> it = ts.iterator();
		while (it.hasNext()) {
			Person p = it.next();
			System.out.print(p);
		}
	}
	
	// 向下限定,不能使用自定义泛型

	// 向下限定,使用类型通配符(只能接收存储Person对象或Person父类对象的集合)
	public static void printCollection_6(Collection<? super Person> ts) {
		System.out.println("\n向下限定,使用类型通配符:");
		// !ts.add(new Worker("k", 12));
		//ts.clear();只能获取或删除,不能添加
		Iterator<? super Person> it = ts.iterator();
		while (it.hasNext()) {
			System.out.print(it.next());
		}
	}
}

class Organism{

	@Override
	public String toString() {
		return "Organism []";
	}
	
}

class Person extends Organism implements Comparable<Person> {

	private String name;
	private int age;

	public Person() {
		super();
	}

	public Person(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + age;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Person other = (Person) obj;
		if (age != other.age)
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}

	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + "]";
	}

	@Override
	public int compareTo(Person o) {
		int temp = this.age - o.age;
		return temp == 0 ? this.name.compareTo(o.name) : temp;
	}

}

class Student extends Person {

	public Student() {
		super();
	}

	public Student(String name, int age) {
		super(name, age);
	}

	@Override
	public String toString() {
		return "Student [name=" + getName() + ", age=" + getAge() + "]";
	}

}

class Worker extends Person {

	public Worker() {
		super();
	}

	public Worker(String name, int age) {
		super(name, age);
	}
}

// 比较器
class ComparatorByName implements Comparator<Person> {

	@Override
	public int compare(Person o1, Person o2) {

		int temp = o1.getName().compareTo(o2.getName());
		return temp == 0 ? o1.getAge() - o2.getAge() : temp;
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值