1.泛型(generic)
泛型:可以按类型进行参数化的类。
2.泛型的好处
- 将运行时期的问题ClassCastException转到了编译时期。
也就是

但如果控制了类型,在运行时期就可以发现问题

-
避免了强制转换的麻烦。
-
提高了编译的安全性。
3.<>使用情况
在操作的引用数据类型不确定的时候。
将要操作引用的数据类型放在<>中就可以。
<>就是一个用于接收具体引用数据类型的参数范围。
在程序中,只要用到了带有<>的类或者接口,就要明确传入的具体引用数据类型。

<E>E就是类型变量,类或者是接口。
4.泛型的擦除和补偿
-
擦除:
泛型技术是给编译器使用的技术,用于编译时期。确保了类型的安全。
运行时,会将泛型去掉,生成的class文件中是不带泛型的,这个就称为泛型的擦除。
擦除的意义在于,为了兼容运行的类加载器。 -
补偿:
在运行时,通过获取元素的类型进行转换动作,不用使用者再进行强制转换。

5.泛型类
使用泛型来接收类中要操作的引用数据类型。
泛型类可以自定义,当类中的操作的引用数据类型不确定的时候,就使用泛型来表示。
举个栗子,来说明泛型的作用
首先先建一个Student类,和Worker类,以及一个Tool类,再在另个类中用Tool调用。
Student类代码:
public class Student extends Person {
public Student() {
super();
}
public Student(String name, int age) {
super(name, age);
}
}
Worker类代码:
public class Worker extends Person {
public Worker() {
super();
}
public Worker(String name, int age) {
super(name, age);
}
}
没有泛型之前,如果想操作所有类,就要找所有类的共性
因此,Tool类的代码就要用Object:
public class Tool {
private Object object;
public Object getObject() {
return object;
}
public void setObject(Object object) {
this.object = object;
}
}
另外一个类里用Tool调用
GenericDemo2代码:
import admin.Student;
import admin.Tool;
public class GenericDemo2 {
public static void main(String[] args) {
Tool tool = new Tool();
tool.setObject(new Student());
Student stu = (Student)tool.getObject();//强转
}
}
上面这个是可以运行的,但是——接着看:
当调用Worker类的时候,编译环境不报错,但是运行却报错,因为Worker不能强转为Student类。

但是如果将Tool类,用泛型自定义,这样的错误就会在编译环境显示出来。
泛型类的Tool类代码:
public class Tool<QQ>{
private QQ q;
public QQ getQ() {
return q;
}
public void setQ(QQ q) {
this.q = q;
}
}
用自定义泛型类调试GenericDemo2:


由此可见,泛型类可以将运行时期会出现的问题转到编译时期。
除此之外还避免了强转的麻烦。泛型类和Object相比较更为安全。
6.泛型方法
将泛型定义到方法上。
当方法静态时,不能访问类上定义的泛型,因为静态是不需要对象的,但是泛型需要对象来明确。
如果静态方法想使用泛型,只能将泛型定义在方法上。
还是延续上一个的栗子
在Tool类中再加几个方法,代码如下:
//泛型自定义到方法上,就会自动找类型匹配。
public <W> void show(W str){
System.out.println("show :"+str.toString());
}
//和对象一样的泛型
public void print(QQ str){
System.out.println("print :"+str);
}
//静态方法想使用泛型,要将泛型定义到方法上。
public static <Y> void method(Y q){
System.out.println("method :"+q);
}
用自定义泛型方法调试GenericDemo3:
import admin.Tool;
public class GenericDemo3 {
public static void main(String[] args) {
Tool<String> tool = new Tool<String>();
//show方法可以打印任意类型
//因为在show方法上自定义了泛型
tool.show(new Integer(4));
tool.show("abca");
//print方法只能打印字符串
//因为print的泛型是跟着对象走的
tool.print("asdf");
//调用静态方法
Tool.method("haha");
Tool.method(new Integer(9));
}
}

使用了泛型,就说明对象不确定,不能使用具体哪个对象的方法,但是具备Object的方法。
7.泛型接口
将泛型定义在接口上。
代码说明:
interface Inter<T>{
public void show(T t);
}
class InterImp1 implements Inter<String>{
public void show(String str){
System.out.println("show :"+str);
}
}
class InterImp2 <A> implements Inter<A>{
public void show(A a){
System.out.println("show :"+a);
}
}
public class GenericDemo4 {
public static void main(String[] args) {
InterImp1 in = new InterImp1();
in.show("abc");
InterImp2 on = new InterImp2();
on.show(new Integer(4));
on.show("abc");
on.show(2);
}
}

8.泛型的通配符
通通都匹配的符号——未知类型?
代码说明:
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class GenericadvanceDemo {
public static void main(String[] args) {
ArrayList<String> a1 = new ArrayList<String>();
a1.add("abc");
a1.add("sdcf");
ArrayList<Integer> a2 = new ArrayList<Integer>();
a2.add(2);
a2.add(56);
printCollection(a1);
printCollection(a2);
}
//迭代并打印集合中元素
public static void printCollection(Collection<?> a){
Iterator<?> it = a.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
}

9.泛型限定
对类型的限定
- 泛型的上限
? extends E
E:接收E类型或者E的子类型对象
举个栗子:
代码:
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import admin.Person;
import admin.Student;
import admin.Worker;
public class GenericadvanceDemo {
public static void main(String[] args) {
ArrayList<Student> a1 = new ArrayList<Student>();
a1.add(new Student("lisi",22));
a1.add(new Student("zhangsan",21));
ArrayList<Worker> a2 = new ArrayList<Worker>();
a2.add(new Worker("wangwu",33));
a2.add(new Worker("gongtou",21));
printCollection(a1);
printCollection(a2);
}
//迭代并打印集合中元素
public static void printCollection(Collection<? extends Person> a){
Iterator<? extends Person> it = a.iterator();
while(it.hasNext()){
System.out.println(it.next().toString());
}
}
}

但是,如果不是Person的子类型就会在编译时报错

- 泛型的下限
? super E
E:接收E类型或者E的父类型对象
举个栗子:
代码:
import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;
import admin.Person;
public class GenericadvanceDemo2 {
public static void main(String[] args) {
TreeSet<Person> a1 = new TreeSet<Person>(new CompByName());
a1.add(new Person("p1",22));
a1.add(new Person("p3",25));
a1.add(new Person("acds",20));
Iterator<Person> it = a1.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
}
class CompByName implements Comparator<Person>{
@Override
public int compare(Person arg0, Person arg1) {
int temp = arg0.getName().compareTo(arg1.getName());
return temp==0? arg0.getAge()-arg1.getAge():temp;
}
}

上限下限的选择
上限:一般在存储元素的时候都是用上限,因为这样取出都是按照上限类型来运算的,不会出现类型安全隐患。
下限:通常对集合中的元素进行取出操作时,可以使用下限。
网友评论