我是靠谱客的博主 害怕绿茶,最近开发中收集的这篇文章主要介绍JAVA进阶学习笔记:泛型,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

一、定义

“参数化类型”,平时定义任何方法时,例如传入int x,y属于典型的形参,调用时传入的1、2就是实参,参数类型在定义的时候参数类型本身参数化,在实际调用时告诉我们传入什么类型的参数

使用泛型的好处

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

二、分类

1、泛型类

2、泛型接口

实现方式分以下两种

1.泛型类的方式实现泛型接口,例码:
public class ImplGenertor<T> implements Genertor<T> {
@Override
public T next() {
return null;
}
}
2.直接规定参数类型,例码:
public class ImplGenertor2 implements Genertor<String> {
@Override
public String next() {
return null;
}
}

3、泛型方法

  • 特点:完全独立,可在任何地方和任何场景中使用,包括普通类和泛型类

  • 与普通方法区别

普通方法:
public class Generic<T> {
private T key;
public Generic(T key) {
this.key = key;
}
/* ---------------- 1 ---------------- */
// 虽然在方法中使用了泛型,但并不是一个泛型方法
// 这只是类中一个普通的成员方法,只不过返回值是在声明泛型类已经声明过的泛型
// 所以在这个方法中才可以继续使用T这个泛型
public T getKey() {
return key;
}
/* ---------------- 2 ---------------- */
// 使用了Generic<Number>这个泛型类做形参的普通方法。
public void show(Generic<Number> num) {
}
}
泛型方法
1.声明在泛型类的方法就不一定是泛型方法
2.泛型类里定义泛型方法需要遵循泛型方法的规则,带<任一大写(国际惯例)字母>
/** 首先在方法权限关键字与返回值之间的<T>必不可少,这表明这是一个泛型方法,并且声明了一个泛型T
* 这个T可以出现在这个泛型方法的任意位置.
* 泛型的数量也可以为任意多个
*
如:public <T,K> K showKeyName(Generic<T> container){
*
...
*
}
*/

三、限定类型变量

泛型类和泛型方法都可使用类型变量的限定,泛型方法使用案例如:对类型变量加以约束,比如计算两个变量的最小,最大值

public static <T> T min(T a,T b){
if(a.compareTo(b) > 0) {
return a;
} else {
return b;
}
}
/* 为了确保传入的两个变量一定有compareTo方法,解决方案为将T限制为实现了接口Comparable的类 */
public static <T extends Comparable> T min(T a, T b){
if(a.compareTo(b) > 0) {
return a;
} else {
return b;
}
}
/*
限定类型可以多个,类和接口均行,若类和接口混用,类必须放在第一位,且只能有一个(原因Java是单继承多实现) */
public static <T extends ArrayList & Comparable & Serializable & ...> T min(T a, T b){
if(a.compareTo(b) > 0) {
return a;
} else {
return b;
}
}

四、约束和局限性

1、不能实例化类型变量

public Restrict() {
this.data = new T();
}

2、静态域或方法里不能引用类型变量(Re:虚拟机创建一个对象时,优先执行static代码,再执行构造方法,泛型的类型只有在对象创建时才知道)

private static T instance;
注:静态方法是泛型方法就没有问题
private static <T> T instance(){}

3、基本类型不允许作为实例化类型参数(Re:基本类型不能作为对象使用)

4、不允许使用instanceof关键字

//
if(restrict instanceof Restrict<Double>)
//
if(restrict instanceof Restrict<T>)

5、在使用泛型时,不管传入什么类型的参数,查询类型始终是泛型类原生类型

Restrict<Double> restrict = new Restrict<>();
Restrict<String> restrictString = new Restrict<>();
System.out.println(restrict.getClass() == restrictString.getClass());
System.out.println(restrict.getClass().getName());
System.out.println(restrictString.getClass().getName());
// Resulet
true
*.Restrict
*.Restrict

6、不能创建参数化类型的数组

// 允许声明数组
Restrict<Double>[] restrictArray;
// 不允许
// Restrict<Double>[] restricts = new Restrict<Double>[10];

7、泛型类不允许作为 Exception/Throwable的派生类

//
private class Problem<T> extends Exception;

8、不能捕获泛型类对象

