Java学习笔记 13、泛型

简介: Java学习笔记 13、泛型

一、认识泛型


首先提出一个问题:为什么有泛型?


设计背景:集合容器在设计阶段/声明阶段不能确定该容器实际存的是什么类型的对象,所以在JDK1.5之前统一将容器中的元素设计为Object,在JDK1.5之后使用泛型来解决。

将元素的类型设计成一个参数,这个参数就叫做泛型。例如:interface Collection<E> extends Iterable<E>其中的E就是泛型,根据传入类型来定。

泛型:就是允许在定义类、接口时通过一个标识表示类中某个属性的类型或者是某个方法的返回值及参数类型。这个类型参数将在使用时确定(例如继承实现某某接口,声明变量,创建对象)。


一个类继承了父类,那么就能通过它的父类找到对应的子类,但是不能通过其他类来找到具体要找的和这个类。

好处:使用泛型能够规范集合中的元素,避免了强转出现异常的情况,没有实现泛型前是类型不安全的。


重要点:JDK1.5改写了集合框架中的全部接口和类,为这些接口、类增加了泛型支持。若是不指定类型也可以默认是Object。



JDK1.7新特性:类型推断


//当我们创建实例时,new后面不需要设置指定类型了(前面一定要有)
Map<String,Integer> map = new HashMap<>();



二、自定义泛型结构


自定义泛型举例


class MyGeneric<T>{
    private String name;
    private T Order;
    public void setOrder(T order) {
        Order = order;
    }
    public T getOrder() {
        return Order;
    }
}


这里T作为泛型,等待创建实例传入指定的类型参数,并且该类属性也能够使用该泛型。


继承泛型类两种方式

方式一:不属于泛型类,直接确定类型


//当子类不使用泛型时,其继承的类需要明确类型
class Type1 extends MyGeneric<String>{//这里使用的上面自定义例子的类
}


方式二:属于泛型类,根据传过来的类型决定


//可以通过创建Type2实例时将类型也传递给MyGeneric
class Type2<T> extends MyGeneric<T>{
}



自定义泛型注意点

1、泛型类可以有多个参数,多个参数要一起放在<>中,例如<T,E,K>。


2、泛型类的构造器不需要使用<E>,和往常一样即可。


3、使用泛型类若是不指定类型,对应类型默认为Object。


4、若泛型类是一个接口或抽象类,不能创建泛型类的对象。


5、泛型指定只能使用引用数据类型,若是想要表示基本数据类型可用包装类代替。


6、异常类不能指定泛型。



三、泛型不同使用情境


泛型表示接口
interface MyGeneric<E>{
    E get();
}


一般泛型接口常用于生成器,即对象工厂,一种专门用来创建类的工厂对象。



泛型方法

泛型方法:在方法中出现泛型的结构,泛型参与类的泛型参数没有任何关系。


情况一:使用类中的泛型


class MyGeneric<T>{
    private String name;
    private T Order;
    //这里的T与创建实例时传入的类型一致
    public List<T> getList(List<T> arr){
        return arr;
    }
}


情况二:若是单独在方法中使用泛型,则需要在返回参数之前加上类似于<E>标记


class MyGeneric<T>{
    private String name;
    private T Order;
    //为了让E不表示一个类而是一个参数则需要在返回参数前加<E>
    public <E> List<E> copy(List<E> arr){
        return arr;
    }
}


不加标记会将E识别为一个类,从而找不到该类出现编译错误:




四、泛型继承上的体现


①类A是类B的超类,G<A> 和 G<B> 二者不具备子父类关系,二者是并列关系



②类A是类B的父类,A<G> 是 B<G> 的父类



总结:对于具有子父类关系的泛型类,其泛型应该一致,否则不具备子父类关系。



五、通配符使用


通配符为:?


通过使用?通配符能够解决之前G<A> 和 G<B>的问题,这两者共同的父类为G<?>



运用到方法中:


import java.util.*;
public class Main {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        List<Integer> list2 = new ArrayList<>();
        traversal(list);
        traversal(list2);
    }
    //可遍历任意list<A> List<B>
    public static void traversal(List<?> list){
        Iterator<?> iterator = list.iterator();
        while(iterator.hasNext()){
            System.out.println(iterator.next());
        }
        //或者
//        for (Object o : list) {
//            System.out.println(o);
//        }
    }
}



注意点:例如上面List使用?不能进行add()的添加操作,获取值也只能获取到Object类型。


@Test


public void test(){
    List<String> list1 = new ArrayList<>();
    //给list1添加两个String字符串
    list1.add("AA");
    list1.add("BB");
    List<?> list2 = null;
    list2 = list1;
    //添加(写入):对于List<?> 就不能向其内部添加数据
    //除了添加null之外
    //        list2.add("AA");
    //        list2.add('?');//两个都会进行报错
    list2.add(null);//添加null值是允许的
    //获取读取:允许读取数据,读取的数据类型为Object
    Object o = list2.get(0);
    System.out.println(o);//AA
}



有限制条件的通配符使用


<? extends Number>:只允许泛型为Number及Number子列的引用调用。


<? super Number>:只允许泛型为Number及Number父类的引用调用。


extends:使用时只能使用对应类及其子类。

super:使用时只能使用对应类及其父类。

例子如下:


public static void main(String[] args) {
    List<? extends Person> list = new ArrayList<>();
    List<? super Person> list2 = new ArrayList<>();
    List<Person> list3 = new ArrayList<>();
    List<Student> list4 = new ArrayList<>();
    List<Object> list5 = new ArrayList<>();
    //赋值操作
    list = list3;
    list = list4;
    list = list5;//无法赋值,Object是Person父类
    list2 = list3;
    list2 = list4;//无法赋值,Student是Person子类
    list2 = list5;
    //获取对应值
    Person person = list.get(0);//由于泛型范围为Person及其子类,所以返回一个最大父类Person
    Object object = list2.get(0);//由于泛型范围为Person及其父类,所以返回一个最大父为Object
}



