Skip to content

Latest commit

 

History

History
376 lines (255 loc) · 7.62 KB

11. Genericity.md

File metadata and controls

376 lines (255 loc) · 7.62 KB

11. Genericity

1. 概念

参数化类型,使用广泛的类型

==使用泛型的原因==:数据类型不明确;装入数据的类型都被当成Object对待,从而丢失实际类型;获取数据时往往需要转型,效率低,且容易产生错误;

==使用泛型的作用==:安全:编译时检查类型安全;

​ 省心:所有的转换都是自动 和隐式的,提高代码重用率;

==泛型不能使用在静态方法和属性上==: 自定义泛型是在使用时确定类型,静态的是在编译时确定类型,冲突

不使用泛型时的代码(繁琐):

1.Student

package com.alexanderli95.gen;

/**
 * Object可以储存任何类型,发生多态
 */
public class Student {
    private Object javase;
    private Object mysql;

    public Student(Object javase, Object mysql) {
        this.javase = javase;
        this.mysql = mysql;
    }

    public Student() {
    }

    public Object getJavase() {
        return javase;
    }

    public void setJavase(Object javase) {
        this.javase = javase;
    }

    public Object getMysql() {
        return mysql;
    }

    public void setMysql(Object mysql) {
        this.mysql = mysql;
    }
}

2,App

package com.alexanderli95.gen;

public class App {
    public static void main(String[] args) {
        // 存整数, int->Integer->Object , 自动装箱
        Student stu=new Student(80,90);

        //Object->Integer->int , 自动拆箱
        int javaseScore=(int )stu.getJavase();
        System.out.println(javaseScore);

        String mysqlScore=null;
        if(stu.getMysql() instanceof String){    //手动类型检查,避免java.lang.ClassCastException
            mysqlScore=(String)stu.getMysql();
            System.out.println(mysqlScore);
        }
    }
}

2. 泛型使用

==常见字母==:

T:Type类型; K V:Key Value,键值;E:Element;?:不确定类型

==不能使用在静态属性,静态方法上==

==使用时不能指定基本数据类型(使用引用类型)==

使用时才确定具体类型

接口中泛型字母只能使用在方法中,不能使用在全局常量中

eg:

package com.alexanderli95.gen02;

public class Student<T1,T2> {  //定义
    private T1 javaseScore;
    private T2 mysqlScore;

    public Student(T1 javaseScore, T2 mysqlScore) {
        this.javaseScore = javaseScore;
        this.mysqlScore = mysqlScore;
    }

    public Student() {
    }

    public T1 getJavaseScore() {
        return javaseScore;
    }

    public void setJavaseScore(T1 javaseScore) {
        this.javaseScore = javaseScore;
    }

    public T2 getMysqlScore() {
        return mysqlScore;
    }

    public void setMysqlScore(T2 mysqlScore) {
        this.mysqlScore = mysqlScore;
    }

    public static void main(String[] args) {
        Student<Integer,String> stu=new Student<Integer, String>(80,"90");  //使用时确定类型
    }
}
package com.alexanderli95.gen02;

public interface Comparator <T> {
    Integer a=0; //T a=0; 报错
    public T b();
}

3. 泛型方法

==定义==:

修饰符<字母> 返回类型 方法名(字母){...}

泛型可以定义在方法中,是否拥有泛型方法与其所在的类是否是泛型类没有关系

package com.alexanderli95.gen02;

import java.io.Closeable;
import java.io.IOException;

public class TestMethod {
    public static void main(String[] args) {
        test("a");  //T->String
    }

    public static <T> void test(T t){  //泛型方法定义
        System.out.println(t);
    }

    // extends在这里表示小于等于后面的类型,T只能是Closeable的实现类
    public static <T extends Closeable> void test(T... t){  //泛型方法定义,T加...表示改变参数
        for(T temp:t){
            try {
                if(temp!=null) {
                    temp.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

4. 派生子类

接口的使用与类一样

子类与父类/接口一样使用泛型;

public abstract class Father <T>{
    private T data;
    public abstract void test(T t);
}
// 子类为泛型类,则具体类型在使用时才确定
class Son2<T> extends Father<T>{
    T data;
    @Override
    public void test(T t) {

    }
}

子类指定具体的类型;

//子类声明时指定具体类型
//属性类型为具体类型,方法同理
class Son1 extends Father<String> implements Comparator<String>{

    String data;
    @Override
    public void test(String s) {

    }

    @Override
    public String b() {
        return "Comparator";
    }
}

子类擦除类型;

public abstract class Father <T>{
    private T data;
    public abstract void test(T t);
}
//子类为泛型类,父类不指定类型,即为泛型的擦除,使用Object替换
class Son3<T,T1> extends Father{

    @Override
    public void test(Object o) {

    }
}

子类与父类/接口同时擦除类型;

public abstract class Father <T>{
    private T data;
    public abstract void test(T t);
}
//子类与父类同时擦除
class Son4 extends Father{
    @Override
    public void test(Object o) {
        
    }
}

==擦除统一使用Object对待==

要么同时擦除,要么子类大于等于父类的类型,不能子类擦除,父类泛型;

1.属性类型:父类中,随父类而定,子类中,随子类而定

2.方法重写:随父类而定


5. 通配符

? extends super

1.可以用在声明类型和声明方法参数上,不能用在声明类上

2.?可以接受泛型的任何类型,只能接收和输出,不能修改

==泛型没有多态==

package com.alexanderli95.gen02;


/**
 * 泛型,?的使用方式
 * 只能用在声明类型和方法上,不能使用时或者声明类
 * ? extends: <= 上限
 * ? super: >=下限
 */
public class A <T>{
    T score;

    public static void main(String[] args) {
        A<?> a=new A<String>();

        test(new A<Integer>());

        //<=
        test2(new A<XiaoMing>());

        //>=
        test3(new A<Object>());
    }

    public static void test(A<?> stu) {

    }

    //<= 使用时只能传Student的子类类型进去
    public static void test2(A<? extends Student> stu){

    }

    //>= 使用时只能传Student的父类类型进去
    public static void test3(A<? super Student> stu){

    }
}

6. 泛型嵌套

==声明==:嵌套适用类型

A<B<C>> a=new A<B<C>>();

==使用==:从外到内,一层层的拆分

package com.alexanderli95.gen02;

public class TestQianTao <T>{
    T stu;

    public static void main(String[] args) {
        TestQianTao<Student<String,Integer>> room=new TestQianTao<Student<String,Integer>>();

        room.stu=new Student<String,Integer>();
        Student<String,Integer> stu2=room.stu;
        String score=stu2.getJavaseScore();
    }
}

7. 泛型与数组

没有泛型数组,不能创建(开辟空间)泛型数组

可以只有声明,可以使用?

A[] a1=null;

A[] a2=new A[10];

所以泛型数组没有意义


8. JDK1.7之后的声明

A a=new A<>(); 声明一次类型即可

使用和创建时不用指定类型;