java 泛型

作者: zhbi98 | 来源:发表于2021-09-08 20:58 被阅读0次

1. 泛型的优点

在没有泛型的情况的下,通过对类型 Object 的引用来实现参数的“任意化”,“任意化”带来的缺点是要做显式的强制类型转换,而这种转换是要求开发者对实际参数类型可以预知的情况下进行的。对于强制类型转换错误的情况,编译器可能不提示错误,在运行的时候才出现异常,这是本身就是一个安全隐患。那么泛型的好处就是在编译的时候能够检查类型安全,并且所有的强制转换都是自动和隐式的。

使用泛型的例子:使用泛型指定数据类型和强制转换的比较,如下代码

public class Generic<T> {
    private T t;

    public void set(T t) {
        this.t = t; 
    }

    public T get() {
        return t;
    }
}


public class GenericLearn {
    // 不指定类型
    public void noSpecifyType() {
        Generic generic = new Generic();
        generic.set("test");

        // 需要使用强制类型转换
        String test = (String) generic.get();
        System.out.println(test);
    }

    // 这里使用泛型指定类型,指定类型为String
    public void specifyType() {
        Generic<String> generic = new Generic<>();
        generic.set("test");

        // 不需要使用强制类型转换
        String test = generic.get();
        System.out.println(test);
    }

    public static void main(String[] args) {

    }
}

2. 使用泛型

1. 在这里我们使用java 的可变长数组ArrayList作为例子说明泛型。

使用ArrayList时,如果不定义泛型类型时,泛型类型实际上就是Object,此时,只能把<T>当作Object使用,没有发挥泛型的优势。

// 编译器发生警告:
List list = new ArrayList();
list.add("Hello");
list.add("World");
String first = (String) list.get(0);
String second = (String) list.get(1);

当我们定义泛型类型<String>后,List<T>的泛型接口变为强类型List<String>。

// 无编译器警告:
List<String> list = new ArrayList<String>();
list.add("Hello");
list.add("World");
// 无强制转型:
String first = list.get(0);
String second = list.get(1);

当我们定义泛型类型<Number>后,List<T>的泛型接口变为强类型List<Number>。

List<Number> list = new ArrayList<Number>();
list.add(new Integer(123));
list.add(new Double(12.34));
Number first = list.get(0);
Number second = list.get(1);

2. 编译器如果能自动推断出泛型类型,就可以省略后面的泛型类型,甚至省略后面的泛型类型后尖括号也可以省略。例如,对于下面的代码:

List<Number> list = new ArrayList<Number>();

可以省略后面的泛型类型转化为

// 这时需要编译器自己推断泛型类型
List<Number> list = new ArrayList<>();

// 甚至省略后面的泛型类型后尖括号也可以省略
List<Number> list = new ArrayList();

3. 在接口中使用泛型


4. 编写泛型类

// 定义类 Apple 时使用了泛型声明
class Apple<T> {
    // 使用T类型形参定义实例属性
    private T info;

    public Apple() {

    }

    // 下面方法中使用T类型形参来定义构造函数
    public Apple(T info) {
        this.info = info;
    }

    public void setInfo(T info) {
        this.info = info;
    }

    public T getInfo() {
        return this.info;
    }
}


public class GenericLearn {
    public static void main(String[] args) {
        // 由于传给T形参的是String,所以构造器参数只能是String
        Apple<String> a1 = new Apple<>("苹果");
        System.out.println(a1.getInfo());

        // 由于传给T形参的是Double,所以构造器参数只能是Double或double
        Apple<Double> a2 = new Apple<>(100.06);
        System.out.println(a2.getInfo());
    }
}
---------------------------------------------------------
Apple
100.06

尖括号放置说明:

20210428205844.jpg

5. 泛型类中的静态方法使用泛型

编写泛型类时,要特别注意,泛型类型<T>不能用于静态方法。无法在静态方法的方法参数和返回类型上使用泛型类型T。那我们该怎么办呢?我们可以这样对于静态方法,我们可以单独改写为“泛型”方法,只需要使用另一个类型即可。例如下面这样:

    // 编译时这将出现无法在静态上下文上引用非静态类型变量T的错误
    public static Apple<T>readObject(T a) {
        return new Apple<T>(a);
    }

