强哥说Java--Java的泛型(一)

简介: 强哥说Java--Java的泛型(一)

1. 什么是泛型



泛型不只是 Java 语言所特有的特性,泛型是程序设计语言的一种特性。


允许程序员在强类型的程序设计语言中编写代码时定义一些可变部分,那些部分在使用前必须做出声明。


Java 中的集合类是支持泛型的,它在代码中是这个样子的


image.png


代码中的<Integer>就是泛型,我们把类型像参数一样传递,尖括号中间就是数据类型,我们可以称之为实际类型参数,这里实际类型参数的数据类型只能为引用数据类型。


那么为什么需要泛型呢?


2. 为什么需要泛型



我们在使用ArrayList实现类的时候,如果没有指定泛型,IDEA会给出警告,代码似乎也是可以顺利运行的。请看如下实例:


import java.util.ArrayList;
public class testDemo1 {
    public static void main(String[] args) {
        ArrayList arrayList = new ArrayList();
        arrayList.add("Hello");
        String str1 = (String) arrayList.get(0);
        System.out.println("str=" + str1);
    }
}


运行结果:


str1=Hello


虽然运行时没有发生任何异常,但这样做有两个缺点:


需要强制类型转换: 由于ArrayList内部就是一个Object[]数组,在get()元素的时候,返回的是Object类型,所以在ArrayList外获取该对象,需要强制类型转换。其它的Collection、Map如果不使用泛型,也存在这个问题;


可向集合中添加任意类型的对象,存在类型不安全风险。例如如下代码中,我们向列表中既添加了Integer类型,又添加了String类型:


package com.caq.oop.demo08;
import java.util.ArrayList;
import java.util.List;
public class Test {
    public static void main(String[] args) {
        //实例化一个空列表
        List arrayList = new ArrayList<>();
        arrayList.add(123);
        arrayList.add("sad");
        String str = (String) arrayList.get(0);
    }
}


Exception in thread “main” java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
at com.caq.oop.demo08.Test.main(Test.java:12)


由于我们的“疏忽”,列表第 1 个元素实际上是整型,但被我们强制转换为字符串类型,这是行不通的,因此会抛出ClassCastException异常。


使用泛型可以解决这些问题。泛型有如下优点:


可以减少类型转换的次数,代码更加简洁;


程序更加健壮:只要编译期没有警告,运行期就不会抛出ClassCastException异常;


提高了代码的可读性:编写集合的时候,就限定了集合中能存放的类型。


3. 如何使用泛型


3.1 泛型使用


在代码中,这样使用泛型:


List<String> list = new ArrayList<String>();
// Java 7 及以后的版本中,构造方法中可以省略泛型类型:
List<String> list = new ArrayList<>();
外币巴伯


要注意的是,变量声明的类型必须与传递给实际对象的类型保持一致,下面是错误的例子:


List<Object> list = new ArrayList<String>();
List<Number> numbers = new ArrayList(Integer);


3.2 自定义泛型类


3.2.1 Java 源码中泛型的定义


在自定义泛型类之前,我们来看下java.util.ArrayList是如何定义的:


image.png


类名后面的<E>就是泛型的定义,E不是 Java 中的一个具体的类型,它是 Java 泛型的通配符(注意是大写的,实际上就是Element的含义),可将其理解为一个占位符,将其定义在类上,使用时才确定类型。


此处的命名不受限制,但最好有一定含义,例如java.lang.HashMap的泛型定义为HashMap<K,V>,K表示Key,V表示Value。


3.2.2 自定义泛型类实例1


下面我们来自定义一个泛型类,自定义泛型按照约定俗成可以叫<T>,具有Type的含义,实例如下:


实例演示


package com.caq.List;
public class Generic01<T> {
    private T abc;//定义在类上的泛型,在类内部可以使用
    public T getAbc() {
        return abc;
    }
    public void setAbc(T abc) {
        this.abc = abc;
    }
    public static void main(String[] args) {
        //实例化对象,指定元素类型为整型
        Generic01<Integer> integerGeneric01 = new Generic01<>();
        //调用方法
        integerGeneric01.setAbc(100);
        System.out.println("integerGeneric01="+ integerGeneric01.getAbc());
        //实例化对象,指定元素类型为长类型
        Generic01<Long> longGeneric01 = new Generic01<>();
        longGeneric01.setAbc(200L);
        System.out.println("longGeneric01="+ longGeneric01.getAbc());
        // 实例化对象,指定元素类型为双精度浮点型
        Generic01<Double> doubleGeneric01 = new Generic01<>();
        doubleGeneric01.setAbc(300.0);
        System.out.println("doubleGeneric01="+ doubleGeneric01.getAbc());
    }
}


运行结果:


integerGeneric01=100
longGeneric01=200
doubleGeneric01=300.


我们在类的定义处也定义了泛型:Generic01<T>;在类内部定义了一个T类型的abc变量,并且为其添加了setter和getter方法。


解释:对于泛型类的使用也很简单,在主方法中,创建对象的时候指定T的类型分别为Integer、Long、Double,类就可以自动转换成对应的类型了。


3.2.3 自定义泛型类实例2


上面我们知道了如何定义含有单个泛型的类,那么对于含有多个泛型的类,如何定义呢?


