java泛型

8 篇文章 0 订阅
本文介绍了Java泛型的基本概念,包括类型参数化、目的(提高代码灵活性、可重用性和安全性)、泛型类和接口的使用示例,以及类型擦除、类型通配符和泛型数组等内容。
摘要由CSDN通过智能技术生成

什么是泛型:

泛型(Generics)是一种在编程语言中用于创建可重用代码的机制。它允许我们在定义类、接口或方法时使用一个或多个类型参数,以便在使用时指定具体的类型。

泛型的本质就是参数化类型,也就是所操作的数据类型被指定为一个参数。

目的:

泛型的主要目的是增加代码的灵活性和可重用性,同时提高代码的安全性和可读性。通过使用泛型,我们可以在不同的场景下使用相同的代码逻辑,只需改变传入的类型参数即可。

JAVA推出泛型以前,程序员可以构建一个元素类型为Object
的集合,该集合能够存储任意的数据类型对象,而在使用该集合的过程中,需要程序员明确知道存储每个元素的数据类型,否则很容易引发ClassCastException异常。

Java泛型(generics)是JDK5中引入的一个新特性,泛型提供了编译时类型安全监测机制,该机制允许我们在编译时检测到非法的类型数据结构。

以list集合为例

类型进行了参数化,其类型类型可以定义成许多种如下

好处在于不用我们自己进行类型转换,且编译期间检查类型,类型安全,消除强制转换。

泛型类型

package com.System;


/**
 * @author cqh
 * @date 2024/1/8
 * @Description
 */
//T 是类型型参
public class FanXIng<T> {

    // T 作为成员变量类型
    private T key;

    // T 作为参数类型
    public FanXIng(T key){
        this.key=key;
    }


    // T 作为返回类型
    public T getKey() {
        return key;
    }

    // T 作为参数类型
    public void setKey(T key) {
        this.key = key;
    }

    @Override
    public String toString() {
        return "FanXIng{" +
                "key=" + key +
                '}';
    }
}

package com.System;

/**
 * @author cqh
 * @date 2024/1/8
 * @Description
 */
public class FanXingTest {
    public static void main(String[] args) {
        FanXIng<String> stringFanXIng = new FanXIng<String>("你好!");
        System.out.println("stringFanXIng = " + stringFanXIng.getKey());

        FanXIng<Integer> integerFanXIng = new FanXIng<Integer>(100);
        System.out.println("integerFanXIng = " + integerFanXIng.getKey());


    }
}

泛型类不支持基本数据类型

同一泛型类根据不同类型创建的对象本质上是一个类型

泛型类派生子类 

 父类

子类

错误写法 

 正确写法

不写父类参数类型默认父类为Object类型 

子类可以泛型扩展但前提是包装有一个与父类相同的参数类型

泛型派生子类中如果子类不是泛型类而是继承父类,父类必须设置具体类型

错误

正确

泛型接口

实现类不是泛型类,接口要明确数据类型
实现类也是泛型类,实现类和接口的泛型类型要一致
 泛型接口

package com.System;

/**
 * @author cqh
 * @date 2024/1/8
 * @Description
 */
public interface Generator<T> {
    T getKey();

}

实现类不是泛型类

第一种泛型接口不使用类型参数 默认类型返回Object

package com.System;

/**
 * @author cqh
 * @date 2024/1/8
 * @Description
 */
public class FanXingTest2 implements Generator {
    @Override
    public Object getKey() {
        return null;
    }
}

第二种一个确定泛型接口类型

实现类是泛型类 与泛型类的派生差不多

正确

package com.System;

/**
 * @author cqh
 * @date 2024/1/8
 * @Description
 */
public class FanXingTest2<T> implements Generator<T> {


    @Override
    public T getKey() {
        return null;
    }
}

 

泛型扩充

泛型接口的实现类,是一个泛型类,那么要保证实现接口的泛型类泛型标识包含泛型接口的泛型标识

package com.System;

/**
 * @author cqh
 * @date 2024/1/8
 * @Description
 */
public class FanXingTest2<T,E> implements Generator<T> {

    private T key;
    private E value;

    public FanXingTest2() {
    }

    public FanXingTest2(T key, E value) {
        this.key = key;
        this.value = value;
    }

    @Override
    public T getKey() {
        return key;
    }

    public void setKey(T key) {
        this.key = key;
    }

    public E getValue() {
        return value;
    }

    public void setValue(E value) {
        this.value = value;
    }

    @Override
    public String toString() {
        return "FanXingTest2{" +
                "key=" + key +
                ", value=" + value +
                '}';
    }
}

