Day14 JavaSE 反射机制(上)

JavaSE 反射机制(上)

前言:反射概述

前提:jvm已加载类。

现在给jvm一个类名,能不能知道类的具体信息?能,通过反射机制。

电脑的反射机制,就是通过一个抽象的类名能够在自己记忆(加载类的内存)中找到相匹配的类的具体信息。

Java Reflection

Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。

  • Java反射机制提供的功能
    • 在运行时判断任意对象所属的类
    • 在运行时构造任意一个类的对象
    • 在运行时判断任意一个类所具有的成员变量和方法
    • 在运行时调用任意一个对象的成员变量和方法
    • 生成动态代理
  • 反射相关的主要API:
    • java.lang,Class 代表一个类
    • java.lang.reflect.Method 代表类的方法
    • java.lang.reflect.Field 代表类的成员变量
    • java.lang.reflect.Constructor 代表类的构造方法

一、Class类

在Object类中定义了以下方法,此方法将被所有子类继承:

public final Class getClass()

以上的方法返回值的类型是一个Class类,此类是Java反射的源头,实际上所谓反射从程序的运行结果来看很好理解,即:可以通过对象反射求出类的名称。

Class类

反射可以得到的信息:某个类的属性、方法和构造器、某个类到底实现了哪个接口。对于每个类而言,JRE都为其保留一个不变的Class类型的对象。一个Class对象包含了特定某个类的有关信息。

  • Class 概述

    • Class本身也是一个类

    • Class对象只能由系统建立对象

    • 一个类在JVM中只能有一个Class实例

    • 一个Class对象对应的是一个加载到JVM中的一个.class文件

    • 每个类的实例都会记得自己是由哪个Class实例所生成

    • 通过Class可以完整地得到一个类中的完整结构

  • 实例化Class类对象(四种方法)

    • 通过类名.class创建指定类的Class实例
    • 通过一个类的实例对象.getClass()获取对应实例对象的类的Class实例
    • 通过Class的静态方法forName()来获取类的Class实例(常用!)
    • ClassLoader(不做介绍)
  • Class 类的常用方法(!!!)

    方法名 功能
    static Class forName(String name) 根据类的全类名(包名+类名)获取Class对象
    Object newInstance() 创建目标类对象
    getName() 获取全类名
    Class getSuperclass() 获取父类的Class对象
    Class[] getInterfaces() 获取所有实现的接口,返回类的数组
    ClassLoader getClassLoader() 获取类的类加载器
    Constuctor[] getConstructors() 获取所有的公有构造器(public修饰 )
    Constructor[] getDeclaredConstructors() 获取类的所有构造方法(包括公有私有)
    getModifiers() 获取构造方法的修饰符(public–>1; private–>2)
    Class[] getParameterTypes() 获取构造方法的参数类型,参数个数为返回数组的元素个数

二、Class类常用方法案例

以上方法的案例展示:(其中包含父类、两个接口、子类以及测试类)

package com.reflection;
//父类
public class Person {
    public String name;
    int age;
}
package com.reflection;
//接口:Move
public interface Move {
    void moveType();
}
package com.reflection;
//接口:Study
public interface Study {
    void studyInfo();
}
package com.reflection;
//子类(继承父类,并实现两个接口)
public class Student extends Person implements Move, Study{

    String school;

    //无参构造
    public Student(){
        System.out.println("调用的是public Student()");
    }
    //有参构造
    public Student(String school){
        System.out.println("调用的是public Student(String school)");
        this.school = school;
    }
    //私有有参构造
    private Student(String name, int age){
        System.out.println("调用的是private Student(String name, int age)");
        this.name = name;
        this.age = age;
    }
    void showInfo(){
        System.out.println("学校是:" + this.school);
    }
    @Override
    public void moveType() {
        System.out.println("骑自行车上学");
    }

    @Override
    public void studyInfo() {
        System.out.println("学习中学知识");
    }
}
package com.reflection;
//测试类
import java.lang.reflect.Constructor;

