JavaSE高级开发之泛型

泛型:只允许接受类,所有基本类型必须使用包装类。

①泛型类:

指在类定义时不会设置类中的属性或方法中参数的具体类型(Object),而是在类使用的时候再定义。
优点:不需强转,需要什么类型,使用时定义什么类型即可。若类型不匹配,编译时就会报错,避免了运行时异常。(因为Object类需要强转或向下转型,若没有做到,只能在运行时报出异常,非常不安全)
语法:

class 类名<T>{
private T num;}

T被称为类型参数,用于指代任何类型。
T:代表一般类
E:代表element 常用于泛型类中的属性
K、V:键值对,用于Map集合:
S:代表subtype,用于表示子类
若类中的成员变量需要不同的类型,则在类定义泛型时定义多个类型参数,用逗号分隔
使用时前写后省Person person=new<> Person();

public class Point<T, R> {
    private T x;
    private R y;

    public Point(T x) {
        this.x = x;
    }

    public Point(T x, R y) {
        this.x = x;
        this.y = y;
    }

    public void getInfo() {
        System.out.println(x);
        
    }

    public static void main(String[] args) {
        //创建泛型类的对象时(使用泛型)必须声明指定的类型
        Point<String,Integer> p = new Point<>("张三");
        //定义类时声明的T,R可以代表任意类型 ,若是基本数据类型必须是包装类
        Point<String,Double> p1 = new Point<String, Double>("张三",24.5);
        p.getInfo();
        p1.getInfo();
    }
}

②泛型方法:

public void method(T t){

}
是个占位符,表示其是泛型方法,与返回值无关

当泛型类与泛型方法共存时,泛型类中的类型参数与泛型方法中的类型参数没有关系,泛型方法始终以自己定义的类型参数为准。
规范起见:泛型方法类型参数与泛型类的类型参数不能同名。

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

泛型方法于泛型类共存:
泛型方法始终以自己定义的类型参数为准,与类定义的泛型无关,为避免混淆,,如果在一个泛型类中存在泛型方法,那么两者的类型参数好不要同名。

public class MethodTest<T> {
    //泛型方法
    public <T> T tell(T t){
        return t;
    }
    public void talk(T t){
        System.out.println(t);
    }

    public static void main(String[] args) {
        MethodTest<Integer> my=new MethodTest<>();
        //方法签名上无泛型声明的方法,其类型与类定义的一致
        my.talk(12);
        //方法签名上有泛型声明的方法,尽管<>中的参数与类的一致,但是使用时其类型与类无关联
        my.tell("你好");
    }
}

通配符:

含有泛型的类作为参数时,需指定其类型,因此就可能会出现多个方法重载,因此

(1)采用通配符 <?> 在方法参数中使用,表示参数可以接收任意类型的参数。
使用通配符的类参数,只能取得类中数据,不能修改数据,因为类型不确定,无法设置确定值。

public class Wildcard {
    public static void main(String[] args) {
    
        Message<Integer> me=new Message<>();
        me.setMess(23);//使用确定的泛型既可以调用set也可以调用get
        me.getMess();


        Message<?> me2=new Message<>();
       // me2.setMess(23);使用通配符的对象不能调用set方法吧,因为不确定类型
        me2.getMess();//使用通配符的对象可以调用使用范型的属性
        me2.setNaem("啥");//确定类型的属性可以调用set方法.
    }
}
class Message<T>{
    private T mess;
    private String naem;

    public String getNaem() {
        return naem;
    }

    public void setNaem(String naem) {
        this.naem = naem;
    }

    public T getMess() {
        return mess;
    }

    public void setMess(T mess) {
        this.mess = mess;
    }
}

(2)采用通配符<? extends 类名>,表示设置泛型的类上限,即只能接收此类及其子类,如 ? extends Number 表示泛型必须是Number及其子类
只能取得类中属性,不能修改值(发生父类到子类的向下转型,需强转,由于子类不确定,因此无法转型)
泛型的类上限既可以用在定义类的时候,也可以用在使用类的时候

public class WildcardUP {
    public static void main(String[] args) {
        //使用设置了上限的泛型类
        //可以设置Number,及其子类
        PMessage<Number> message = new PMessage<>();
        message.getMes();
        message.setMes(34);
        //PMessage<String> message1=new PMessage<String>();//error,String 不是Number的子类
   
    Message<? extends Number> message1=new Message<>();
   // message1.setMess(23);//error,设置泛型上限的对象不能调用set方法
    }
}

//泛型的上限在泛型类定义的时候使用
class PMessage<T extends Number> {
    private T mes;

    public T getMes() {
        return mes;
    }

    public void setMes(T mes) {
        this.mes = mes;
    }
}

(3)<?super 类名>表示设置泛型的类下限,只能接收此类及其父类,如<? super String>表示只能接收String 以及其父类Object.
可以设置属性值,因为子类到父类是会自动向上转型
泛型类的下限只能用在使用类的时候

public static void main(String[] args) {
        //在使用泛型的类的时候使用类的下限
        Message<? super String> message = new Message<>();
        message.setMess("hello");//可以设置属性内容
        message.getMess();//可以获取属性内容
    }

③泛型接口
interface 接口名
子类实现接口可以保留泛型,继续成为泛型类
class 子类 implements 接口名{}
子类实现接口确定好类型
class 子类 implements 接口名{}

public interface IMessage <T>{
   void print(T x);
    //1.匿名内部类实现接口的泛型方法
  IMessage<String> imessage=new IMessage<String>() {
        @Override
        public  void print(String str) {
            System.out.println(str);
        }
    };
}

//2.指定泛型参数的类型
class IMessage2 implements IMessage<String> {
    
    @Override
    public void print(String o) {
        System.out.println(o);
    }
}
//3.继续保留泛型参数
class IMessage1<T> implements IMessage<T> {
    
    @Override
    public void print(T t) {
        System.out.println(t);
    }
}

(面)
类型擦除(语法糖):仅存在源码阶段,编译后就消失不见。如泛型,自动拆装箱、String类中的+
泛型信息仅存在于代码编译阶段,进入JVM之前,与泛型相关信息会被擦除掉,专业术语:类型擦除
换句话说:泛型与普通类在Java虚拟机中没有任何区别
泛型类进入JVM之前会进行类型擦除,之前泛型类的类型参数若没有指定上限,会被擦除为Object类型。如果指定上限,则类型参数会被擦除为相应类型上限。

public class Wipe<T> {
    public static void main(String[] args) {
        Wipe<Integer> integerWipe=new Wipe<>();
        Wipe<String> stringWipe= new Wipe<>();
        System.out.println(integerWipe.getClass().getName());//com.sweet.generics.Wipe
        System.out.println(stringWipe.getClass().getName());//  com.sweet.generics.Wipe
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_42962924/article/details/84941908