java泛型

为什么需要泛型

在使用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类型,在取出数据的时候,需要将类型强转过来,这个时候可能出错
这里写图片描述

以下是错误代码

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)

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

这里写图片描述

常见的几种泛型

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

泛型方法

定义泛型方法
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
这里写图片描述

类型通配符

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

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不能理解为互等
看一个通配符列子
这里写图片描述

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 {

}

这里写图片描述

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

说明

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

<? extends T>表示该通配符所代表的类型是T类型的子类。
<? super T>表示该通配符所代表的类型是T类型的父类。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值