反射的具体实现

165 阅读3分钟

反射

Class.newInstance()方法用来创造实例

例如TargetObject targetObject = (TargetObject) tagetClass.newInstance();就创造出了TargetObject的实例

2. java targetClass.getDeclaredMethods();如果未填入参数,则获取该类中的所有方法。 for (Method method : methods) { System.out.println(method.getName()); } 可通过增强for循环依次输出类中的方法名

Method publicMethod = targetClass.getDeclaredMethod("publicMethod",
                String.class);
java.lang.Class.getDeclaredMethod(String name,class......)方法返回一个Method对象,它反映此Class对象所表示的类或接口的指定已声明方法。
    如果填入参数,则第一个参数为方法名字,第二个参数开始即为该方法的形参列表。
    则判断getDeclaredMethod的形参个数为 所调用方法的形参个数+1

4.在3的条件下:publicMethod.invoke(targetObject, "JavaGuide");

targetObject为某个对象的实例,“、JavaGuide”即为传入publicMethod方法的参数,若该方法无参,则invoke()中只用填写实例对象

field.setAccessible(true);
        field.set(targetObject, "JavaGuide");

        /**
         * 调用 private 方法
         */
        Method privateMethod = targetClass.getDeclaredMethod("privateMethod");
        //为了调用private方法我们取消安全检查
        privateMethod.setAccessible(true);
        privateMethod.invoke(targetObject);

详见javaguide反射部分。

下面是尚硅谷视频的反射的具体实现

image.png

image.png

image.png

image.png

大的要来了(一定要吃透下面的代码)

下面的代码都基于此Person类

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


    public void show(){
        System.out.println("你好,我是一个人");
    }
    private String showNation(String nation){
        System.out.println("你好,我的国籍是"+ nation);
        return nation;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    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 Person() {
    }

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

反射前创建公共对象,调用属性,方法

//反射之前,对于Person类的操作
@Test
public void test(){
    //1.创建Person类的对象
    Person p1 = new Person("Tom",12);

    //2.通过对象,调用其内部属性,方法
    p1.age=10;
    System.out.println(p1.toString());//Person{name='Tom', age=10}
    p1.show();//你好,我是一个人

    //由于封装性的限制:
    // 在Person类外部,不可以通过Person类的对象调用其内部私有结构
    //比如:name,showNation(),以及私有的构造器
}

反射后创建公共对象,调用属性,方法

@Test
public void test1() throws Exception{
    Class<Person> clazz = Person.class;
    //调用公共属性方法
    //1.通过反射,创建Person类的对象
    Constructor<Person> cons = clazz.getConstructor(String.class, int.class);
    Object obj = cons.newInstance("Tom", 12);
    Person p = (Person) obj;
    System.out.println(p.toString());//Person{name='Tom', age=12}
    //2.通过反射,调用对象指定的属性,方法
    //通过反射对属性进行修改
    Field age = clazz.getDeclaredField("age");
    age.set(p,10);
    System.out.println(p.toString());//Person{name='Tom', age=10}

    //调用方法
    Method show = clazz.getDeclaredMethod("show");
    Object invoke = show.invoke(p);//你好,我是一个人

反射后创建私有对象,调用属性,方法

@Test
public void test1() throws Exception{
    Class<Person> clazz = Person.class;
    //调用公共属性方法
    //1.通过反射,创建Person类的对象
    Constructor<Person> cons = clazz.getConstructor(String.class, int.class);
    Object obj = cons.newInstance("Tom", 12);
    Person p = (Person) obj;
    System.out.println(p.toString());//Person{name='Tom', age=12}
    //2.通过反射,调用对象指定的属性,方法
    //通过反射对属性进行修改
    Field age = clazz.getDeclaredField("age");
    age.set(p,10);
    System.out.println(p.toString());//Person{name='Tom', age=10}

    //调用方法
    Method show = clazz.getDeclaredMethod("show");
    Object invoke = show.invoke(p);//你好,我是一个人
    System.out.println("**********");

    //调用私有属性方法
    //通过反射,可以调用Person类的私有结构,比如私有的构造器,方法,属性
    Constructor<Person> cons1 = clazz.getDeclaredConstructor(String.class);
    cons1.setAccessible(true);
    Person p1 = cons1.newInstance("Jerry");
    System.out.println(p1.toString());//Person{name='Jerry', age=0}

    //调用私有属性
    Field name = clazz.getDeclaredField("name");
    name.setAccessible(true);
    name.set(p1,"xiaokasidi");
    System.out.println(p1.toString());//Person{name='xiaokasidi', age=0}

    //调用私有方法
    Method showNation = clazz.getDeclaredMethod("showNation",String.class);
    showNation.setAccessible(true);
    Object invoke1 = showNation.invoke(p1, "中国");//你好,我的国籍是中国
    System.out.println(invoke1);//此时的返回值为形参列表

那么,在上述例子中我们想必会产生一些疑问

1.通过直接new的方式或反射的方式都可以调用公共结构,那么在实际需求时应该使用哪种?

建议:直接new的方式。

什么时候会使用反射呢?

回答:首先,反射具有动态性。那么如果在编译期时无法确定要new哪个对象,那么就可以使用反射的方式创建对象。即在登录,注册,找回密码等等无法确定用户要干什么的时候,这个时候使用反射获取前端发来的具体的类来创建对象。

2.反射的机制与面向对象的封装性是不是矛盾的?

答案:不矛盾。封装性更多是主观上不让你去调用,简单来说就是用反射调用了也没什么用。