反射机制

通过java语言的反射机制可以操作字节码文件,让程序更加灵活。与反射机制相关的重要的类有:

1.java.lang.Class:每个类运行时的类型信息是用Class对象表示的,每个类都有一个Class对象。

2.java.lang.reflect.Method:代表字节码中的方法字节码。代表类中的方法。

3.java.lang.reflect.Constructor:代表字节码中的构造方法字节码。代表类中的构造方法。

4.java.lang.reflect.Field:代表字节码中的属性字节码。代表类中的成员变量。

获取Class对象的三种方式

1.Class c = Class.forName(“全限定类名”);
Class.forName()的执行会导致类的加载

	  	try {
            Class c1 = Class.forName("java.lang.String");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

2.Class c = 对象.getClass();

String s = "a";
Class c2 = s.getClass();

3.Class c = 任何类型.class;

Class c3 = String.class;

字节码文件装载到JVM的时候只装载一份

System.out.println(c1 == c2); // true
System.out.println(c2 == c3); // true

创建由Class类对象表示的类的新实例

Object o = c.newInstance(); c为Class对象
通过反射机制获取实例化对象的方法更加灵活,只需要改变配置文件,就可以实例化出不同的对象。

public static void instance() {
		// 绑定配置文件,通过修改classinfo.properties文件中的value值可以实例化不同的对象
        ResourceBundle bundle = ResourceBundle.getBundle("classinfo");
        // classinfo.properties文件中的内容为:className=java.util.Date
        // className = java.util.Date(任意全限定类名)
        String className = bundle.getString("className");  

        try {
            Class c = Class.forName(className);
            // o为Date类的实例
            Object o = c.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

newInstance()底层调用的是该类的无参构造方法。如果没有无参构造方法会出现“实例化”异常。

使用反射机制获取目标类的成员变量

package com.xs.bean;

public class Student {
    public int no;
    private String name;
    protected int age;
    boolean sex;
    private static final Double MATH_PI = 3.1415926;
}

package com.xs.reflection;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

public class ReflectionField {

    public static void main(String[] args) {
        try {
            // 获取整个类
            Class studentClass = Class.forName("com.xs.bean.Student");
			
			// obj就是Student对象
			Object obj = studentClass.newInstance();  

			// 给成员变量赋值
            Field noField = studentClass.getDeclaredField("no");
            System.out.println(noField);  // public int com.xs.bean.Student.no
            noField.set(obj,15);      // 给obj对象的no属性赋值
            System.out.println(noField.get(obj));  // 获取obj对象的no属性的值:15

			Field nameField = studentClass.getDeclaredField("name");
            // 打破封装 (反射机制的缺点,打破封装可能给不法分子留下机会)
            // 这样设置完后,在外部也可以访问private。
            nameField.setAccessible(true);
            nameField.set(obj,"张三");  // 给obj对象的name属性赋值
            System.out.println(nameField.get(obj));  // 获取obj对象的name属性的值:张三            


            // 获取类名
            String name1 = studentClass.getName();
            System.out.println("完整类名:" + name1);  // 完整类名:com.xs.bean.Student

            String name2 = studentClass.getSimpleName();
            System.out.println("简单类名:" + name2);  // 简单类名:Student

            // 获取类中所有的public修饰的Field
            Field[] fields = studentClass.getFields();
            System.out.println(fields.length); // 1
            System.out.println(fields[0]);   // public int com.xs.bean.Student.no
            String name3 = fields[0].getName();
            System.out.println(name3);  // no
            
            // 获取所有的Field
            Field[] fields1 = studentClass.getDeclaredFields();
            System.out.println(fields1.length);  // 5
            
            for (Field field : fields1) {
                // 获取属性的修饰符列表,返回的是一个数字,每个数字对应不同的修饰符
                int i = field.getModifiers();
                System.out.println(i);  // 1 、2 、4 、0 、26
                
                // 将数字转换成对应的修饰符
                String modifierString = Modifier.toString(i);
                System.out.println(modifierString); // public、 private、 protected、空 、private static final
                
                // 获取属性的类型
                Class<?> type = field.getType();
                System.out.println(type); // int、class java.lang.String、 int、 boolean、 class java.lang.Double
                System.out.println(type.getSimpleName()); // int、 string、 int、 boolean、 Double
                
                // 获取属性的名字
                System.out.println(field.getName()); // no、 name、 age、 sex、 MATH_PI
            }
            
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

将代码中的字符串替换成配置文件,修改属性的值只需要修改配置文件,不需要修改源代码。

使用反射机制调用目标类的方法

目标类

package com.xs.service;

public class UserService {

    public boolean login(String username, String password) {
        return "admin".equals(username) && "123456".equals(password);
    }

    public void logout() {
        System.out.println("系统已经安全退出");
    }
}

使用反射机制调用UserService类中的方法

package com.xs.reflection;

import java.lang.reflect.Method;

public class ReflectionMethod2 {

    public static void main(String[] args) {
        try {
            Class methodClass = Class.forName("com.xs.service.UserService");
            // 获取对象
            Object obj = methodClass.newInstance();
            // 获取Method
            Method loginMethod = methodClass.getDeclaredMethod("login", String.class, String.class);
            // 调用方法
            Object retValue = loginMethod.invoke(obj, "admin", "123456");
            System.out.println(retValue);  // true
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

使用反射机制调用目标类构造方法

目标类

package com.xs.bean;

public class Account {

    private int id;
    private String name;

    public Account() {
    }

    public Account(int id, String name) {
        this.id = id;
        this.name = name;
    }

    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

使用反射机制调用Account类的构造方法

package com.xs.reflection;

import java.lang.reflect.Constructor;

public class ReflectionConstructor {

    public static void main(String[] args) {
        try {
            Class constructorClass = Class.forName("com.xs.bean.Account");

            // 调用无参构造方法
            Object obj1 = constructorClass.newInstance();
            System.out.println(obj1);  // Account{id=0, name='null'}

            // 调用有参数的构造方法
            // 获取有参数的构造方法
            Constructor con = constructorClass.getDeclaredConstructor(int.class, String.class);
            // 调用构造方法new对象
            Object obj2 = con.newInstance(20, "李四");
            System.out.println(obj2);  // Account{id=20, name='李四'}

			// 获取无参数的构造方法
            Constructor con2 = constructorClass.getDeclaredConstructor();
            // 调用无参数的构造方法
            Object obj3 = con2.newInstance();
            System.out.println(obj3);  // Account{id=0, name='null'}
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

通过反射机制获取目标类的父类及其实现的所有接口

package com.xs.reflection;

public class ReflectionTest {

    public static void main(String[] args) {
        try {
            Class stringClass = Class.forName("java.lang.String");

            // 获取String的父类
            Class superClass = stringClass.getSuperclass();
            System.out.println(superClass.getSimpleName());
            
            // 获取String类实现的所有接口
            Class[] interfaces = stringClass.getInterfaces();
            for (Class in : interfaces) {
                System.out.println(in.getName());
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}
运行结果:
Object
java.io.Serializable
java.lang.Comparable
java.lang.CharSequence
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值