反射

1、什么是反射

反射是使用"类"的一种方式,它可以使我们的程序在运行时,动态的去加载某个类,然后去获取它内部的成员信息,进而可以创建这个类对象,并且调用它的成员。反射的主要作用是解开类和类之间的耦合关系,有利于后期开发的更新与迭代。下面使用代码讲解一下具体的实现机理:

之前使用类,先创建对象:

创建Student类


public class Student {//创建一个学生对象
    public Student(){
        System.out.println("创建了一个Student对象");
    }
}

 编写测试类

/*
    class文件的加载:
 */
public class Demo02 {
    public static void main(String[] args) throws InterruptedException {
        Student stu1 = new Student();//第一次创建对象
        for (int i = 0; i < 15; i++) {
            System.out.println("i = " + i);
            Thread.sleep(1000);
        }
        Student stu2 = new Student();//第二次创建对象
        Student stu3 = new Student();//第三次创建对象
    }
}

内存中创建对象的实现机理

//1.运行main方法,查看方法区里面是否存在Class类的对象的相关信息,如果没有。执行第二步;

//2.从磁盘里面加载Student类的相关信息进内存,执行第三步;

//3.在方法区中创建一个Class类的对象Student,包括Student类的构造方法,成员属性,成员方法等

//4.在堆中开辟Stu1的内存空间

//5.当main函数运行到第二次创建student对象时,

//6.jvm直接在方法区中访问student类,

//7.在栈中开辟第二块Student地址空间。

这样创建对象后,会使我们的类与被使用的类产生了"依赖"关系。不利于后期的更新、维护。

使用反射以后:

如上图的绿色线,使用反射技术以后,系统不经过JVM虚拟机,直接获取CLASS对象,如果存在Class对象,获取这个对象,然后操作这个对象,如果不存在Class对象,先创建一个Class对象,然后再对这个Class对象进行操作。

2.Class类

从jdk1.6文档中可以知道,Class类是java.lang下面的一个类,继承于object类,实现了Serializable, AnnotatedElement, GenericDeclaration, Type四个接口,并且Class类没有公共的构造方法。

Class类的常用方法

      1).获取构造方法:
            A).批量获取:
                1).public Constructor[] getConstructors():获取所有的"公有"构造方法。
                2).public Constructor[] getDeclaredConstructors():获取所有的构造方法,包括公有、受保护、默认、私有的。
                

            B).获取单个:
                3).public Constructor getConstructor(Class<?>... parameterTypes):获取某个公有构造方法
                4).public Constructor getDeclaredConstructor(Class<?>... parameterTypes):获取某个构造方法,可以是:公有、受保护、默认、私有
            -创建对象:通过调用Constructor的newInstance(Object ... params)方法来进行对象的新建
                注意:
                如果没有访问权限,要先设置一下:暴力访问
                Constructor-->setAccessible(true):

代码示例:

创建学生类,分别设置无参构造、有参构造、受保护的构造、默认的构造、私有的构造方法

public class Student {
    public Student(){
        System.out.println("调用了公有、无参的构造方法...");
    }

    public Student(int a) {
        System.out.println("调用了公有、int参数的构造方法...");
    }

    protected Student(String string) {
        System.out.println("调用了受保护、String参数的构造方法...");
    }

    Student(double d) {
        System.out.println("调用了默认的、double参数的构造方法...");
    }