我们可以看一下HashMap类是如何定义的。如下是 Java 源码的截图:


image.png


参照HashMap<K,V>类的定义,下面我们来看看如何定义含有两个泛型的类


package com.caq.List;


public class Generic02<K, V> {//这次是定义两个泛型在类上


//定义类型为K的key属型
    private K key;
    //定义类型为V的value属型
    private V value;
    //封装里的知识,通过Getter和Setter方法来设置和获取私有属型的值
    public K getKey() {
        return key;
    }
    public void setKey(K key) {
        this.key = key;
    }
    public V getValue() {
        return value;
    }
    public void setValue(V value) {
        this.value = value;
    }
    public static void main(String[] args) {
        //实例化对象,分别指定类型为整型,长整型
        Generic02<Integer, Long> integerLongGeneric02 = new Generic02<>();
        //实例化对象,分别指定类型为浮点型、字符串类型
        Generic02<Float, String> floatStringGeneric02 = new Generic02<>();
        integerLongGeneric02.setKey(100);
        integerLongGeneric02.setValue(200L);
        System.out.println("key=" + integerLongGeneric02.getKey());
        System.out.println("value=" + integerLongGeneric02.getValue());
        floatStringGeneric02.setKey(0.9f);
        floatStringGeneric02.setValue("巴啦啦能量");
        System.out.println("key=" + floatStringGeneric02.getKey());
        System.out.println("value=" + floatStringGeneric02.getValue());
    }
}


运行结果:


key=100value=200key=0.9value=巴啦啦能量


相关文章
|
5月前
|
安全 Java 编译器
揭秘JAVA深渊:那些让你头大的最晦涩知识点,从泛型迷思到并发陷阱,你敢挑战吗?
【8月更文挑战第22天】Java中的难点常隐藏在其高级特性中,如泛型与类型擦除、并发编程中的内存可见性及指令重排,以及反射与动态代理等。这些特性虽强大却也晦涩,要求开发者深入理解JVM运作机制及计算机底层细节。例如,泛型在编译时检查类型以增强安全性,但在运行时因类型擦除而丢失类型信息,可能导致类型安全问题。并发编程中,内存可见性和指令重排对同步机制提出更高要求,不当处理会导致数据不一致。反射与动态代理虽提供运行时行为定制能力,但也增加了复杂度和性能开销。掌握这些知识需深厚的技术底蕴和实践经验。
100 2
|
3月前
|
Java API
[Java]泛型
本文详细介绍了Java泛型的相关概念和使用方法,包括类型判断、继承泛型类或实现泛型接口、泛型通配符、泛型方法、泛型上下边界、静态方法中使用泛型等内容。作者通过多个示例和测试代码,深入浅出地解释了泛型的原理和应用场景,帮助读者更好地理解和掌握Java泛型的使用技巧。文章还探讨了一些常见的疑惑和误区,如泛型擦除和基本数据类型数组的使用限制。最后,作者强调了泛型在实际开发中的重要性和应用价值。
63 0
[Java]泛型
|
3月前
|
存储 安全 Java
🌱Java零基础 - 泛型详解
【10月更文挑战第7天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
23 1
|
4月前
|
Java 编译器 容器
Java——包装类和泛型
包装类是Java中一种特殊类,用于将基本数据类型(如 `int`、`double`、`char` 等)封装成对象。这样做可以利用对象的特性和方法。Java 提供了八种基本数据类型的包装类:`Integer` (`int`)、`Double` (`double`)、`Byte` (`byte`)、`Short` (`short`)、`Long` (`long`)、`Float` (`float`)、`Character` (`char`) 和 `Boolean` (`boolean`)。包装类可以通过 `valueOf()` 方法或自动装箱/拆箱机制创建。
48 9
Java——包装类和泛型
|
3月前
|
Java 语音技术 容器
java数据结构泛型
java数据结构泛型
33 5
|
3月前
|
存储 Java 编译器
Java集合定义其泛型
Java集合定义其泛型
22 1
|
3月前
|
存储 Java 编译器
【用Java学习数据结构系列】初识泛型
【用Java学习数据结构系列】初识泛型
25 2
|
4月前
|
安全 Java API
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
String常量池、String、StringBuffer、Stringbuilder有什么区别、List与Set的区别、ArrayList和LinkedList的区别、HashMap底层原理、ConcurrentHashMap、HashMap和Hashtable的区别、泛型擦除、ABA问题、IO多路复用、BIO、NIO、O、异常处理机制、反射
|
4月前
|
存储 安全 搜索推荐
Java中的泛型
【9月更文挑战第15天】在 Java 中,泛型是一种编译时类型检查机制,通过使用类型参数提升代码的安全性和重用性。其主要作用包括类型安全,避免运行时类型转换错误,以及代码重用,允许编写通用逻辑。泛型通过尖括号 `&lt;&gt;` 定义类型参数,并支持上界和下界限定,以及无界和有界通配符。使用泛型需注意类型擦除、无法创建泛型数组及基本数据类型的限制。泛型显著提高了代码的安全性和灵活性。
|
3月前
|
安全 Java 编译器
Java基础-泛型机制
Java基础-泛型机制
30 0