前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【Java基础】JavaCore核心-反射技术

【Java基础】JavaCore核心-反射技术

原创
作者头像
互联网小阿祥
发布2023-05-28 21:59:44
2980
发布2023-05-28 21:59:44
举报

@TOC

在这里插入图片描述
在这里插入图片描述
1.什么是反射技术
  • Java的反射(reflection)机制是指在程序的运行状态中
    • 可以构造任意一个类的对象
    • 可以了解任意一个对象所属的类
    • 可以了解任意一个类的成员变量和方法
    • 可以调用任意一个对象的属性和方法。
  • 这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制
  • 核心:得到编译以后得class文件对象,提供了一个Class类型,就是编译后的class类对象
代码语言:java
复制
HelloWorld.java -> javac -> HelloWorld.class

Class clz = HelloWorld.class
  • 分类
  • 类字节码 Class (本身也是一个类,是Java反射的源头)
  • 构造器 Constructor
  • 成员变量 Field
  • 方法 Method
2.反射-获取类对象方式
代码语言:java
复制
public class ReflexTest {

    public static void main(String[] args) throws ClassNotFoundException {

        //1.类名.class 获取
        Class<User> userClass1 = User.class;
        System.out.println(userClass1);

        //2.对象获取
        User user = new User();
        Class<? extends User> userClass2 = user.getClass();
        System.out.println(userClass2);

        //3.全限定名称获取,Class.forName
        Class<?> userClass3 = Class.forName("com.lixiang.reflex.User");
        System.out.println(userClass3);

        //4.通过classLoader类加载器
        ClassLoader classLoader = ReflexTest.class.getClassLoader();
        Class<?> userClass4 = classLoader.loadClass("com.lixiang.reflex.User");
        System.out.println(userClass4);

    }

}

public class User {

    private String name;

    private int age;

}
在这里插入图片描述
在这里插入图片描述
  • 反射API比较多,宏观分类
    • get+要获取的东西,例如:获取属性为getField()、获取方法为getMethod()
      • 只能获取公有的东西
      • 注意:getMethod可以获取到本类及其父类的方法
    • get+Declared+要获取的东西,例如:获取属性为getDeclaredField()、获取方法为geDeclaredtMethod()
      • 可以获取全部的东西
      • 注意:getDeclaredMethod只能获取到本类的方法
3.反射-获取声明构造器
代码语言:java
复制
public class ReflexTest {

    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {

        //1.类名.class 获取
        Class<User> userClass = User.class;

        Constructor<?>[] declaredConstructors = userClass.getDeclaredConstructors();

        //获取本类的全部构造方法
        for (Constructor<?> declaredConstructor : declaredConstructors) {
            System.out.println(declaredConstructor.getName() + " "+ declaredConstructor.getParameterCount());
        }

        System.out.println("--------------------");

        //获取String类型的高燥方法
        Constructor<User> declaredConstructor = userClass.getDeclaredConstructor(String.class);
        System.out.println(declaredConstructor.getName() + " "+ declaredConstructor.getParameterCount());

    }
}
在这里插入图片描述
在这里插入图片描述
4.反射-对象创建实战
  • JDK9后用构造器创建对象,class.getDeclaredConstructor( ).newInstance( )
  • 日常开发定义的POJO类里面,开发规范都推荐显示的写出空构造函数
  • 一是方便通过反射创建对象 ,二是子类继承父类时,默认调用super( ) 保证父类有空构造函数

方法名

说明

T newInstance( )

根据类的空参的构造器创建对象,类必须提供空参的构造器和public权限

T newInstance(Object...initargs)

根据指定的构造方法创建对象

  • 反射创建对象有多种方式,常用步骤如下
  • 根据全类名获取对应的Class对象
  • 调用指定参数结构的构造器,生成Constructor的实例
  • 通过Constructor的实例创建对应类的对象,并初始化类属性
代码语言:java
复制
public class ReflexTest {

    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {

        //1.类名.class 获取
        Class<User> userClass = User.class;

        //创建无参User对象
        Constructor<User> userConstructor1 = userClass.getDeclaredConstructor();
        User user = userConstructor1.newInstance();
        System.out.println(user);

        System.out.println("-----------------------");

        //创建一个参数的对象
        Constructor<User> userConstructor2 = userClass.getDeclaredConstructor(String.class);
        User user1 = userConstructor2.newInstance("李祥");
        System.out.println(user1);
    }

}
在这里插入图片描述
在这里插入图片描述
5.反射-方法和属性实战
  • 通过class获取方法

方法

说明

getMethods()

获取当前运行类和 父类中声明的方法,需要是public访问权限的方法

getDeclaredMethods()

获取当前运行时类中声明的全部方法,不包含父类中声明的方法

  • 方法method的方法

方法

说明

getReturnType()

获取全部的返回值

getParameterTypes()

获取全部的参数

getModifiers()

获取修饰符

getExceptionTypes()

获取异常信息

代码语言:java
复制
public class ReflexTest {

    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {

        //获取类对象
        Class<User> clazz = User.class;

        //获取当前运行类和 父类中声明的方法,需要是public访问权限的方法
        Method[] methods = clazz.getMethods();
        for(Method method:methods){
            System.out.println("修饰符="+method.getModifiers()+",返回值="+method.getReturnType().getName()+",整体="+method);
        }

        System.out.println("——————————————————");

        //返回当前类中所有的方法,无视修饰符
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for(Method method:declaredMethods){

            System.out.println("修饰符="+method.getModifiers()+",返回值="+method.getReturnType().getName()+",整体="+method);
        }
    }

}
在这里插入图片描述
在这里插入图片描述
  • 通过class对象获取属性

方法名

说明

getFields( )

获取当前运行类和 父类中声明的属性,需要是public访问权限的属性

