Java基础-反射基础

一、基础概念

反射机制:在运行状态中,对于任意一个类都能够在知道这个类的全限定名的情况下获取这个类的构造方法、属性和方法,并且对于任意一个对象,都能够调用它的任意方法,这种动态获取信息以及动态调用对象方法的功能称之为Java语言的反射机制。

二、反射设计相关的类

java.lang.Class:反射核心类,可以获取类的构造方法(私有和公有的)
java.lang.Constructor:表示类的构造方法,可以用来返回对象的实例
java.lang.reflect.Field:保存类的成员变量,可以用来获取和设置类之中的属性值
java.lang.reflect.Method:表示类的方法,可以用来获取类中的方法信息,或执行方法
package Reflect;

/**
 * Created by luckyboy on 2018/8/6.
 */
public class Person {
    private int age;
    private String name;

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

    public int getAge() {
        return age;
    }

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

    private String getName() {
        return name;
    }

    private void setName(String name) {
        this.name = name;
    }
    public String toString(){
        return "Person:["+this.name+" "+ this.age+"]";
    }
}

使用Class类获取Person类的构造方法、实例域、一般方法

package Reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * Created by luckyboy on 2018/8/7.
 */
public class ReflectTest2 {
    public static void main(String[] args){
        try {
            Class clazz = Class.forName("Reflect.Person");
            Field[] fields = clazz.getFields();
            Constructor[] constructors = clazz.getConstructors();
            Method[] methods = clazz.getMethods();
            printArray(fields);
            System.out.println("--------------");
            printArray(methods);
            System.out.println("--------------");
            printArray(constructors);

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    private static void printArray(Object[] objects){
        for(Object o:objects){
            System.out.println(o.toString());
        }
    }
}

输出结果

public java.lang.String Reflect.Person.toString()
public void Reflect.Person.setAge(int)
public int Reflect.Person.getAge()
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()
--------------
public Reflect.Person(int,java.lang.String)
public Reflect.Person(int)

从以上结果我们可以看出,

  • 获取类的方法时会获取到从父类继承下来的构造方法。
  • 对于一个类的私有方法和私有构造方法通过这种方法是获取不到的。
  • 那么如果我们要获取一个对象的私有构造方法应该通过设置Constructor.setAccessible(true)的方法获取。

三、反射获取类实例对象

Class.newInstance()                                             //通过类的无参构造方法获取类的实例对象
Constructor<T> getConstructor(Class ...parameterTypes)          //获取类的构造器,通过指定参数类型
Constructor<T> getDeclaredConstructor(Class...parameterTypes)   //获取类的构造器,通过指定参数类型

使用反射机制获取类的对象实例步骤

  • 使用Class.forName(类的全限定名)获取Class对象
  • 使用Class.newInstance()或者是Constructor.newInstance()方法获取类的对象实例
package Reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class ReflectTest1 {
    public static void main(String[] args){
        try {
            Class clazz = Class.forName("Reflect.Person");

            //方法一:使用newInstance()的方法获取对象实例
            Person person = (Person)clazz.newInstance();
            person.setAge(23);
            person.setName("Markliwei");
            System.out.println(person.toString());

            System.out.println("----------------------");
            //方式二:使用构造器Class.getDeclaredConstructor()+Constructor.newInstance()方式获取对象
            Constructor constructor = clazz.getDeclaredConstructor(int.class,String.class);
            Person person1 = (Person) constructor.newInstance(25,"Jide");
            System.out.println(person1.toString());

            System.out.println("----------------------");
            //方式三:使用Class.getConstructor()+Constructor.newInstance()方式获取对象
            Constructor cosntructor1 = clazz.getConstructor(int.class,String.class);
            Person person2 = (Person) constructor.newInstance(23,"Xianyu");
            System.out.println(person2.toString());

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}

输出结果

Person:[Markliwei 23]
----------------------
Person:[Jide 25]
----------------------
Person:[Xianyu 23]

四、使用反射机制破坏单例设计模式

Singletone是一个单例类,因此通常我们只能使用静态的方法来构造一个对象。

package Reflect;

public class Singletone {
    private static Singletone instance = new Singletone();
    private Singletone(){};
    public static Singletone getInstance(){
        return instance;
    }
}

现在我们通过反射的方式获取对象的私有构造方法,然后构造对象。

package Reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;


public class DestroySingletone {
    public static void main(String[] args){
        Singletone singletone1 = Singletone.getInstance();
        Singletone singletone2 = Singletone.getInstance();
        System.out.println("singletone1 == singletone2 : "+(singletone1 == singletone2));
        try {
            Class clazz = Class.forName("Reflect.Singletone");
            Constructor constructor = clazz.getDeclaredConstructor();
            constructor.setAccessible(true);//一定要设置这个构造器时可访问的
            Singletone singletone3 = (Singletone) constructor.newInstance();

            System.out.println("singletone1 == singletone3 : "+(singletone1 == singletone3));
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}

输出结果

singletone1 == singletone2 : true
singletone1 == singletone3 : false

这里我们需要注意就像前面提到过的一样,我们无法获取对象的私有构造方法,这个时候我们只能通过设置Constructor.setAccessible(true)的方式设置构造器是可访问的。

参考文章

https://blog.csdn.net/xu__cg/article/details/52877573

猜你喜欢

转载自blog.csdn.net/makeliwei1/article/details/81463140