反射

反射(reflect)机制的作用

  1.反编译:.class--->.java

  2.通过反射机制访问java类的属性,方法,构造方法等

获取Class的三种方式

package com.yuijam.reflect;

public class Employee {
    
    private String name;
    
    public Employee(){
        
    }
    
    public Employee(String name){
        this.name = name;
    }
    
    public void m1(){
        
    }
    
}
package com.yuijam.reflect;

public class ReflectTest01 {

    public static void main(String[] args) throws Exception{
        //第一种
        Class c1 = Class.forName("com.yuijam.reflect.Employee");
        //c1保存内存地址指向堆中的对象,该对象代表的是Employee整个类
        
        //第二种
        //Java中任何一个对象都有getClass方法
        Class c2 = Employee.class;
        
        //第三种
        //Java中每个类型都有class属性,注意这里说的是类型不是类,所以可以int.class
        Employee e = new Employee();
        Class c3 = e.getClass();
        
        //因为Employee这个类在JVM中只有一个,所以c1,c2,c3的内存地址是一样的,指向堆中的唯一一个对象
        System.out.println(c1==c2);
        System.out.println(c3 == c2);
    }

}

一个知识点

package com.yuijam.reflect;

public class ReflectTest02 {

    public static void main(String[] args) throws Exception{
        //将A.class文件装载到JVM的过程,会执行静态语句块,打印输出
        Class c1 = Class.forName("com.yuijam.reflect.A");
        
        //不会执行静态语句块
        Class c2 = A.class;
        
    }

}

class A{
    static{
        System.out.println("A----");
    }
}

通过Class类对象创建java对象

package com.yuijam.reflect;

import java.text.SimpleDateFormat;
import java.util.Date;

public class ReflectTest03 {

    public static void main(String[] args) throws Exception{
        Class c = Class.forName("com.yuijam.reflect.Employee");
        
        //创建此Class对象所表示的类的一个新实例
        Object o = c.newInstance();//调用Employee的无参数构造方法
        //如果将Employee的无参数构造方法注释掉,会抛出异常
        System.out.println(o);
        
        Class d = Class.forName("java.util.Date");
        Object o1 = d.newInstance();
        if ( o1 instanceof Date){
            Date t = (Date)o1;
            System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS").format(t));
        }
        
    }

}

Employee的无参数构造方法执行!
com.yuijam.reflect.Employee@15db9742
2016-10-23 21:41:20 754

关于Java的可变长参数

package Test;

/**
 * Created by Arenas on 2016/10/24.
 */
public class ReflectTest04 {
    //该方法在调用的时候传递的实参可以是0~N个
    public static void m1(int... i){
        System.out.println("test");
    }
    //如果有可以精确匹配的方法,则调用该方法,而不会调用可变长参数的那个方法
    public static void m1(int i){
        System.out.println(i);
    }
    //可变长参数可以等同看作数组
    public static void m2(String... s){
        for (String s1 : s) {
            System.out.println(s1);
        }
    }
    //可变长参数只能出现一次,并且只能出现在参数列表最后一个,下面这样是不行的
//    public static void m3(int... i , String s){
//
//    }
    //这个是可以的
    public static void m3(int s , int... i){

    }

    public static void main(String[] args) {
        m1();
        m1(1);
        m1(1,2);
        m1(3,4,5);

        m2("kobe" , "kg" , "duncan" , "tracy");
    }

}

test
1
test
test
kobe
kg
duncan
tracy

Properties和IO的使用

首先在D盘新建一个文件info.txt,内容为username=tracy

package Test;

import java.io.FileInputStream;
import java.util.Properties;

/**
 * Created by Arenas on 2016/10/24.
 */
public class PropertiesIOTest {