getDeclaredFields( )

获取当前运行时类中声明的全部属性,不包含父类中声明的属性

  • 属性Field的方法

方法

说明

getModifiers()

整数形式返回此Field的修饰符,整数对应在 java.lang.reflect.Modifier里面

getType()

返回 Field的属性类型

getName()

返回 Field的名称

代码语言:java
复制
public class ReflexTest {

    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {

        //获取类对象
        Class<User> clazz = User.class;

        //都是private,则获取不了; 属性改为public才行
        Field[] fields = clazz.getFields();
        for(Field field:fields){
            System.out.println("属性名="+field.getName()+",属性类型="+field.getType().getName()+",属性修饰符="+field.getModifiers());
        }
        System.out.println("——————————————————");

        // 获取当前运行时类中声明的全部属性,不包含父类中声明的属性
        Field[] declaredFields = clazz.getDeclaredFields();
        for(Field field:declaredFields){
            System.out.println("属性名="+field.getName()+",属性类型="+field.getType().getName()+",属性修饰符="+field.getModifiers());
        }
    }

}
在这里插入图片描述
在这里插入图片描述
6.反射-属性值操作实战
  • 对反射进行相关操作,但如果构造器、方法、属性 没权限怎么操作?
  • 可以通过 setAccessible(true) ,修改访问权限,Method和Field、Constructor对象都有setAccessible()方法
在这里插入图片描述
在这里插入图片描述
代码语言:java
复制
public class ReflexTest {

    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {

        //获取类对象
        Class<User> clazz = User.class;

        //获取public空构造函数,并创建对象(把构造函数private私有化)
        Constructor<User> declaredConstructor = clazz.getDeclaredConstructor();

        //修改访问权限,true表示暴力反射,攻破权限
        declaredConstructor.setAccessible(true);
        User user = declaredConstructor.newInstance();
        user.setAge(11);
        user.setName("李祥");

        System.out.println(user);
    }
}
在这里插入图片描述
在这里插入图片描述
  • Field相关方法

方法

说明

get(Object obj)

获取取指定对象obj上此Field的属性内容

set(Object obj,Object value)

设置指定对象obj上此Field的属性内容

在这里插入图片描述
在这里插入图片描述
代码语言:java
复制
public class ReflexTest {

    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException {

        Class clazz = User.class;

        //创建运行时类的对象
        //获取类对象

        //获取public空构造函数,并创建对象
        Constructor<User> declaredConstructor = clazz.getDeclaredConstructor();
        //修改访问权限,true表示保留反射
        declaredConstructor.setAccessible(true);
        //创建对象
        User user = declaredConstructor.newInstance();
        System.out.println(user.toString());


        //获取运行时类中指定变量名的属性
        Field name = clazz.getDeclaredField("name");
        //保证当前属性是可访问的

        name.setAccessible(true);
        //设置指定对象的的属性值
        name.set(user,"李祥");

        //打印对象的name属性值
        System.out.println(name.get(user));

        System.out.println(user.toString());
		}
}
在这里插入图片描述
在这里插入图片描述
7.反射-invoke运行类方法
  • 运行类的指定方法步骤
    • 获取class对象,创建对象
    • 获取方法,invoke调用
  • 什么是invoke调用 Object invoke(Object obj, Object … args)
    • invoke的中文意思是【调用、召唤】
    • 用来调用某个类中的方法的,但是它不是通过当前类直接去调用而是通过反射的机制去调用
      • 参数说明:obj是调用类的实例对象, args:调用方的方法参数,是可变长度的
      • Object 对应原方法的返回值,若原方法无返回值,此时返回null
      • 如果原方法为静态方法,此时形参 obj可为null
      • 如果原方法形参列表为空,则args为null
      • 如果原方法声明为private,则需要在调用此invoke()方法前,调用对象的setAccessible(true)方法
  • 编码实战
  • User类中加入这三个方法
在这里插入图片描述
在这里插入图片描述
代码语言:java
复制
public class ReflexTest {

    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException {

        //获取类对象
        Class<User> clazz = User.class;

        //获取public空构造函数,并创建对象
        Constructor<User> declaredConstructor = clazz.getDeclaredConstructor();
        //确保有访问权限,true表示暴力反射
        declaredConstructor.setAccessible(true);
        User user = declaredConstructor.newInstance();
        user.setName("李祥");

        System.out.println("—————————调用普通方法———————————");
        //获取指定的某个方法, 参数1,指明获取的方法的名称  参数2,指明获取的方法的形参列表
        Method say = clazz.getDeclaredMethod("say", String.class);
        //保证当前方法是可访问的
        say.setAccessible(true);

        //invoke调用,参数1 方法的调用者  参数2 给方法形参赋值的实参,
        // 返回值 是 对应类中调用的方法的返回值。
        Object returnValue = say.invoke(user, "李祥");
        System.out.println(returnValue);


        System.out.println("—————————调用静态方法———————————");
        //获取指定的某个方法, 参数1,指明获取的方法的名称  参数2,指明获取的方法的形参列表
        Method sleepMethod = clazz.getDeclaredMethod("sleep",String.class);
        //保证可以访问
        sleepMethod.setAccessible(true);

        //调用静态方法,不需要获取类对象。
        Object returnValue2 = sleepMethod.invoke(null,"李祥");
        //如果调用的运行时类中的方法没有返回值,则此invoke()返回null
        System.out.println(returnValue2);
    }
}
在这里插入图片描述
在这里插入图片描述

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.什么是反射技术
  • 2.反射-获取类对象方式
  • 3.反射-获取声明构造器
  • 4.反射-对象创建实战
  • 5.反射-方法和属性实战
  • 6.反射-属性值操作实战
  • 7.反射-invoke运行类方法
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
http://www.vxiaotou.com