    private Student(String name, int age) {
        System.out.println("调用了私有的、String、int参数的构造方法...String = " + name + " age = " + age);
    }

main方法

import java.lang.reflect.Constructor;

/*
    通过Class获取类的构造方法:
        A).批量获取:
				1).public Constructor[] getConstructors():获取所有的"公有"构造方法。
				2).public Constructor[] getDeclaredConstructors():获取所有的构造方法,包括公有、受保护、默认、私有的。
			B).获取单个:
                3).public Constructor getConstructor(Class<?>... parameterTypes):获取某个公有构造方法
                4).public Constructor getDeclaredConstructor(Class<?>... parameterTypes):获取某个构造方法,可以是:公有、受保护、默认、私有

 */
public class Demo04 {
    public static void main(String[] args) throws Exception {
        //1.获取Class对象
        Class stuClass = Class.forName("com.itheima.demo04.Student");

        System.out.println("获取所有[共有]构造方法:");
        Constructor[] cs = stuClass.getConstructors();//获取Student类里面所有的公有构造方法
        for (Constructor c : cs) {
            System.out.println(c);
        }

        System.out.println("获取[所有的]构造方法:");
        Constructor[] cs2 = stuClass.getDeclaredConstructors();
        for (Constructor constructor : cs2) {
            System.out.println(constructor);
        }

        System.out.println("获取公有、无参的构造方法:");
        Constructor c1 = stuClass.getConstructor();
        System.out.println(c1);

        System.out.println("获取公有、int参数的构造方法:");
        Constructor c2 = stuClass.getConstructor(int.class);
        System.out.println(c2);


        System.out.println("获取私有的,String和int参数的构造方法:");
        Constructor c3 = stuClass.getDeclaredConstructor(String.class, int.class);
        System.out.println(c3);

//获取到class类的构造方法后,还需要创建对象,在创建的同时,也可以通过有参构造,经行对对象的赋值。但是创建的对象想要访问私有的构造方法,需要设置暴力访问,暴力访问的主要作用是不进行权限修饰符的验证。

        System.out.println("【创建对象】调用公有、无参构造:");
        Object o1 = c1.newInstance();

        System.out.println("【创建对象】调用公有、int参数的构造方法:");
        Object o2 = c2.newInstance(22);

        System.out.println("【创建对象】调用私有、String、int参数的构造方法:");
        c3.setAccessible(true);//设置暴力访问——不进行权限修饰符的验证
        Object o3 = c3.newInstance("张三", 20);
    }


        2).获取成员属性:
            A).批量获取:
                1).public Field[] getFields():获取所有的"公有"成员属性。
                2).public Field[] getDeclaredFields():获取所有的成员属性,包括公有、受保护、默认、私有的。
          B).获取单个:
                3).public Field getField(String fieldName):获取某个公有成员属性
                4).public Field getDeclaredField(String fieldName):获取某个成员属性,可以是:公有、受保护、默认、私有
            -设置属性的值:
                Field-->set(Object targetObj , Object value)
            -获取属性的值:
                Field-->get(Object obj):
            -设置暴力访问:
                Field-->setAccessible(true)

创建Student类

public class Student {
    public String name;

    private boolean marry;


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

获取成员属性

import java.lang.reflect.Field;

/*
    2).获取成员属性:
			A).批量获取:
				1).public Field[] getFields():获取所有的"公有"成员属性。
				2).public Field[] getDeclaredFields():获取所有的成员属性,包括公有、受保护、默认、私有的。
			B).获取单个:
				3).public Field getField(String fieldName):获取某个公有成员属性
				4).public Field getDeclaredField(String fieldName):获取某个成员属性,可以是:公有、受保护、默认、私有
 */
public class Demo05 {
    public static void main(String[] args) throws Exception {
        //1.获取Class
        Class stuClass = Class.forName("com.itheima.demo05.Student");

        System.out.println("获取公有、name属性:");
        Field nameFiled = stuClass.getField("name");
        System.out.println(nameFiled);

        System.out.println("获取私有、marry属性:");
        Field marryField = stuClass.getDeclaredField("marry");
        System.out.println(marryField);

        //2.创建Student对象
        Object obj = stuClass.getConstructor().newInstance();

        //3.为obj对象的name和marry属性赋值
        nameFiled.set(obj, "张三");
        System.out.println(obj);

        //4.为obj对象的marry属性赋值为:true
        marryField.setAccessible(true);//设置暴力访问
        marryField.set(obj, true);
        System.out.println(obj);

        //获取
        System.out.println("姓名:" + nameFiled.get(obj));
        System.out.println("婚否:" + marryField.get(obj));

    }


