Java系列文章目录
IDEA使用指南:快速高效掌握工具的配置与技巧(必用功能,JDK,Maven等)
文章目录
一、前言
目的:对泛型的笔记总结
- 此篇是对B站博主AlbertShen讲的泛型内容进行笔记总结
- 个人感觉讲的详细且逻辑清晰所以也进行学习总结
二、学习内容:
- 泛型概念
- 泛型类
- 类型参数的约束
- 类型安全
- 泛型方法
- 通配符
三、问题描述
本人想加深对泛型的理解
- 一些课本关于泛型的知识没有简洁的实践操作
四、解决方案:
4.1 泛型概念
允许在类、接口和方法中定义类型参数,从而实现代码的复用、类型安全
可以创建一个可以处理不同数据类型的类或方法,从而避免重复代码。
- 打印整型
package org.example;
public class IntegerPrinter {
Integer content;
IntegerPrinter(Integer content) {
this.content = content;
}
public void print() {
System.out.println(content);
}
}
package org.example;
public class Main {
public static void main(String[] args) {
IntegerPrinter printer = new IntegerPrinter(123);
printer.print();
}
}
- 打印字符串
package org.example;
public class Main {
public static void main(String[] args) {
StringPrinter printer = new StringPrinter("Hello");
printer.print();
}
}
package org.example;
public class StringPrinter {
String content;
StringPrinter(String content) {
this.content = content;
}
public void print() {
System.out.println(content);
}
}
- 泛型的引入
为了减少像上面这样重复的代码我们引入泛型
- 使用泛型就在在大括号与类名之间添加 <>
- 外界参数可作为特殊参数传入( T 与 K )
- 特殊参数作为泛型使用
- 可以是任何类型参数包括类
4.2 类型参数的约束
有时候不需要满足所有类型要给一个限制
4.2.1 通过extend约束参数
- 参数解释
类型参数必须是Machine的子类
类型参数必须实现Thing接口方法
- Thing 也是用 extends
- 接口Thing必须放在Machine类后面
如图所示:
- Car 继承了 Machine 同时实现了Thing接口方法
观察下面两张图
- 注意不管是父类还是子类只要参数类型实现了Thing方法即可
继承了Machine类
实现了Thing接口的方法
4.3 类型安全
4.3.1 类型安全举例
- 假如现在List的泛型参数使用Object这样就可以在列表加入任何类型
这样IDEA不报错
注意:不建议这样使用
- 运行后可以显示出结果
能运行也没报错为什么不建议用呢
- 尝试获取并显示列表里面的元素
- 运行出现错误
泛型的工作方式是在编译阶段进行类型检查而不是在运行阶段
IDEA不报错但是运行报错
了解下面概念
类型擦除:
- Java 编译器会在编译时将泛型类型替换为其原始类型。
- 比如,
List<String>
会被替换为List。这就导致了在运行时,无法根据类型信息判断某个对象是否真的符合指定的泛型。
编译时类型检查:
- 在编译阶段,编译器检查代码以确保类型安全。这意味着,它会检查所有的类型引用,确保在编译时这些类型是合法的。
- 例如,如果你创建了一个
List<String>
对象并添加了一个字符串,编译器会允许你这么做,因为这在类型上是合法的。
运行时类型错误:
- 由于无论是
List<String>
、List<Integer>
还是List<Object>
的实际实现类在运行时都是List - 运行时无法区分这些具体类型。这可能导致一些运行时错误。
- 例如,当你尝试将一个非字符串对象从一个
List<Object>
强制转换为 String 时,就会抛出 ClassCastException。
总的来说原因如下
在运行时,JVM 会检查 list.get(1) 的实际类型,发现它是 Integer,而不是 String,因此会抛出 ClassCastException。
- 当你尝试将 Object 强制转换为 String 时,Java 编译器并不会在编译阶段检查这个转换是否合法。它不会知道 list.get(1) 实际上是一个 Integer 对象。
- 只有在运行时,JVM 才会检查这个具体的类型,结果会因为 Integer 不能转换为 String 而抛出
ClassCastException。
此例目标类型String 对象类型Object
4.3.2 强制转换概念(补充)
一个类型的对象转换为另一个类型,但只有在这两种类型之间存在合法的转换时,这种转换才是有效的。
在 Java 中,强制转换(type casting)的成功与否取决于对象的实际类型以及目标类型之间的兼容性。
类型兼容性:
- Java 类型系统要求两种类型之间有直接的关系。
- 例如,Integer 和 String 在类型层次结构中没有直接关系,不能互相转换。
- 只有当对象的实际类型与目标类型相同或是目标类型的子类型时,强制转换才是有效的。
此例目标类型String 对象类型Integer
运行时检查:
- Java 在运行时会检查对象的实际类型。
- 如果你尝试将一个 Integer 对象强制转换为 String,Java 会发现这两者之间没有直接的转换路径,因此会抛出ClassCastException。
Object obj = new Integer(10); // obj 实际上是 Integer
String str = (String) obj; // 试图将 Integer 转换为 String
- 当你执行到 String str = (String) obj; 阶段时
- Java 虚拟机会检查 obj 中实际存储的数据类型(即Integer)。
- 由于 Integer 和 String 是不兼容的类型,JVM 会检测到这一点并抛出 ClassCastException。
Object obj = "Hello"; // obj 是 String 类型
String str = (String) obj; // 成功转换
不能直接将一个对象强制转换为与其实际类型无关的类型,因为这没有逻辑上的支持,也违反了 Java 的类型安全
4.4 泛型方法与通配符
T是占位符
加上< T >告诉Java这是泛型
注意结构
跟之前一样可以用多个参数或者继承
- 每次使用都要换比较麻烦所以引入泛型
- 通配符传参
- Super 与 Extends 的使用
五、总结:
5.1 学习总结:
- 泛型概念:主要为了解决重复代码问题
- 泛型类:学会使用 <> 与多参数的使用
- 类型参数的约束:extends
- 类型安全:注意类型转换问题
- 泛型方法:<> 在 static 与 void 之间
- 通配符:掌握通配符 ?与 extends
(后续有遇到问题再添加)
声明:如本内容中存在错误或不准确之处,欢迎指正。转载时请注明原作者信息(麻辣香蝈蝈)。