Java高级

Java高级-----泛型之旅

2020-11-25  本文已影响0人  初夏的雪

前言

​ Java泛型是JDK 1.5引入的一个新特性,他本质就是将所要操作的数据类型指定为一个参数,这种参数类型可以作用在在类、接口和方法中。

​ 白话理解:

​ 我们之前在使用数据类型的时候是直接指定数据类型,而泛型则是将具体的数据类型参数化。类似于参数意义传递数据的类型。

1、为什么要用泛型?

​ 泛型通过在编译时检测到更多错误类增加代码的稳定性。

1、多种类型数据需要执行相同的代码时,不需要重载很多方法来完成;

2、指定数据类型,不需要做强制类型转换;在编译期,进行类型擦除后可以提早发现类型转换异常的风险;

2、泛型该如何定义呢?

​ 泛型中常用的几个类型参数名称:

E: Element

K:Key

N:Number

T:Type

V:Value

​ 等等,也可以使用其他大写字符,来增加可读性,例如:VIEWBINDING ,DATAMODEL ......

2.1 泛型类:

​ 在类名后面加上 <T> ,其中 T 是可以随意输入的大写字母,多个类型参数则用逗号 , 分隔

//泛型类,和普通的类的不同的是:在类名字后面加上“<T>”
public class Box<T>{
    private T data;
}
// 泛型类,定义多个类型参数,用逗号隔开
public class Car<T,K>{
    
}
//下面的类不是
public class Box{
    private String name;
    
    public <T> String getBoxName(T box){
        return box.name;
    }
}

2.2 泛型接口;

//泛型接口的定义
public interface CallBack<T>{

}

2.3 泛型方法:

在方法的返回值之前添加"<T>",该方法在调用时,方法名前面加上<具体类型>来告知具体的类型,当然也可以不加(会根据后面传入的参数类型自行判断)

//泛型方法:在返回值void之前 加上"<T>" 
public <T> void getBoxName(T box){
    return box.getName();
}

//下面的不是泛型方法,参数的泛型T,只能说明该方法需要接受一个泛型参数而已,不代表是方法方法
public void getBoxName(T box){
    return box.getName();
}

//下面的也不是泛型方法,他只是返回值类型是泛型
public T getBox(){
    return box;
}

特别说明:

  1. 泛型类与泛型方法的类型是没有关系的,他们两者之间是完全独立的;
  2. 类的泛型只能影响类的普通方法;
  3. 泛型方法中的泛型与泛型类中的泛型没有关系;他们可以相同,也可以不同

3、泛型的限定

extends 上限:(只读)

​ 即限定泛型的类型上限,只能传入extends 后面的类型或其子类(小于等于后面的类型);

​ 只读:因为编译器不能确定所持有的具体类型,只知道是Fruit及其类型,所以不能写入具体的子类;而读出来也是extends之后的类型Fruit或Object类型;

​ 用来限定类型参数,通常用于表示扩展(在类中)或者实现(在接口中)。多个泛型类型参数时,对需要限定的类型参数进行extends即可

public class Plate<T extends Fruit>{
//T 进行了上限的类型限定
}

super 下限:(只写)

​ 即限定泛型的类型下限,只能传入super后面的类型或其父类(大于等于后面的类型)

​ 只写:由于编译器能确定写入的是Apple的父类,但是不能确定读出去到底是哪一父类。

public class Plate<T super Apple>{

}

多重限定

如果类型的限定有多个的时候,并且有一个是类,那么这个类必须首先指定它。

public class Box <T extends A & B & C>{

}

//只有A是类,BC 是接口或者类,A必须首先指定

4、泛型约束与局限性

1、不能实例化类型变量

2、静态域或方法是不能引用类型变量的(因为静态域不属于对象,且由于构造之前执行)

​ 如: private static T mInstance = 。。。,是不允许的

3、静态方法本身是泛型则可以的;

4、泛型不能传入基本数据类型(int ,float ,double ,char等),只能传入包装类型(因为基本类型不是对象)

5、泛型不能继承Exception ,不能捕获泛型对象异常,但是可以抛出泛型异常

6、泛型数组不能初始化, 如:Class<T> []

7、泛型不管传入什么类型,他们的类型都是原生类型,与任何的T、P等无关;

5、 泛型继承

1.两个有继承关系的两个类,传入到泛型中,则这两个类是毫不相关的两个类型;即:父子关系的两个类传入到泛型中后,则父子关系就会消失;

public class Box<T>{
}

new Box<Integer>();
new Box<Number>();

//Integer 是Number的之类,那么上面两个new出来的对象是不存在父子关系的

2.泛型类可以 继承、扩展其他泛型类

public class View<T>{
}

public interface CallBack<T>{
}

public class CustomView<T,P> extends View<T> implements CallBack<P> {
    
}

6、 java对泛型的处理

java 语言引入了泛型,以在编译时提供更加严格的类型坚持并支持泛型编程。为了实现泛型,java编译器将类型擦除用于:

1、 如果类型参数不受限制,则将通用类型中的所有类型参数替换为其边界(上下界)或Object .因此产生的字节码仅包含普通的类,接口和方法;

2、必要时插入类型转换,已保持类型安全;

3、生成桥接方法以在扩展的泛型类型中保留多态;

​ 在泛型类型的擦除过程中,java编译器将擦除所有类型参数,如果类型参数是有界的,则将每个参数替换为其第一个边界,其他的父类型在真实使用时,强制类型转换;如果类型是无界的,则将其替换为Object。

上一篇下一篇

猜你喜欢

热点阅读