1、反射

(1)概念:

反射:将类的各个组成部分封装为对象,对于任何一个实体类,都能够知道这个类的属性和方法,对于任意一个对象,都能够调用它的任意方法和属性。

(2)好处:

         可以在程序运行的过程中,操作这些对象。

         解耦,提高可扩展性。

反射(反射、获取成员变量、构造方法、成员方法)_配置文件

(3)获取Class对象的三种方法:

Class.forname("包名.类名");此方式用于配置文件方式,通过配置文件加载类名。

反射(反射、获取成员变量、构造方法、成员方法)_配置文件_02

 

类名.class,多用于参数传递。

对象.getClass(),用于对象获取字节码对象的方式。

(4)三种方法获取Class对象:

Person类:

package pers.reflect.person;

public class Person {
private String name;
private int age;
public Person(){
    
}
public Person(String name,int age){
    this.name=name;
    this.age=age;
}
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;
}

}

测试类:

import pers.reflect.person.Person;

public class ReflectDemo {
    public static void main(String[] args) throws Exception {
        Class c1 = Class.forName("pers.reflect.person.Person");
        System.out.println("c1 = " + c1);

        Class c2 = Person.class;
        System.out.println("c2 = " + c2);

        Person p1 = new Person();
        Class c3 = p1.getClass();
        System.out.println("c3 = " + c3);
        System.out.println(c1==c2);
        System.out.println(c2==c3);
        System.out.println(c1==c3);

    }
}

反射(反射、获取成员变量、构造方法、成员方法)_java_03

通过程序运行结果可以看出,不管通过哪种方式,获取的字节码文件对象是同一个。也就是说,运行期间,一个类只产生一个Class对象。

 

 2、Class对象获取成员变量

(1)Class类的常用方法(获取Field对象):

反射(反射、获取成员变量、构造方法、成员方法)_构造方法_04

反射(反射、获取成员变量、构造方法、成员方法)_加载_05

创建Person类:

package pers.reflect.person;

public class Person {
private String name;
private int age;
public String hobby;
public String height;
protected String sex;
String address;

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


@Override
public String toString() {
    return "Person [name=" + name + ", age=" + age + ", hobby=" + hobby
            + ", height=" + height + ", sex=" + sex + ", address=" + address
            + "]";
}
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;
}

}
import java.lang.reflect.Field;

import pers.reflect.person.Person;

public class ReflectDemo {

    public static void main(String[] args) throws SecurityException,
            NoSuchFieldException, IllegalArgumentException,
            IllegalAccessException {

        Class c = Person.class;
        System.out.println("getFields(),获取公共的成员变量:");
        Field[] fields = c.getFields();
        for (Field field : fields) {
            System.out.println(field);
        }

        System.out.println("getField(),获取指定的公共的成员变量:");

        Field hobbyField = c.getField("hobby");
        System.out.println(hobbyField);

        System.out.println("getDeclaredFields(),获取所有的成员变量,与修饰符无关。");

        Field[] fields1 = c.getDeclaredFields();
        for (Field field : fields1) {
            System.out.println(field);
        }

        System.out.println("获取私有的指定的成员变量");

        Field nameField = c.getDeclaredField("age");

        System.out.println(nameField);

    }
}

(2)Field类的常用方法:

返回变量的类型:

反射(反射、获取成员变量、构造方法、成员方法)_构造方法_06

返回属性的名字:

反射(反射、获取成员变量、构造方法、成员方法)_加载_07

import java.lang.reflect.Field;

import pers.reflect.person.Person;


public class ReflectDemo1 {
public static void main(String[] args) {
    Class c = Person.class;
    System.out.println("getDeclaredFields(),获取所有的成员变量,与修饰符无关。");
    System.out.println();

    Field[] fields1 = c.getDeclaredFields();
    for (Field field : fields1) {
        System.out.println("成员变量:"+field);
        System.out.println("属性的类型:"+field.getType());
        System.out.println("属性的名字:"+field.getName());
        System.out.println();
    }
}
}

反射(反射、获取成员变量、构造方法、成员方法)_java_08

 

反射(反射、获取成员变量、构造方法、成员方法)_配置文件_09

