栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java基础程序——反射

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java基础程序——反射

目录

一、类加载器

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);
    }
}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/874207.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号