Java 反射详解。(入门篇)

一、什么是反射?

请结合注解学习

1.定义

将类的各个组成部分封装为其他对象(Field,Constructor,Method),就是反射机制

2. 比如将class文件中的成员变量封装为第二阶段Class类中的Field类

在这里插入图片描述

二、反射有什么用?

  1. 运行的时候操作这些对象,
    比如:你使用idea时候的class. 然后自动弹出的可用的提示方法
    在这里插入图片描述
  2. 降低程序的耦合性。

三、如何获取Class对象的3种方式,

1. 三种方式

  1. Class.forName(“全类名”) : 阶段1可以使用,将class文件,加载进内存并返回Class对象
    多用于配置文件,读取文件,加载类

  2. Student.class : 阶段2 可用,类的的属性class **
    多用于
    传参**

  3. student.getClass() : 阶段3可用,对象实例的方法
    多用于对象获取字节码文件

2. 代码示例

package Java学习.Java高级.注解和反射.反射.获取Class类的方法;

/**
 * 1. Class.forName("全类名") : 阶段1可以使用,**将class文件,加载进内存并返回Class对象**
 * 多用于**配置文件,读取文件,加载类**
 *
 *
 * 2. Student.class : 阶段2 可用,**类的的属性class **
 * 多用于**传参**
 *
 * 3. student.getClass() : 阶段3可用,**对象实例的方法**
 * 多用于**对象**获取字节码文件
 */
public class Demo01黑马 {
    public static void main(String[] args) throws ClassNotFoundException {
        //1.
        System.out.println("----1. Class.forName(\"全类名\")------");
        System.out.println(Class.forName("Java学习.Java高级.注解和反射.反射.获取Class类的方法.Student01"));
        //2.
        System.out.println("--------2. Student.class---------");
        System.out.println(Student01.class);
        //3.
        System.out.println("-----3. student.getClass()-----");
        System.out.println(new Student01().getClass());
        System.out.println("-------123是否相等----------");
        System.out.println(new Student01().getClass().hashCode());
        System.out.println(Student01.class.hashCode());
        System.out.println(Class.forName("Java学习.Java高级.注解和反射.反射.获取Class类的方法.Student01").hashCode());
        System.out.println("HashCode的值相等,地址值相等,");
        System.out.println("结论: 同一个class字节码文件的在程序的运行中,只会被加载一次" +
                "\n无论通过哪一种方式获取的class对象都是同一个.");

    }
}
class Student01{

}

Run:
----1. Class.forName(“全类名”)------
class Java学习.Java高级.注解和反射.反射.获取Class类的方法.Student01
--------2. Student.class---------
class Java学习.Java高级.注解和反射.反射.获取Class类的方法.Student01
-----3. student.getClass()-----
class Java学习.Java高级.注解和反射.反射.获取Class类的方法.Student01
-------123是否相等----------
1915910607
1915910607
1915910607
HashCode的值相等,地址值相等,
结论: 同一个class字节码文件的在程序的运行中,只会被加载一次
无论通过哪一种方式获取的class对象都是同一个.

Process finished with exit code 0

四、获取的反射对象有什么用?通过Class 获取该类的Field,Constructor和Method对象,并且可以使用对应部分的方法(例如fiead.get())

1. Field

(1)知识点
 * 一、获取成员变量Field
 * 1. getField("publicField") (public权限)1个字段publicField
 * 2. getFields() (public权限)全部字段们
 *
 * 3. getDeclaredField("privateField") (所有权限)的1个字段privateField
 * 4. getDeclaredFields() (所有权限)的字段们
 * 二、使用field
 *  1.get():    .get(person02)
 *  2.set():    .set(person02,"设置的值")
 *  3.暴力反射:获取非public字段后需要暴力反射才能使用privateField的方法(比如get())
 *  privateField1.setAccessible(true);
(2) 代码
package Java学习.Java高级.注解和反射.反射.heima.使用Class对象02.获取字段Field021;

import Java学习.Java高级.注解和反射.反射.heima.使用Class对象02.Person02;

import java.lang.reflect.Field;

