Java泛型

泛型简介

泛型的意义在于代码复用,简化多种数据类型执行的相同的代码。

泛型中的类型在使用时指定,不需要强制类型转换(类型安全,编译器会检查类型)

引入泛型,它将提供类型的约束,提供编译前的检查:

List<String> list = new ArrayList<String>();

泛型有三种使用方式,分别为:泛型类、泛型接口、泛型方法。

泛型的使用

泛型类

一元泛型类:

class Point<T>{         // 此处可以随便写标识符号,T是type的简称  
    private T var;
    public T getVar(){
        return var;  
    }
    public void setVar(T var){
        this.var = var;  
    }
}

多元泛型类:

class func<K,V>{       // 此处指定了两个泛型类型  
    private K key;
    private V value;
    public K getKey(){  
        return this.key;  
    }  
    public V getValue(){  
        return this.value;  
    }  
    public void setKey(K key){  
        this.key = key;  
    }  
    public void setValue(V value){  
        this.value = value;  
    }  
}

泛型接口

interface Info<T>{        // 在接口上定义泛型  
    public T getVar(); // 定义抽象方法,抽象方法的返回值就是泛型类型  
}
class InfoImpl<T> implements Info<T>{
    private T var;
    public InfoImpl(T var){     // 通过构造方法设置属性内容  
        this.setVar(var);
    }
    public void setVar(T var){
        this.var = var;
    }
    public T getVar(){
        return this.var;
    }
}

泛型方法

泛型方法的定义:

/**
* 泛型方法
* @param c 用来创建泛型对象(本身是一个Class对象)
* @param <T> 声明一个泛型
* @return
*/
public<T> T getObject(Class<T> c) throws InstantiationException, IllegalAccessException {
    T t = c.newInstance();
    return t;
}

newInstance()方法无法提供参数,因此,使用该泛型方法的类需要提供一个参数列表为空的构造方法。

泛型方法的返回值未必一定该泛型,但是需要在返回值前添加<T>,来声明这是一个泛型方法。

泛型方法的意义在于可以在调用的时候指明类型,更加灵活。泛型类要在实例化的时候就指明类型,如果想换一种类型,就需要重新new一次。

泛型方法的调用:

Generic generic = new Generic();
Object object = generic.getObject(Class.forName("User"));

forName()方法中传入实体类的完整路径,通过泛型方法生成该类对象。

泛型的边界

假设我们有:

class A{}
class B extends A {}
class C extends String{}

这是一个错误的代码段:

public static void funA(List<A> listA) {
    // ...
}
public static void funB(List<B> listB) {
    funA(listB);         
}

为了解决泛型中隐含的转换问题,Java泛型加入了类型参数的上下边界机制。

<? extends A>表示该类型参数可以是A(上边界)或者A的子类类型。编译时擦除到类型A,即用A类型代替类型参数。如果传入的实例类型B是在这个范围内的话允许转换,运行时会把对象当做A的实例看待。

同理,<? super A>表示该类型参数可以是A(下边界)或者A的父类类型。

public static void funA1(List<? extends A> listA) {
    System.out.println("funA1");
}
public static void funA2(List<? super A> listA) {
    System.out.println("funA2");
}
public static void funB(List<B> listB,List<Object> listO) {
    funA1(listB);
    funA2(listO);
}

public static void main(String[] args) {
    List<B> listB = new ArrayList<>();
    List<Object> listO = new ArrayList<>();
    funB(listB,listO);
}

我们也可以用这种方式定义泛型类的边界:

class number<T extends Number>{    // 此处泛型只能是数字类型
    private T var;
    public T getVar(){
        return var;  
    }
    public void setVar(T var){
        this.var = var;  
    }
}

我们可以使用 & 符号声明更多的限制:

//工资低于2500元的上斑族并且站立的乘客车票打8折
public static <T extends Staff & Passenger> void discount(T t){

}

为了获得最大限度的灵活性,要在表示生产者或者消费者的输入参数上使用通配符,使用的规则是:生产者有上限、消费者有下限

  1. 如果参数化类型表示一个 T 的生产者,使用 < ? extends T>;
  2. 如果它表示一个 T 的消费者,就使用 < ? super T>;
  3. 如果既是生产又是消费,那使用通配符就没什么意义了,因为你需要的是精确的参数类型。

泛型数组

List<String>[] list1 = new ArrayList<String>[10]; //编译错误,非法创建 
List<String>[] list1 = new ArrayList<?>[10]; //编译错误,需要强转类型 
List<String>[] list1 = (List<String>[]) new ArrayList<?>[10]; //OK,但是会有警告 
List<?>[] list1 = new ArrayList<String>[10]; //编译错误,非法创建 
List<?>[] list1 = new ArrayList<?>[10]; //OK 
List<String>[] list6 = new ArrayList[10]; //OK,但是会有警告

合理的使用:

public <T> void ArrayWithTypeToken(Class<T> type, int size) {
    T[] array = (T[]) Array.newInstance(type, size);
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

惊雲浅谈天

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值