Java 泛型

泛型(Generic)
    在编译阶段识别泛型,但是在jvm运行之前就将泛型的痕迹擦除
    泛型即参数化类型,在jdk1.5的版本之后才开始的概念
    参数化类型?
        将一种数据类型以参数的形式传递给类,接口,方法中
    好处:可以将运行期间的问题提前到编译阶段进行检查
    泛型接口:
        public interface List<E> extends Collection<E>{}
    泛型类:
        public class ArrayList<E>
            extends AbstractList<E>
            implements List<E>, RandomAccess, Cloneable, Serializable
    泛型方法:
        static <T> List<T>            asList(T... a)
                                           返回有指定数组支持的固定大小的列表

    泛型标记命名是可以自定义的
        jdk中常见的泛型的名称有:
            K(key键)
            V(value值)
            E(Element元素)
            T(Type类型)
            <?>通配符 任意的类型都可以 Object


public class MyClass<I,F,D> {
    //访问控制修饰符 返回值数据类型 方法名(参数列表){
    //          方法体;
    // }
    public I add(I a,I b){
        System.out.println(a);
        System.out.println(b);
        return null;
    }
    public static void main(String[] args){
        //创建对象的时候指定数据类型
        MyClass<Integer,Float,Double> mc = new MyClass<>();
        Integer x = mc.add(10,20);

        MyClass<Double,Float,Integer> m = new MyClass<>();

    }
}



    泛型上下边界的限定<? extends E><? super E>
    <? extends E> 是 Upper Bound(上限)的通配符,用来限制元素的类型的上限的 比如:
    List<? extends Fruit> fruits;
    表示集合中的元素类型上限为Fruit类型,即只能是Fruit或者Fruit的子类,因此对于下面的
    赋值合理的是:
        fruits = new ArrayList<Fruit>();
        fruits = new ArrayList<banana>();
    如果集合中的元素类型为Fruit的父类就会出现错误,比如:
    fruits = new ArrayList<Object>();//出现编译不通过的情况

            /**
             * 1、写入:
             *  因为集合fruits中装的元素类型为Fruit或者它的子类,直觉告诉我们,往集合中添加一个
             *  fruit类型的元素或者它的子类对象是可行的
             *      fruits.add(new Fruit());
             *      fruits.add(new Banana());
             *  结果都是编译不通过.为什么呢?
             *      因为<? extends Fruit>只能够告诉编译器,集合中元素类型的上限,但是具体是什么
             *      类型编译器不知道,fruits可以指向ArrayList<Fruit>,也可以指向:ArrayList<Banana>
             *      ArrayList<Apple>,也就是说它的类型是不确定的,既然不确定,为了安全性起见,
             *      编译器只能阻止添加元素
             *
             *  2、读取
             *      无论fruits指向指向什么,编译器都可以确定获取的元素是Fruit类型,
             *      所以读取集合中的是被允许操作的,代码是可以编译通过的
             *
             */



    <? super E>是Lower Bound(下限)的通配符,用来限制元素的类型下限,比如:
        List<? super Apple> apples;
        表示集合中的元素的类型下限是Apple类型,即只能是Apple或者Apple的父类,
        因此合理的赋值:
            apples = new ArrayList<Apple>();
            apples = new ArrayList<Fruit>();
            apples = new ArrayList<Object>();

        如果Apple的兄弟类和子类会编译失败

                /**
                 * 写入:
                 *      因为apples中装得元素是Apple或者Apple的父类,我们无法确定是哪个具体的但是,
                 *  但是可以确定Apple就是Apple,所以可以添加进去一个元素。
                 *      如果apple还有子类,Apple和Apple的子类和一个不确定类型的类:比如隔壁的banana
                 *  就无法正常兼容,我们可以添加apple但是为了安全性起见,不能添加别的类进来
                 *
                 * 读取:
                 *      无法确定读取出来的是什么类型,所以给到了一个Object类型的变量中,
                 *      然后需要进行强制转换
                 */
public class Animal {
}

--------------------------------------------------------

public class Cat extends Animal{
}

--------------------------------------------------------

public class Dog extends Animal{
}

--------------------------------------------------------



