Java反射机制

111 阅读5分钟

一、反射应用

1、正射的概念

指的是我们知道类的定义和类中的方法名称,直接先创建对象,然后通过对象去调用方法。
例如:
Apple apple = new Apple(); //直接初始化,「正射」
apple.setPrice(15);

2、反射的概念

 指的是一开始不知道我要初始化的类对象是什么,自然也无法使用 new 关键字来创建对象,需要用JDK 提供的反射 API 进行反射调用。需要通过类的路径字符串创建对象,通过方法名称字符串调用方法。
例如:
public class Apple {
    private int price; 
    public int getPrice() { 
        return price; 
    } 
    public void setPrice(int price) {
         this.price = price;
    }

 public static void main(String[] args) throws Exception{
     //正常的调用 
   // Apple apple = new Apple();  //创建对象
  //   apple.setPrice(15);         //执行setPrice方法
  //  System.out.println(apple.getPrice()); //获取价格

    //使用反射调用 
    //获取Apple类
    Class clz = Class.forName("com.jbrh.api.Apple"); 
    //通过类创建对象
    Object appleObj =clz.newInstance();
    //通过构造器创建对象
   //   Constructor appleConstructor = clz.getConstructor();
   //  Object appleObj = appleConstructor.newInstance();
    
    //获取setPrice方法第一个参数是方法名称,第二个参数是方法的参数类型列表
    Method setPriceMethod = clz.getMethod("setPrice", int.class);
   // 执行setPrice()方法
    setPriceMethod.invoke(appleObj, 15);   
   // 获取getPrice()方法
    Method getPriceMethod = clz.getMethod("getPrice"); 
    // 执行getPrice方法
    System.out.println(getPriceMethod.invoke(appleObj));
    } 
}

3、反射机制

java源文件从创建到运行会经历3个阶段
1)源码阶段
2Class类对象阶段
3)运行阶段

image.png

image.png

4、为什么学反射

如果你事先创建好了B类,那么你可以直接创建B对象并调用其方法,那么如果我和另外一位老铁分开开发程序,这个B类是他写的,我们彼此开发完全独立,我需要在我的程序中创建B对象,然后调用B方法获取学生的年龄,这个时候可能这位老铁还没有完成B类的开发,这怎么办?
这就用到了反射了,我在开发程序的时候只需要跟他约定好B类的信息,例如类名称,字段名称、方法名称,我就可以通过反射的机制在他还未写B类的时候动态创建B对象并调用其方法了。等他的B类完成创建之后,我们的代码合并部署运行,我就可以调用到B的方法了。

5、反射的优缺点

1、优点:在运行时获得类的各种内容,进行反编译,对于Java这种先编译再运行的语言,能够让我们很方便的创建灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代码的链接,更加容易实现面向对象。

2、缺点:
(1)反射会消耗一定的系统资源,因此,如果不需要动态地创建一个对象,那么就不需要用反射;
(2)反射调用方法时可以忽略权限检查,因此可能会破坏封装性而导致安全问题。

6、类对象和类的对象

1)类对象是类加载的产物,封装了一个类的所有信息(类名、父类、接口、属性、方法、构造方法)
2)类的对象是基于某个类new出来的对象,也称为实例对象

image.png

7、三种获取类对象的方法

1)通过类的对象,获取类对象
Person person = new Person(); 
Class cla = person.getClass();
场景:常用于对象的字节码获取方式
2)通过类名获取类对象
Class cla = 类名.class;
场景:常用于参数的传递
3)以静态方法通过全类名获取类对象
Class cla = Class.forName("全类名");
场景:常用于读取配置文件,将类名定义在配置文件中。读取文件,加载类对象。

二、Class对象的常用方法

1、获取成员变量

image.png

 package com.mylifes1110.java.bean;
import java.lang.reflect.Field;


class Person {
    private String   name;
    public Integer   age;
    protected Double score;


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




public class TestReflectFiled {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        Person person = new Person();
        Class<? extends Person> personClass = person.getClass();


        //获取 public 修饰的所有成员变量
        Field[] fields = personClass.getFields();
        for (Field field : fields) {
            System.out.println(field);      //public java.lang.Integer com.mylifes1110.java.bean.Person.age
        }


        //获取 public 修饰的指定名称的成员变量
        Field age = personClass.getField("age");
        System.out.println(age);            //public java.lang.Integer com.mylifes1110.java.bean.Person.age
        //获取成员变量age的值
        Object ageValue = age.get(person);
        System.out.println(ageValue);       //null
        //设置age的值
        age.set(person, 18);
        System.out.println(person);         //Person{name='null', age=18, score=null}



