您的位置:首页 > 编程语言 > Java开发

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

2016-11-26 00:06 405 查看
今天学习的内容是泛型

一、泛型的意义

泛型意味着“类型安全”,它实现了参数化类型的概念。实际上泛型就是将运行时可能发生的问题放到编译期解决。比如:在泛型出现之前,任意类型的引用都可以存储进集合,并被向上转型为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) {
}

}


三、泛型与集合

b4bd

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

修饰符 <T> 返回值类型 方法名(Collection<T> c){} 或者修饰符 <T extends X> 返回值类型 方法名(Collection<T> c){}
方法名(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;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: