java基础---泛型

目录

泛型的基本概念

引例:Stack类

泛型类的定义

案例

泛型类的使用语法

案例

改造后的Stack类

小案例:年终抽奖器(可能会是奖金,也可能是奖品)

总结:泛型类注意事项


泛型的基本概念

泛型(Generics) 是 Java 中的一种机制,它允许我们在定义类、接口和方法时使用类型参数,从而使得代码可以适用于多种数据类型。泛型的核心思想是 参数化类型,即在使用时再指定具体的类型,从而提高代码的复用性和类型安全性。

引例:Stack类

手动实现栈操作(数据先进后出)

public class Stack {
    //定义数组
    private int[] arr;
    private int i = -1;
    public Stack(int size){
        arr = new int[size];
    }

    //添加数据
    public void add(int value){
        i++;
        arr[i]= value;
    }

    //输出数据
    public int get(){
        return arr[i--];
    }
}

public class Test {
    public static void main(String[] args) {
        Stack stack = new Stack(10);
        stack.add(1);
        stack.add(2);
        stack.add(3);
        stack.add(4);
        System.out.println(stack.get());
        System.out.println(stack.get());
        System.out.println(stack.get());
        System.out.println(stack.get());
    }
}

输出结果为:

现在则出现了问题:我们实现的栈存储1234这样的数值类型的数据是没有问题的,但是如果想要存储字符串或者浮点类型的数据能存储吗?

答案是否定的。

如何解决呢?以字符串类型的数据为例:

public class StringStack {
    private String[] arr;
    private int i = -1;
    public StringStack(int size){
        arr = new String[size];
    }

    //添加数据
    public void add(String value){
        i++;
        arr[i]= value;
    }

    //输出数据
    public String get(){
        return arr[i--];
    }
}

public class Test {
    public static void main(String[] args) {
        StringStack stringStack = new StringStack(5);
        stringStack.add("北京");
        stringStack.add("上海");
        stringStack.add("保定");

        System.out.println(stringStack.get());
        System.out.println(stringStack.get());
        System.out.println(stringStack.get());
    }
}

输出结果为:

如果我们现在想要存储float或者布尔类型的数据都要重新写一个"**Stack.java",这样效率很低下。

于是乎,引出了泛型,一切类型都可以进行转换。

泛型类的定义

  • 泛型类的定义语法
class 类名称 <泛型标识、泛型标识,...> {
    private 泛型标识 变量名;
    ......
}

常用的泛型标识 T、E、K、V

  • T:表示任意类型(Type)
  • E:表示集合中的元素类型(Element)
  • K:表示键类型(Key)
  • V:表示值类型(Value)

案例

/**
 * 泛型类的定义
 * @param <T> 泛型标识-----类型形参
 *           T 创建对象的时候里面具体制定的数据类型
 */
public class Generic<T> {

    // T 是由外部使用类的时候来指定的。
    private T key;

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

    public T getKey() {
        return key;
    }

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

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

泛型类的使用语法

  • 使用语法
类名<具体的数据类型> 对象名 = new 类名<具体的数据类型>();
  • java 1.7以后,后边的<>中具体的数据类型可以省略不写
类名<具体的数据类型> 对象名 = new 类名<>();

案例

public static void main(String[] args) {
    // 泛型类在创建对象的时候来指定操作的具体数据类型
    Generic<String> stringGeneric = new Generic<>("a");
    String key = stringGeneric.getKey();
    System.out.println("key:" + key);

    System.out.println("------------------------");
    Generic<Integer> integerGeneric = new Generic<>(100);
    Integer key1 = integerGeneric.getKey();
    System.out.println("key1:"+key1);
    // 总结:泛型的本质是参数化类型,也就是所操作的数据类型被指定为一个参数。

    System.out.println("----------注意点1:--------------");
    // 泛型类在创建对象的时候,没有指定泛型类,将按照Object类型来操作
    Generic generic = new Generic("ABC");
    Object key3 = generic.getKey();
    System.out.println("key3:"+key3);
    
    System.out.println("----------注意点2:--------------");
    // 泛型类不支持基本数据类型,原因就是我们在编译期间会将这个 T 编译成 Object
    // 基本数据类型无法转化为 object类型
    // Generic<int> intGeneric = new Generic<>(100);

    System.out.println("----------注意点3:--------------");
    // 同一泛型类,根据不同的数据类型创建的对象,本质上是同一类型
    System.out.println(integerGeneric.getClass() == stringGeneric.getClass());
}

改造后的Stack类

原来的 Stack 类只能处理特定类型的数据(如 int、String),要处理其他类型的需要重复编写代码。通过使用泛型,可以将 Stack 类改造为能够处理任意类型的数据。

public class Stack<T> {
    //定义数组
    private T[] arr;
    private int i = -1;
    public Stack(int size){
        arr = (T[])new Object[size];  //object类是所有类型的子类,父类转成子类要强转
    }

    //添加数据
    public void add(T value){
        i++;
        arr[i]= value;
    }

    //输出数据
    public T get(){
        return  arr[i--];
    }
}

public class Test {
    public static void main(String[] args) {
        System.setOut(new PrintStream(System.out, true, StandardCharsets.UTF_8));
        Stack stack = new Stack(10);
        stack.add(1);
        stack.add("北京");
        stack.add(1==1);
        stack.add(10.0);
        System.out.println(stack.get());
        System.out.println(stack.get());
        System.out.println(stack.get());
        System.out.println(stack.get());
    }
}

输出结果为:

小案例:年终抽奖器(可能会是奖金,也可能是奖品)

/**
 * 抽奖器
 * @param <T>
 */
 
//ProductGetter<T> 是一个泛型类,其中<T>表示可以接受任意类型的数据,这使得该类可以适用于各种类型的奖品(如String、Integer等)
public class ProductGetter<T> {
    //用于存储抽中的奖品
    private T product;

    // 用于存储所有可能的奖品(即奖池)
    ArrayList<T> arrayList = new ArrayList<>();

    //将奖品添加到奖池arrayList中
    public void addProduct(T t){
        arrayList.add(t);
    }

    // 定义一个随机数,用来抽选奖品
    Random random = new Random();

    //抽奖
    public T getProduct(){
        product = arrayList.get(random.nextInt(arrayList.size()));
        /**random.nextInt(arrayList.size()) 会生成一个从 0 到 arrayList.size() - 1 之间的随机整数,这个整数作为索引,用于在 arrayList 中随机选择一个元素。
         arrayList.get(index) 方法用于获取 arrayList 中指定索引位置的元素。
         通过传入 random.nextInt(arrayList.size()) 作为索引,arrayList.get(...) 返回奖品池中对应位置的奖品。
         * **/

        return product;
    }
}

输出结果为:

总结:泛型类注意事项

未指定泛型类型时的默认类型:如果在使用泛型类时没有指定具体的类型参数,那么默认会将 T 视为 Object 类型。

Generic generic = new Generic("ABC"); // T 将被视为 Object 类型 Object key = generic.getKey();

泛型不支持基本数据类型:泛型的类型参数只能是包装类类型,不能是基本数据类型(如 int, char, double)。因为泛型在编译期间会被类型擦除为 Object,而基本数据类型无法直接转换为 Object。

// Generic<int> intGeneric = new Generic<>(100); // 错误 Generic<Integer> intGeneric = new Generic<>(100); // 正确

不同类型的泛型实例在运行时是同一类型:虽然泛型在逻辑上可以看作是多个不同的类型,但在运行时,它们实际上是同一类型。

System.out.println(integerGeneric.getClass() == stringGeneric.getClass()); // true

  • 13
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值