重学Java之反射

反射 就是把Java类中的各个成分映射成一个个的Java对象。
即在运行状态中,对于任意一个类,都能够知道它的所有属性和方法;对于任意一个对象,都能调用它的任意一个方法和属性。

最常见的场景就是访问某个类的私有属性、私有方法。

1.新建一个类

新建一个类 Avenger ,关注它的 私有属性、私有构造方法、私有方法。

package com.lah.reflect;

public class Avenger {
	
	//私有属性
    private static final String TAG = "TAG_Avenger";

    private int id;
    private String name;

    public Avenger(){

    }
	
	//私有构造函数
    private Avenger(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
	
	//私有方法
    private String answersQuestion(int question){
        String text = "nothing";
        switch (question){
            case 0:text = "Your question is 0";
            case 1:text = "Your question is 1";
            case 2:text = "Your question is 2";
            default:break;
        }

        return text;
    }

	//私有方法
    private String talkToSomeone(int id1, int id2, String msg){
        System.out.println("Talk msg(" + msg + ") to " + id1 + " and " + id2);
        return "talk well";
    }

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

2.正常创建对象

正常调用,通过公有方法新建 Avenger 类。

public class TestReflect {

    public static void main(String[] args) {
        Avenger avenger = new Avenger();
        avenger.setId(100);
        avenger.setName("Avenger100");
        System.out.println(avenger.toString());

    }
}

运行结果,

Avenger{id=100,name=Avenger100}

一切正常。

3.反射创建对象

public class TestReflect {

    public static void main(String[] args) {
        Avenger avenger = new Avenger();
        avenger.setId(100);
        avenger.setName("Avenger100");
        System.out.println(avenger.toString());

        reflectNewInstance();

    }

    // 创建对象
    public static void reflectNewInstance() {
        try {
            Class classAvenger= Class.forName("com.lah.reflect.Avenger");//注释1
            Object objectBook = classAvenger.newInstance();
            Avenger avenger1 = (Avenger) objectBook;
            avenger1.setId(1);
            avenger1.setName("Avenger1");
            System.out.println(avenger1.toString());
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

运行结果,

Avenger{id=100,name=Avenger100}
Avenger{id=1,name=Avenger1}

说明反射成功了。

需要注意的是,如 注释1 处,反射时要传入完整的包名类名。

4.反射获取所有属性和方法

通过反射,可以获取到类的所有属性和方法,

package com.lah.reflect;

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

public class TestReflect {

    public static void main(String[] args) {
        Avenger avenger = new Avenger();
        avenger.setId(100);
        avenger.setName("Avenger100");
        System.out.println(avenger.toString());

        reflectAllProperty();
    }

    //反射获取所有属性和方法
    public static void reflectAllProperty() {
        try {
            Field[] fields = Avenger.class.getDeclaredFields();
            System.out.println(Avenger.class.getName() + "有如下属性:");
            for (Field f : fields){
                System.out.println(f);
            }

            System.out.println("\n");
            Method[] methods = Avenger.class.getDeclaredMethods();
            System.out.println(Avenger.class.getName() + "有如下方法:");
            for (Method  m: methods){
                System.out.println(m);
            }
        } catch (SecurityException e) {
        }
    }
}

运行结果,

Avenger{id=100,name=Avenger100}
com.lah.reflect.Avenger有如下属性:
private static final java.lang.String com.lah.reflect.Avenger.TAG
private int com.lah.reflect.Avenger.id
private java.lang.String com.lah.reflect.Avenger.name


com.lah.reflect.Avenger有如下方法:
public java.lang.String com.lah.reflect.Avenger.toString()
public java.lang.String com.lah.reflect.Avenger.getName()
public int com.lah.reflect.Avenger.getId()
public void com.lah.reflect.Avenger.setName(java.lang.String)
private java.lang.String com.lah.reflect.Avenger.answersQuestion(int)
private java.lang.String com.lah.reflect.Avenger.talkToSomeone(int,int,java.lang.String)
public void com.lah.reflect.Avenger.setId(int)

5.反射私有构造函数

Avenger 类中如下构造函数是私有的,无法直接调用。

	//私有构造函数
    private Avenger(int id, String name) {
        this.id = id;
        this.name = name;
    }

用反射,

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

public class TestReflect {

    public static void main(String[] args) {
        Avenger avenger = new Avenger();
        avenger.setId(100);
        avenger.setName("Avenger100");
        System.out.println(avenger.toString());

        reflectPrivateConstructor();

    }

    // 反射私有的构造方法
    public static void reflectPrivateConstructor() {
        try {
            Class classAvenger = Class.forName("com.lah.reflect.Avenger");
            Constructor declaredConstructorAvenger = classAvenger.getDeclaredConstructor(int.class, String.class);//注释2
            declaredConstructorAvenger.setAccessible(true);//注释3
            Object objectBook = declaredConstructorAvenger.newInstance(2,"Avenger2");
            Avenger avenger2 = (Avenger) objectBook;
            System.out.println(avenger2.toString());
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

注释2 处,类的构造方法传入的两个参数分别是 int 、String 类型,所以要这样写。
注释3 处,这样就破坏了私有属性。

运行结果,

Avenger{id=100,name=Avenger100}
Avenger{id=2,name=Avenger2}

6.反射私有属性

在 Avenger 类中,TAG 属性是私有的,

private static final String TAG = "TAG_Avenger";

反射拿到,

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

public class TestReflect {

    public static void main(String[] args) {
        Avenger avenger = new Avenger();
        avenger.setId(100);
        avenger.setName("Avenger100");
        System.out.println(avenger.toString());

        reflectPrivateField();
    }


    // 反射私有属性
    public static void reflectPrivateField() {
        try {
            Class classAvenger = Class.forName("com.lah.reflect.Avenger");
            Object objectBook = classAvenger.newInstance();
            Field fieldTag = classAvenger.getDeclaredField("TAG");
            fieldTag.setAccessible(true);
            String tag = (String) fieldTag.get(objectBook);
            System.out.println(tag);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

运行结果,

Avenger{id=100,name=Avenger100}
TAG_Avenger

7.反射私有方法

在 Avenger 类中,如下方法是私有的,

	private String answersQuestion(int question){
        String text = "nothing";
        switch (question){
            case 0:text = "Your question is 0";
            case 1:text = "Your question is 1";
            case 2:text = "Your question is 2";
            default:break;
        }

        return text;
    }
    
	private String talkToSomeone(int id1, int id2, String msg){
        System.out.println("Talk msg(" + msg + ") to " + id1 + " and " + id2);
        return "talk well";
    }

反射调用,

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

public class TestReflect {

    public static void main(String[] args) {
        Avenger avenger = new Avenger();
        avenger.setId(100);
        avenger.setName("Avenger100");
        System.out.println(avenger.toString());

        reflectPrivateMethod();
        reflectPrivateMethod2();
    }

    // 反射私有方法
    public static void reflectPrivateMethod() {
        try {
            Class classAvenger = Class.forName("com.lah.reflect.Avenger");
            Method methodBook = classAvenger.getDeclaredMethod("answersQuestion",int.class);//注释4
            methodBook.setAccessible(true);
            Object object = classAvenger.newInstance();
            String string = (String) methodBook.invoke(object,1);//注释5

            System.out.println("reflectPrivateMethod, string:" + string);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

	// 反射私有方法
    public static void reflectPrivateMethod2() {
        try {
            Class classAvenger = Class.forName("com.lah.reflect.Avenger");
            Method methodBook = classAvenger.getDeclaredMethod("talkToSomeone", int.class, int.class , String.class);//注释6
            methodBook.setAccessible(true);
            Object objectBook = classAvenger.newInstance();
            String string = (String) methodBook.invoke(objectBook,98,99, "haha");

            System.out.println("reflectPrivateMethod2, string:" + string);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

注释4 处,反射调用方法,需要传入方法名,该方法需要的参数是 int 类型,所以用 int.class 。
注释5 处,给 answersQuestion 方法传入参数1 。
注释6 处,传入多个参数,写法和注释4类似。

运行结果,

Avenger{id=100,name=Avenger100}
reflectPrivateMethod, string:Your question is 2
Talk msg(haha) to 98 and 99
reflectPrivateMethod2, string:talk well

你可能感兴趣的:(Java,java,反射)