/**
 * 一、获取成员变量Field
 * 1. getField("publicField") (public权限)1个字段publicField
 * 2. getFields() (public权限)全部字段们
 * <p>
 * 3. getDeclaredField("privateField") (所有权限)的1个字段privateField
 * 4. getDeclaredFields() (所有权限)的字段们
 * 二、使用field
 * 1.get():    .get(person02)
 * 2.set():    .set(person02,"设置的值")
 * 3.暴力反射:获取非public字段后需要暴力反射才能使用privateField的方法(比如get())
 * privateField1.setAccessible(true);
 * <p>
 * --------------------------------------------------------------------------
 * 一、获取构造方法Constructor
 * 1. getConstructor(String.class) (public权限)1个String参数的Constructor
 * 2.3.4.同理
 * 二、使用constructor
 * 1.newInstance(): 新建Person的实例 ,newInstance(String "name",int age)
 * <p>
 * -----------------------------------------------
 * 一、获取成员方法Method
 * 1. getMethod("方法名eat",String.class) public权限的字段
 * String.class方法的参数的类型String
 * 2.3.4同上
 * 二、Method的使用
 * 1.invoke(): 调用方法 invoke("蛇皮怪"),蛇皮怪就是方法的参数。
 * <p>
 * -----------------------------------------------
 * 一、获取类名getName
 * 1. getName()
 */
public class Demo02 {
    public static void main(String[] args) throws Exception {
        Person02 person02 = new Person02();
        Class<? extends Person02> class1 = person02.getClass();
        /**
         *  * 一、获取成员变量Field
         *  * 1. getField(String name) public权限的字段
         *  * 2. getFields() 全部public权限字段们
         *  *
         *  * 3. getDeclaredField(String name) 获取所有权限的(public --private)的字段
         *  * 4. getDeclaredFields() 获取所有权限的(public --private)的字段们
         *  拓展
         *  5.获取class1对象下字段privateField的值 privateField.get(class1)
         *  6.设置值: privateField.set(class1,"设置的值")
         *  7.暴力反射获取
         *  privateField1.setAccessible(true);
         */
        Field publicField = class1.getField("publicField");
        System.out.println("-----------一、.---------");
        System.out.println("1.getField(\"publicField\");-------");
        System.out.println(publicField);
        Object[] fields;
        fields = class1.getFields();
        System.out.println("2.getFields()-------");
        for (int i = 0; i < fields.length; i++) {
            System.out.println(fields[i]);
        }
        System.out.println("结论:只能获取public类型的field");
        System.out.println("4.getDeclaredFields()--------");
        fields = class1.getDeclaredFields();
        for (int i = 0; i < fields.length; i++) {
            System.out.println(fields[i]);
        }
        /**
         *          *  拓展
         *          *  5.获取class1对象下字段privateField的值 privateField.get(class1)
         *          *  6.设置值: privateField.set(class1,"设置的值")
         *          *  7.暴力反射获取
         *              privateField1.setAccessible(true);
         */
        System.out.println("5.获取class1对象下字段privateField的值 privateField.get(person02)-------\n" +
                "6.设置值: privateField.set(person02,\"设置的值\")-------");

        Field privateField = class1.getField("publicField");
        System.out.println("privateField.get(person02): " + privateField.get(person02));
        privateField.set(person02, "set的值");
        System.out.println("privateField.set(person02,\"set的值\"): " + privateField.get(person02));

        System.out.println("暴力反射privateField1.setAccessible(true);----------");
        Field privateField1 = class1.getDeclaredField("privateField");
        //暴力反射前访问私有报错java.lang.IllegalAccessException
        //System.out.println(privateField1.get(person02));
        privateField1.setAccessible(true);
        System.out.println("暴力反射就能获取私有Field: " + privateField1.get(person02));
    }
}

Run:
-----------一、.---------
1.getField(“publicField”);-------
public java.lang.String Java学习.Java高级.注解和反射.反射.heima.使用Class对象02.Person02.publicField
2.getFields()-------
public java.lang.String Java学习.Java高级.注解和反射.反射.heima.使用Class对象02.Person02.publicField
结论:只能获取public类型的field
4.getDeclaredFields()--------
private java.lang.String Java学习.Java高级.注解和反射.反射.heima.使用Class对象02.Person02.privateField
java.lang.String Java学习.Java高级.注解和反射.反射.heima.使用Class对象02.Person02.defaltField
protected java.lang.String Java学习.Java高级.注解和反射.反射.heima.使用Class对象02.Person02.protectField
public java.lang.String Java学习.Java高级.注解和反射.反射.heima.使用Class对象02.Person02.publicField
5.获取class1对象下字段privateField的值 privateField.get(person02)-------
6.设置值: privateField.set(person02,“设置的值”)-------
privateField.get(person02): null
privateField.set(person02,“set的值”): set的值
暴力反射privateField1.setAccessible(true);----------
暴力反射就能获取私有Field: null

