02 反射 泛型(II)
目录
一、反射
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());}}@Overridepublic void setContent(String value) { // 重写父类方法,参数类型为 Stringsuper.setContent(value.toUpperCase());}@Overridepublic String getContent() { // 重写父类方法,返回类型为 Stringreturn 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;}// 新增方法:重置内容为 nullpublic 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()); // 输出: falseintBox.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 CharlieprintList(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.0System.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());}}@Overridepublic void setContent(String value) { // 重写父类方法,参数类型为 Stringsuper.setContent(value.toUpperCase());}@Overridepublic String getContent() { // 重写父类方法,返回类型为 Stringreturn super.getContent();}}
public class BridgeMethodDemo {public static void main(String[] args) {for (Method method : StringBox.class.getDeclaredMethods()) {if (method.isBridge()) {System.out.println("桥接方法:" + method);}}}
}
运行结果为:

相关文章:
02 反射 泛型(II)
目录 一、反射 1. 反射引入 2. 创建对象 3. 反射核心用法 二、泛型 1. 泛型的重要性 (1)解决类型安全问题 (2)避免重复代码 (3)提高可读性和维护性 2. 泛型用法 (1)泛型类 …...
Spring Boot 七种事务传播行为只有 REQUIRES_NEW 和 NESTED 支持部分回滚的分析
Spring Boot 七种事务传播行为支持部分回滚的分析 支持部分回滚的传播行为 REQUIRES_NEW:始终开启新事务,独立于外部事务,失败时仅自身回滚。NESTED:在当前事务中创建保存点(Savepoint),可局部…...
ZLMediaKit 源码分析——[5] ZLToolKit 中EventPoller之延时任务处理
系列文章目录 第一篇 基于SRS 的 WebRTC 环境搭建 第二篇 基于SRS 实现RTSP接入与WebRTC播放 第三篇 centos下基于ZLMediaKit 的WebRTC 环境搭建 第四篇 WebRTC学习一:获取音频和视频设备 第五篇 WebRTC学习二:WebRTC音视频数据采集 第六篇 WebRTC学习三…...
元宇宙浪潮下,前端开发如何“乘风破浪”?
一、元宇宙对前端开发的新要求 元宇宙的兴起,为前端开发领域带来了全新的挑战与机遇。元宇宙作为一个高度集成、多维互动的虚拟世界,要求前端开发不仅具备传统网页开发的能力,还需要掌握虚拟现实(VR)、增强现实&#…...
2025年3月 Scratch 图形化(二级)真题解析 中国电子学会全国青少年软件编程等级考试
2025.03Scratch图形化编程等级考试二级真题试卷 一、选择题 第 1 题 甲、乙、丙、丁、戊五人参加100米跑比赛,甲说:“我的前面至少有两人,但我比丁快。”乙说:“我的前面是戊。”丙说:“我的后面还有两个人。”请从前往后(按照速度快慢&a…...
【新能源汽车整车动力学模型深度解析:面向MATLAB/Simulink仿真测试工程师的硬核指南】
1. 前言 作为MATLAB/Simulink仿真测试工程师,掌握新能源汽车整车动力学模型的构建方法和实现技巧至关重要。本文将提供一份6000+字的深度技术解析,涵盖从基础理论到Simulink实现的完整流程。内容经过算法优化设计,包含12个核心方程、6大模块实现和3种验证方法,满足SEO流量…...
MCP协议的Streamable HTTP:革新数据传输的未来
引言 在数字化时代,数据传输的效率和稳定性是推动技术进步的关键。MCP(Model Context Protocol)作为AI生态系统中的重要一环,通过引入Streamable HTTP传输机制,为数据交互带来了革命性的变化。本文将深入解读MCP协议的…...
dify中配置使用Ktransformer模型
一共是两个框架一个是Ktransformer,一个是dify。 Ktransformer用来部署LLM,比如Deepseek,而LLm的应用框架平台Dify主要用来快速搭建基于LLM应用。 这篇教程主要是用来介绍两个框架的交互与对接的,不是部署Ktransformer也部署部署Dify,要部署Dify、Ktransformer可以直接参考…...
从代码学习深度学习 - GRU PyTorch版
文章目录 前言一、GRU模型介绍1.1 GRU的核心机制1.2 GRU的优势1.3 PyTorch中的实现二、数据加载与预处理2.1 代码实现2.2 解析三、GRU模型定义3.1 代码实现3.2 实例化3.3 解析四、训练与预测4.1 代码实现(utils_for_train.py)4.2 在GRU.ipynb中的使用4.3 输出与可视化4.4 解析…...
二叉树 递归
本篇基于b站灵茶山艾府的课上例题与课后作业。 104. 二叉树的最大深度 给定一个二叉树 root ,返回其最大深度。 二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。 示例 1: 输入:root [3,9,20,null,null,15,7] 输出&…...
#SVA语法滴水穿石# (002)关于 |-> + ##[min:max] 的联合理解
今天,我们着重理解一些概念。依靠死记硬背去理解知识点,是不长久的,必须深刻理解知识点的精髓,才能长久记忆。 先看如下的代码: property a2b_p; //描述属性@(posedge clk) $rose(tagError) |-> ##[2:4] $rose(tErrorBit); endproperty a2b_a: asser…...
反常积分和定积分的应用 2
世界尚有同类 前言伽马函数的推论关于数学的思考平面图形的面积笛卡尔心形线伯努利双纽线回顾参数方程求面积星型线摆线 旋转体体积一般轴线旋转被积函数有负数部分曲线的弧长最后一个部分内容-旋转曲面侧表面积直角坐标系极坐标系参数方程 总结 前言 力大出奇迹。好好加油。 …...
新零售系统是什么样的?有什么好处?
一、新零售系统的核心架构与特征 技术驱动的分层架构 **前端展示层:**支持多终端适配(如APP、小程序、线下智能设备),采用响应式设计提升用户体验。 **业务中台层:**基于微服务架构(如Spring Clou…...
Element-plus弹出框popover,使用自定义的图标选择组件
自定义的图标选择组件是若依的项目的 1. 若依的图标选择组件 js文件,引入所有的svg图片 let icons [] // 注意这里的路径,一定要是自己svg图片的路径 const modules import.meta.glob(./../../assets/icons/svg/*.svg); for (const path in modules)…...
16进制在蓝牙传输中的应用
在蓝牙传输中,16进制(Hexadecimal)是一种常用的数据表示方法。它主要用于描述数据包的内容、地址、命令、参数等信息。以下是16进制在蓝牙传输中的具体应用场景和作用: 1. 数据包的表示 蓝牙通信中,所有数据最终都以二…...
思维链 Chain-of-Thought(COT)
思维链 Chain-of-Thought(COT):思维链的启蒙 3. 思维链 Chain-of-Thought(COT)存在问题?2. 思维链 Chain-of-Thought(COT)是思路是什么?1. 什么是 思维链 Chain-of-Thoug…...
硬件电路(23)-输入隔离高低电平有效切换电路
一、概述 项目中为了防止信号干扰需要加一些隔离电路,而且有时传感器的信号是高有效有时是低有效,所以基于此背景,设计了一款方便实现高低电平有效检测切换电路。 二、应用电路...
多表查询的多与一
1.查寻表需要的条件 1.1.首先我们要了解查询表有哪些 1.1.1.多对一 多对一就是一个年表拥有例外一个表的多条数据 一个表对应立一个表的多条数据,另一个表对应这个表的多条数据 这个点被称为多对一 1.1.2.多对多 多对多简单来说就是需要一个中间商 中间商就…...
大模型学习二:DeepSeek R1+蒸馏模型组本地部署与调用
一、说明 DeepSeek R1蒸馏模型组是基于DeepSeek-R1模型体系,通过知识蒸馏技术优化形成的系列模型,旨在平衡性能与效率。 1、技术路径与核心能力 基础架构与训练方法 DeepSeek-R1-Zero:通过强化学习(RL)训练&…...
相机的曝光和增益
文章目录 曝光增益增益原理主要作用增益带来的影响增益设置与应用 曝光 参考:B站优致谱视觉 增益 相机增益是指相机在拍摄过程中对图像信号进行放大的一种操作,它在提高图像亮度和增强图像细节方面起着重要作用,以下从原理、作用、影响以…...
Linux内核物理内存组织结构
一、系统调用sys_mmap 系统调用mmap用来创建内存映射,把创建内存映射主要的工作委托给do_mmap函数,内核源码文件处理:mm/mmap.c 二、系统调用sys_munmap 1、vma find_vma (mm, start); // 根据起始地址找到要删除的第一个虚拟内存区域 vma 2…...
【PostgreSQL内核学习:深入理解 PostgreSQL 中的 tuplesort_performsort 函数】
深入理解 PostgreSQL 中的 tuplesort_performsort 函数 函数概述函数源码函数签名核心功能相关函数简介 代码结构与逻辑分析1. 内存上下文切换2. 调试跟踪(可选)3. 状态机逻辑(switch 分支)4. 调试跟踪(完成时…...
谷歌 Gemini 2.5 Pro 免费开放
2025 年 3 月 30 日,谷歌宣布将最新的 Gemini AI 旗舰模型 Gemini 2.5 Pro 免费向所有 Gemini 应用用户开放。以下是关于此次免费开放的一些具体信息1: 背景:此前,Gemini 2.5 Pro 仅向支付 19.99 美元月费的 Gemini Advanced 用户…...
(多看) CExercise_05_1函数_1.2计算base的exponent次幂
题目: 键盘录入两个整数:底(base)和幂指数(exponent),计算base的exponent次幂,并打印输出对应的结果。(注意底和幂指数都可能是负数) 提示:求幂运算时,基础的思路就是先无脑把指数转…...
leetcode刷题 - 数组理论基础
数组是内存空间连续存储、相同类型数据的集合。遍历方式:下标索引 下标:从 0 开始 数组的元素不能删除,只能覆盖 定义一维数组: int arr0[10]; int arr1[10] { 100, 90,80,70,60,50,40,30,20,10 }; int arr2[ ] { 100,90,80,7…...
Jetpack Compose `ACTION_HOVER_EXIT` 事件异常解决方案
Jetpack Compose 1.6.6 版本中 ACTION_HOVER_EXIT 事件异常解决方案 问题现象 在 Android 应用开发中使用 Jetpack Compose 1.6.6 版本时,部分设备会出现以下崩溃日志: java.lang.IllegalStateException: The ACTION_HOVER_EXIT event was not cleare…...
Vuue2 element-admin管理后台,Crud.js封装表格参数修改
需求 表格数据调用列表接口,需要多传一个 Type字段,而Type字段的值 需要从跳转页面Url上面获取到,并赋值给Type,再传入列表接口中,最后拿到表格数据并展示 遇到的问题 需求很简单,但是因为表格使用的是统…...
Tiktok矩阵运营中使用云手机的好处
Tiktok矩阵运营中使用云手机的好处 云手机在TikTok矩阵运营中能够大幅提高管理效率、降低封号风险,并节省成本,是非常实用的运营工具。TikTok矩阵运营使用云手机有很多优势,特别是对于需要批量管理账号、提高运营效率的团队来说。以下是几个…...
Linux下调试器gdb_cgdb使用
文章目录 一、样例代码二、使用watchset var确定问题原因条件断点 一、样例代码 #include <stdio.h>int Sum(int s, int e) {int result 0;int i;for(i s; i < e; i){result i;}return result; }int main() {int start 1;int end 100;printf("I will begin…...
Vite环境下解决跨域问题
在 Vite 开发环境中,可以通过配置代理来解决跨域问题。以下是具体步骤: 在项目根目录下找到 vite.config.js 文件:如果没有,则需要创建一个。配置代理:在 vite.config.js 文件中,使用 server.proxy 选项来…...