        //获取所有成员变量,不被修饰符限制
        Field[] declaredFields = personClass.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println(declaredField);
        }
        /*
          private java.lang.String com.mylifes1110.java.bean.Person.name
          public java.lang.Integer com.mylifes1110.java.bean.Person.age
          protected java.lang.Double com.mylifes1110.java.bean.Person.score
         */




        //获取指定名称的成员变量,不被修饰符限制
        Field name = personClass.getDeclaredField("name");
        //忽略访问修饰符的安全检查
        name.setAccessible(true);           //暴力反射
        Object nameValue = name.get(person);
        System.out.println(nameValue);      //null
    }
}

2、获取构造方法

image.png

package com.mylifes1110.java.bean;


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


class Person {
    private String   name;
    public Integer   age;
    protected Double score;


    public Person() {}


    public Person(String name, Integer age, Double score) {
        this.name  = name;
        this.age   = age;
        this.score = score;
    }


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


public class TestReflectConstructor {
    public static void main(String[] args) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException, InstantiationException {
        Person person = new Person();
        Class<? extends Person> personClass = person.getClass();


        //获取 public 修饰的无参构造
        Constructor<? extends Person> constructor = personClass.getConstructor();
        System.out.println(constructor);    //public com.mylifes1110.java.bean.Person()
        //通过无参构造创建实例对象
        Person p1 = constructor.newInstance();
        System.out.println(p1);             //Person{name='null', age=null, score=null}


        Constructor<? extends Person> constructor2 = personClass.getConstructor(String.class, Integer.class, Double.class);
        System.out.println(constructor2);   //public com.mylifes1110.java.bean.Person(java.lang.String,java.lang.Integer,java.lang.Double)
        Person p2 = constructor2.newInstance("Ziph", 18, 100.00);
        System.out.println(p2);             //Person{name='Ziph', age=18, score=100.0}




        //获取 public 修饰的所有构造方法
        Constructor<?>[] constructors = personClass.getConstructors();
        for (Constructor<?> constructor1 : constructors) {
            System.out.println(constructor1);
        }
        /*
          public com.mylifes1110.java.bean.Person()
          public com.mylifes1110.java.bean.Person(java.lang.String,java.lang.Integer,java.lang.Double)
         */
    }
}

3、获取方法

image.png

package com.mylifes1110.java.bean;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

class Person {
    private String   name;
    public Integer   age;
    protected Double score;


    public void jump() {
        System.out.println("跳起来。");
    }


    public void run(Integer meters) {
        System.out.println("我今天跑步跑了" + meters + "米。");
    }


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


public class TestReflectMethod {
    public static void main(String[] args) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        Person person = new Person();
        Class<? extends Person> personClass = person.getClass();


        //获取 public 修饰的jump无参方法
        Method jump = personClass.getMethod("jump");
        //执行获取到的jump无参方法
        jump.invoke(person);                //跳起来。


        //获取 public 修饰的run有参方法
        Method run = personClass.getMethod("run", Integer.class);
        //执行获取到的run有参方法
        run.invoke(person, 2000);            //我今天跑步跑了2000米。


        //获取 public 修饰的所有方法
        Method[] methods = personClass.getMethods();
        for (Method method : methods) {
            System.out.println(method);
            //获取方法名
            System.out.println(method.getName());
        }
        /*
            public void com.mylifes1110.java.bean.Person.run(java.lang.Integer)
            run
            public java.lang.String com.mylifes1110.java.bean.Person.toString()
            toString
            public void com.mylifes1110.java.bean.Person.jump()
            jump
            public final void java.lang.Object.wait() throws java.lang.InterruptedException
            wait
            public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
            wait
            public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
            wait
            public boolean java.lang.Object.equals(java.lang.Object)
            equals
            public native int java.lang.Object.hashCode()
            hashCode
            public final native java.lang.Class java.lang.Object.getClass()
            getClass
            public final native void java.lang.Object.notify()
            notify
            public final native void java.lang.Object.notifyAll()
            notifyAll
         */
    }
}

4、获取类名

image.png

public class TestReflectClassName {
    public static void main(String[] args) {
        Person person = new Person();
        Class<? extends Person> personClass = person.getClass();


        //获取全类名
        String className = personClass.getName();
        System.out.println(className);      //com.mylifes1110.java.bean.Person
    }
}