注意其中引用赋值范围以及获取对应泛型参数值的范围!!!


六、泛型中E、T、K等含义


其实可以使用任何合法的Java标识字符串,习惯用法是单一的字母表示,为了好辨识某些泛型的含义,特使用如下几个字母:


E:可表示Element,一般在集合中使用,集合中存放元素。

T:可表示Type,Java类。

K:可表示Key,作为键,Map中使用到。

V:可表示Value,作为值,Map中使用到。

N:Number,数值类型。

?:表示不确定的java类型。


相关文章
|
2月前
|
安全 Java 编译器
揭秘JAVA深渊:那些让你头大的最晦涩知识点,从泛型迷思到并发陷阱,你敢挑战吗?
【8月更文挑战第22天】Java中的难点常隐藏在其高级特性中,如泛型与类型擦除、并发编程中的内存可见性及指令重排,以及反射与动态代理等。这些特性虽强大却也晦涩,要求开发者深入理解JVM运作机制及计算机底层细节。例如,泛型在编译时检查类型以增强安全性,但在运行时因类型擦除而丢失类型信息,可能导致类型安全问题。并发编程中,内存可见性和指令重排对同步机制提出更高要求,不当处理会导致数据不一致。反射与动态代理虽提供运行时行为定制能力,但也增加了复杂度和性能开销。掌握这些知识需深厚的技术底蕴和实践经验。
54 2
|
2月前
|
存储 Java
Java学习笔记 List集合的定义、集合的遍历、迭代器的使用
Java学习笔记 List集合的定义、集合的遍历、迭代器的使用
|
18天前
|
Java 编译器 容器
Java——包装类和泛型
包装类是Java中一种特殊类,用于将基本数据类型(如 `int`、`double`、`char` 等)封装成对象。这样做可以利用对象的特性和方法。Java 提供了八种基本数据类型的包装类:`Integer` (`int`)、`Double` (`double`)、`Byte` (`byte`)、`Short` (`short`)、`Long` (`long`)、`Float` (`float`)、`Character` (`char`) 和 `Boolean` (`boolean`)。包装类可以通过 `valueOf()` 方法或自动装箱/拆箱机制创建。
25 9
Java——包装类和泛型
|
21天前
|
安全 Java API
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
String常量池、String、StringBuffer、Stringbuilder有什么区别、List与Set的区别、ArrayList和LinkedList的区别、HashMap底层原理、ConcurrentHashMap、HashMap和Hashtable的区别、泛型擦除、ABA问题、IO多路复用、BIO、NIO、O、异常处理机制、反射
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
|
22天前
|
存储 安全 Java
Java修仙之路,十万字吐血整理全网最完整Java学习笔记(基础篇)
从Java环境的搭建到实际代码的编写,从基本用法的讲解到底层原理的剖析,深度解析Java基础知识。本文是《Java学习路线》专栏的起始文章,旨在提供一套完整的Java学习路线,覆盖Java基础知识、数据库、SSM/SpringBoot等框架、Redis/MQ等中间件、设计模式、架构设计、性能调优、源码解读、核心面试题等全面的知识点,并在未来不断更新和完善,帮助Java从业者在更短的时间内成长为高级开发。
Java修仙之路,十万字吐血整理全网最完整Java学习笔记(基础篇)
|
22天前
|
存储 安全 Java
Java修仙之路,十万字吐血整理全网最完整Java学习笔记(进阶篇)
本文是Java基础的进阶篇,对异常、集合、泛型、Java8新特性、I/O流等知识进行深入浅出的介绍,并附有对应的代码示例,重要的地方带有对性能、底层原理、源码的剖析。适合Java初学者。
Java修仙之路,十万字吐血整理全网最完整Java学习笔记(进阶篇)
|
18天前
|
存储 安全 搜索推荐
Java中的泛型
【9月更文挑战第15天】在 Java 中,泛型是一种编译时类型检查机制,通过使用类型参数提升代码的安全性和重用性。其主要作用包括类型安全,避免运行时类型转换错误,以及代码重用,允许编写通用逻辑。泛型通过尖括号 `&lt;&gt;` 定义类型参数,并支持上界和下界限定,以及无界和有界通配符。使用泛型需注意类型擦除、无法创建泛型数组及基本数据类型的限制。泛型显著提高了代码的安全性和灵活性。
|
22天前
|
存储 安全 Java
Java修仙之路,十万字吐血整理全网最完整Java学习笔记(高级篇)
本文是“Java学习路线”中Java基础知识的高级篇,主要对多线程和反射进行了深入浅出的介绍,在多线程部分,详细介绍了线程的概念、生命周期、多线程的线程安全、线程通信、线程同步,并对synchronized和Lock锁;反射部分对反射的特性、功能、优缺点、适用场景等进行了介绍。
Java修仙之路,十万字吐血整理全网最完整Java学习笔记(高级篇)
|
2月前
|
安全 Java Go
Java&Go泛型对比
总的来说,Java和Go在泛型的实现和使用上各有特点,Java的泛型更注重于类型安全和兼容性,而Go的泛型在保持类型安全的同时,提供了更灵活的类型参数和类型集的概念,同时避免了运行时的性能开销。开发者在使用时可以根据自己的需求和语言特性来选择使用哪种语言的泛型特性。
38 7
|
2月前
|
jenkins Java Shell
jenkins学习笔记之十三:配置SonarScanner扫描Java项目
jenkins学习笔记之十三:配置SonarScanner扫描Java项目
下一篇
无影云桌面