Process finished with exit code 0

2, Constructor

(1)知识点
 * 一、获取构造方法Constructor
 * 1. getConstructor(String.class) (public权限)1个String参数的Constructor
 * 2.3.4.同理
 * 二、使用constructor
 * 1.newInstance(): 新建Person的实例 ,newInstance(String "name",int age)
(2)code
package Java学习.Java高级.注解和反射.反射.heima.使用Class对象02.获取构造方法Method022;


import Java学习.Java高级.注解和反射.反射.heima.使用Class对象02.Person02;

import java.lang.reflect.Constructor;

public class Demo022 {
    public static void main(String[] args) throws Exception {
        /**
         * 一、获取构造方法Constructor
         * 1. getConstructor(String.class) (public权限)1个String参数的Constructor
         * 2.3.4.同理
         * 二、使用constructor
         * 1.newInstance(): 新建Person的实例 ,newInstance(String "name",int age)
         */
        Person02 person02 = new Person02();
        Class<? extends Person02> aClass = person02.getClass();
        Constructor<? extends Person02> constructor = aClass.getConstructor();//获取无参构造
        Constructor<? extends Person02> constructor1 = aClass.getConstructor(String.class);//获取一个参数的构造
        System.out.println("无参构造: " + constructor);
        System.out.println("1参构造: " + constructor1);
        System.out.println("-------二、获取构造的作用,newInstance()新建person对象实例------------");
        Person02 person021 = constructor1.newInstance("参数1");
        System.out.println(person021);

    }
}

Run:
无参构造: public Java学习.Java高级.注解和反射.反射.heima.使用Class对象02.Person02()
1参构造: public Java学习.Java高级.注解和反射.反射.heima.使用Class对象02.Person02(java.lang.String)
-------二、获取构造的作用,newInstance()新建person对象实例------------
Person02{privateField=‘参数1’, defaltField=‘null’, protectField=‘null’, publicField=‘null’}

Process finished with exit code 0

3.Method

(1)知识点
 * 一、获取成员方法Method
 * 1. getMethod("方法名eat",String.class) public权限的字段
 * String.class方法的参数的类型String
 * 2.3.4同上
 * 二、Method的使用
 * 1.invoke(): 调用方法 invoke("蛇皮怪"),蛇皮怪就是方法的参数。
(2)code
package Java学习.Java高级.注解和反射.反射.heima.使用Class对象02.获取成员方法们Method023;

import Java学习.Java高级.注解和反射.反射.heima.使用Class对象02.Person02;

import java.lang.reflect.Method;

/**
 *  * 一、获取成员方法Method
 *  * 1. getMethod("方法名eat",String.class) public权限的字段
 *  * String.class方法的参数的类型String
 *  * 2.3.4同上
 *  * 二、Method的使用
 *  * 1.invoke(): 调用方法 invoke("蛇皮怪"),蛇皮怪就是方法的参数。
 *  
 * 1.使用class获取Method
 * 2.使用Method
 * (1)使用method调用方法
 * (2)使用method获取方法名称
 */
public class Demo_023 {
    public static void main(String[] args) throws Exception {
        //1.使用class获取Method
        Person02 person02 = new Person02();
        Class<? extends Person02> aClass = person02.getClass();
        Method eatMethod = aClass.getMethod("eat", String.class);
        //2.使用method调用方法invoke()
        eatMethod.invoke(person02, "个蛇皮");
        System.out.println(eatMethod.getName());
    }
}

Run:
eat…个蛇皮
eat

Process finished with exit code 0

五、案例练习.

1. 需求:

  1. 写一个框架,不能改变类的任何的代码的情况下,创建类的对象,并且执行其中的任意代码

2. 实现原理:

  1. 配置文件
  2. 反射

3. 实现步骤

  1. 需要将创建对象的全类名和需要执行的文件定义在配置文件
className=Java学习.Java高级.注解和反射.反射.heima.反射项目.Person
methodName=eat
  1. 在程序中加载读取配置文件
//2.在程序中**加载读取配置文件**----------
//2.1创建Properties对象
Properties properties = new Properties();
//2.2加载load()方法,加载配置文件,储存key value 的值在properties中
//2.2.1 :load() 需要传递参数InputStream
String configuration = "D:\\Program Files\\JetBrains\\test1\\Lab\\src\\Java学习\\Java高级\\注解和" +
        "反射\\反射\\heima\\反射项目\\configuration.properties";
