• 泛型


    泛型

    泛型的作用

    • 多种数据类型执行相同的代码
    • 规范数据类型,在编译时发出警告,防止出现cast异常(类型异常:Ineger和String类型比较就会发生cast异常)

    泛型的使用

    • 泛型类
    public class NormalGeneric<T>{
    	private T data;
    	
    	public T getData(){
    		return data;
    	}
    }
    
    public static void main(String[] args) {
            NormalGeneric<String> normalGeneric = new NormalGeneric<>();
            normalGeneric.setData("12345");
            System.out.println(normalGeneric.getData());  // 输出12345
        }
    

    声明了一个泛型类,泛型为T,T类似一个形参,在使用这个类的时候为这个T传入一个实参,类中所有用到的T都替换成实参String,实参必须是一个对象类型;

    • 泛型接口:
    public interface People<T>{
            public T talk();
        }
    

    定义了一个People接口,指定了一个泛型T,接口内部有一个talk抽象方法;

    实现方式1:泛型类实现泛型接口

    class Student<T> implements People<T>{
            @Override
            public T talk() {
                return null;
            }
        }
    

    实现方式2:普通类实现泛型接口(直接指定泛型的实际类型)

    class Teacher implements People<String>{
            @Override
            public String talk() {
                return null;
            }
        }
    
    • 泛型方法:
    public  <T> T plus(){
            T result = null;
            //  todo
            return result;
        }
    

    在使用这个方法的时候指定泛型的实际类型

    normalGeneric.<Integer>plus(123);
    

    也可以省去泛型的实际类型,编译器借助传入的参数会自动设置泛型的值

    normalGeneric.plus("abc");
    

    泛型变量的限定

    public <T extends Comparable> T max(T a,T b){
            return a.compareTo(b)>0?a:b;
        }
    
    class Man<T extends Comparable>{
            T man;
            public T getMan() {
                man.compareTo(man);  //  具有Compareable接口属性
                return man;
            }
        }
    

    如果我们需要泛型变量具有特定接口的属性,可以给泛型T 继承一个接口,用来限定这个泛型的变量必须拥有这个接口的属性,传入的a和b必须实现Compareable接口;
    T的extends后面,如果有类必须写在第一个,并且只能有一个类,可以有多个多实现

    泛型的局限

    • 不能实例化泛型类型:不能new T()
    • 静态域不能引用类型变量:应为static静态属性先加载,而泛型的确认是在对象new的时候才知道;
    • 必须是包装类型,不能是基础类型
    • 不能使用instanceof判断对象类型

    img

    • 泛型类不能继承异常

    img

    泛型的通配符

    类型之间的继承关系不能保证泛型之间的继承关系
    下面举一个例子说明这句话的意思

    首先声明了如下四个继承关系的类

    public class Food {
    }
    
    public class Fruit extends Food {
    }
    
    public class Apple extends Fruit {
    }
    
    public class Orange extends Fruit {
    }
    

    再声明一个标准的泛型类

    public class GenericType<T> {
        private T data;
        public void setData(T data) {
            this.data = data;
        }
        public T getData() {
            return data;
        }
    }
    

    img

    我们声明了一个eat方法,传入的参数是泛型为Fruit的标准泛型类,创建了两个标准泛型类,一个泛型是Fruit,一个泛型是Apple,当调用eat方法时,只有fruit有效,apple却不行,可是apple明明继承了fruit,也是水果,为什么不能吃呢??

    因为类型的继承不能保证泛型变量之间的继承关系,为了解决吃apple的问题,引入了通配符 ?

    img

    我们将泛型的"实参"改成? extends Fruit,表示接收上界为Fruit的类型(Fruit和Fruit的子类)

    下面再理解一句话:通配符用于安全的访问数据

    img

    为什么setdata()的时候不管传入fruit还是apple都是不行的,因为通配符? extends Fruit规定了可能是Fruit,可能是Apple,也可能是Orange,不确定传入的是哪个,所以set的时候都不可以,但是在取出的时候,有一点可以保证,那就是一定是Fruit,(因为Apple和Orange也是Fruit),所以通配符用于安全的访问数据。

    通配符只能用在泛型方法上,不可以用在泛型类上

    super Apple表示Apple 和 Apple 的父类:安全的写入数据

    img

    super通配符可以set当前类和其子类,get Object类
    extends通配符不能set , 只能get当前类和其父类

    img

    super通配符可以set当前类和其子类,get Object类
    extends通配符不能set , 只能get当前类和其父类

    泛型的原理

    类型擦除:(在编译期完成)

    在jdk中的泛型是伪泛型,泛型类型在编译的时候会被擦除,jvm看到的只有原始类型ArrayList<String> 和 ArrayList<Object> 在jvm看来是一样的

    转载

  • 相关阅读:
    Linux 简介
    5设计模式之桥接模式(结构模式)
    2设计模式之简单工厂模式(构造模式)
    3异步和多线程
    1设计模式之单例模式
    性能测试知多少---吞吐量
    NumberFormat DecimalFormat
    Java 005 枚举
    log4j
    Java Basic
  • 原文地址:https://www.cnblogs.com/AronJudge/p/14553392.html
Copyright © 2020-2023  润新知