//
public <T extends Throwable> void doWork(T t) {
//
try {
//
//
} catch (T e) {
//
// do something
//
}
//
}
/* 注:虽然不能捕获它,但可以抛出写到throws子句里 */
public <T extends Throwable> void doWork(T t) throws T {
try {
} catch (Throwable throwable) {
throw
t;
}
}

五、泛型类型的继承规则

案例说明:类Pair为泛型类,类Worker是类Employee的派生类,以下为Pair类的节选代码


private static <T> void set(Pair<Employee> p){
}
public static void main(String[] args) {
Pair<Employee> employeePair = new Pair<>();
Pair<Worker> workerPair = new Pair<>();
Employee employee = new Worker();
// Pair<Employee>和Pair<Worker>没有任何继承关系
// Pair<Employee> employeePair2 = new Pair<Worker>();
Pair<Employee> pair = new ExtendPair<>();
set(employeePair);
// set(workerPair);
}
/*泛型类可以继承或者扩展其他泛型类,比如List和ArrayList*/
private static class ExtendPair<T> extends Pair<T>{
}

六、通配符(类型之间的继承关系不代表泛型参数化使用的继承关系,通配符可以很好地解决此问题)[通配符只能在方法中使用]

案例说明:类Fruit派生于类Food,类Apple和类Orange派生于类Fruit,类RedFuji派生于类Apple,类GenericType为泛型类,以下是类WildCard节选代码


public static void print(GenericType<Fruit> p) {
System.out.println(p.getData().getColor());
}
public static void use() {
GenericType<Fruit> a = new GenericType<>();
print(a);
GenericType<Orange> b = new GenericType<>();
//print(b); 方法print不允许传入对象b
}
/* --------------------------- 通配符的引入 --------------------------- */
public static void print2(GenericType<? extends Fruit> p) {
System.out.println(p.getData().getColor());
}
public static void use2() {
GenericType<Fruit> a = new GenericType<>();
print2(a);
GenericType<Orange> b = new GenericType<>();
print2(b);
/** 注:? extends X代表类型的上界,类型参数是X或X的子类 */
//print2(new GenericType<Food>());
// 对象c可赋值于a或b,GenericType<? extends Fruit> c = a/b;
GenericType<? extends Fruit> c = new GenericType<>();
/* ? extends X 主要用于安全访问数据 */
Apple apple = new Apple();
Fruit fruit = new Fruit();
// 编译器不知道传入是类Fruit或类Fruit的子类
//c.setData(apple);
//c.setData(fruit);
// 调用方法getData()获得的是Fruit类型
//Apple x = c.getData();
//Orange x = c.getData();
Fruit x = c.getData();
}
/** ? super X 表示类型的下界,类型参数是X或X的超类,主要用于安全写入数据 */
public static void printSuper(GenericType<? super Apple> p){
System.out.println(p.getData());
}
public static void useSuper(){
GenericType<Fruit> fruitGenericType = new GenericType<>();
GenericType<Apple> appleGenericType = new GenericType<>();
GenericType<RedFuji> redFujiGenericType = new GenericType<>();
GenericType<Orange> orangeGenericType = new GenericType<>();
printSuper(fruitGenericType);
printSuper(appleGenericType);
//printSuper(redFujiGenericType); // 类Apple的子类,故报错
//printSuper(orangeGenericType); // 平级类,跟类Apple没关系
// 表示GenericType的类型参数的下界是Apple
GenericType<? super Apple> x = new GenericType<>();
// 方法setData()编译器不知道传入的确切类型,但传入类Apple或类Apple的子类能安全转型为对象Apple
x.setData(new Apple());
x.setData(new HongFuShi());
//x.setData(new Fruit());
// 返回一定是Apple的超类,具体哪个超类不知道,唯一确定是类Object是类Apple的超类
Object data = x.getData();
}

七、虚拟机实现泛型方式 — 类型擦除

以类GenericRaw为例

public class GenericRaw<T> {
private T data;
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public static void main(String[] args) {
}
}
在JDK里类型擦除可理解为擦除成Object
public class GenericRaw<Object> {
private Object data;
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public static void main(String[] args) {
}
}

学习笔记,如有错漏,理解不到位,烦请多多提点,拜谢!
若需转载,声明出处即可
简书 && github


最后

以上就是害怕绿茶为你收集整理的JAVA进阶学习笔记:泛型的全部内容,希望文章能够帮你解决JAVA进阶学习笔记:泛型所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(62)

评论列表共有 0 条评论

立即
投稿
返回
顶部