Java泛型

1、为什么需要泛型

 先举个例子:List list=new ArrayList();(list中参数是Object类型,所以可以添加任何类型的元素(子类))

则list.add(“lucy”);

list.add(1);

list.add(new Person()); 所以这个列表中就有三种不同类型的元素了,因为元素类型不同,所以他们可以执行不同的操作。每对一个元素进行一系列操作时都要使用for(int i=0;i<list.size();i++){ }判断元素的类型,才能执行不同的操作,这样会耗费大量的资源。

并且以上操作存在一些问题:当我们将一个对象放入集合中,集合不会记住此对象的类型,当再次从集合中取出此对象时,这个对象的编译类型变成了Object类型,但其运行时类型依然为其本身类型。因此,取出集合元素时需要人为的强制类型转化到具体的目标类型,且很容易出现
“java.lang.ClassCastException”异常。
那么有没有什么办法可以使集合能够记住集合内元素各类型,且能够达到只要编译时不出现问题,运行时就不会出现“java.lang.ClassCastException”异常呢?答案就是使用泛型。

2、什么是泛型

 泛型(Generic),此技术的最大特点是类中的属性的类型可以由外部决定。泛型,即“参数化类型”。通俗的讲,就是讲类型变成参数,在使用时将其传入具体类型。

Java源码中就有许多示例,例如:

 Comparator这个接口就使用了泛型。

又或者使用了泛型的列表:

List<String> list = new ArrayList<String>();此时列表就只能传入String类型的数据,方便了后续的一系列操作。如果此时再写list.add(100); 那就会在 编译期就发生错误。
(注意:泛型只是作用于代码编译阶段,在编译过程中,对于正确检验泛型结果后,会将泛型的相关信息擦除,也就是说,成功编译过后的class文件中是不包含任何泛型信息的。泛型信息不会进入到运行时阶段。)

3、自定义泛型接口、泛型类

 用法示例:

public class Demo {
        private static Object Demo;

        public static void main(String[] args) {
            person1<String> p =new person1<String>();
            System.out.println(p.play("张飞"));
        }
}
class person1<T>
{
    T name;
    int age;

    public person1() {
    }

    public person1(T name, int age) {
        this.name = name;
        this.age = age;
    }

    public T getName()
    {
        return name;
    }

}
interface play<T>
{
    public T play();
}

运行结果:

张飞 

4、通配符

 问题:

person1<Number> a1 = new person1<Number>();
person1<Integer> a2 = new person1<Integer>();
a1=a2;

此时发现转换异常,虽然Integer是Number的子类,但是此时不能转换。
public static void getData(Node<Number> data) {
System.out.println("data :" + data.getData());
}
此时,我们可以使用通配符来解决
“?”表示的是可以接收任意的泛型类型,但是只是接收输出,并不能修改。
public static void getData(Node<?> data) {
System.out.println("data :" + data.getData());
}

<?>只提供了一个只读的功能,它去除了增加具体元素的能力,只保留与具体类型无关的功能。

使用通配符可以引用其他各种参数化类型,通配符定义的变量主要用作引用,可以调用与参数无关的方法,不能调用与参数有关的方法。
用法示例:
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.*;

public class Demo {
        private static Object Demo;

        public static void main(String[] args) {
            person1<Number> p =new person1<>(10,18);
            person1<Integer> p1 =new person1<>(20,18);
            p.getData1(p);
            p.getData1(p1);


        }
}
class person1<T> implements play<T>
{
    T name;
    int age;

    public person1() {
    }

    public person1(T name, int age) {
        this.name = name;
        this.age = age;
    }

    public void setName(T name) {
        this.name = name;
    }

    public T getName()
    {
        return name;
    }

    @Override
    public T play(T name) {
        return name;
    }
    public void getData1(person1<?> p){
        System.out.println(p.name);
    }
}
interface play<T>
{
    public T play(T name);
}

运行结果:

10

20

5、泛型方法

 泛型除了在类中定义之外,还可以在方法上定义,而且在方法上使用泛型,此方法所在的类不一定是泛型的操作类。
定义一个方法,实现任意类型数组中两个位置值的调换
public static <T> T[] func(T[] array,int i,int t){
T temp = array[i];
array[i] = array[t];
array[t] = temp;
return array;
}

6、泛型的嵌套使用

Java在Map中的entrySet实现了Set接口,里面存放的是键值对。一个K对应一个V

Set<Map.Entry<K, V>> entrySet();

传入具体类型后: Set<Map.Entry<Integer, String>> entrySet = map.entrySet();

这就属于泛型的嵌套使用。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

心态特好

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

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

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

打赏作者

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

抵扣说明:

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

余额充值