目录
一、反射
1. 反射引入
2. 创建对象
3. 反射核心用法
二、泛型
1. 泛型的重要性
(1)解决类型安全问题
(2)避免重复代码
(3)提高可读性和维护性
2. 泛型用法
(1)泛型类
(2)泛型方法
(3)泛型类派生子类
(4)类型通配符
3. 泛型擦除
(1)为什么需要泛型擦除
(2)泛型擦除带来的限制
4. 桥接方法
(1)问题
(2)桥接方法的作用
一、反射
1. 反射引入
MyClass obj = new MyClass();
obj.doSth();
类加载过程:
(1)加载 Loading
JVM将类的字节码文件(.class)加载到内存,创建Class对象
(2)链接 Linking
① 验证:确保字节码符合规范
② 准备:为静态变量分配内存并赋予默认值(如int初始化为0)
③ 解析:将符号引用转换为直接引用
(3)初始化 Initialization
执行类的静态代码块(static{})和静态变量显式赋值
2. 创建对象
(1)通过new关键字创建对象
new关键字会直接触发类的完整加载、链接和初始化过程;
① 若类未加载:立即执行加载、链接,完成后强制触发类的初始化(执行static代码块和初始化静态变量)。
② 初始化完成后:调用构造函数创建对象
(2)通过反射创建对象
通过反射(Class.newInstance() 或 Constructor.newInstance() )创建对象时,允许分阶段控制类的加载过程:
① 触发加载但不初始化:使用ClassLoader.loadClass() 可加载类但不初始化:
此时尚未执行静态代码块或静态变量显式赋值。
② 按需触发初始化:在首次需要初始化时才触发(如反射调用newInstance() ):
③ 选择性初始化控制
通过Class.forName可指定是否初始化:
public class Main {
public static void main(String[] args) throws Exception {
// 反射示例:
ClassLoader loader = MyClass.class.getClassLoader();
// 加载类但不初始化(第三个参数为类加载器)
System.out.println("加载类但不初始化1...");
// 以下第二个参数为“是否初始化”
Class<?> clazz2 = Class.forName("com.zhaowa.galaxy.reflection.MyClass", false, loader);
// 加载类但不初始化
System.out.println("加载类但不初始化2...");
Class<?> clazz = loader.loadClass("com.zhaowa.galaxy.reflection.MyClass"); // 无输出
// 触发初始化前,类的静态代码块仍未执行
System.out.println("准备创建对象...");
Object obj = clazz.newInstance(); // 输出:静态代码块执行!
// 加载类同时触发初始化
System.out.println("加载类同时触发初始化...");
Class<?> clazz1 = Class.forName("com.zhaowa.galaxy.reflection.MyClass2");
}
}
class MyClass {
static {
System.out.println("静态代码块执行!"); // 初始化触发
}
}
class MyClass2 {
static {
System.out.println("静态代码块2执行!"); // 初始化触发
}
}
输出结果:
3. 反射核心用法
反射允许程序在运行时动态获取类的信息并操作类或对象。核心类是Class,关键操作包括
① 动态创建对象(newInstance() )
② 调用方法(method.invoke() )
③ 访问/修改字段(field.get()/set() )
示例:
(1)通过无参构造函数创建实例对象
public class ReflectionExample1 {
public static void main(String[] args) {
try {
// 1. 获取Class对象(触发类加载,可能初始化)
Class<?> clazz = Class.forName("com.zhaowa.galaxy.reflection.User");
// 2. 获取无参构造方法(需处理异常)
Constructor<?> constructor = clazz.getDeclaredConstructor();
// 3. 调用newInstance()创建实例(无参数)
Object instance = constructor.newInstance();
System.out.println("实例创建成功:" + instance.getClass());
} catch (Exception e) {
e.printStackTrace();
}
}
}
class User {
public User() {
System.out.println("无参构造函数被调用!");
}
}
运行结果:
(2)通过有参构造函数创建实例对象
public class ReflectionExample2 {
public static void main(String[] args) {
try {
// 1. 获取Class对象(注意使用全限定类名)
Class<?> clazz = Class.forName("com.zhaowa.galaxy.reflection.User2");
// 2. 指定参数类型列表,获取有参构造方法
Class<?>[] paramTypes = {String.class, int.class}; // 参数类型顺序严格匹配
Constructor<?> constructor = clazz.getDeclaredConstructor(paramTypes);
// 3. 传递参数值实例化对象
Object[] initArgs = {"张三", 25}; // 参数值顺序与类型列表一致
Object instance = constructor.newInstance(initArgs);
System.out.println("实例创建成功:" + instance.getClass());
} catch (Exception e) {
e.printStackTrace();
}
}
}
class User2 {
private String name;
private int age;
public User2(String name, int age) {
this.name = name;
this.age = age;
System.out.println("有参构造函数被调用!name=" + name + ", age=" + age);
}
}
运行结果:
(3)反射通过私有构造函数创建对象,破坏单例模式
class Singleton {
private static Singleton instance;
private Singleton() {
// 私有构造函数
}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
public class ReflectionExample3 {
public static void main(String[] args) {
try {
// 通过正常方式获取单例对象
Singleton instance1 = Singleton.getInstance();
System.out.println("正常实例:" + instance1);
// 方式 1:通过反射创建新实例(直接访问构造函数)
Class<Singleton> clazz = Singleton.class;
Constructor<Singleton> constructor = clazz.getDeclaredConstructor();
constructor.setAccessible(true); // 访问私有构造函数
Singleton instance2 = constructor.newInstance();
// 方式 2:通过反射多次创建实例(动态控制)
for (int i = 0; i < 3; i++) {
Constructor<Singleton> ctor = clazz.getDeclaredConstructor();
ctor.setAccessible(true);
Singleton instance = ctor.newInstance();
System.out.println("反射实例 " + (i+1) + ": " + instance);
}
// 验证两个实例是否相同
System.out.println("instance1 == instance2 ? " + (instance1 == instance2));
} catch (Exception e) {
e.printStackTrace();
}
}
}
运行结果:
(4)通过反射获得类的public属性值(getField与getDeclaredField两者的区别)
① getField()的特点:
- 只能获取当前类及继承类中声明为public的属性;
- 无法获取非public属性;
- 可以直接访问继承的父类public属性;
② getDeclaredField()的特点:
- 能获取当前类中声明的所有属性(public、private、protected、默认访问修饰符);
- 无法获取父类声明的属性;
- 访问非public属性需要通过setAccessible(true);
class Parent {
public String parentPublicField = "Parent-Public";
private String parentPrivateField = "Parent-Private";
}
class Child extends Parent {
public String childPublicField = "Child-Public";
private String childPrivateField = "Child-Private";
}
public class ReflectionExample4 {
public static void main(String[] args) {
Child child = new Child();
Class<?> clazz = Child.class;
try {
// ======================= 使用 getField() ========================
// 1. 获取子类的 public 属性(成功)
Field childPublicField = clazz.getField("childPublicField");
System.out.println("[getField] 子类 public 属性: " + childPublicField.get(child));
// 2. 获取父类的 public 属性(成功)
Field parentPublicField = clazz.getField("parentPublicField");
System.out.println("[getField] 父类 public 属性: " + parentPublicField.get(child));
// 3. 尝试获取子类的 private 属性(失败,触发异常)
clazz.getField("childPrivateField");
} catch (Exception e) {
System.err.println("[getField 失败] " + e.getClass().getSimpleName() + ": " + e.getMessage());
}
try {
// ================== 使用 getDeclaredField() ======================
// 1. 获取子类的 public 属性(成功)
Field childPublicDeclaredField = clazz.getDeclaredField("childPublicField");
System.out.println("[getDeclaredField] 子类 public 属性: " + childPublicDeclaredField.get(child));
// 2. 获取子类的 private 属性(需解除访问限制)
Field childPrivateDeclaredField = clazz.getDeclaredField("childPrivateField");
childPrivateDeclaredField.setAccessible(true); // 强制访问私有属性
System.out.println("[getDeclaredField] 子类 private 属性: " + childPrivateDeclaredField.get(child));
// 3. 尝试获取父类的属性(失败,无论是否是 public)
clazz.getDeclaredField("parentPublicField");
} catch (Exception e) {
System.err.println("[getDeclaredField 失败] " + e.getClass().getSimpleName() + ": " + e.getMessage());
}
}
}
运行结果:
(5)通过反射获得类的private、protected、默认访问修饰符的属性值
获取对象值时要将对象实例传入,但如果是静态属性值,不用传对象实例,null就可以
class Student {
private String privateField = "私有属性值";
protected String protectedField = "受保护属性值";
String defaultField = "默认访问属性值"; // 包级私有
public String publicField = "公有属性值";
}
public class ReflectionExample5 {
public static void main(String[] args) {
Student student = new Student();
try {
// 获取类的 Class 对象
Class<?> clazz = Student.class;
// ================== 访问私有属性 ==================
Field privateField = clazz.getDeclaredField("privateField");
privateField.setAccessible(true); // 解除私有访问限制
String privateValue = (String) privateField.get(student);
System.out.println("privateField: " + privateValue);
// ================== 访问受保护属性 ==================
Field protectedField = clazz.getDeclaredField("protectedField");
protectedField.setAccessible(true); // 无需继承关系即可访问
String protectedValue = (String) protectedField.get(student);
System.out.println("protectedField: " + protectedValue);
// ================== 访问默认(包级私有)属性 ==================
Field defaultField = clazz.getDeclaredField("defaultField");
defaultField.setAccessible(true);
String defaultValue = (String) defaultField.get(student);
System.out.println("defaultField: " + defaultValue);
// ================== 访问公有属性 ==================
// 方式 1:getDeclaredField + setAccessible(强制访问)
Field publicField1 = clazz.getDeclaredField("publicField");
publicField1.setAccessible(true); // 即使公有也强制解除限制(非必须)
String publicValue1 = (String) publicField1.get(student);
System.out.println("publicField(强制访问): " + publicValue1);
// 方式 2:直接通过 getField 获取(不推荐,仅用于对比)
Field publicField2 = clazz.getField("publicField");
String publicValue2 = (String) publicField2.get(student);
System.out.println("publicField(正常访问): " + publicValue2);
} catch (NoSuchFieldException e) {
System.err.println("字段不存在: " + e.getMessage());
} catch (IllegalAccessException e) {
System.err.println("访问权限失败: " + e.getMessage());
}
}
}
运行结果:
(6)通过反射获得类的private方法
class MyClass3 {
private String privateMethod(String param) {
return "私有方法被调用,参数: " + param;
}
}
public class ReflectionExample6 {
public static void main(String[] args) {
try {
// 创建类的实例
MyClass3 myObject = new MyClass3();
// 获取Class对象
Class<?> clazz = MyClass3.class;
// 获取私有方法,需指定方法名和参数类型
Method method = clazz.getDeclaredMethod("privateMethod", String.class);
// 解除访问限制(关键步骤)
method.setAccessible(true);
// 调用方法,传入实例及参数
String result = (String) method.invoke(myObject, "Hello");
// 输出结果
System.out.println("调用结果: " + result);
} catch (NoSuchMethodException e) {
System.err.println("方法未找到: " + e.getMessage());
} catch (IllegalAccessException e) {
System.err.println("非法访问: " + e.getMessage());
} catch (InvocationTargetException e) {
System.err.println("方法内部错误: " + e.getCause());
}
}
}
运行结果:
(7)通过反射实现一个工具BeanUtils,可以将一个对象属性相同的值赋值给另一个对象
class BeanUtils {
/**
* 将源对象的属性值复制到目标对象(浅拷贝)
* @param source 源对象
* @param target 目标对象
*/
public static void copyProperties(Object source, Object target) {
if (source == null || target == null) {
throw new IllegalArgumentException("源对象和目标对象不能为 null");
}
// 获取源对象和目标对象的所有字段(包含父类字段)
List<Field> sourceFields = getAllFields(source.getClass());
List<Field> targetFields = getAllFields(target.getClass());
for (Field sourceField : sourceFields) {
// 查找目标对象中与源对象字段同名的字段
Field targetField = findField(targetFields, sourceField.getName());
if (targetField == null) continue;
// 检查类型是否兼容(支持基本类型和包装类型)
if (!isTypeCompatible(sourceField.getType(), targetField.getType())) continue;
try {
// 设置字段可访问性
sourceField.setAccessible(true);
targetField.setAccessible(true);
// 复制值
Object value = sourceField.get(source);
targetField.set(target, value);
} catch (IllegalAccessException e) {
// 处理无法访问的异常
System.err.println("字段复制失败: " + sourceField.getName() + " -> " + targetField.getName());
}
}
}
/**
* 获取类及其父类的所有字段(非静态)
*/
private static List<Field> getAllFields(Class<?> clazz) {
List<Field> fields = new java.util.ArrayList<>();
while (clazz != null && clazz != Object.class) {
fields.addAll(Arrays.stream(clazz.getDeclaredFields())
.filter(f -> !isStatic(f))
.collect(Collectors.toList()));
clazz = clazz.getSuperclass();
}
return fields;
}
/**
* 根据字段名从字段列表中查找字段
*/
private static Field findField(List<Field> fields, String fieldName) {
return fields.stream()
.filter(f -> f.getName().equals(fieldName))
.findFirst()
.orElse(null);
}
/**
* 判断字段是否为静态
*/
private static boolean isStatic(Field field) {
return java.lang.reflect.Modifier.isStatic(field.getModifiers());
}
/**
* 判断源类型与目标类型是否兼容
*/
private static boolean isTypeCompatible(Class<?> sourceType, Class<?> targetType) {
// 处理基本类型与包装类型的兼容(例如 int -> Integer)
if (sourceType.isPrimitive()) {
return targetType.isPrimitive() ? sourceType.equals(targetType) : getWrapperType(sourceType).equals(targetType);
} else if (targetType.isPrimitive()) {
return getWrapperType(targetType).equals(sourceType);
} else {
return targetType.isAssignableFrom(sourceType);
}
}
/**
* 获取基本类型对应的包装类型
*/
private static Class<?> getWrapperType(Class<?> primitiveType) {
if (primitiveType == int.class) return Integer.class;
if (primitiveType == long.class) return Long.class;
if (primitiveType == boolean.class) return Boolean.class;
if (primitiveType == byte.class) return Byte.class;
if (primitiveType == char.class) return Character.class;
if (primitiveType == short.class) return Short.class;
if (primitiveType == double.class) return Double.class;
if (primitiveType == float.class) return Float.class;
return primitiveType;
}
}
// 父类
class Person {
protected String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
// 子类
class Employee extends Person {
private double salary;
private Integer departmentId;
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public Integer getDepartmentId() {
return departmentId;
}
public void setDepartmentId(Integer departmentId) {
this.departmentId = departmentId;
}
}
// 目标类
class EmployeeDTO {
private String name;
private int age; // 基本类型
private Double salary; // 包装类型
private Integer departmentId;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Double getSalary() {
return salary;
}
public void setSalary(Double salary) {
this.salary = salary;
}
public Integer getDepartmentId() {
return departmentId;
}
public void setDepartmentId(Integer departmentId) {
this.departmentId = departmentId;
}
}
public class ReflectionExample7 {
public static void main(String[] args) {
// 准备数据
Employee emp = new Employee();
emp.name = "张三";
emp.setAge(30);
emp.setSalary(15000.5);
emp.setDepartmentId(101);
// 目标对象
EmployeeDTO dto = new EmployeeDTO();
// 复制属性
BeanUtils.copyProperties(emp, dto);
// 验证结果
System.out.println("DTO.name: " + dto.getName());
System.out.println("DTO.age: " + dto.getAge());
System.out.println("DTO.salary: " + dto.getSalary());
System.out.println("DTO.departmentId: " + dto.getDepartmentId());
}
}
运行结果:
二、泛型
泛型是编程语言中一种支持参数化类型的特性,允许在定义类、接口、方法时使用类型参数(TypeParameters),而在使用时执行具体的类型。泛型的核心目标是提高代码的类型安全性、可重用性和可读性。
参数化类型
定义时不确定类型:在编写类、接口或方法时使用类型占位符(如<T>),实际使用时再传入具体类型(如String、Integer)
类型安全和编译时检查
编译器可以检查参数类型是否正确,并在编译时而不是运行时捕获类型错误。
1. 泛型的重要性
(1)解决类型安全问题
在泛型出现之前,Java集合类(如ArrayList、HashMap)默认使用Object类型存储元素。这导致两个问题:
① 强制类型转换:从集合中取出元素时需要显示转换类型;
② 运行时类型错误风险:如果类型不一致,会抛出ClassCastException。
示例:没有泛型的代码:
通过泛型改进后:
(2)避免重复代码
在没有泛型时,如果要支持不同类型,需要为每种类型编写相似的代码(如分别实现IntegerBox、StringBox)。
泛型的代码复用:
(3)提高可读性和维护性
泛型让代码的意图更明确,例如Map<String, Integer>清楚地表示“键是String,值是Integer”。
清晰的类型约束:直接声明数据类型,避免混乱的类型转换。
自解释性:代码能直接表达其设计的通用性。
2. 泛型用法
(1)泛型类
将泛型定义在类上,用户使用该类的时候,才把类型明确下来。这样的话,用户明确了什么类型,该类就代表着什么类型,用户在使用的时候就不用担心强转的问题和运行时转换异常的问题了。
(2)泛型方法
除了在类上使用泛型,可能就仅仅在某个方法上需要使用泛型,外界仅仅关心该方法,不关心类其他的属性,这时可以采用类型方法。
(3)泛型类派生子类
泛型类是拥有泛型特性的类,本质上还是一个Java类,所以可以被继承或实现。
class Box<T> {
private T content; // 泛型字段
public void setContent(T content) {
System.out.println("调用父类 setContent 方法");
this.content = content;
}
public T getContent() {
System.out.println("调用父类 getContent 方法");
return content;
}
}
① 子类固定父类泛型类型(StringBox 继承自 Box<String>)
子类直接指定父类泛型参数的具体类型,使用于特定场景的扩展
// 子类继承时指定父类泛型类型为 String
class StringBox extends Box<String> {
// 新增方法:专为字符串内容设计
public void toUpperCase() {
String value = getContent(); // 直接使用 String 类型
if (value != null) {
setContent(value.toUpperCase());
}
}
@Override
public void setContent(String value) { // 重写父类方法,参数类型为 String
super.setContent(value.toUpperCase());
}
@Override
public String getContent() { // 重写父类方法,返回类型为 String
return super.getContent();
}
}
public class Main {
public static void main(String[] args) {
StringBox box = new StringBox();
box.setContent("hello");
box.toUpperCase();
System.out.println(box.getContent()); // 输出: HELLO
}
}
运行结果:
② 子类保留父类泛型类型(AdvancedBox<T> 继承自 Box<T>)
子类保持父类泛型参数的灵活性,并扩展新功能
// 父类定义不变,与示例1相同
// 子类保留父类的泛型参数 <T>
class AdvancedBox<T> extends Box<T> {
// 新增方法:检查内容是否为空
public boolean isEmpty() {
return getContent() == null;
}
// 新增方法:重置内容为 null
public void clear() {
setContent(null);
}
}
public class Main2 {
public static void main(String[] args) {
AdvancedBox<Integer> intBox = new AdvancedBox<>();
intBox.setContent(100);
System.out.println(intBox.isEmpty()); // 输出: false
intBox.clear();
System.out.println(intBox.getContent()); // 输出: null
}
}
运行结果:
③ 添加子类自己的泛型参数(KeyValuePair<K, V> 继承自 Pair<K>)
父子类均使用泛型,子类引入新的类型参数
// 泛型父类
class Pair<T> {
private T first;
private T second;
public Pair(T first, T second) {
this.first = first;
this.second = second;
}
public T getFirst() { return first; }
public T getSecond() { return second; }
}
// 子类添加新的泛型参数 V,与父类参数 K 独立
class KeyValuePair<K, V> extends Pair<K> {
private V value;
public KeyValuePair(K key, V value) {
super(key, key); // 父类需要两个同类型参数,此处复用 key 作为示例
this.value = value;
}
// 新增方法:获取键值对的独立值
public V getValue() { return value; }
}
public class Main3 {
public static void main(String[] args) {
KeyValuePair<String, Integer> entry = new KeyValuePair<>("Age", 30);
String key = entry.getFirst(); // 类型为 String(父类返回值)
int value = entry.getValue(); // 类型为 Integer(子类新增方法)
System.out.println(key + ": " + value); // 输出: Age: 30
}
}
运行结果:
④ 约束父类类型边界(InCalculator 继承自 NumberCalculator<Integer>)
子类继承时遵循父类的泛型约束(如<T extends Number>)并进一步具体化
// 泛型父类,约束类型必须为 Number 的子类
class NumberCalculator<T extends Number> {
protected T value;
public NumberCalculator(T value) {
this.value = value;
}
public double doubleValue() {
return value.doubleValue();
}
}
// 子类指定父类泛型类型为 Integer
class IntCalculator extends NumberCalculator<Integer> {
public IntCalculator(Integer value) {
super(value);
}
// 新增方法:计算平方(专为 Integer 设计)
public int squareInt() {
return value * value;
}
}
public class Main4 {
public static void main(String[] args) {
IntCalculator calc = new IntCalculator(5);
System.out.println(calc.doubleValue()); // 输出: 5.0(调用父类方法)
System.out.println(calc.squareInt()); // 输出: 25(子类专属方法)
}
}
运行结果:
(4)类型通配符
① 无界通配符(<?>)
用于处理未知类型的集合,适合只读取集合内容的场景
public class UnboundedWildcardDemo {
/**
* 打印任意类型集合的元素
* @param list 使用无界通配符 <?>,表示接受任意类型的 List
*/
public static void printList(List<?> list) {
for (Object item : list) {
System.out.print(item + " ");
}
System.out.println();
}
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
List<Integer> numbers = Arrays.asList(1, 2, 3);
printList(names); // 输出: Alice Bob Charlie
printList(numbers); // 输出: 1 2 3
}
}
② 上界通配符(<? extends Number>)
限制类型为Number 或其子类(如Integer、Double),适合读取子类
public class UpperBoundedWildcardDemo {
/**
* 计算数值列表的总和
* @param list 使用上界通配符 <? extends Number>
* @return Sum of numbers as double
*/
public static double sumOfList(List<? extends Number> list) {
double sum = 0.0;
for (Number num : list) {
sum += num.doubleValue(); // 调用 Number 的方法
}
return sum;
}
public static void main(String[] args) {
List<Integer> integers = Arrays.asList(1, 2, 3);
List<Double> doubles = Arrays.asList(1.1, 2.2, 3.3);
System.out.println(sumOfList(integers)); // 输出: 6.0
System.out.println(sumOfList(doubles)); // 输出: 6.6
}
}
③ 下界通配符(<? super Integer>)
限制类型为Integer或其父类(如Number、Object),适合写入场景:
public class LowerBoundedWildcardDemo {
/**
* 向集合中添加多个 Integer 值
* @param dest 使用下界通配符 <? super Integer>
* @param values 要添加的多个 Integer 值
*/
public static void addNumbersToList(List<? super Integer> dest, List<Integer> values) {
dest.addAll(values); // 可安全写入 Integer 或其父类型(如 Number、Object)
}
public static void main(String[] args) {
List<Number> numberList = new ArrayList<>();
addNumbersToList(numberList, Arrays.asList(10, 20, 30));
System.out.println(numberList); // 输出: [10, 20, 30]
List<Object> objectList = new ArrayList<>();
addNumbersToList(objectList, Arrays.asList(100, 200));
System.out.println(objectList); // 输出: [100, 200]
}
}
3. 泛型擦除
(1)为什么需要泛型擦除
泛型擦除是Java为向后兼容性设计的关键机制,具体原因如下:
① 兼容旧版本代码
java在5.0版本(2004年)引入泛型。
泛型擦除让新代码(带泛型)和旧代码(无泛型)共享同一个类文件结构。例如:
泛型擦除后,两者本质都是List,从而保证旧代码无需修改即可在新JVM上运行。
② 避免JVM修改
泛型擦除无需修改JVM的底层机制。JVM仍使用同样的字节码指令处理泛型和非泛型集合,极大降低了实现复杂度。
③ 减少代码冗余
如果泛型类行不擦除,List<String> 和 List<Integer> 会分别生成不同的类文件,导致代码膨胀;擦除后,所有泛型实例共享同一个类文件,提升执行效率。
(2)泛型擦除带来的限制
① 无法使用基本类型参数
② 运行时无法获取泛型类型信息
③ 无法创建泛型数组
4. 桥接方法
(1)问题
① 由于泛型擦除,Box<String>编译后的原始方法是:
set(Object value) --> 原来set(String value)
get() 的返回值类型是Object(原来String)
② StringBox中的重写方法是set(String) 和 get(): String,与父类擦除后的set(Object) 和 get(): Object方法签名不匹配。
这会导致多态性失效:通过Box<String> box = new StringBox() 调用set方法时,JVM期望的签名是set(Object),但StringBox只有set(String)。
(2)桥接方法的作用
① 保证方法重写的多态性
- JVM通过方法签名(方法名+参数类型)和返回类型确定方法分派。
- 在类型擦除后,父类与子类的方法签名不匹配,桥接方法充当中间层,确保父类引用能正确调用子类的具体方法。
② 强制类型安全
桥接方法中会插入类型检查:
若传入非法类型(如Integer),运行时会抛出ClassCastException,避免了类型混乱。
// 子类继承时指定父类泛型类型为 String
class StringBox extends Box<String> {
// 新增方法:专为字符串内容设计
public void toUpperCase() {
String value = getContent(); // 直接使用 String 类型
if (value != null) {
setContent(value.toUpperCase());
}
}
@Override
public void setContent(String value) { // 重写父类方法,参数类型为 String
super.setContent(value.toUpperCase());
}
@Override
public String getContent() { // 重写父类方法,返回类型为 String
return super.getContent();
}
}
public class BridgeMethodDemo {
public static void main(String[] args) {
for (Method method : StringBox.class.getDeclaredMethods()) {
if (method.isBridge()) {
System.out.println("桥接方法:" + method);
}
}
}
}
运行结果为: