泛型

2017-11-27  本文已影响0人  咸鱼有梦想呀

1.泛型(generic)
泛型:可以按类型进行参数化的类。

2.泛型的好处

情况演示

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

有类型后情况演示

3.<>使用情况
在操作的引用数据类型不确定的时候。
将要操作引用的数据类型放在<>中就可以。

<>就是一个用于接收具体引用数据类型的参数范围。

在程序中,只要用到了带有<>的类或者接口,就要明确传入的具体引用数据类型。

<E>

<E>E就是类型变量,类或者是接口。

4.泛型的擦除和补偿

补偿演示

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;
    }
}
运行结果

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

上一篇 下一篇

猜你喜欢

热点阅读