类加载机制和反射(反射与泛型)

tech2022-08-21  110

类加载机制和反射

类的加载、连接、初始化

当系统在第一次使用某个类时,加载该类,也可能预加载机制来加载某个类时。 加载 就是指将 class 文件读入内存,并为之创建一个 Class 对象。 任何类被使用时系统都会建立一个 Class 对象 连接 验证 是否有正确的内部结构,并和其他类协调一致 准备 负责为类的静态成员分配内存,并设置默认初始化值 解析 将类的二进制数据中的符号引用替换为直接引用 初始化

类的初始化

类的初始化阶段,虚拟机负责对类进行初始化,主要是对类变量进行初始化,声明类变量时可以给定初始值,或者使用静态初始化块为类变量指定初始化值。 static int a=5; static int b; //或者 static { b=9; }

类加载器

概念:将.class文件加载到内存中,并生成相对应的Class对象 分类以及作用 1.根类加载器//负责Java核心类的加载 2.扩展类加载器//负责Jre的扩展目录中jar包的加载 3.系统类加载器//负责在JVM启动时加载来自java命令的class文件,以及classpath环境变量所指定的jar包和类路径

反射

Java中的反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称 为 java 语言的反射机制。 创建一个学生类,以此举例: public class Student { public String name; int age; private double height; public Student(String name, int age, double height) { this.name = name; this.age = age; this.height = height; System.out.println("有参构造调用了"); } public Student() { System.out.println("无参构造调用了"); } private Student(String name,int age){ this.name=name; this.age=age; System.out.println("私有构造调用了"); } public void show(){ System.out.println("空参方法"); } public void show1(int age){ System.out.println(age); } private void show2(String name,int age){ System.out.println(name+"=="+age); } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + ", height=" + height + "," + '}'; } }

获取class对象

在Java中获取对象可以用三种方式: 1forName(String clazzName)静态方法,且传入参数为完整包名。 2、调用class属性来获取对象。 3getClass()方法。 三种方法对比,第二种方法代码更安全,性能更好。

从class获取信息

