泛型的基本介绍

本文深入浅出地介绍了Java泛型的基本概念,包括泛型的作用、泛型擦除、泛型类、泛型接口、泛型方法等核心内容,并探讨了泛型通配符的使用方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.为什么需要泛型?泛型是什么?

public class WhyGeneric {
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add("aaa");
        list.add(111);
        for (int i = 0; i < list.size(); i++) {
            String s = (String) list.get(i);
            System.out.println(s);
        }
    }
}

上面例子运行会报ClassCastException错误,list里面放入了String和Integer类型的数据,编译时不报错,读取运行时报错,加上泛型在编译时我们就不能给集合中添加两种以以上类型的数据。

泛型是参数化的类型,在具体使用的过程中才会变成具体的类型。泛型的类型不可以是基本类型,只能是引用类型!

2.泛型擦除

    @Test
    public void caiChu() {
        List<String> L1 = new ArrayList<String>();
        List<Integer> L2 = new ArrayList<Integer>();
        Class c1 = L1.getClass();
        Class c2 = L2.getClass();
        if(L1.equals(L2)) {
            System.out.println("泛型擦除了");
        }
    }

输出结果是“泛型擦除了”,证明在字节码中泛型就消失了。

3.泛型的使用:

  • 泛型类
/**
 * Created by Alsidun on 2018/7/12.
 * 泛型类
 */
public class Generic<T> {
    private T key;

    public Generic(T key) {
        this.key = key;
    }

    public T getKey() {
        return key;
    }
}  

public class TestGenericClass {
    public static void main(String[] args) {
        Generic<String> gs = new Generic<String>("abc");
        Generic<Integer> gi = new Generic<>(1);

        System.out.println("传入的参数是 " + gs.getKey());
        System.out.println("传入的参数是 " + gi.getKey());

        //这里不指定参数类型,那么就是Object
        Generic ga = new Generic(1);
        Generic gb = new Generic(1.5555);
        Generic gc = new Generic(false);

        System.out.println("传入的参数是 " + ga.getKey());
        System.out.println("传入的参数是 " + gb.getKey());
        System.out.println("传入的参数是 " + gc.getKey());
    }
}
/*
传入的参数是 abc
传入的参数是 1
传入的参数是 1
传入的参数是 1.5555
*/

上面的例子定义了一个泛型类及它的使用,只有在类实例化时才知道这个类的具体成员参数类型

定义的泛型类,不一定要传入泛型实参,在使用泛型的时候如果传入泛型实参,则会根据传入的泛型实参做相应的限制,此时泛型才会起到本应起到的限制作用。如果不传入泛型类型实参的话,在泛型类中使用泛型的方法或成员变量定义的类型可以为任何的类型

  • 泛型接口
/**
 * Created by Alsidun on 2018/7/12.
 */
public interface GenericIntface<T> {
    T say();
}

/**
 * 未传入泛型实参时,与泛型类的定义相同,在声明类的时候,需将泛型的声明也一起加到类中
 * AnimalGeneric implements GenericIntface<T>  报错!!!
 * @param <T>
 */
class GenericImpl<T> implements GenericIntface<T> {
    @Override
    public T say() {
        return null;
    }
}

/**
 * 在实现类实现泛型接口时,如已将泛型类型传入实参类型,则所有使用泛型的地方都要替换成传入的实参类型
 */
class AnimalGeneric implements GenericIntface<String> {
    private String[] animal = new String[]{"dog", "cat", "pig"};
    @Override
    public String say() {
        System.out.println("输出狗 " + animal[0]);
        return animal[1];
    }

    public static void main(String[] args) {
        AnimalGeneric ag = new AnimalGeneric();
        ag.say();
    }
}
  • 泛型方法
    泛型方法是指在调用方法的时候在指明方法的参数类型

public <T> T show(Generic<T> container)

/**
 * Created by Alsidun on 2018/7/12.
 * 泛型方法
 */
public class GenericFruit  {
    static class Fruit {
        @Override
        public String toString(){
            return  "fruit";
        }
    }

    static class Apple extends Fruit {
        @Override
        public String toString() {
            return "apple";
        }
    }

    static class Animal {
        @Override
        public String toString() {
            return "person";
        }
    }

    static class GenericTest<T> {
        public void show1(T t) {
            System.out.println("输出 " + t.toString());
        }

        //此处的泛型可以和泛型类相同也可不同
        public <T> void show2(T t) {
            System.out.println("输出 " + t.toString());
        }

        public <E> void show3(E t) {
            System.out.println("输出 " + t.toString());
        }
    }

    public static void main(String[] args) {
        /*成员方法,变量,内部类同一级别,必须通过类的实例调用
        * 静态方法里面不可以访问外部类的非静态变量,普通内部类(都是静态才可访问)
        * 静态访问静态
        * */
        Apple apple = new Apple();
        Animal animal = new Animal();

        GenericTest<String> gs = new GenericTest<String>();
        GenericTest<Fruit> gf = new GenericTest<Fruit>();

        gs.show1("abc");
        gf.show1(apple);
        //gf.show1(animal);  无法编译通过
        gf.show2(apple);
        gf.show2("qwe");
        gf.show2(animal);
        gf.show3(apple);
        gf.show3(animal);
    }
}

这里会输出对应的对象

4.泛型的通配符
向上转型问题

public void printList(List<Integer> nums) {
        System.out.println("打印数字");
    }

比如存在一个这样的方法,如果传入List型参数,会发现编译报错,尽管Integer是Number的子类,但是这里不能向上转型,与多态理念违背

可以将上述方法的形参改成List<?>类型,使用通配符,此处’?’是类型实参,而不是类型形参,和Number、String、Integer一样都是一种实际的类型,可以把?看成所有类型的父类。是一种真实的类型

这样就可以传入任意类型的list集合参数,为了防止运行错误,我们可以使用List<? extends List>和List<? super List>来对泛型进行限制。

使用时不知道类型使用通配符
ArrayList<?>代表Object
ArrayList<? extends List> List及其子类
ArrayList<? super List> List及其父类

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值