错误 

泛型方法 

泛型类,是在实例化类的时候指明泛型的具体类型。
泛型方法,是在调用方法的时候指明泛型的具体类型。

写法

 

使用 

 注意:

普通泛型类成员方法采用类类型不能使用static修饰

而泛型方法可以 

泛型方法可变参数

    public static <E>void  print(E... e){
        for (int i = 0; i < e.length; i++) {
            System.out.println("e = " + e[i]);
        }
    }

类型通配符

类型通配符一般是使用"?"代替具体的类型实参。
所以,类型通配符是类型实参,而不是类型形参。
 

问题

通配符解决

package com.System;

/**
 * @author cqh
 * @date 2024/1/8
 * @Description
 */
public class BoxTst {
    public static void main(String[] args) {

        Box<String> stringBox = new Box<>();
        stringBox.setFirst("你好");
        showBox(stringBox);

        Box<Integer> integerBox = new Box<>();
        integerBox.setFirst(100);
        showBox(integerBox);

    }


    public static void showBox(Box<?> box){
      Object first = box.getFirst();
        System.out.println("first = " + first);
    }
}

类型通配符上限 

要求该泛型的类型,只能是实参类型,或实参类型的子类类型。
 

 不能填充元素

类型通配符下限 

 

泛型通配符下限在比较器中的应用

 在上面几个实体类中分别加入属性并实现构造方法

 

 

然后编写测试类及自定义比较器实现类进行实验发现

package com.demo2;

import java.util.Comparator;
import java.util.TreeSet;

/**
 * @author cqh
 * @date 2024/1/12
 * @Description
 */
public class Test02 {
    public static void main(String[] args) {
        TreeSet<Cat> cats = new TreeSet<>(new MyComparator1());
        //TreeSet<Cat> cats = new TreeSet<>(new MyComparator2());
        //TreeSet<Cat> cats = new TreeSet<>(new MyComparator3());
        cats.add(new Cat("jerry",21));
        cats.add(new Cat("amy",13));
        cats.add(new Cat("franck",27));
        cats.add(new Cat("jim",18));
        cats.forEach(cat -> System.out.println("cat = " + cat));
    }


}

class MyComparator1 implements Comparator<Animal>{

    @Override
    public int compare(Animal o1, Animal o2) {
        return o1.name.compareTo(o2.name);
    }
}


class MyComparator2 implements Comparator<Cat>{

    @Override
    public int compare(Cat o1, Cat o2) {
        return o1.age - o2.age;
    }
}

class MyComparator3 implements Comparator<MiniCat>{

    @Override
    public int compare(MiniCat o1, MiniCat o2) {
        return o1.level - o2.level;
    }
}

第一个按照名字字母顺序排序了

第二个按照年龄从小到大排列了 

然而第三个报错了

原因是第三个比较器是使用cat 的子类minicat的level 来进行比较的但是cat中没有level所有报错了

泛型擦除

概念

泛型是Java 1.5版本才引进的概念,在这之前是没有泛型的,但是,泛型代码能够很好地和之前版本的代码兼容。那是因为,泛型信息只存在于代码编译阶段,在进入JVM之前,与泛型相关的信息会被擦除掉,我们称之为--类型擦除。

上面虽然ArrayList分别是integer和String 类型但本质还是arraylist 并且是同一个类

 

编译运行后进行类型擦除这里是无限制类型擦除

有限制类型擦除

编译器运行后将类型转化为上限类型

擦除方法中类型定义参数

桥接方法

 泛型数组

创建注意

可以声明带泛型的数组引用,但是不能直接创建带泛型的数组对象

但可以先创建一个集合数组然后将字符数组集合指向该集合数组

但当创建一个Integer类型的集合并存入一个元素后,将该集合添加到字符集合中取得时候就会出现问题

这样是可以的

正确写法1


可以通过java.lang.reflect.Array的newInstance(Class<T>,int)创建T[]数组

创建泛型数组

完整代码

package com.demo5;

import com.System.FanXIng;

import java.lang.reflect.Array;
import java.util.ArrayList;

/**
 * @author cqh
 * @date 2024/1/12
 * @Description
 */
public class Fruit<T> {

    private T[] array;

    public Fruit(Class<T> clz,int length){
        array= (T[])Array.newInstance(clz,length);
    }

    // 填充数组元素
    public void put(int index,T item){
        array[index] =item;
    }

    // 获取数组元素
    public T get(int index){
        return array[index];
    }

    public T[] getArray(){
        return array;
    }
}

 

 

泛型和反射

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值