FileInputStream fileInputStream = new FileInputStream(configuration);
properties.load(fileInputStream);
//2.3 获取配置文件的数据:
String className = properties.getProperty("className");
String methodName = properties.getProperty("methodName");
  1. 使用反射技术加载类进内存
Class.forName("全类名")
  1. 创建Person对象
//4.创建Person对象------
//4.1因为Class类的创建Person对象方法newInstance()已经弃用
//我们先创建获得构造函数类Constructor在创建Person对象
//获得构造函数类Constructor 无参
Constructor<?> constructor = aClass.getConstructor();
//4.2 newInstance()创建Person对象
Object person = constructor.newInstance();
  1. **5.用aClass获取getMethod对象,然后再使用新建的person对象invoke(person)执行方法 **
//5.用aClass获取getMethod对象,然后再使用新建的person对象invoke(person)执行方法---------------
Method method = aClass.getMethod(methodName);
method.invoke(person);

4. 代码:

1.配置文件 configuration.properties

className=Java学习.Java高级.注解和反射.反射.heima.反射项目.Person
methodName=eat

2.Person 类:Person.java

package Java学习.Java高级.注解和反射.反射.heima.反射项目;

public class Person {
    private String privateField;
    String defaltField;
    protected String protectField;
    public String publicField;
    public void eat(){
        System.out.println("eat....");
    }
    public void eat(String food){
        System.out.println("eat..."+food);
    }
    public Person() {
        this.privateField = privateField;
    }

    public Person(String privateField) {
        this.privateField = privateField;
    }

    @Override
    public String toString() {
        return "Person02{" +
                "privateField='" + privateField + '\'' +
                ", defaltField='" + defaltField + '\'' +
                ", protectField='" + protectField + '\'' +
                ", publicField='" + publicField + '\'' +
                '}';
    }

    public Person(String privateField, String defaltField, String protectField, String publicField) {
        this.privateField = privateField;
        this.defaltField = defaltField;
        this.protectField = protectField;
        this.publicField = publicField;
    }

    public String getPrivateField() {
        return privateField;
    }

    public void setPrivateField(String privateField) {
        this.privateField = privateField;
    }

    public String getDefaltField() {
        return defaltField;
    }

    public void setDefaltField(String defaltField) {
        this.defaltField = defaltField;
    }

    public String getProtectField() {
        return protectField;
    }

    public void setProtectField(String protectField) {
        this.protectField = protectField;
    }

    public String getPublicField() {
        return publicField;
    }

    public void setPublicField(String publicField) {
        this.publicField = publicField;
    }
}

Demo_01.java

package Java学习.Java高级.注解和反射.反射.heima.反射项目;

import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Properties;

/**
 * 一、Properties类是Map的子类,性质类
 * 1. Properties 对象可以把以properties结尾的文件
 * 用load方法读取到内存里面形成一个集合
 *
 */
public class Demo_01 {
    public static void main(String[] args) throws Exception {
        //2.在程序中**加载读取配置文件**----------
        //2.1创建Properties对象
        Properties properties = new Properties();
        //2.2加载load()方法,加载配置文件,储存key value 的值在properties中
        //2.2.1 :load() 需要传递参数InputStream
        String configuration = "D:\\Program Files\\JetBrains\\test1\\Lab\\src\\Java学习\\Java高级\\注解和" +
                "反射\\反射\\heima\\反射项目\\configuration.properties";
        InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream(configuration),"GBK");
//        解码出错,properties是GBK格式

        properties.load(inputStreamReader);
        //2.3 获取配置文件的数据:
        String className = properties.getProperty("className");
        String methodName = properties.getProperty("methodName");
        System.out.println(className);
        //3. 使用**反射**技术加载类**进内存**-----------
        Class aClass = Class.forName(className);
        //4.创建Person对象------
        //4.1因为Class类的创建Person对象方法newInstance()已经弃用
        //我们先创建获得构造函数类Constructor在创建Person对象
        //获得构造函数类Constructor 无参
        Constructor<?> constructor = aClass.getConstructor();
        //4.2 newInstance()创建Person对象
        Object person = constructor.newInstance();
        //5.用aClass获取getMethod对象,然后再使用新建的person对象invoke(person)执行方法---------------
        Method method = aClass.getMethod(methodName);
        method.invoke(person);

    }
}

Run:
Java学习.Java高级.注解和反射.反射.heima.反射项目.Person
eat…

Process finished with exit code 0

原创文章 132 获赞 11 访问量 4686

猜你喜欢

转载自blog.csdn.net/jarvan5/article/details/106106980
今日推荐