泛型的简单介绍和使用

一、泛型出现的背景

早期Java是使用Object来代表任意类型的,这样使用会出现两个问题:

  • Collection、Map集合对元素的类型无法做限制。本来我的Collection集合想装载的只能是Dog对象,但是外边把Cat对象存储到集合中,是没有任何语法错误的。
  • 把对象扔进集合中,集合是不知道元素的类型是什么的,仅仅知道是Object。因此在get()的时候,返回的是Object,还需要强制转换。

为了解决这两个问题,泛型应运而生,我们通过泛型可以限制某个类(常应用在集合类中)中元素的类型,并且get时不需要进行强转。

二、自定义一个简单的泛型类

public class GenericTest<T> {

    private T genericValue;

    public T getGenericValue() {
        return genericValue;
    }

    public void setGenericValue(T genericValue) {
        this.genericValue = genericValue;
    }

    public static void main(String[] args) {
        GenericTest<String> stringGenericTest = new GenericTest<>();
//     1、只能set String类型的值
        stringGenericTest.setGenericValue("123");
//     2、存放整形的值会报错
//        stringGenericTest.setGenericValue(123);
//     3、取出的值不需要强转
        String stringValue = stringGenericTest.getGenericValue();
        System.out.println(stringValue);
//     4、且必须用String来接收,不然会报错
//        Integer integer = stringGenericTest.getGenericValue();
    }

}

三、注意事项

  • 什么是类型擦除?
    Java中的泛型是在编译器这个层次来实现的,生成的Java字节码中是不包含泛型的类型信息的。而泛型的类型参数,会在编译器在编译的时候去掉,这个过程就称为类型擦除。
    如:
    第五条:在代码中定义的ArrayList和ArrayList类型,在编译后都会变成List。
    第六条:通过反射可以在Integer集合中的Integer类型被擦除后存放字符串
//      5、泛型的类型擦除证明:两个ArrayList编译后的类型是相同的
        ArrayList<String> stringArrayList = new ArrayList<>();
        stringArrayList.add("123");
        ArrayList<Integer> integerArrayList = new ArrayList<>();
        integerArrayList.add(123);
        System.out.println(stringArrayList.getClass() == integerArrayList.getClass());
//      6、类型擦除的证明:通过反射可以跳过编译阶段的类型检测将字符串存到整形集合中
        integerArrayList.getClass().getMethod("add",Object.class).invoke(integerArrayList,"我是字符串");
        System.out.println(integerArrayList.get(1));

更多细节参考大神博文:泛型的类型擦除

  • 引用和内存中的实例
    下面的代码中,集合"arrayList"和“linkedList”的引用类型都是List,内存中的实例分别是“ArrayList”和“LinkedList”,需要注意的是我们在使用的时候调用的是引用类型List的相关方法,跟内存中的实例是什么无关。
		List arrayList = new ArrayList();
        List linkedList = new LinkedList();

泛型的限制也是如此,

//        泛型声明在实例对象中不起作用
        ArrayList arrayList = new ArrayList<Integer>();
//        泛型声明在引用中可以起作用
        ArrayList<Integer> genericArrayList = new ArrayList<>();
### Java 的概念 Java 是一种允许编写可以处理多种数据类型的代码的技术。通过使用,可以在定义类、接口方法时不指定具体的类型,在使用这些组件时再指明具体的数据类型[^1]。 #### 的优点 引入的主要目的是为了在编译期提供更强的类型检查,并支持编程。这有助于减少强制类型转换的需求并提高程序的安全性可读性[^2]。 ### 的基本用法 #### 定义类 可以通过声明带有类型参数的类来创建类。例如: ```java public class Box<T> { private T content; public void setContent(T content) { this.content = content; } public T getContent() { return content; } } ``` 这段代码展示了如何定义一个名为 `Box` 的简单容器类,它可以保存任何类型的对象[^3]。 #### 使用类 当实例化此类时,需指定要使用的特定类型作为类型参数的实际值: ```java Box<String> stringBox = new Box<>(); stringBox.setContent("Hello"); System.out.println(stringBox.getContent()); ``` 这里创建了一个专门用于存储字符串 (`String`) 的盒子实例。 #### 定义方法 除了类外,还可以定义接受或返回任意类型的方法。下面是一个简单的例子: ```java public static <E> List<E> asList(E... elements) { ArrayList<E> list = new ArrayList<>(elements.length); Collections.addAll(list, elements); return list; } ``` 该静态工厂方法能够接收不定数量的不同元素并将它们封装到列表中去。 ### 类型擦除机制 值得注意的是,尽管源码层面看起来像是存在不同的类型版本,但实际上 JVM 上只有一种非形式的存在——这就是所谓的“类型擦除”。这意味着所有的信息都会被移除掉,取而代之的是最通用的对象表示或者边界限定内的某个具体类型[^4]。 对于有界类型参数的情况,比如 `<T extends Number>` 这样的表达方式,JVM 将会把所有涉及的地方都替换成它的第一个上限(即 `Number`),而对于无界的则一律视为 `Object` 处理。 ### 继承与 当子类继承自具有参数的父类时,可以选择立即固定住这个参数的具体类型,从而使自己变成普通的非类;也可以继续保留特性以便于进一步定制化[^5]。 ```java // 子类明确了父类中的类型为 String class ChildClass extends ParentClass<String> {} ``` 上述片段说明了怎样让子类成为普通类的同时还锁定了来自超类的那个未绑定过的类型变量。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

-乾坤-

????????????????????????

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

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

打赏作者

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

抵扣说明:

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

余额充值