关于后端:精通Java却不了解泛型

46次阅读

共计 3663 个字符,预计需要花费 10 分钟才能阅读完成。

大家好,我是小菜,一个渴望在互联网行业做到蔡不菜的小菜。可柔可刚,点赞则柔,白嫖则刚!死鬼~ 看完记得给我来个三连哦!

本文次要介绍 Java 中泛型的应用

如有须要,能够参考

如有帮忙,不忘 点赞

微信公众号已开启,小菜良记,没关注的同学们记得关注哦!

咱们下面既然都说到了泛型,那么咱们这篇文章就来从新温习一下泛型吧!

一、初识泛型

在没有泛型的呈现之前,咱们通常是应用类型为 Object 的元素对象。比方咱们能够构建一个类型为 Object 的汇合,该汇合可能存储任意数据类型的对象,然而咱们从汇合中取出元素的时候咱们须要明确的晓得存储每个元素的数据类型,这样能力进行元素转换,不然会呈现 ClassCastException 异样。

1. 什么是泛型

泛型是在 Java1.5 之后引入的一个新个性,它个性提供了编译时类型平安监测机制,该机制容许咱们在编译时监测出非法的类型数据结构。

它的实质就是参数化类型,也就是所操作的数据类型被指定为一个参数。这种参数类型能够用在 类、接口和办法 中,别离被称为 泛型类、泛型接口和泛型办法

2. 应用益处

  • 类型平安

有了泛型的存在,只有编译时没有呈现正告,那么运行时就不会呈现 ClassCastException 异样

  • 打消强制类型转换

从泛型汇合中取出元素咱们能够不必进行类型的转换

  • 可读性更高

能够间接看出汇合中寄存的是什么数据类型的元素

二、泛型的应用

1. 应用场景

1)泛型类

根本语法
 class 类名称 < 泛型标识,泛型标识,…> {
  private 泛型标识 变量名; 
  .....
 }
应用示例
 class Result<T>{private T data;}

注:

  • Java 1.7 之后能够进行类型推断,前面 <> 中的具体的数据类型能够省略不写:

 类名 < 具体的数据类型 > 对象名 = new 类名 <>();

  • 如果咱们应用的时候没有用到 <> 来制订数据类型,那么操作类型则是 Object
  • 泛型内的类型参数只能是 类型,而不能是根本数据类型,例如int,double,float...
  • 当咱们传入不同数据类型进行结构对象时,逻辑上能够看成是多个不同的数据类型,但实际上都是雷同类型

以上便是泛型类的简略用法,咱们想要应用哪种类型,就在创立的时候指定类型,应用的时候,该类就会主动转换成用户想要应用的类型。

那么如果咱们定义了一个泛型类,结构对象的时候却没有申明数据类型,那么默认为 Object 类型,取出数据的时候则须要进行类型转换:

 Result objectRes = new Result("testObejct");
 String str = (String) objectRes.getData();
 System.out.println(str);

规定:

  • 子类也是泛型类,那么子类和父类的泛型类型要统一
 public class ResultChild<T> extends Result<T> {}
  • 子类不是泛型类,那么父类要指定数据类型
 public class ResultChild extends Result<String> {}

2)泛型接口

根本语法
 public 接口名称 < 泛型标识, 泛型标识, ...>{泛型标识 办法名();
  ...
 }
应用示例
 public interface ResultInterface<T> {T getData();
 }

泛型接口与泛型类一样,有以下规定:

  • 实现类不是泛型类,接口要明确数据类型
  • 实现类也是泛型类,实现类和接口的泛型类型要统一

3)泛型办法

Java 中,泛型类和泛型接口的定义绝对比较简单,然而 泛型办法 就比较复杂。

  • 泛型类,是在实例化类的时候指明泛型的具体类型
  • 泛型办法,是在调用办法的时候指明泛型的具体类型
根本语法

 修饰符 <T, E, …> 返回值类型 办法名(形参列表){}

  • 修饰符与返回值类型之间的 <T> 用于申明此办法为泛型办法
  • 只有申明了 <T> 的办法才是泛型办法,就算返回值类型中的泛型类应用泛型的成员办法也并不是泛型办法
  • <T> 表明该办法将应用泛型类型 T,此时才能够在办法中应用泛型类型 T