public class Test {
    public static void main(String[] args) {
        //上限:
        //<? extends 父类>
        //ArrayList<? extends Animal> animals = new ArrayList<Object>();
        ArrayList<? extends Animal> animals = new ArrayList<Animal>();
        ArrayList<? extends Animal> animals1 = new ArrayList<Dog>();
        ArrayList<? extends Animal> animals2 = new ArrayList<Cat>();

        //下限
        //<? super 子类>
        ArrayList<? super Dog> dogs = new ArrayList<Object>();
        ArrayList<? super Animal> arrayList = new ArrayList<Animal>();
        ArrayList<? super Dog> dogs1 = new ArrayList<Dog>();
        //ArrayList<? super Dog> dogs2 = new ArrayList<Cat>();


        //赋值
        ArrayList<Dog> dogs2 = new ArrayList<Dog>();
        dogs2.add(new Dog());
        dogs2.add(new Dog());
        dogs2.add(new Dog());
        ArrayList<? extends Animal> animals3 = dogs2;
        System.out.println(animals3.size());

        ArrayList<Animal> animals4 = new ArrayList<Animal>();
        animals4.add(new Animal());
        animals3 = animals4;
        System.out.println("----" + animals3.size());

        ArrayList<Object> objects = new ArrayList<Object>();
        objects.add(new Object());
        //ArrayList<? extends Animal> animals4 = objects;

        ArrayList<Dog> dogs3 = new ArrayList<Dog>();
        dogs3.add(new Dog());

        ArrayList<? super Dog> dogss = dogs3;
        dogss = objects;
        dogss = animals4;




    }
}

JavaJava中一种强大的特性,允许编写类安全且可重用的代码,能创建灵活的组件处理不同数据类,同时保持代码的简洁性和可读性,对于编写高质量Java程序至关重要[^2]。 ### 基本概念 通俗理解,让类可以像方法的参数一样传递。例如`List<String>`中的`String`就是类参数,它告知编译器该`List`只能存放`String`类的对象[^3]。 ### 使用场景 - **类安全**:在没有时,需要强制类转换,容易导致`ClassCastException`,而使用能在编译时检查类安全,避免运行时异常。 - **代码复用**:不使用时,为不同类需要编写相似的代码,使用一套代码就可以适用于多种类。 - **代码清晰度**:没有时,需要查看文档或注释才能知道集合中存储的类,使用可直接从类声明了解集合中存储的类[^3]。 ### 使用方法 #### 类 在实例化类的时候指明的具体类。例如: ```java class Box<T> { private T t; public void set(T t) { this.t = t; } public T get() { return t; } } // 使用 Box<String> stringBox = new Box<>(); stringBox.set("Hello"); String value = stringBox.get(); ``` #### 方法 在调用方法的时候指明的具体类。示例如下: ```java public <T> T genericMethod(Class<T> tClass) throws InstantiationException, IllegalAccessException { T instance = tClass.newInstance(); return instance; } // 使用 try { String str = genericMethod(String.class); } catch (InstantiationException | IllegalAccessException e) { e.printStackTrace(); } ``` ### 通配符 在代码中,问号`?`称为通配符,用来表示未知类。通配符可在多种情况下使用,如作为参数、字段或局部变量的类,有时也可作为返回类,但永远不会用作调用方法、创建类或超类实例的类参数。例如: ```java public static void printList(java.util.List<?> list) { for (Object element : list) { System.out.println(element); } } ``` ### 原理 Java是通过类擦除实现的。在编译时,编译器会把信息擦除,替换为原始类(如`List<String>`会被擦除为`List`),并在必要的地方插入类转换代码,以保证类安全。 ### 最佳实践 - **合理使用类和方法**:根据实际需求选择合适的形式,若类参数与类的整体相关,可使用类;若只与某个方法相关,则使用方法。 - **使用通配符提高灵活性**:当需要处理不同的集合时,合理使用通配符能提高代码的灵活性和复用性。 - **注意类擦除的影响**:由于类擦除,在运行时无法获取的具体类信息,编写代码时需考虑这一点。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小猿king

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

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

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

打赏作者

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

抵扣说明:

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

余额充值