java 反射机制

1.概述

以下是SUN提供的反射机制中的类:

简介
java.lang.ClassClass c =ox123;对应反射类的整体
java.lang.reflect.ConstructorConstructor c =ox456;对应反射类中的构造方法
java.lang.reflect.FieldField f = ox789;对应反射类中的参数对象等
java.lang.reflect.MethodMethod m = ox963;对应反射类中的方法
java.lang.reflect.ModifierModifier m = ox741;对应反射类中的各种修饰,如public、private等

反射机制的作用?

  • 反编译:.class–>.java
  • 通过反射机制访问java对象的属性,方法,构造方法等。

2.引入反射机制及其一些实际应用

获取Class类型对象的三种方式:

/**
 * 获取Class类对象的三种方式
 * 
 * 获得的Class可以通过newInstance()方法来调用java对象的无参数构造方法。如果确实无参构造方法将报错。
 */
public class ReflectTest01 {
    public static void main(String[] args) throws ClassNotFoundException {
        // 方式1:
        // c1引用保存内存地址指向堆吃对象,该对象代表的是DeadLock整个类。Class.forName(String className); className所需的类的完全限定名
        Class c1 = Class.forName("com.cqy.practice.thread.DeadLock");// 将DeadLock.class文件装载到JVM中的过程,静态方法将被执行。
        System.out.println(c1);
        
        // 方式2:
        // java中每个类中都有class属性,使用.class获取
        Class c2 = com.cqy.practice.thread.DeadLock.class;// 不会执行DeadLock中的静态语句块
        System.out.println(c2);
        
        // 方式3:
        // java语言中任何一个java对象都有getClass()方法
        DeadLock d = new DeadLock();// com.cqy.practice.thread.DeadLock
        Class c3 = d.getClass();
        System.out.println(c3);// c3是运行时类(d的运行时类是DeadLock)
        
        // 因为类在JVM中只有一个,所以c1,c2,c3的内存地址是相同的,指向堆中唯一的一个对象。
        System.out.println(c1 == c2);// true
        System.out.println(c3 == c2);// true
    }
}

IO+Properties的联合应用:

/**
 * IO+Properties
 * dataBase.properties这样的文件称作配置文件,其作用就是使程序更加灵活
 * 
 * 注意:一般在程序中可变的东西不要写死,推荐写到配置文件中,可以运行相同代码产生不同结果
 * 
 * 属性文件在java规范中要求以“.properties”作为后缀
 * 
 * 属性文件格式要求:
 *      key和value之间可以使用“空格”、“冒号”、“等号”。
 *      如果“空格”、“冒号”、“等号”都有,按最前的作为分隔符
 * 
 * tip:在cmd.exe中native2ascii命令可以将中文转换为Unicode码,属性文件中中文使用Unicode码可以解决乱码的情况
 */
public class IOAndProperties {
    public static void main(String[] args) throws IOException {
        // 1、创建属性对象
        Properties ps = new Properties();// 和Map一样,只不过key和value只能存储字符串类型
        // 2、创建输入流
        FileInputStream is = new FileInputStream("E:\\learing\\temporary\\dataBase.properties");// username=name
                                                                                                // password=123456
        // 将is流中的所有数据加载到属性对象中,其结果是一组组键值对
        ps.load(is);
        // 关闭流
        is.close();
        // 通过getProperty(K)方法,使用key值获取value,
        System.out.println("username>>>" + ps.getProperty("username"));
        System.out.println("password>>>" + ps.getProperty("password"));
    }
}

IO+Properties+reflect的联合应用:

// 实体类
class User {
    private String id;
    public int age;
    protected String addr;
    boolean sex;
    User() {}
    User(String id, String addr) {
        this.id = id;
        this.addr = addr;
    }
    public String toString() {
        return "User["+id+" , "+addr+"]";
    }
    // 登入
    public boolean login(String name, String pwd) {
        if ("admin".equals(name) && "123".equals(pwd)) {
            return true;
        }
        return false;
    }
    // 退出
    public void loginOut() {
        System.out.println("系统已安全退出!");
    }
}
// 综合应用
public class IOAndProtoertiseAndReflect {
    public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException, SecurityException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException {
        // 1、创建属性对象
        Properties pro = new Properties();
        // 2、创建输入流
        FileInputStream fis = new FileInputStream("E:\\learing\\temporary\\IOProRef.properties");// className=com.cqy.practice.reflect.User声明-->
                                                                                                 // private String id;public int age;boolean sex;
        // 3.加载
        pro.load(fis);
        // 关闭流
        fis.close();
        String className = pro.getProperty("className");
        System.out.println("className-->" + className);
        // 通过反射机制创建对象,通过配置文件使得此处代码更加灵活
        Class c = Class.forName(className);
        Object o = c.newInstance(); // 创建对象
        System.out.println("Object-->" + o);
        
        // 获取public声明的变量名
        Field[] fs = c.getFields();
        System.out.println(fs[0].getName());// age
        
        // 获取指定的变量,更加灵活的方式对属性赋值,将id放到配置文件中将大大提高配置和获取属性的灵活性
        Field fid = c.getDeclaredField("id");
        System.out.println(fid.getName());
        
        // 打破封装,可以获取private和protected修饰的变量和方法
        fid.setAccessible(true);
        
        fid.set(o, "001");// 给o对象的id赋值001
        String id = (String) fid.get(o);// 从o对象中读取id的值
        System.out.println("id-->" + id);// 输出:id-->001
        
        // 获取反射机制对应类的相关信息
        StringBuffer sb = new StringBuffer();
        sb.append(Modifier.toString(c.getModifiers()));// 类名修饰符
        sb.append(" class ");
        sb.append(c.getSimpleName());// 获取类名
        sb.append(" {");
        sb.append("\n");// 换行
        Field[] fs2 = c.getDeclaredFields();
        for (Field f2 : fs2) {
            sb.append("\t");// 缩进
            sb.append(Modifier.toString(f2.getModifiers()));// 获取修饰符
            sb.append(" ");
            sb.append(f2.getType().getSimpleName()); // 获取类型
            sb.append(" ");
            sb.append(f2.getName());// 获取变量名
            sb.append(";");
            sb.append("\n");// 换行
        }
        
        // 获取特定方法,用于方法调用
        Method m1 = c.getDeclaredMethod("login", String.class, String.class);// 方法+形参列表,可以将此配置到配置文件中提高灵活性

        // 通过o对象的m1方法,传递“admin”、“123”参数,方法的执行结果是returnValue
        Object returnValue = m1.invoke(o, "admin", "123");
        System.out.println("returnValue-->" + returnValue);// 输出:returnValue-->true
        
        // 获取所有构造方法,反编译参考方法的获取过程
        Constructor[] cs = c.getDeclaredConstructors();
        
        // 获取特定的构造方法
        Constructor con = c.getDeclaredConstructor(String.class, String.class);
        Object obj = con.newInstance("002", "北京清华大学东门公厕内!");
        System.out.println("Constructor-->" + obj);
        
        // 获取所有方法
        Method[] ms = c.getDeclaredMethods();
        for (Method m :ms) {
            sb.append("\t");// 缩进
            sb.append(Modifier.toString(m.getModifiers()));// 方法修饰符
            sb.append(" ");
            sb.append(m.getReturnType().getSimpleName());// 返回值类型
            sb.append(" ");
            sb.append(m.getName());
            sb.append("(");
            Parameter[] ps = m.getParameters();// 获取所有入参参数
            // m.getParameterTypes();// 获取所有类型
            int i = 0;
            for (Parameter p : ps) {
                sb.append(p.getType().getSimpleName());
                sb.append(" ");
                sb.append(p.getName());
                if (i < ps.length - 1) {
                    sb.append(", ");
                } 
                i++;
            }
            sb.append(") {\n");
            sb.append("\t}\n");
        }
        sb.append("\n");
        sb.append(" }");
        System.out.println(sb.toString());
        
        // 通过反射机制获取父类和父接口
        Class cStr = Class.forName("java.lang.String");
        Class superC = cStr.getSuperclass();
        // 输出父类名称
        System.out.println(superC.getName());
        // 获取父类接口
        Class[] classes = cStr.getInterfaces();
        for (Class css : classes) {
            System.out.println(css.getName());
        }
    }
}

3.反射机制的两个缺点:

反射机制是一种强大的工具,主要有以下两点不足:

  • 性能问题。使用反射机制是一种解释操作,我们告诉JVM,我们希望做什么并且它满足我们的要求。用于字段和方法接入时,反射要远慢于直接代码。性能问题的程度取决于程序中是如何使用反射的。如果它作为程序运行中很少涉及的部分,缓慢的性能将不是一个问题。
  • 使用反射会模糊程序内部实际要发生的事情。程序员希望在源代码中看到程序的逻辑,反射等绕过了源代码的技术会带来维护问题。反射代码比相应的直接代码更复杂。解决这些问题的最佳方案是保守的使用反射——仅在它可以真正增加灵活性的地方——记录其在目标类中的作用。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值