        3).获取成员方法:
            A).批量获取:
                1).public Method[] getMethods():获取所有的"公有"成员方法。
                2).public Method[] getDeclaredMethods():获取所有的成员方法,包括公有、受保护、默认、私有的。
             B).获取单个:
                3).public Method getMethod(String methodName,Class ... params):获取某个公有成员方法
                4).public Method getDeclaredMethod(String methodName,Class... params):获取某个成员方法,可以是:公有、受保护、默认、私有
                
            -调用方法:
                Method-->invoke(Object targetObj,Object ... params)
                注意:
                如果没有访问权限,要先设置一下:暴力访问:
                Method-->setAccessible(true)

创建学生类

public class Student {
    public void show1(){
        System.out.println("调用了公有、无参的show1()...");
    }

    private int show2(String name,int age){
        System.out.println("调用了String、int参数的show2(),String = " + name + " int = " + age);
        return 200;
    }

获取成员方法

import java.lang.reflect.Method;

/*
    3).获取成员方法:
			A).批量获取:
				1).public Method[] getMethods():获取所有的"公有"成员方法。
				2).public Method[] getDeclaredMethods():获取所有的成员方法,包括公有、受保护、默认、私有的。


			B).获取单个:
				3).public Method getMethod(String methodName,Class ... params):获取某个公有成员方法
				4).public Method getDeclaredMethod(String methodName,Class... params):获取某个成员方法,可以是:公有、受保护、默认、私有

		    -调用方法:
		        Method类-->invoke(Object targetObj , Object ... params)
 */
public class Demo06 {
    public static void main(String[] args) throws Exception {
        //1.获取Class对象
        Class aClass = Class.forName("com.itheima.demo06.Student");

        System.out.println("获取公有、无参的show1():");
        Method show1Method = aClass.getMethod("show1");
        System.out.println(show1Method);

        System.out.println("获取私有、有参、有返回值的show2():");
        Method show2Method = aClass.getDeclaredMethod("show2", String.class, int.class);
        System.out.println(show2Method);

        //2.创建对象
        Object obj = aClass.getConstructor().newInstance();

        //3.调用方法:
        show1Method.invoke(obj);

        show2Method.setAccessible(true);
        Object result = show2Method.invoke(obj, "张三", 20);
        System.out.println("返回值:" + result);
    }

3. 反射的使用步骤

1)先获取类

    获取Class对象的三种方式:
        A).Object类的getClass()【已有对象了,通过对象获取】
        B).任何数据类型(包括基本类型).class【对基本类型、类库中的类】 '
        C).Class类的静态方法:forName(String className)【常用——对于我们自己的类】

        以上三种方式,工作流程都一样:如果没有此类的Class对象,会先新建一个,然后返回;如果有,就直接获取并返回。

2)获取类的内部成员信息

3)创建这个类对象,并调用他的成员

反射demo案例

游戏类



public class MyGame {
    public void run(){
    System.out.println("沙漠地图...");
}
}


import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Properties;

/*
    反射的效果演示:

 */
public class Demo01 {
    public static void main(String[] args) throws Exception {
        //1.正常使用
        /*Game game = new Game();
        game.paoTu();*/

        String className = getValue("className");//com.itheima.demo01.Game
        String methodName = getValue("methodName");

        //2.下面使用了反射
        Class aClass = Class.forName(className);
        Object obj = aClass.getConstructor().newInstance();
        Method method = aClass.getMethod(methodName);
        method.invoke(obj);

        //以上四行代码,就相当于:
        /*Game game = new Game();
        game.paoTu();*/
    }

    //编写一个方法,获取配置文件中某个键的值
    public static String getValue(String key) {
        Properties pro = new Properties();
        try (FileReader in = new FileReader("game.properties")) {
            pro.load(in);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return pro.getProperty(key);
    }
}

配置文件game.properties

className=com.itheima.demo21.student
filedName=name
filedAge=age


    

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

成神之路.java

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值