Java开发之泛型详解

一、什么是泛型

Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。

泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。泛型有什么好处?写个例子一目了然,我们要封装一个消息响应类:

public class Result implements Serializable {

    // 响应码
    Integer code;

    // 是否成功
    Boolean success;

    // 返回体数据
    User user;

    public Result(Integer code, Boolean success, User user) {
        this.code = code;
        this.success = success;
        this.user = user;
    }

    @Override
    public String toString() {
        return "Result{" +
                "code=" + code +
                ", success=" + success +
                ", user=" + user +
                '}';
    }

    public static void main(String[] args) {

        User user = new User(1, "Tony");
        Result result = new Result(200, true, user);
        System.out.println(result);

    }

}

class User implements Serializable {

    Integer id;

    String name;

    public User(Integer id, String name) {
        this.id = id;
        this.name = name;

    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

返回结果:

Result{code=200, success=true, user=User{id=1, name='Tony'}}

进程已结束,退出代码0

 这样这个反应体就可以返回请求状态和用户信息了。可现在需求又需要返回关于手机的信息,那我们又得封装一个能返回手机信息的响应类了,到后面还有衣服、鞋子那不得累死?这时候泛型登场了:

public class Result<T> implements Serializable {

    // 响应码
    Integer code;

    // 是否成功
    Boolean success;

    // 返回体数据
    T data;

    public Result(Integer code, Boolean success, T data) {
        this.code = code;
        this.success = success;
        this.data = data;
    }

    @Override
    public String toString() {
        return "Result{" +
                "code=" + code +
                ", success=" + success +
                ", data=" + data +
                '}';
    }

    public static void main(String[] args) {

        User user = new User(1, "Tony");
        Result<User> resultUser = new Result<>(200, true, user);
        System.out.println(resultUser);
        Phone phone = new Phone(999.99, "Yellow");
        Result<Phone> resultPhone = new Result<>(200, true, phone);
        System.out.println(resultPhone);

    }

}

class User implements Serializable {

    Integer id;

    String name;

    public User(Integer id, String name) {
        this.id = id;
        this.name = name;

    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

class Phone implements Serializable {

    Double price;

    String color;

    @Override
    public String toString() {
        return "Phone{" +
                "price=" + price +
                ", color='" + color + '\'' +
                '}';
    }

    public Phone(Double price, String color) {
        this.price = price;
        this.color = color;
    }
}

结果:

Result{code=200, success=true, data=User{id=1, name='Tony'}}
Result{code=200, success=true, data=Phone{price=999.99, color='Yellow'}}

进程已结束,退出代码0

可见,利用泛型,可以统一标识需要返回的实体类。不管你来什么类,我都可以给你塞进去!

第一次接触可能看不太明白,下面就详细讲解。

二、泛型方法

你可以写一个泛型方法,该方法在调用时可以接收不同类型的参数。根据传递给泛型方法的参数类型,编译器适当地处理每一个方法调用。

1、语法规则

所有泛型方法声明都有一个类型参数声明部分(由尖括号分隔),该类型参数声明部分在方法返回类型之前,比如说这是一个用来打印数组的泛型方法:

private static <E> void printArray(E[]inputArray)

每一个类型参数声明部分包含一个或多个类型参数,参数间用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。比如这个方法:

private static <E,T> void printArray(E[] inputArray, T data)

类型参数能被用来声明返回值类型,并且能作为泛型方法得到的实际参数类型的占位符。

泛型方法体的声明和其他方法一样。注意类型参数只能代表引用型类型,不能是原始类型(int double char等)

2、泛型标记符
  • E Element 集合元素
  • T Type Java类
  • K Key 键
  • V Value 值
  • N Number 数值类型
  • ? 表示不确定的Java类型

这些标记并不是限定只有对应的类型才能使用,即使你统一使用A-Z英文字母的其中一个,编译器也不会报错。之所以又不同的标记符,这是一种**约定。**在开发中很多规则都是一种约定,它能提高我们代码的可读性,方便团队见的合作开发,写个完整的例子:

public class TFunction {

    public static void main(String[] args) {

        // 创建各种类型的数组
        Integer[] intArray = {1, 2, 3, 4, 5};
        Double[] doubleArray = {1.1, 2.2, 3.3, 4.4};
        Character[] charArray = {'H', 'E', 'L', 'L', 'O'};

        System.out.println("整型数组元素为:");
        printArray(intArray); // 传递一个整型数组

        System.out.println("\n双精度型数组元素为:");
        printArray(doubleArray); // 传递一个双精度型数组

        System.out.println("\n字符型数组元素为:");
        printArray(charArray); // 传递一个字符型数组

    }

    // 泛型方法
    private static <E> void printArray(E[] inputArray) {

        // 遍历打印数组
        Arrays.stream(inputArray).forEach(e -> {
            System.out.printf("%s ", e);
        });
        System.out.println();

    }
    
}

三、泛型类 

泛型类的声明与非泛型类几乎相同,唯一的不同在于类名的后面添加了参数声明部分。

这边就不举例子了,因为开篇的例子就是封装了一个泛型类,当时不太理解的可以再回去看一下

public class Result<T> implements Serializable {

    //省略属性定义
    //
    //省略方法定义
}

四、类型通配符 

1、无界通配符<?>

通配符我们一般用?表示,我们一般可以使用?来承接所有的引用类型,搬运一个菜鸟上的例子:

public class GenericTest {
     
    public static void main(String[] args) {
        List<String> name = new ArrayList<String>();
        List<Integer> age = new ArrayList<Integer>();
        List<Number> number = new ArrayList<Number>();
        
        name.add("icon");
        age.add(18);
        number.add(314);
 
        getData(name);
        getData(age);
        getData(number);
       
   }
 
   public static void getData(List<?> data) {
      System.out.println("data :" + data.get(0));
   }
}

结果:

data :icon
data :18
data :314
2、上界通配符<?extends T >

这是泛型上边界,只有T对象的子类可以被传入,如果是? extends C,那么只有D和E允许被传入,否则会编译报错

3、下界通配符<? super T >

这是泛型下边界,只有T对象的父类可以被传入,如果是? super D,那么只有C和A允许被传入,否则会编译报错

 

4、T 和 ?

不知道看到这里,有没有疑惑。T和?好像作用差不多啊,有什么区别?

? 通配符是无法作用于声明类的类型参数,一般作用于方法和参数上。而 类型变量 T 在类定义时具有更广泛的应用。

5、T 和 Object 

其实,在JDK5之前,都是用的Object,但其存在很多的问题,JDK5之后便引入了泛型。

Object是所有类的父类,在编码过程中就难免出现类型转化问题,虽然在编译阶段不会报错,但是写起来麻烦,还要不停的进行类型转化,还很容易在运行阶段才暴露问题,大大降低了程序的安全性和健壮性!

举例说明:

结果:class java.lang.Integer cannot be cast to class java.lang.String(整型不能被强制转换成字符串类型)

泛型的出现,当类型转化出现问题的时候,在编译阶段就会暴露出来。解决了Object存在的诸多问题,让代码更加优雅,程序更加安全,更加健壮。

  • 14
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

易雪寒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值