当前位置:   article > 正文

JAVA泛型浅析

JAVA泛型浅析

Java范型generics,是JDK1.5引入的新特性,是一种编译时类型安全检测机制,可以在编译时检测到非法的类型。范型的本质是将类型参数化,将类型指定成一个参数。java中的集合就有使用,并且对外提供的三方库和SDK中使用也极为常见。
特点是运行效率高,在定义时不设限在使用时再写入具体类型。 定义泛型参数时还可以使用继承,例如 <T extends User> ,后面都可以使用User类或它的子类接收在必要的时再强转指定类型。

泛型只在编译期间生效,运行期泛型会被擦除,比如List<String> 和 List<Integer>的两个空集合,equals判断为true。
范型的参数只能是引用类型,不能是基本数据类型。

三种使用范围:范型类、范型接口、范型方法。

1、范型类:  用在构造方法在实例化的时候检测类型

范型的参数可以是系统定义的类也可以是自定义类;构造方法传入的实参类型需要与范型的参数类型相同,<T>  类型由调用方决定。

1.1 定义一个泛型类

  1. public class GenericUser<T> {
  2. private T name;
  3. private T age;
  4. public GenericUser(T nameOrAge) {
  5. //这里为了学习总结,实际不会这样乱赋值
  6. this.name = nameOrAge;
  7. this.age = nameOrAge;
  8. }
  9. public GenericUser() {
  10. }
  11. public T getName(){
  12. return name;
  13. }
  14. public T getAge(){
  15. return age;
  16. }
  17. //注意:静态方法使用范型:必须将静态方法也定义成范型方法,否则报错。即使类已经定义了也会报错,必须在修饰符和返回值之间static之后加上这个范型
  18. private static <T> T getNameS(T t){
  19. return t;
  20. }
  21. }

1.2 使用泛型类

  1. GenericUser<String> genericUser1 = new GenericUser<>("Tom");
  2. Log.e(TAG, "onClick: name= "+genericUser1.getName() );
  3. GenericUser<Integer> genericUser2 = new GenericUser<>(8);
  4. Log.e(TAG, "onClick: age="+genericUser2.getAge() );
  5. //todo 不是使用定义了范型的类就一定要传入范型,如果传了什么就用什么,如果不传就可以是任意类型。需要做类型判断
  6. GenericUser genericUser3 = new GenericUser<>("随便写");
  7. Log.e(TAG, "onClick: name="+genericUser3.getName()+" age="+genericUser3.getAge());
  8. 结果打印:
  9. //2024-02-18 18:33:34.884 22735-22735/com.example.testdemo3 E/FanXingActivity: onClick: name= Tom
  10. //2024-02-18 18:33:34.884 22735-22735/com.example.testdemo3 E/FanXingActivity: onClick: age=8
  11. //2024-02-18 18:33:34.885 22735-22735/com.example.testdemo3 E/FanXingActivity: onClick: name=随便写 age=随便写

2、泛型方法

在方法调用时检测类型,在返回值类型之前的<T>是范型方法的象征,此处表示声明了一个范型T,范型数量也可以多个比如<T,E>;
下面getNanme1和getNanme2是泛型方法,但getNanme3方法不是范型方法它只是在形参中使用了范型而已。

  1. private <T> T getName1(GenericUser<T> user){
  2. return user.getName();
  3. }
  4. //也有这种返回但不传入
  5. private <T> T getName1(T str){
  6. GenericUser<T> genericUser = new GenericUser<>(str);
  7. Log.e(TAG, "getName1: name= "+genericUser.getAge() );
  8. return genericUser.getAge();
  9. }
  10. private <T,E> T getName2(GenericUser<T> user){
  11. return user.getName();
  12. }
  13. //不是泛型方法
  14. private String getName3(GenericUser<String> user){
  15. return user.getName();
  16. }
  17. //范型方法也可以普通方法一样使用可变参数
  18. private <T> void getName4(T...ts){
  19. for (T t : ts) {
  20. Log.e(TAG, "getName4: "+t );
  21. }
  22. }

3、泛型接口:一般和范型类或方法搭配使用且与范型类用法类似

  1. interface GenericInter<T> {
  2. T getNumber();
  3. }

3.1 泛型类使用泛型接口

当实现范型接口的类不传范型实参:比如下面的也需要在类名增加GenericInterUser1<T>和接口一样的范型。

  1. public class GenericInterUser1<T> implements GenericInter<T>{
  2. @Override
  3. public T getNumber() {
  4. return null;
  5. }
  6. }

如果当实现范型接口的类传入自己范型参数: 如GenericInterUser1不需要在类名加范型参数

  1. public class GenericInterUser2 implements GenericInter<String>{
  2. private String number = "000001";
  3. @Override
  4. public String getNumber() {
  5. return number;
  6. }
  7. }

泛型的子类限制

  1. public class GenericUserSun<T extends Number> extends GenericUser{
  2. private T age;
  3. public GenericUserSun(T age){
  4. super(age);
  5. this.age = age;
  6. }
  7. public T getAge() {
  8. return age;
  9. }
  10. }

//上面案例GenericUserSun可以传入的泛型就有了限制,不是所有类型都可以,而必须是Number的子类,比如Integer、Byte、Short、Float等等。

注意:如果我们想写一个接口实现类做泛型参数也要使用<T extends 接口>和类一样 而不是<T implements 接口>,报错如下。

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号