反射(反射、获取成员变量、构造方法、成员方法)_构造方法_10

import java.lang.reflect.Field;

import pers.reflect.person.Person;


public class ReflectDemo2 {
public static void main(String[] args) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
    Class c = Person.class;
    System.out.println("getField(),获取指定的公共的成员变量:");
    Field hobbyField = c.getField("hobby");
    System.out.println(hobbyField);
    Person p=new Person();
    Object value=hobbyField.get(p);
    System.out.println(value);
    hobbyField.set(p, "张可可");
    System.out.println(p);
    System.out.println();
}
}

反射(反射、获取成员变量、构造方法、成员方法)_配置文件_11

访问不是被public修饰的成员变量(要用暴力反射,否者无法访问):

import java.lang.reflect.Field;

import pers.reflect.person.Person;

public class ReflectDemo3 {
    public static void main(String[] args) throws SecurityException,
            NoSuchFieldException, IllegalArgumentException,
            IllegalAccessException {
        Class c = Person.class;
        Field nameField = c.getDeclaredField("name");
        nameField.setAccessible(true);//暴力反射
        System.out.println(nameField);
        Person p = new Person();
        Object value = nameField.get(p);
        System.out.println(value);
        nameField.set(p, "赵晓霞");
        System.out.println(p);
    }
}
setAccessible(true);忽略权限修饰符的安全检查。

3、获取构造方法
package pers.reflect.Constructor;

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

import pers.reflect.person.Person;

