Java反射

Posted rhodesis

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java反射相关的知识,希望对你有一定的参考价值。

Java反射

概念  

  java反射指的是,在程序运行过程中,程序可以动态地获取任何一个类有哪些方法和属性,对于一个对象可以获取它的属性和方法进行调用,我们把这种动态地获取类的属性和方法的过程叫做反射机制

反射的实现方法

  反射一共有三种实现方式:1、通过Class.forName()方法;2、通过getClass()方法;3、通过.Class获取对象。示例如下:

  我们先定义一个待通过反射获取的POJO类Person,后面所有有关于反射的演示都是通过该类进行

 

public class Person 
    public String name;
    private int age;
    private String sex;

    public Person() 

    

    private Person(String name, int age, String sex) 
        this.name = name;
        this.age = age;
        this.sex = sex;
    

    public String getName() 
        return name;
    

    public void setName(String name) 
        this.name = name;
    

    public int getAge() 
        return age;
    

    public void setAge(int age) 
        this.age = age;
    

    public String getSex() 
        return sex;
    

    public void setSex(String sex) 
        this.sex = sex;
    

    @Override
    public String toString() 
        return  "名称为:" + name + ",年龄为:" + age + ",性别为:" + sex;
    

 

  下面我们演示三种实现反射机制的三种方式

public class Reflect 
    public static void main(String[] args) throws Exception 
        /*第一种方式*/
        Class<?> c1 = Class.forName("com.lwj.designPattern.Reflect.Person");
        /*第二种方式*/
        Person person = new Person();
        Class<?> c2 = person.getClass();
        /*第三种方式*/
        Class<?> c3 = Person.class;
    

  上面三种方式,其中我们经常用到的是第一种方式通过Class.forName(“类的路径+类名”)来获取该类的信息,第二种方式需要new一个指定对象出来,既然已经可以new一个Person对象那么久没有必要通过反射机制来得到了,而第三种方式需要导入Person类的包,依赖性太强。所以一般使用反射机制都使用第一种方式。

反射常用的方法

  一般我们使用反射机制,无非就是获取类的方法、属性、构造函数等等。或者是通过反射创建类的实例,然后调用实例对象中的字段、方法这一类。下面我们看一下反射常用的方法:

  获取构造方法

  下面是常用的集中获取对象的构造方法的用法,一般我们获取到了构造方法,就可以通过对应的构造方法创建对象的实例了

  /*  一、构造方法*/
        System.out.println("-------------------获取所有声明的构造方法---------------------");
        Constructor[] constructors1 = c1.getDeclaredConstructors();
        for (Constructor constructor : constructors1) 
            System.out.println(constructor);
        
        System.out.println("-------------------获取所有公有的的构造方法---------------------");
        Constructor[] constructors2 = c1.getConstructors();
        for (Constructor constructor : constructors2) 
            System.out.println(constructor);
        
        System.out.println("-------------------获取无参的公有构造方法---------------------");
        System.out.println(c1.getDeclaredConstructor(null));
        System.out.println("-------------------获取已声明的对应的构造方法---------------------");
        System.out.println(c1.getDeclaredConstructor(new Class[]String.class, int.class, String.class));

执行结果如下:

-------------------获取所有声明的构造方法---------------------
public com.lwj.designPattern.Reflect.Person()
private com.lwj.designPattern.Reflect.Person(java.lang.String,int,java.lang.String)
-------------------获取所有公有的的构造方法---------------------
public com.lwj.designPattern.Reflect.Person()
-------------------获取无参的公有构造方法---------------------
public com.lwj.designPattern.Reflect.Person()
-------------------获取已声明的对应的构造方法---------------------
private com.lwj.designPattern.Reflect.Person(java.lang.String,int,java.lang.String)

  获取类的属性

 /*二、类属性*/
        System.out.println("-------------------获取所有声明的字段---------------------");
        Field[] fields1 = c1.getDeclaredFields();
        for (Field field : fields1) 
            System.out.println(field);
        
        System.out.println("-------------------获取所有公有声明的字段---------------------");
        Field[] fields2 = c1.getFields();
        for (Field field : fields2) 
            System.out.println(field);
        
        System.out.println("-------------------操作Person类公有的字段---------------------");
        /*首先通过反射的方式获取Person对象的实例*/
        Constructor cs1=c1.getDeclaredConstructor(new Class[]String.class, int.class, String.class);
        cs1.setAccessible(true);
        Object obj = cs1.newInstance("张三",18,"男");
        /*获取字段name,修改前*/
        Field field=c1.getDeclaredField("name");
        System.out.println(field.get(obj));
        /*修改name,再输出*/
        field.set(obj,"李四");
        System.out.println(field.get(obj));
        System.out.println("-------------------操作Person类私有的字段---------------------");
        Field field1=c1.getDeclaredField("age");
        field1.setAccessible(true);
        System.out.println(field1.get(obj));
        field1.set(obj,20);
        System.out.println(field1.get(obj));