    public static void main(String[] args) throws Exception{
        //创建输入流
        FileInputStream fis = new FileInputStream("D:/info.txt");

        //创建属性对象,和Map一样,只不过key和value只能是字符串类型
        Properties properties = new Properties();
        //将file流中的所有数据加载到属性对象中
        properties.load(fis);

        //关闭流
        fis.close();
        
        String v = properties.getProperty("username");
        System.out.println(v);
    }
}

输出:tracy

info这样的文件通常称为配置文件,配置文件的作用是使程序更加灵活。像info这样一个具有特殊内容的配置文件,通常又称为属性文件。Java规范中要求属性文件以.properites结尾

属性文件的要求:

  1.key和value之间可以使用“空格”,“冒号”,“等号”作为分隔符

  2.当“空格”,“冒号”,“等号”同时出现时,按最先出现的那个作为分隔符

这里注意一个问题,在info文件中再加一条带中文的,如chinesename=麦迪

输出一个乱码:ÂóµÏ

这个时候进入cmd,输入如下:

再将转换成的unicode码复制到info中替换中文麦迪,即可输出中文麦迪

利用reflect、IO、properties创建Java对象

在D盘新建文件ClassInfo.properites,内容为className=java.util.Date

package Test;

import java.io.FileReader;
import java.util.Properties;

/**
 * Created by Arenas on 2016/10/24.
 */
public class ReflectTest05 {

    public static void main(String[] args)throws Exception{
        //创建属性对象
        Properties properties = new Properties();
        //创建流
        FileReader reader = new FileReader("D:/ClassInfo.properites");
        //加载
        properties.load(reader);
        //记得关闭流
        reader.close();
        //通过key获取value
        String className = properties.getProperty("className");
        //创建对象并打印出来
        Class c = Class.forName(className);
        System.out.println(c.newInstance());
    }
}

输出:Mon Oct 24 19:35:54 CST 2016

反编译某个类的所有Field

新建User

package Test;

/**
 * Created by Arenas on 2016/10/24.
 */
public class User {
    private String name;
    private int age;
    protected String addr;
    boolean married;

    private User(){

    }

    public User(String name , int age){
        this.name = name;
        this.age = age;
    }

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

    public void loginout(){
        System.out.println("login out");
    }
}
package Test;

import java.io.FileReader;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Properties;

/**
 * Created by Arenas on 2016/10/24.
 */
public class ReflectTest06 {

    public static void main(String[] args) throws Exception{
        Properties properties = new Properties();
        FileReader reader = new FileReader("D:/ClassInfo.properties");
        properties.load(reader);
        reader.close();
        String className = properties.getProperty("className");
        Class c = Class.forName(className);
        Field[] fields = c.getDeclaredFields();
        for (Field field : fields){
            int i = field.getModifiers();
            System.out.println(Modifier.toString(i));
            Class type = field.getType();
            String str = field.getName();
            System.out.println(type.getName());
            System.out.println(str);
        }
    }
}

private
java.lang.String
name
public
int
age
protected
java.lang.String
addr

boolean
married

反编译User类

package Test;

import java.io.FileReader;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Properties;

/**
 * Created by Arenas on 2016/10/24.
 */
public class ReflectTest06 {