public class Test1 {
    public static void main(String[] args) {

        try {
            Class clazz = Class.forName("com.reflection.Student"); //获取指定类的Class实例

            Class superClazz = clazz.getSuperclass(); //获取父类

            System.out.println("父类: " + superClazz.getName());

            Class[] interfaces = clazz.getInterfaces();//获取当前类的所有接口
            for (Class i : interfaces) {
                System.out.println("接口: " + i.getName());
            }
            System.out.println("===============================================");

            //获取公有构造器,内含获取参数类型
            //修饰符为1,表示public修饰; 修饰符为2,表示private修饰
            Constructor[] cons = clazz.getConstructors(); //仅能求出公有的构造方法
            for (Constructor con : cons) {
                System.out.println("构造方法名称: " + con.getName() + "的修饰符是: " + con.getModifiers());

                Class[] paramClazz = con.getParameterTypes(); //获取构造方法的参数类型,参数个数为数组元素个数
                for (Class pc : paramClazz) {
                    System.out.println("构造方法: " + con.getName()+ "的参数类型是: " + pc.getName());
                }
                System.out.println();
            }
            System.out.println("===============================================");

            //获取所有构造器(公有+私有),内含获取参数类型
            Constructor[] cons1 = clazz.getDeclaredConstructors(); //获取类的所有构造方法,包括公有的和私有的
            for (Constructor c : cons1) {
                System.out.println("构造方法名称: " + c.getName() + "的修饰符是: " + c.getModifiers());
                Class[] paramClazz = c.getParameterTypes(); //获取构造方法的参数类型,参数个数为数组元素个数
                for (Class pc : paramClazz) {
                    System.out.println("构造方法: " + c.getName()+ "的参数类型是: " + pc.getName());
                }
                System.out.println();
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}
/*运行结果:
父类: com.reflection.Person
接口: com.reflection.Move
接口: com.reflection.Study
===============================================
构造方法名称: com.reflection.Student的修饰符是: 1
构造方法: com.reflection.Student的参数类型是: java.lang.String

构造方法名称: com.reflection.Student的修饰符是: 1

===============================================
构造方法名称: com.reflection.Student的修饰符是: 2
构造方法: com.reflection.Student的参数类型是: java.lang.String
构造方法: com.reflection.Student的参数类型是: int

构造方法名称: com.reflection.Student的修饰符是: 1
构造方法: com.reflection.Student的参数类型是: java.lang.String

构造方法名称: com.reflection.Student的修饰符是: 1

*/

三、通过反射创建一个对象

Person类、Student类、Move接口、Study接口 同(二)中案例。

现编写Test2类如下:

package com.reflection;

import java.lang.reflect.Constructor;

public class Test2 {
    public static void main(String[] args) {
        try {
            Class clazz1 = Class.forName("com.reflection.Student");

            //如何用反射的构造方法来创建对象
            try {
                Object obj = clazz1.newInstance(); //相当于调用Student类的无参公有构造方法
                Student stu = (Student)obj;
                System.out.println(stu.school);
                System.out.println("---------------------------------------");

                Constructor c1 = clazz1.getConstructor(String.class);//指定获取有一个参数为String类型的共有的构造方法
                Student stu1 = (Student)c1.newInstance("第一中学"); //通过newInstance实例话对象,相当于调用public Student(String school)
                System.out.println(stu1.school);
                System.out.println("---------------------------------------");

                //调用私有构造方法,通过反射机制强制调用
                Constructor c2 = clazz1.getDeclaredConstructor(String.class,int.class); //指定获取有两个参数(String, int)的构造方法

                c2.setAccessible(true); //解除私有封装

                Student stu2 = (Student)c2.newInstance("zhangsan",12);
                System.out.println("---------------------------------------");

            } catch (Exception e){
                e.printStackTrace();
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}
/*运行结果
调用的是public Student()
null
---------------------------------------
调用的是public Student(String school)
第一中学
---------------------------------------
调用的是private Student(String name, int age)
---------------------------------------
*/

注: 注意各个构造器的调用方式。

写在最后

祝你有个好心情,无论何时何地!

To Demut and Dottie!

发布了32 篇原创文章 · 获赞 39 · 访问量 1731

猜你喜欢

转载自blog.csdn.net/qq_44958172/article/details/104809619