Java基础程序——反射

Java基础程序——反射,第1张

目录

一、类加载器

1.1、类的加载

1.2、类的加载时机

1.3、类加载器

1.4、类加载器的组成

二、反射

2.1、Class类

2.2、通过反射获取构造方法并使用

2.3、通过反射方式,获取私有构造方法,创建对象

2.4、通过反射获取成员变量并使用

2.5、通过反射,创建对象,获取指定的成员变量,进行赋值与获取值 *** 作

2.6、通过反射获取成员方法并使用

2.7、通过反射,创建对象,调用指定的方法

2.8、通过反射,创建对象,调用指定的private 方法

三、反射应用

3.1、泛型擦除

3.2、反射配置文件


一、类加载器 1.1、类的加载

当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载、连接、初始三步来实现这个类的初始化。

加载 

  •  指将class文件读入内存,并为之创建一个Class对象
  • 任何类被使用时,系统都会建立一个Class对象

连接

  • 验证:是否有正确的内部结构,并和其他类协调一致
  • 准备:负责为类的静态成员分配内存,并设置默认初始化值
  • 解析:将类的二进制数据中的符号引用替换为直接引用

初始化

  • 初始化步骤(new 对象)

1.2、类的加载时机
  • 创建类的实例
  • 类的静态变量,或者为静态变量赋值
  • 类的静态方法
  • 使用反射方式来强制创建某个类或接口对应的java.long.Class对象
  • 初始化某个类的子类
  • 直接使用java.exe命令来运行某个主类

1.3、类加载器

负责将.class文件加载到内存中,并为之生成对应的Class对象


1.4、类加载器的组成
  • Bootstrap ClassLoader 根类加载器,也被称为引导类加载器,负责java核心类的加载。比如System、String等,在JDK中lib目录下rt.jar文件中
  • Extension ClassLoader 扩展类加载器,负责JRE中的扩展目录下的jar包的加载,在JDK中jre的lib目录下ext目录
  • System ClassLoader系统类加载器,负责在JVM启动时,加载来自java命令的class文件,以及classpath环境变量所指定的jar包和类路径

二、反射

定义:在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性,这种动态获取的信息以及动态调用对象的功能称为Java语言的反射机制


2.1、Class类

Class没有公共构造方法。Class对象时加载类时有Java虚拟机以及通过调用类加载器中defineClass方法自动构造的

获取Class对象的三种方式

  • 通过Object类中的getClass() 方法
        Person person = new Person();
        Class c = person.getClass();
  • 通过  类名.class 获取字节码文件对象
Class c = Person.class();
  • 通过 Class类中的方法
 Class c = Class.forName("Person");

注意:第三种和前两种的区别

  • 前两种必须明确Person类型
  • 第三种是指定这种类型的字符串即可,这种扩展性更强。不需要知道类,只需要提供字符串,按照配置文件加载即可

2.2、通过反射获取构造方法并使用

在反射机制中,把类成员(构造方法、成员方法、成员变量)都封装成了对应的类进行表示

构造方法使用Constructor类表示。可以通过Class类中提供的方法来获取构造方法:

  • 返回一个构造方法
  1. getConstructor(Class..param) 获取public修饰,指定参数类型所对应的构造方法
  2. getDeclaredConstructor(Class...param)
  • 获取构造方法:
  1. 获取到Class对象
  2. 获取指定的构造方法
  3. 通过构造方法类Constructor中的方法,创建对象   public T newInstance(Object... initargs)

Person类