    public static void main(String[] args) throws Exception{
        Properties properties = new Properties();
        FileReader reader = new FileReader("D:/ClassInfo.properties");
        properties.load(reader);
        reader.close();
        String className = properties.getProperty("className");
        Class c = Class.forName(className);
        Field[] fields = c.getDeclaredFields();

        StringBuilder builder = new StringBuilder();
        builder.append(Modifier.toString(c.getModifiers()));
        builder.append(" class ");
        builder.append(c.getSimpleName());
        builder.append("{
");

        for (Field field : fields){
            builder.append("	");
            builder.append(Modifier.toString(field.getModifiers()));
            builder.append(" ");
            builder.append(field.getType().getSimpleName());
            builder.append(" ");
            builder.append(field.getName());
            builder.append(";
");
        }
        builder.append("}");
        System.out.println(builder.toString());
    }
}

将User换成java.lang.String等也同样可以顺利打出

获取某个指定的Field

package Test;

import java.lang.reflect.Field;

/**
 * Created by Arenas on 2016/10/25.
 */
public class ReflectTest07 {
    //获取某个指定的属性
    public static void main(String[] args) throws Exception{
        Class c = Class.forName("Test.User");
        //获取age属性,这里如果用getField只能获取public的属性,如果属性为private会抛出异常
        Field field = c.getDeclaredField("age");
        //使用反射机制可以打破封装属性,导致了Java对象的属性不安全
        //这里如果注释掉这条,对于private属性来说会抛出异常
        field.setAccessible(true);
        Object o = c.newInstance();
        //给o对象的age属性赋值110
        field.set(o , 110);
        System.out.println(field.get(o));
    }
}

 获取所有方法

package Test;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

/**
 * Created by Arenas on 2016/10/25.
 */
public class ReflectTest08 {

    public static void main(String[] args) throws Exception{
        Class c = Class.forName("Test.User");
        Method[] methods = c.getDeclaredMethods();
        for (Method method : methods){
            //获取返回值类型
            System.out.println(method.getReturnType().getSimpleName());
            System.out.println(Modifier.toString(method.getModifiers()));
            System.out.println(method.getName());
            //获得形参
            Class[] paras = method.getParameterTypes();
            for (Class para : paras){
                System.out.println(para.getSimpleName());
            }
        }
    }

}

boolean
public
login
String
String
void
public
loginout

获取指定方法

package Test;

import java.lang.reflect.Method;

/**
 * Created by Arenas on 2016/10/25.
 */
public class ReflectTest09 {

    public static void main(String[] args)throws Exception{
        Class c = Class.forName("Test.User");
        //通过方法名和形参列表确定一个方法
        Method method = c.getDeclaredMethod("login" , String.class , String.class);
        Object o = c.newInstance();
        //调用o对象中的method方法,并传入两个参数,获取返回值returnValue
        Object returnValue = method.invoke(o , "admin" , "123456");
        System.out.println(returnValue);
    }
}

true

获取所有构造方法

package Test;

import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;

/**
 * Created by Arenas on 2016/10/25.
 */
public class ReflectTest10 {

    public static void main(String[] args) throws Exception{
        Class c = Class.forName("Test.User");
        Constructor[] constructors = c.getDeclaredConstructors();
        StringBuilder builder = new StringBuilder();
        for (Constructor constructor : constructors){
            String modifer = Modifier.toString(constructor.getModifiers());
            builder.append(modifer);
            builder.append(" ");
            String constructorName = constructor.getName();
            builder.append(constructorName);
       builder.append(" "); Class[] paras
= constructor.getParameterTypes(); for (Class para : paras){ builder.append(para.getSimpleName()); builder.append(","); } builder.append(" "); } System.out.println(builder.toString()); } }

private Test.User
public Test.User String,int,

同理可以根据参数类型来确定特定的构造方法

通过getSuperclass()来获取父类,单继承,所以只有一个父类

通过getInterfaces()获取接口,可以实现多个接口,所以返回一个Class数组

反射的两个缺点

  1.性能问题

  用反射基本上属于一种解释操作,我们可以告诉JVM,我们希望做什么,并且他满足我们的要求。用字段和方法接入时,反射要远慢与直接代码。性能问题的程度取决于程序是如何使用反射的,如果他作为程序中很少涉及的部分,缓慢的性能将不会是一个问题。大量使用反射要慎重

  2.使用反射会模糊程序内部实际要发生的事情,程序员希望在源代码中看到程序的逻辑,反射等绕过了源代码的技术会带来维护问题。反射代码比直接代码更复杂。保守的使用反射,仅在他真正可以增加灵活性的地方使用。

  

原文地址:https://www.cnblogs.com/i-love-kobe/p/5991138.html