应用示例
 private <T> Result<T> getResult(T data) {return new Result<T>(data);
 }

泛型办法与可变参数:

 private <T> void printData(T... data) {for (T t : data) {System.out.println(t);
  }
 }

注:

  • 泛型办法能使办法独立于类而产生变动
  • 如果 动态(static) 办法 要应用泛型能力,就必须使其成为泛型办法

2. 类型通配符

1)什么是类型通配符

  • 类型通配符个别应用 ” ? “ 代替具体的实参类型
  • 类型通配符是 实参类型 ,而不是 形参类型

类型通配符又分为 类型通配符的下限 类型通配符的上限

2)根本语法

类型通配符的下限

 类 / 接口 <? extends 实参类型 >

注:要求该泛型的类型,只能是实参类型,或实参类型的 子类 类型

类型通配符的上限:

 类 / 接口 <? super 实参类型 >

注:要求该泛型的类型,只能是实参类型,或实参类型的 父类 类型

2)应用示例

类型通配符的下限

如果咱们要打印一个 List 的值,咱们可能会这么做:

 private void printData(List list) {for (int i = 0; i < list.size(); i++) {System.out.println(list.get(i));
  }
 }

看上去没啥问题,然而又感觉怪怪的。因为这就跟黑匣子一样,我基本不晓得这个 List 外面装的是什么类型的参数。那咱们就在传参的时候定义一下类型:

 private void printData(List<Object> list) {for (Object o : list) {System.out.println(o);
  }
 }

然而这样定义又太宽泛了,Object 是所有类型的父类,如果说我想这个办法只能操作数字类型的元素,那我就能用上 类型通配符的下限 来解决这个问题了:

 private void printData(List<? extends Number> numList) {for (Number number : numList) {System.out.println(number);
  }
 }

但咱们须要应用这个办法时候咱们就很直观的能够看进去,这个办法传的实参只能是 Number 的子类。

printData(Arrays.asList(1, 2, 3));
printData(Arrays.asList(1L, 2L, 3L));

类型通配符的上限

下面咱们理解到 类型通配符下限的应用 ,那么 类型通配符下限 是如何应用的?

类型通配符下限 在咱们平时开发中应用的频率也绝对较少。编译器只晓得汇合元素是上限的父类型,但具体是哪一种父类型是不确定的。因而,从汇合中取元素只能被当成Object 类型解决(编译器无奈确定取出的到底是哪个父类的对象)。

咱们能够自定义一个复制汇合的函数:

  • 首先定义两个类:
public class Animal {
}
public class Pig extends Animal{}
  • 定义一个复制函数:
private static <T> Collection<? super T> copy(Collection<? super T> parent, Collection<T> child) {for (T t : child) {parent.add(t);
    }
    return parent;
}
  • 应用:
List<Animal> animals = new ArrayList<>();
List<Pig> pigs = new ArrayList<>();
pigs.add(new Pig());
pigs.add(new Pig());
copy(animals,pigs);
System.out.println(animals);

3. 类型擦除

因为泛型信息只存在于代码编译阶段,所以在进入 JVM 之前,会把与泛型相干的信息擦除,这就称为 类型擦除

1)无限度类型擦除

类型擦除前:

public class Result<T>{private T data;}

类型擦除后:

public class Result{private Object data;}

2)有限度类型擦除

类型擦除前:

public class Result<T extends Number>{private T data;}

类型擦除后:

public class Result{private Number data;}

3)擦除办法中类型定义的参数

类型擦除前:

private <T extends Number> T getValue(T value){return value;}

类型擦除后:

private Number getValue(Number value){return value;}

END

泛型的介绍就告一段落啦,这篇文章中咱们介绍了泛型的应用场景,类型通配符和类型擦除。内容不多,但也要好好看哦!路漫漫,小菜与你一起求索!

明天的你多致力一点,今天的你就能少说一句求人的话!

我是小菜,一个和你一起学习的男人。 ????

微信公众号已开启,小菜良记,没关注的同学们记得关注哦!

正文完
 0