public class Person {
public String name;
public int age;
private String address;
public Person() {
System.out.println("空参构造方法");
}
public Person(String name) {
this.name = name;
System.out.println("带有String的构造方法");
}
private Person(String name, int age) {
this.name = name;
this.age = age;
System.out.println("带有String, int的构造方法");
}
public Person(String name, int age, String address) {
this.name = name;
this.age = age;
this.address = address;
System.out.println("带有String, int, String的构造方法");
}
public void method1() {
System.out.println("没有返回值没有参数的方法");
}
public void method2(String name) {
System.out.println("没有返回值, 有参数的方法, name = " +
name);
}
public int method3() {
System.out.println("有返回值, 没有参数的方法");
return 123;
}
public String method4(String name) {
System.out.println("有返回值, 有参数的方法");
return name;
}
private void method5() {
System.out.println("私有方法");
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", address='" + address + '\'' +
'}';
}
}
public class Demo {
    public static void main(String[] args) {
        try {
            Class c3  = Class.forName("day0507.fanshe.Person");
            Constructor declaredConstructor = c3.getDeclaredConstructor(String.class);
            Object instance = declaredConstructor.newInstance("小镭");
            System.out.println(instance);
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

2.3、通过反射方式,获取私有构造方法,创建对象
  • AccessibleObject 类是 Field、Method 和 Constructor 对象的父类。它提供了将反射的对象,标记为在使用时取消默认 Java 语言访问控制检查的能力。
  • 对于公共成员、默认(打包)访问成员、受保护成员和私有成员,在分别使用 Field、 Method 或 Constructor 对象来设置或获取字段、调用方法,或者创建和初始化类的新实例 的时候,会执行访问检查。常用方法如下:
  • public void setAccessible(boolean flag) throws SecurityException 参数值为 true,则指示反射的对象在使用时应该取消 Java 语言访问检查。参数值为 false,则指示反射的对象应该实施 Java 语言访问检查。

获取私有构造方法,创建对象:

  1. 获取到Class对象
  2. 获取指定的构造方法
  3. 暴力访问,通过setAccessible(boolean flag)方法
  4. 通过构造方法类Constructor中的方法,创建对象  public T newInstance(Object... initargs)
public class Demo {
    public static void main(String[] args) {
        try {
            Class c3  = Class.forName("day0507.fanshe.Person");
            Constructor declaredConstructor = c3.getDeclaredConstructor(String.class);
            // 取消java语言的访问检查 
            declaredConstructor.setAccessible(true);
            Object instance = declaredConstructor.newInstance("小镭");
            System.out.println(instance);
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

2.4、通过反射获取成员变量并使用

在反射机制中,把类中成员变量使用Field类表示。可通过Class类中提供的方法获取成员变量:

  • 返回一个成员变量
  1. getField(String name) 获取指定的public修饰的变量
  2. getDeclaredField(String) 获取指定的任意变量
  • 返回多个成员变量
  1. getFields() 获取指定的public修饰的变量
  2. getDeclaredFields() 获取所有的变量
public class FiledDemo {
public static void main(String[] args) throws
ClassNotFoundException, NoSuchFieldException {
Class clazz =
Class.forName("com.kaylee.reflect.Person");
Field name = clazz.getField("name");
System.out.println(name);
Field address = clazz.getDeclaredField("address");
System.out.println(address);
Field[] fields = clazz.getFields();
System.out.println("所有public修饰的变量:");
for (Field field : fields) {
System.out.println(field);
}
Field[] fields2 = clazz.getDeclaredFields();
System.out.println("所有的变量:");
for (Field field : fields2) {
System.out.println(field);
}
}
}
2.5、通过反射,创建对象,获取指定的成员变量,进行赋值与获取值 *** 作

获取成员变量,步骤如下:

  1. 获取Class对象 
  2. 获取构造方法
  3. 通过构造方法,创建对象
  4. 获取指定成员变量(私有成员变量,通过setAccessible(boolean flag) 取消访问检查)
  5. 通过Field提供的方法,给指定成员变量进行赋值或获取值的 *** 作
  • get(Object obj) 获取指定成员变量的值
  • set(Object obj, Object value) 给指定成员变量赋值
public class FiledDemo2 {
public static void main(String[] args) throws
ClassNotFoundException, NoSuchFieldException,
NoSuchMethodException, IllegalAccessException,
InvocationTargetException, InstantiationException {
Class clazz =
Class.forName("com.kaylee.reflect.Person");
Constructor constructor =
clazz.getDeclaredConstructor(String.class);
Object instance = constructor.newInstance("张三");
Field name = clazz.getField("name");
Field age = clazz.getField("age");
Field address = clazz.getDeclaredField("address");
address.setAccessible(true);
// 获取指定成员变量的值
System.out.println("name = " + name.get(instance));
System.out.println("age = " + age.get(instance));
System.out.println("address = " +
address.get(instance));
System.out.println("==================");
// 给指定成员变量赋值
name.set(instance, "李四");
age.set(instance, 22);
address.set(instance, "地球村");
System.out.println("name = " + name.get(instance));
System.out.println("age = " + age.get(instance));
System.out.println("address = " +
address.get(instance));
}
}

2.6、通过反射获取成员方法并使用

在反射机制中,把类中的成员方法使用Method类表示。可通过Class类中提供的方法获取成员方法:

  • 返回获取一个方法
  1. getMethod(String name,Class..param)获取public修饰的方法
  2. getDeclaredMethod(String name,Class..param)获取任意修饰的方法
  • 返回获取多个方法
  1. getMethods() 获取本类与父类中的所有public修饰的方法
  2. getDeclaredMethods() 获取本类中所有的方法
public class MethodDemo {
public static void main(String[] args) throws
ClassNotFoundException, NoSuchMethodException {
Class clazz =
Class.forName("com.kaylee.reflect.Person");
Method[] methods = clazz.getMethods();
for(Method method : methods) {
System.out.println(method);
}
System.out.println("============================");
Method[] methods2 = clazz.getDeclaredMethods();
for(Method method : methods2) {
System.out.println(method);
}
System.out.println("============================");
Method method1 = clazz.getMethod("method1", null);
System.out.println(method1);
Method method2 = clazz.getMethod("method2",
String.class);
System.out.println(method2);
Method method5 = clazz.getDeclaredMethod("method5",
null);
System.out.println(method5);
}
}

2.7、通过反射,创建对象,调用指定的方法

获取成员方法,步骤如下:

  1. 获取Class对象
  2. 获取构造方法
  3. 通过构造方法,创建对象
  4. 获取指定的方法
  5. 执行找到的方法
  • public Object invoke(Object obj, Object... args)
  • 执行指定对象obj中,当前Method对象所代表的方法,方法要传入的参数 通过args指定。  
public class MethodDemo {
public static void main(String[] args) throws
ClassNotFoundException, NoSuchMethodException {
Class clazz =
Class.forName("com.kaylee.reflect.Person");
Method[] methods = clazz.getMethods();
for(Method method : methods) {
System.out.println(method);
}
System.out.println("============================");
Method[] methods2 = clazz.getDeclaredMethods();
for(Method method : methods2) {
System.out.println(method);
}
System.out.println("============================");
Method method1 = clazz.getMethod("method1", null);
System.out.println(method1);
Method method2 = clazz.getMethod("method2",
String.class);
System.out.println(method2);
Method method5 = clazz.getDeclaredMethod("method5",
null);
System.out.println(method5);
}
}

2.8、通过反射,创建对象,调用指定的private 方法

获取私有成员方法,步骤如下:

  1. 获取Class对象
  2. 获取构造方法
  3. 通过构造方法,创建对象
  4. 获取指定的方法
  5. 开启暴力访问 
  6. 执行找到的方法  
public class MethodDemo2 {
public static void main(String[] args) throws
ClassNotFoundException, NoSuchMethodException,
IllegalAccessException, InvocationTargetException,
InstantiationException {
Class clazz =
Class.forName("com.kaylee.reflect.Person");
Constructor constructor =
clazz.getDeclaredConstructor(String.class, int.class,
String.class);
Object obj = constructor.newInstance("张三", 22, "地球村");
Method method1 = clazz.getMethod("method1", null);
method1.invoke(obj, null);
Method method4 = clazz.getMethod("method4",
String.class);
Object result = method4.invoke(obj, "哈哈哈");
System.out.println("返回值:" + result);
Method method5 = clazz.getDeclaredMethod("method5",
null);
method5.setAccessible(true);
method5.invoke(obj, null);
}
}

三、反射应用 3.1、泛型擦除

将已存在的ArrayList集合中添加一个字符串数据

程序编译后产生的.class文件中是没有泛型类型约束的,这种现象我们称为泛型的擦除。因此,我们通过反射技术,来完成

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;

public class ReflectTest {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        ArrayList list = new ArrayList<>();
        list.add(1);
        list.add(2);
        // list.add("哈哈哈")   // 因为有泛型的约束不能添加字符串类型数据
        System.out.println(list);

        //Class c1 = list.getClass();
        //Class c2 = ArrayList.class;

        Class clazz = Class.forName("java.util.ArrayList");
        Method add = clazz.getMethod("add", Object.class);
        add.invoke(list,"哈哈哈");
        System.out.println(list);
    }
}

3.2、反射配置文件

通过反射配置文件,运行配置文件中指定类对应的方法

读取Personproperties.txt文件中的数据,通过反射技术,来完成对Person对象的创建

Personproperties的内容如下:

className=day0507.fanshe.Person
methodName=method5
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;

public class ReflectTest2 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, IOException, InstantiationException {
        // 通过Personproperties集合从文件中读取数据
        Properties prop = new Properties();
        // 读取文件中的数据到集合中
        prop.load(new FileInputStream("D:\\实训\\Demo\\src\\day0507\\fanshe\\Personproperties.txt"));

        // 获取键所对应的值
        String className = prop.getProperty("className");
        // 获取字节码文件对象
        Class clazz = Class.forName(className);
        // 获取构造方法
        Constructor con = clazz.getDeclaredConstructor(null);
        // 创建对象
        Object obj = con.newInstance(null);

        //获取指定的方法
        String methodName = prop.getProperty("methodName");
        Method method5 = clazz.getDeclaredMethod(methodName,null);
        method5.setAccessible(true);
        // 执行方法
        method5.invoke(obj,null);
    }
}

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/905697.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-15
下一篇 2022-05-15

发表评论

登录后才能评论

评论列表(0条)

保存