执行结果如下:

-------------------获取所有声明的字段---------------------
public java.lang.String com.lwj.designPattern.Reflect.Person.name
private int com.lwj.designPattern.Reflect.Person.age
private java.lang.String com.lwj.designPattern.Reflect.Person.sex
-------------------获取所有公有声明的字段---------------------
public java.lang.String com.lwj.designPattern.Reflect.Person.name
-------------------操作Person类公有的字段---------------------
张三
李四
-------------------操作Person类私有的字段---------------------
18
20

  上面展示了获取类的属性的方法,同时通过获取类的构造函数并且创建类的实例对象来演示操作对象属性的方法,在上面我们可以看到有一个方法field1.setAccessible(true),这个方法主要作用就是设置是够取消java语言访问限制,如果为true则取消,一般情况如果我们访问private修饰的对象时如果先调用该方法则会抛出java.lang.IllegalAccessException异常,这个一定要注意,同时使用setAccessible(true)方法还会在一定程度上增加反射的使用效率。

  获取和调用类的方法

 System.out.println("-------------------获取所有声明的方法---------------------");
        Method[] methods1=c1.getDeclaredMethods();
        for (Method method:methods1)
            System.out.println(method);
        
        System.out.println("-------------------获取所有的公用方法---------------------");
        Method[] methods2=c1.getMethods();
        for (Method method:methods2)
            System.out.println(method);
        
        System.out.println("-------------------操作Person定义的ToString方法---------------------");
        Method method=c1.getMethod("toString",null);
        Object invoke = method.invoke(obj);
        System.out.println(invoke);

 

执行结果如下:

-------------------获取所有声明的方法---------------------
public java.lang.String com.lwj.designPattern.Reflect.Person.toString()
public java.lang.String com.lwj.designPattern.Reflect.Person.getName()
public void com.lwj.designPattern.Reflect.Person.setName(java.lang.String)
public java.lang.String com.lwj.designPattern.Reflect.Person.getSex()
public void com.lwj.designPattern.Reflect.Person.setSex(java.lang.String)
public int com.lwj.designPattern.Reflect.Person.getAge()
public void com.lwj.designPattern.Reflect.Person.setAge(int)
-------------------获取所有的公用方法---------------------
public java.lang.String com.lwj.designPattern.Reflect.Person.toString()
public java.lang.String com.lwj.designPattern.Reflect.Person.getName()
public void com.lwj.designPattern.Reflect.Person.setName(java.lang.String)
public java.lang.String com.lwj.designPattern.Reflect.Person.getSex()
public void com.lwj.designPattern.Reflect.Person.setSex(java.lang.String)
public int com.lwj.designPattern.Reflect.Person.getAge()
public void com.lwj.designPattern.Reflect.Person.setAge(int)
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
-------------------操作Person定义的ToString方法---------------------
名称为:李四,年龄为:20,性别为:男

上图我们可以看到,调用getMethods()方法和getDeclaredMethods()方法返回的方法不一样,其中getMethods()方法会返回所有该对象能够调用的方法。

总结

  java反射机制在我们编码当中虽然不常用到,但是我们在开发过程却与反射息息相关,例如:Spring IOC通过配置文件创建对象的实例即通过解析xml文件通过反射来实例化对象,同时Spring AOP中调用被代理对象的方法method.invoke()方法也是通过反射机制来实现的,还有需要使用到的框架都是基于反射来实现的,所以掌握反射机制对我们来说极为重要。

 

以上是关于Java反射的主要内容,如果未能解决你的问题,请参考以下文章

JAVA反射Field

反射机制在java中如何做呀?

如何利用java的反射机制动态创建对象

说说对java反射的理解,使用反射如何获取一个类的所有方法,使用反射需要注意哪些问题?

请问java中的反射机制与用法

Java反射机制