欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

java泛型

程序员文章站 2022-05-23 14:22:07
...

为什么需要泛型

在使用java集合时,我们常常见到泛型,为什么要使用泛型呢?

先看一个列子

package dj.generic;

import java.util.ArrayList;

public class ArrayListTest {

    public static void main(String[] args) {
        ArrayList list = new ArrayList();
        list.add("abc");
        list.add("ff");

        for (Object object : list) {
            String string = (String) object;
            System.out.println(string);
        }
    }

}

其中add方法参数为Object类型,在取出数据的时候,需要将类型强转过来,这个时候可能出错
java泛型

以下是错误代码

package dj.generic;

import java.util.ArrayList;

public class ArrayListTest {

    public static void main(String[] args) {
        ArrayList list = new ArrayList();
        list.add("abc");
        list.add("ff");
        //取出数据时,强转为String会出错
        list.add(1);

        for (Object object : list) {
            String string = (String) object;
            System.out.println(string);
        }
    }

}

输出信息

abc
ff
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
    at dj.generic.ArrayListTest.main(ArrayListTest.java:15)

为了防止这种情况的发生,我们引入泛型,修改以上错误代码,编译时候会提示报错

java泛型

常见的几种泛型

泛型方法、泛型类、泛型接口

泛型方法

定义泛型方法
GenericA

package dj.generic;

public class GenericA {

    public <T> void printArr(T[] arrys) {

        for (T t : arrys) {
            System.out.println(t);
        }

        System.out.println("========");
    }

    //T的作用域仅在方法上有效
    public <T> void otherT() {

    }

    //26个大写字母都可以
    public <E> void otherE() {

    }

    //可以同时声明多个泛型参数
    public <K, V> void otherKV() {

    }
}

测试
DriveTestA

package dj.generic;

public class DriveTestA {

    public static void main(String[] args) {
        // 创建不同类型数组: Integer, Double 和 Character
        Integer[] intArray = { 1, 2, 3, 4, 5 };
        Double[] doubleArray = { 1.1, 2.2, 3.3, 4.4 };
        Character[] charArray = { 'H', 'E', 'L', 'L', 'O' };

        GenericA genericA = new GenericA();

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

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

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

}

输出结果

整型数组元素为:
1
2
3
4
5
========

双精度型数组元素为:
1.1
2.2
3.3
4.4
========

字符型数组元素为:
H
E
L
L
O
========

泛型类

泛型类的声明和非泛型类的声明类似,除了在类名后面添加了类型参数声明部分。

和泛型方法一样,泛型类的类型参数声明部分也包含一个或多个类型参数,参数间用逗号隔开。
泛型变量作用域为整个类,变量,方法都可以使用

Box

package dj.generic;

public class Box<T> {
    // 变量可使用
    private T t;

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

    public T get() {
        return t;
    }
}

测试方法
DriveTestA

package dj.generic;

public class DriveTestA {

    public static void main(String[] args) {
        Box<Integer> integerBox = new Box<Integer>();
        Box<String> stringBox = new Box<String>();

        integerBox.add(new Integer(10));
        stringBox.add(new String("使用菜鸟教程上的列子"));

        System.out.printf("整型值为 :%d\n\n", integerBox.get());
        System.out.printf("字符串为 :%s\n", stringBox.get());
      }

}

输出结果

整型值为 :10

字符串为 :使用菜鸟教程上的列子

个人理解,改操作相当于为类规定了某些内部变量使用类型

泛型接口

定义一个泛型接口
InterfaceGeneric

package dj.generic;

public interface InterfaceGeneric<T> {

    void test(T t);

}

实现泛型接口时候,指明类型

package dj.generic;

public class ImplGeneric implements InterfaceGeneric<String> {

    @Override
    public void test(String t) {
        System.out.println(t);
    }


}

若不指明类型,该变量类型相当于Object
java泛型

类型通配符

通配符一般有三种表现形式

1.一般是使用?代替具体的类型参数。

package dj.generic;

import java.util.ArrayList;

public class ArrayListTest {
    //以下语句都是正确的
    public static void main(String[] args) {
        ArrayList<Object> list = new ArrayList<Object>();
        ArrayList<?> list2 = new ArrayList<Object>();

        ArrayList<?> list3 = new ArrayList<String>();

    }

}

其中:通配符?与Object不能理解为互等
看一个通配符列子
java泛型

List<?> 在逻辑上是List<String>,List<Integer> 等所有List<具体类型实参>的父类。而**List<Object>是与List<String>,List<Integer> 等平级**

2.上边界

类型通配符上限通过形如List来定义,如此定义就是通配符泛型值接受Number及其下层子类类型。
GenericTest

package dj.generic;

import java.util.ArrayList;
import java.util.List;

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);

        //getUperNumber(name);//错误
        getUperNumber(age);// 2
        getUperNumber(number);// 3

    }

    public static void getData(List<?> data) {
        System.out.println("data :" + data.get(0));
    }

    public static void getUperNumber(List<? extends Number> data) {
        System.out.println("data :" + data.get(0));
    }
}

name变量类型为String,不属于? extends Number,属于错误类型

3.下边界

下界关键字为<? supers Number>,这里不举例说明,和上边界相反

如何理解上下边界

package dj.generic;

public class A {

}

package dj.generic;

public class B extends A {

}
package dj.generic;

public class C extends B {

}
package dj.generic;

public class D extends C {

}

java泛型

<? extends T> 是定义上边界,? >= T
<? super T> 是定义下边界,? <= T

说明

<? extends T>和<? super T>的区别

<? extends T>表示该通配符所代表的类型是T类型的子类。
<? super T>表示该通配符所代表的类型是T类型的父类。
相关标签: 泛型