简单了解Java泛型|Java基础

359 阅读4分钟

这是我参与8月更文挑战的第1天,活动详情查看:8月更文挑战

废话:迄今为止,工作也一年有余了,一直没有对知识体系有一个系统的总结。就让我从这个8月开始吧。我只是Android路上的一个小菜鸡,其实呢,这篇文章之前在其他博客发过一次,希望大家帮忙指正错误的地方。 The nonsense is over!

为什么使用泛型

在介绍为什么使用泛型前我们需要了解什么是泛型?
泛型的定义主要有以下两种:

  1. 在程序编码中一些包含类型参数的类型,也就是说泛型的参数只可以代表类,不能代表个别对象。(这是当今较常见的定义)
  2. 在程序编码中一些包含参数的。其参数可以代表类或对象等等。(现在人们大多把这称作模板

不论使用哪个定义,泛型的参数在真正使用泛型时都必须作出指明。

一些强类型程序语言支持泛型,其主要目的是加强类型安全及减少类转换的次数,但一些支持泛型的程序语言只能达到部分目的。(摘自百度百科)


正文:当我们将一个对象放入集合中,集合并不会记住此对象的类型,当再次从集合中取出此对象时,该对象的编译类型变成了Object类型,但其运行时类型,依然为其本身类型。 因此,在取出集合元素时,需要人为的进行强制转换到具体的目标类型,且容易出java.lang.ClassCastException。

所以泛型的好处就是:

  • 适用于多种数据类型执行相同的代码
  • 在使用是就制定泛型中的类型,不需要强制转换

泛型类与泛型接口的定义

  • 泛型,即“参数化类型”。提到参数,我们熟悉的就是定义方法时有形参然后调用此方法时传递参数。那么参数化类型是什么?
  • 顾名思义,就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(类型形参),然后在使用/调用时传入具体的类型(类型实参)。

什么是泛型类

如果之前有看过我写的单例模式文章的同学,应该对这个类不陌生。"我的理解为在声明类名出声明出泛型的类便是泛型类"

import java.util.Objects;
 
/**
 * 泛型类
 * 泛型类是允许有多个类型变量的,例如Singleton<T,V>
 * @param <T>
 */
public abstract class Singleton<T>{
 
    private T instance;
 
    public abstract T create();
 
    public final T getInstance(){
 
        if(Objects.isNull(instance)){
            synchronized (this){
                if(Objects.isNull(instance)) instance = create();
            }
        }
        return instance;
    }
}

什么是泛型接口

泛型接口,在接口名处,声明出泛型类型。

public interface Generator<T> {
    public T next();
}

泛型方法辨析

泛型方法,是在调用方法时指明泛型的具体类型,泛型方法可以在地方和场景中使用,包括普通类和泛型类。

public class GenertorMethod<T> {
    
    private T key;
 
    /**
     *  泛型方法是独立的,没必要声明在泛型类和泛型方法中
     *
     * @param a
     * @param <T>
     * @return
     */
    public <T> T genericMethod(T...a){
        return a[a.length/2];
    }
 
    /**
     * 虽然返回值是泛型,但他不是泛型方法
     * 若此类不是泛型类,编译报错。
     * @return
     */
    public T commonMethod(){
        return key;
    }
 
    /**
     * @param str 在定义方法的时候,只需将最后一个形参后加上"…",就可以表示该形参可以接收多个参数值,多个参数值被当成数组传入
     * @return
     */
    public String demo_1(String...str){
        for (String s : str) {
            if(s == "ok"){
                return s;
            }
        }
        return null;
    }
 
}

限定类型变量

  • <T extend Comparable>有时需要对类型变了加以约束,比如比较大小。
  • 同时extends左右都允许有多个,如 T,V extends Comparable & Serializable
  • 注意限定类型中,只允许有一个类,而且如果有类,这个类必须是限定列表的第一个。这种类的限定既可以用在泛型方法上也可以用在泛型类上。
    /**
     * @param a
     * @param b
     * @param <T> T必须为Comparable的派生类,或者实现接口, 但是类只可以有一个,因为Java单继承
     *           extends 左右俩边可以有多个参数
     * @return
     */
    public static <T extends ArrayList & Comparable & Serializable> T min(T a, T b){
        if (a.compareTo (b) > 0)return b;else return a;
    }

泛型中的约束和布局

  • 不能用基本类型实例化参数类型 不被允许的使用
GenertorMethod<int> genertorMethod = new GenertorMethod();

正确的使用

GenertorMethod<Integer> genertorMethod = new GenertorMethod();
  • 泛型类的静态上下文中类型变量失效,静态域或者方法里不能引用类型变量,静态方法本身是泛型方法可以。 不被允许的使用
private static T getInstances(){return null;}

正确的使用

private static <T> T getT(){return null;}
  • 不能创建参数化类型的数组,其实主要是为了避免数组里出现类型不一致的元素** 不被允许的使用
GenertorMethod<Integer>[] genertorMethods = new GenertorMethod<Integer>[10];

泛型类型的继承规则

//请问arrayList_1和arrayList_2是继承关系吗?
//答案:不是,他们之间没有什么关系
ArrayList<ArrayList> arrayList_1 = new ArrayList();
ArrayList<AbstractList> arrayList_2 = new ArrayList();

image.png

通配符类型

? extends X  表示类型的上界,类型参数是X的子类
? super X  表示类型的下界,类型参数是X的超类