张小飞的Java之路——第三十五章——泛型类

文章讨论了泛型类的概念,通过对比非泛型类和对象,解释了泛型类如何提高代码的重用性和安全性。举例说明了泛型类在处理不同数据类型时避免类型转换错误的作用,并阐述了何时及如何使用泛型类,包括成员方法和成员变量中使用泛型的注意事项。

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

写在前面:

视频是什么东西,有看文档精彩吗?

视频是什么东西,有看文档速度快吗?

视频是什么东西,有看文档效率高吗?


泛型类

诸小亮:接着我们聊一聊——泛型类

张小飞:泛型类是什么意思?

诸小亮:泛型类——在定义类时,使用:类名<泛型> 这种形式的都是泛型类,比如:

//<T>:表示定义一个泛型T,T:是随便起的名字,可以小写,但一般都是大写
class Tool<T>{//如果要定义多个泛型,使用逗号分隔,比如:<T,E>

}

张小飞:Tool 就是一个泛型类?就这么简单?

诸小亮:没错,就这么简单,集合框架中的 ArrayList、LinkedList、HashSet等都是泛型类

为什么需要泛型类?

张小飞:原来如此,我听说泛型可以——提高代码的重用性和安全性

诸小亮:是的,

张小飞:能否具体说一说?

诸小亮:来,我们自定义一个集合类,用于处理 Hero 类型的数据

public class HeroList {
    //用于测试,只存储 10 个对象
    private Hero[] items = new Hero[10];
    private int size = 0;

    public void add(Hero item) {
        items[size++] = item;
    }

    public Hero get(int index) {
        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
        }
        return items[index];
    }
}

张小飞:然后呢?

诸小亮:如果现在又想自定义一个集合类,处理 Person 类型的数据,怎么办?

张小飞:这还不简单,看我的

public class PersonList {
    //用于测试,只存储 10 个对象
    private Person[] items = new Person[10];
    private int size = 0;

    public void add(Person item) {
        items[size++] = item;
    }

    public Person get(int index) {
        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
        }
        return items[index];
    }
}

诸小亮:你有没有发现一个问题,HeroList 和 PersonList 代码都差不错,非常相似

张小飞:嗯,发现了,那,这样行不行?

public class ObjectList {
    //用于测试,只存储 10 个对象
    private Object[] items = new Object[10];
    private int size = 0;

    public void add(Object item) {
        items[size++] = item;
    }

    public Object get(int index) {
        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
        }
        return items[index];
    }
}

诸小亮:这样做确实节省了一些代码量,不过操作都是 Object 啊

张小飞:有什么问题吗?

诸小亮:因为 Object 是所有类的父类,所以可以添加任何类型的数据

但在使用时可能需要进行类型转换,而类型转换可能会引起运行时错误,比如:

ObjectList list = new ObjectList();
list.add("Hello");
String s = (String) list.get(0);

张小飞:这也没什么问题啊

诸小亮:不要着急,还没有写完呢,看下面

list.add(123);
String s = (String) list.get(1); 

张小飞:你添加了一个 int 类型,取出来的时候转换为 String ,肯定报错啊

诸小亮:是啊,那应该怎么办呢?

张小飞:可以先用 instanceof 判断它是什么类型的

诸小亮:判断?每个类都是一种数据类型,你怎么判断?

张小飞:这。。。。

诸小亮:这个时候就可以使用泛型,看下面代码

public class ObjectList<T> {
    //用于测试,只存储 10 个对象
    private T[] items = new T[10];
    private int size = 0;

    public void add(T item) {
        items[size++] = item;
    }

    public T get(int index) {
        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
        }
        return items[index];
    }
}

诸小亮:使用泛型类型 T 数组存储元素,将 add() 方法的参数类型设置为 T,get() 方法的返回值类型也是 T

GenericList<String> list = new GenericList<>();
list.add("Hello");
String s = list.get(0);  // 不需要进行类型转换

诸小亮:使用泛型类的好处

  • 提高代码复用率
  • 在编译时就可以检查类型安全性,避免在运行时出现类型转换错误;
  • 可以避免使用时进行类型转换,代码更加简洁、易读;

张小飞:明白了,不过具体说明时候使用泛型类呢?

诸小亮:当需要操作的数据类型不明确时,就应该使用泛型,具体操作那种类型,然用户在使用时自己指定

成员方法中使用泛型

诸小亮:在泛型类中的方法中使用泛型,还需要注意两点

张小飞:哪两点?

诸小亮:在类上定义过泛型后,在方法上可以直接使用

//<T>:表示定义一个泛型T,T:是随便起的名字,可以小写,但一般都是大写
class Tool<T>{

    //因为,类上已经定义,索引方法中就可以使用 T 这种类型,
    //当前方法,参数是T类型,返回值也是T类型
    //也就是说,参数和返回值必须是同一种类
    public T assemble(T t){
        //TODO 各种配置
        return t;
    }
}

使用:

public static void main(String[] args) throws Exception {
    Tool<Hero> tool = new Tool<Hero>();//可以简写:Tool<Hero> tool = new Tool<>();
    //1. assemble 既可以处理 Hero 类型的数据
    Hero yase = tool.assemble(new Hero("yase"));

    //2. 也可以处理 Person 类型的数据
    Tool<Person> tool = new Tool<Person>();
    Person lvbu = tool.assemble(new Person("lvbu"));
}

张小飞:了解

诸小亮:另外,如果创建Tool对象时候,没有指定类型,则:

image.png

诸小亮:因为 tool 对象创建时没有指定类型,所以 assemble 的返回值,只能使用 Object 接收

张小飞:使用 Hero 接收,竟然直接报错:

image.png

诸小亮:是的,所以做好是提前指定泛型

张小飞:明白了

成员变量使用泛型

张小飞:泛型类种的普通成员变量也可以直接使用泛型吗?

诸小亮:当然可以,比如:

//<T>:表示定义一个泛型T,T:是随便起的名字,可以小写,但一般都是大写
class Tool<T>{

    T name;//表示name属于T类型
}

使用:

public static void main(String[] args) {
    Tool<String> tool = new Tool<String>();
    //name 属性,这时候只能存储String
    tool.name = "yase";

    Tool<Integer> tool2 = new Tool<Integer>();
    //name 属性,这时候只能存储Integer
    tool2.name = 110;
}

张小飞:如果创建 Tool 对象时候,没有指定类型呢?

诸小亮:那就什么类型都可以设置了,比如:

image.png
上图,name既可以是字符串,又可以是数字,但是一般不推荐这样使用
原因:

  • 使用泛型的目的就是为了限定数据类型
  • 如果使用上图的方式,还不如定义name属性时候:Objec name;

泛型类注意点

诸小亮:如果类名那里没有定义泛型,那么在类的成员中不能随意使用,比如:

image.png

上图,因为类名那里没有定义T,所以 属性、方法 中不能随意使用

诸小亮:另外,静态方法中不能使用类名上定义的泛型

image.png

张小飞:嗯嗯,我记下了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值