public class ReflectDemo1 {
public static void main(String[] args) throws SecurityException, NoSuchMethodException, IllegalArgumentException,
InstantiationException, IllegalAccessException, InvocationTargetException { Class c = Person.class; System.out.println("getDeclaredConstructors(),获取所有的构造方法:"); Constructor[] cons = c.getDeclaredConstructors(); for (Constructor con : cons) { System.out.println(con); } System.out.println(); System.out.println("getConstructors(),获取所有的构造方法:"); Constructor[] cons1 = c.getConstructors(); for (Constructor con : cons1) { System.out.println(con); } System.out.println(); Constructor con=c.getConstructor(String.class,int.class); Object p=con.newInstance("张珊珊",12); System.out.println(p); Constructor con1=c.getConstructor();//空参数的构造方法创建Person类对象 Object p1=con1.newInstance(); System.out.println(p1); } }

反射(反射、获取成员变量、构造方法、成员方法)_成员变量_12

 4、获取成员方法

(1)常用方法:

反射(反射、获取成员变量、构造方法、成员方法)_成员变量_13

 public Method getMethod(String name, Class<?>... parameterTypes)   获取Public修饰的一个方法

 public Method getDeclaredMethod(String name, Class<?>... parameterTypes)  获取所有权限的一个方法

 public Method[] getMethods()                      本类与父类中所有public 修饰的方法所有方法

public Method[] getDeclaredMethods()          获取本类中所有的方法

(2)应用:           

package pers.reflect.person;

public class Person {
private String name;
private int age;
public String hobby;
public String height;
protected String sex;
String address;

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

protected  void sports() {
    System.out.println("我爱运动");
}
private  void sport() {
    System.out.println("我不爱运动");
}
public String toString() {
    return "Person [name=" + name + ", age=" + age + ", hobby=" + hobby
            + ", height=" + height + ", sex=" + sex + ", address=" + address
            + "]";
}
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 void study(String name){
    System.out.println(name+"爱学习");
}
}

获取公共的空参的成员方法:

package pers.reflect.method;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.rmi.StubNotFoundException;

import pers.reflect.person.Person;

public class reflectDemo {
    public static void main(String[] args) throws SecurityException,
            NoSuchMethodException, IllegalArgumentException,
            IllegalAccessException, InvocationTargetException {
        Class c = Person.class;
        Method study_method = c.getMethod("study");
        Person p = new Person();
        study_method.invoke(p);
    }
}

获取公共的带参数的成员方法:

package pers.reflect.method;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import pers.reflect.person.Person;

public class reflectDemo {
    public static void main(String[] args) throws SecurityException,
            NoSuchMethodException, IllegalArgumentException,
            IllegalAccessException, InvocationTargetException {
        Class c = Person.class;
        Method study_method1 = c.getMethod("study",String.class);
        Person p = new Person();
        study_method1.invoke(p,"Tom");
    }
}

获取所有的公共的方法:

package pers.reflect.method;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import pers.reflect.person.Person;

public class reflectDemo {
    public static void main(String[] args) throws SecurityException,
            NoSuchMethodException, IllegalArgumentException,
            IllegalAccessException, InvocationTargetException {
        Class c = Person.class;
        Method[] methods = c.getMethods();
        for (Method method:methods){
            System.out.println(method);
        }
    }
}

获取方法名字:

反射(反射、获取成员变量、构造方法、成员方法)_加载_14

package pers.reflect.method;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import pers.reflect.person.Person;

public class reflectDemo {
    public static void main(String[] args) throws SecurityException,
            NoSuchMethodException, IllegalArgumentException,
            IllegalAccessException, InvocationTargetException {
        Class c = Person.class;
        Method[] methods = c.getMethods();
    for(Method method:methods){
        System.out.println(method.getName());
    }
    }
}

获取所有的方法(忽略权限修饰符):

package pers.reflect.method;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import pers.reflect.person.Person;

public class reflectDemo {
    public static void main(String[] args) throws SecurityException,
            NoSuchMethodException, IllegalArgumentException,
            IllegalAccessException, InvocationTargetException {
        Class c = Person.class;
        Method[] methods = c.getDeclaredMethods();
        
    for(Method method:methods){
        method.setAccessible(true);
        System.out.println(method);
    }
    }
}

 5、反射的好处(转载自博客园:https://www.cnblogs.com/bihanghang/p/9992237.html

我们在第一次接触反射的时候,总会有个很大的疑问,反射看起来好麻烦啊,各种get.get,他究竟有什么好处,能用来做什么呢?

我们先来看一下《编程思想》这本书中是怎么说的.

RTTI和反射之间真正的区别只在于,对RTTI来说,编译器在在编译时打开和检查.class文件.(换句话说,我们可以用"普通"方式调用对象的所有方法).对于反射机制来说,.class文件在编译时是不可获取的,所以在运行时打开和检查.class文件。 --《编程思想》

  这段话看起来很叼的样子,有点云里雾里的,首先RTTI的意思就是以普通的方式来创建对象,调用方法,就是我们常用的new关键字。这段话的意思简化版就是:编译器将.java文件编译成.class文件之后,普通方式创建的对象就不能再变了,我只能选择是运行还是不运行这个.class文件。是不是感觉很僵硬,假如现在我有个写好的程序已经放在了服务器上,每天供人家来访问,这时候Mysql数据库宕掉了,改用Oracle,这时候该怎么怎么办呢?假如没有反射的话,我们是不是得修改代码,将Mysql驱动改为Oracle驱动,重新编译运行,再放到服务器上。是不是很麻烦,还影响用户的访问。

假如我们使用反射Class.forName()来加载驱动,只需要修改配置文件(配置文件不参与编译)就可以动态加载这个类,Class.forName()生成的结果在编译时是不可知的,只有在运行的时候才能加载这个类,换句话说,此时我们是不需要将程序停下来,只需要修改配置文件里面的信息就可以了。这样当有用户在浏览器访问这个网站时,都不会感觉到服务器程序程序发生了变化。

所以在《Mybatis技术原理与实战》是这么说反射的好处的。

配置性大大提高,如同Spring IOC容器,给很多配置设置参数,使得java应用程序能够顺利跑起来,大大提高了Java的灵活性和可配置性,降低模块间的耦合。--《Mybatis技术原理与实战》


简单来说就是,没有反射的话如果想要调用其他方法和属性就必须重新修改代码,再编译运行。使用反射修改代码后就不需要再次编译程序了

每个人都会有一段异常艰难的时光 。 生活的压力 , 工作的失意 , 学业的压力。 爱的惶惶不可终日。 挺过来的 ,人生就会豁然开朗。 挺不过来的 ,时间也会教你 ,怎么与它们握手言和 ,所以不必害怕的。 ——杨绛