通过反射获取构造方法,并实例化。 public class Demo1 { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { //获取当前对象的字节码对象 Class<?> student = Class.forName("com.westore.reflect.Student"); /** * 获取当前字节码对象的构造方法(不包括私有) * public com.westore.reflect.Student() * public com.westore.reflect.Student(java.lang.String,int,double) */ Constructor<?>[] constructors = student.getConstructors(); for (Constructor<?> constructor : constructors) { System.out.println(constructor); } System.out.println("==========="); /** * 获取当前字节码对象的所有构造方法(包括私有) * private com.westore.reflect.Student(java.lang.String,int) * public com.westore.reflect.Student() * public com.westore.reflect.Student(java.lang.String,int,double) */ Constructor<?>[] declaredConstructors = student.getDeclaredConstructors(); for (Constructor<?> declaredConstructor : declaredConstructors) { System.out.println(declaredConstructor); } System.out.println("=========="); /** * 无参构造实例化可直接通过字节码实例化,也可先获取无参构造对象创建对象 */ Object o2 = student.newInstance(); System.out.println("=================="); /** * 获取指定的构造方法,传入形式参数的字节码对象 * 不能获取私有的构造 */ Constructor<?> constructor = student.getConstructor(String.class, int.class, double.class); System.out.println(constructor); //调用构造方法 Object o1 = constructor.newInstance("lee",18,178); System.out.println("=============="); /** * 可获取私有的构造方法 */ Constructor<?> constructor1 = student.getDeclaredConstructor(String.class, int.class); System.out.println(constructor1); //切记,私有的使用时必须调用此方法打破封装 constructor1.setAccessible(true); Object o = constructor1.newInstance("LEE",18); System.out.println("==============="); } } //输出结果 public com.westore.reflect.Student() public com.westore.reflect.Student(java.lang.String,int,double) =========== private com.westore.reflect.Student(java.lang.String,int) public com.westore.reflect.Student() public com.westore.reflect.Student(java.lang.String,int,double) ========== 无参构造调用了 ================== public com.westore.reflect.Student(java.lang.String,int,double) 有参构造调用了 ============== private com.westore.reflect.Student(java.lang.String,int) 私有构造调用了 ===============

通过反射获取字段,并设置值

public class Demo2 { //获取类的字段 public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, InstantiationException { Class<?> aClass = Class.forName("com.westore.reflect.Student"); //实例化无参构造 Object o = aClass.newInstance(); //获取公共字段 Field[] fields = aClass.getFields(); for (Field field : fields) { System.out.println(field); } //获取所有的字段 Field[] declaredFields = aClass.getDeclaredFields(); for (Field declaredField : declaredFields) { System.out.println(declaredField); } //获取任意单个字段,并可以对字段进行设置set时需要传入对象和value,获取时通过get方法获取 Field age = aClass.getDeclaredField("age"); age.set(o,23); System.out.println(age.get(o)); System.out.println(age); //获取私有字段设置私有字段时,必须首先打破封装,否则会出现如下 Field height = aClass.getDeclaredField("height"); height.setAccessible(true); height.set(o,140); System.out.println(height.get(o)); } } //输出结果 无参构造调用了 public java.lang.String com.westore.reflect.Student.name ==================== public java.lang.String com.westore.reflect.Student.name int com.westore.reflect.Student.age private double com.westore.reflect.Student.height protected double com.westore.reflect.Student.weight 23 int com.westore.reflect.Student.age 140.0

通过反射获取方法并调用

public class Demo3 { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException { Class<?> aClass = Class.forName("com.westore.reflect.Student"); Object o = aClass.newInstance(); // 获取所有的公共方法,包括父类 Method[] methods = aClass.getMethods(); for (Method method : methods) { System.out.println(method); } // 获取当前类的所有方法(不包括父类) Method[] declaredMethods = aClass.getDeclaredMethods(); for (Method declaredMethod : declaredMethods) { System.out.println(declaredMethod); } //获取指定无参方法,并调用(只适合公开的方法) Method show = aClass.getMethod("show"); Object invoke = show.invoke(o); //获取指定有参方法,并调用(只适合公开的方法) Method show1 = aClass.getMethod("show1", int.class); Object invoke1 = show1.invoke(o, 23); //获取指定有参方法,可获取所有类型修饰的方法,私有方法必须打破封装 Method show2 = aClass.getDeclaredMethod("show2", String.class, int.class); show2.setAccessible(true); Object lee = show2.invoke(o, "zhangsan", 24); } } //输出结果 无参构造调用了 public java.lang.String com.westore.reflect.Student.toString() public void com.westore.reflect.Student.show() public void com.westore.reflect.Student.show1(int) public final void java.lang.Object.wait() throws java.lang.InterruptedException public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException public boolean java.lang.Object.equals(java.lang.Object) public native int java.lang.Object.hashCode() public final native java.lang.Class java.lang.Object.getClass() public final native void java.lang.Object.notify() public final native void java.lang.Object.notifyAll() public java.lang.String com.westore.reflect.Student.toString() public void com.westore.reflect.Student.show() public void com.westore.reflect.Student.show1(int) private void com.westore.reflect.Student.show2(java.lang.String,int) 空参方法 23 zhangsan==24

反射与泛型

在JDK5之后加入了泛型这个功能,name使用反射就可以对泛型做一些事情。比如说使用反省可以避免强制转换: public class demo4 { public static <T> T getInstance(Class<T> cls){ try { return cls.getConstructor().newInstance(); }catch (Exception e) { e.printStackTrace(); return null; } } public static void main(String[] args) { Date d =demo0806.getInstance(Date.class); JFrame frame=demo0806.getInstance(JFrame.class); } } 接下来当使用这个demo的时候,无须强制转换,系统会执行严格检查,进一步的如果对Array进行操作可以再改写成: public class Demo5 { public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { ArrayList<Integer> arrayList=new ArrayList<>(); arrayList.add(100); arrayList.add(200); //直接添加其他类型会出现以下错误 //arrayList.add("我"); Error:(10, 18) java: 对于add(java.lang.String), 找不到合适的方法 //方法 java.util.Collection.add(java.lang.Integer)不适用*/ //获取arrlist字节码对象 Class<? extends ArrayList> aClass = arrayList.getClass(); //获取方法对象 Method add = aClass.getMethod("add", Object.class); //调用方法 Object o = add.invoke(arrayList, "反射"); //遍历集合 for (int i=0;i<arrayList.size();i++){ System.out.println(arrayList.get(i)); } } } //输出结果 100 200 反射
最新回复(0)