单独改写为“泛型”方法后的

    public static <K> Apple<K>readObject(K a) {
        return new Apple<K>(a);
    }

具体实现:

// 定义类 Apple 时使用了泛型声明
class Apple<T> {
    // 使用T类型形参定义实例属性
    private T info;

    public Apple() {

    }

    // 下面方法中使用T类型形参来定义构造函数
    public Apple(T info) {
        this.info = info;
    }

    public void setInfo(T info) {
        this.info = info;
    }

    public T getInfo() {
        return this.info;
    }

    public static <K> Apple<K>readObject(K a) {
        return new Apple<K>(a);
    }
}


public class GenericLearn {
    public static void main(String[] args) {
        // 由于传给T形参的是String,所以构造器参数只能是String
        Apple<String> a1 = new Apple<>("Apple");
        System.out.println(a1.getInfo());

        // 由于传给T形参的是Double,所以构造器参数只能是Double或double
        Apple<Double> a2 = new Apple<>(100.06);
        System.out.println(a2.getInfo());

        Apple<Number> a3 = Apple.readObject(2021);
        System.out.println(a3.getInfo());
    }
}
----------------------------------------------
Apple
100.06
2021

6. 支持多个泛型类型

泛型还可以定义多种类型。例如,我们希望Apple不总是存储两个类型一样的对象,就可以使用类型<T, K>同时指定泛型参数类型,例如像下面这样:

class Apple<T, K> {
    private T phone;
    private K series;

    public Apple(T phone, K series) {
        this.phone = phone;
        this.series = series;
    }

    public T readPhone() {
        return phone;
    }

    public K readNumber() {
        return series;
    }
}


public class GenericLearn {
    public static void main(String[] args) {
        // 使用的时候,需要指出两种类型 [String, Integer]
        Apple<String, Integer> a1 = new Apple<>("iphone", 12);

        System.out.println(a1.readPhone());
        System.out.println(a1.readNumber());
    }
}
-----------------------------------------------------------------
iphone
12

相关文章

  • Java泛型教程

    Java泛型教程导航 Java 泛型概述 Java泛型环境设置 Java泛型通用类 Java泛型类型参数命名约定 ...

  • 第二十八课:泛型

    泛型出现之前 泛型出现之后 Java深度历险(五)——Java泛型

  • Kotlin 泛型

    说起 kotlin 的泛型,就离不开 java 的泛型,首先来看下 java 的泛型,当然比较熟悉 java 泛型...

  • java泛型中类型擦除的一些思考

    java泛型 java泛型介绍 java泛型的参数只可以代表类,不能代表个别对象。由于java泛型的类型参数之实际...

  • Java泛型

    参考:Java知识点总结(Java泛型) 自定义泛型类 自定义泛型接口 非泛型类中定义泛型方法 继承泛型类 通配符...

  • Java泛型—Java语法糖,只在编译有作用,编译后擦出泛型

    Java泛型—Java语法糖,只在编译有作用,编译后擦出泛型 在代码进入和离开的边界处,会处理泛型 Java泛型作...

  • JAVA 核心笔记 || [xxx] 泛型

    泛型 JAVA 的参数化类型 称为 泛型 泛型类的设计 Learn12.java 运行

  • 简单回顾Java泛型之-入门介绍

    什么时候开始有了Java泛型?什么是Java泛型?为什么要引入Java泛型?什么时候用到了泛型?可不可以给泛型下一...

  • Kotlin 泛型

    Kotlin 支持泛型, 语法和 Java 类似。例如,泛型类: 泛型函数: 类型变异 Java 的泛型中,最难理...

  • JAVA-泛型

    JAVA-泛型 sschrodinger 2018/11/15 简介 泛型是Java SE 1.5的新特性,泛型的...

网友评论

    本文标题:java 泛型

    本文链接:https://www.haomeiwen.com/subject/dgfhrltx.html