返回顶部
首页 > 资讯 > 后端开发 > JAVA >Java 基础进阶篇(十七):反射概述及获取对象的方式
  • 211
分享到

Java 基础进阶篇(十七):反射概述及获取对象的方式

java开发语言反射 2023-09-30 08:09:19 211人浏览 薄情痞子
摘要

文章目录 一、反射概述二、反射获取类对象三、反射获取构造器对象四、反射获取成员变量对象五、反射获取方法对象六、 反射的作用6.1 绕过编译阶段为集合添加数据6.2 通用框架的底层原理

文章目录


一、反射概述

反射是指对于任何一个Class类,在 “运行的时候”,不用创建对象,就可以直接得到这个类全部成分。

  • 在运行时,可以直接得到这个类的构造器对象:Constructor
  • 在运行时,可以直接得到这个类的成员变量对象:Field
  • 在运行时,可以直接得到这个类的成员方法对象:Method

这种运行时动态获取类信息以及动态调用类中成分的能力称为 Java 语言的反射机制。

反射的作用:反射是在运行时获取类的字节码文件对象,然后可以解析类中的全部成分。
反射的关键:反射的第一步都是先得到编译后的 Class 类对象,然后就可以得到 Class 的全部成分。

在这里插入图片描述

注意:“类对象”和“类的对象”之间的区别,“类的对象”是 new 出来对象,而“类对象”是其本身,即 class 文件,是“类”类型。


二、反射获取类对象

反射的第一步:获取 Class 类的对象。

在这里插入图片描述

在这里插入图片描述

三种方式:

Class c1 = Class.forName(“全类名");Class c2 = 类名.class;Class c3 = 对象.getClass();

举例:

public class Test {    public static void main(String[] args) throws Exception {        // 1、Class类中的一个静态方法:forName(全限名:包名 + 类名)        Class c = Class.forName("com.itheima.d2_reflect_class.Student");        System.out.println(c); // Student.class        // 2、类名.class        Class c1 = Student.class;        System.out.println(c1);        // 3、对象.getClass() 获取对象对应类的Class对象。        Student s = new Student();        Class c2 = s.getClass();        System.out.println(c2);    }}

三、反射获取构造器对象

步骤:

在这里插入图片描述
获取构造器的方法:
在这里插入图片描述

Constructor类中用于创建对象的方法:
在这里插入图片描述

注:反射可以破坏封装性,私有的也可以执行了。

举例:

public class Student {private String name;private int age;// 构造器私有化private Student(){    System.out.println("无参数构造器执行!");}public Student(String name, int age) {    System.out.println("有参数构造器执行!");    this.name = name;    this.age = age;}...}
@Testpublic void getDeclaredConstructor() throws NoSuchMethodException {// 1. 第一步:获取类对象Class c = Student.class;// 2. 定位单个构造器对象 (按照参数定位到无参构造器)Constructor con = c.getDeclaredConstructor();System.out.println(con.getName() + " ==> " + con.getParameterCount()); // Student.class ==> 0// 3. 定位单个构造器对象 (按照参数定位到有参构造器)Constructor con1 = c.getDeclaredConstructor(String.class, int.class);System.out.println(con1.getName() + " ==> " + con1.getParameterCount()); // Student.class ==> 2}@Testpublic void getDeclaredConstructors(){    // 1. 第一步:获取类对象    Class c = Student.class;        // 2. 提取类中的全部构造方法    Constructor[] constructors = c.getDeclaredConstructors();        // 3. 遍历构造器    // 拿到所有的构造器    for (Constructor con : constructors) {        System.out.println(con.getName() + " ==> " + con.getParameterCount());    }}

暴力反射举例:

@Testpublic void getDeclaredConstructor() throws Exception {// 1. 第一步:获取类对象Class c = Student.class;// 2. 定位单个构造器对象 (按照参数定位到无参构造器)Constructor con = c.getDeclaredConstructor();// 遇到私有的构造器对象,可以暴力反射con.setAccessible(true);Student student = (Student) con.newInstance();System.out.println(student); // Student{name='null', age=0}}

四、反射获取成员变量对象

步骤:
在这里插入图片描述

反射的第一步是先得到类对象,然后从类对象中获取类的成分对象。

Class类中用于获取成员变量的方法:
在这里插入图片描述

Field类中用于取值、赋值的方法:
在这里插入图片描述
注:某成员变量是非public的,需要打开权限(暴力反射),然后再取值、赋值。

举例:

public class Student {    private String name;    private int age;    public static String schoolName;    public static final String  COUNTTRY = "中国";....}
@Testpublic void getDeclaredField() throws Exception {// 1. 第一步:获取类对象Class c = Student.class;// 2. 第二步:根据名称定位某个成员变量Field f = c.getDeclaredField("age");System.out.println(f.getName() +" ===> " + f.getType()); // age ===> int} @Testpublic void getDeclaredFields(){// 1. 第一步:获取类对象Class c = Student.class;// 2. 第二步:根据名称定位某个成员变量Field[] fields = c.getDeclaredFields();// 3. 第三步:遍历for (Field field : fields) {System.out.println(field.getName() + " ==> " + field.getType());// name ==> class java.lang.String ...}}

暴力反射举例:

@Testpublic void setField() throws Exception {// 1. 第一步:反射第一步,获取类对象Class c = Student.class;// 2. 第二步:提取某个成员变量Field ageF = c.getDeclaredField("age");ageF.setAccessible(true); // 暴力打开权限// 3. 第三步:赋值Student s = new Student();ageF.set(s, 18);  // 相当于 s.setAge(18);System.out.println(s);// 4. 第四步:取值int age = (int) ageF.get(s);System.out.println(age);}

五、反射获取方法对象

步骤:
在这里插入图片描述

获取成员方法的方法:
在这里插入图片描述

Method类中用于触发执行的方法:
在这里插入图片描述
注:某成员方法是非 public 的,需要打开权限(暴力反射),然后再取值、赋值。

举例:

public class Dog {    public void run(){        System.out.println("狗跑的贼快~~");    }    private void eat(){        System.out.println("狗吃骨头");    }    private String eat(String name){        System.out.println("狗吃" + name);        return "吃的很开心!";    }    public static void sleep(){        System.out.println("狗在睡觉!");    }}
@Testpublic void getDeclaredMethods(){// 1. 第一步:获取类对象Class c = Dog.class;// 2. 第二步:提取全部方法;包括私有的Method[] methods = c.getDeclaredMethods();// 3. 第三步:遍历全部方法for (Method method : methods) {    System.out.println(method.getName() +" 返回值类型:"             + method.getReturnType() + " 参数个数:" + method.getParameterCount());}// getName 返回值类型:String 参数个数:0 ...}

暴力反射举例:

@Testpublic void getDeclaredMethod() throws Exception {// 1. 第一步:获取类对象Class c = Dog.class;// 2. 第二步:提取单个方法对象Method eat = c.getDeclaredMethod("eat");Method eat2 = c.getDeclaredMethod("eat", String.class);// 暴力打开权限了eat.setAccessible(true);eat2.setAccessible(true);// 3. 第三步: 触发方法的执行Dog d = new Dog();// 注意:方法如果是没有返回值,那么返回的是null。Object result = eat.invoke(d); // 狗吃骨头System.out.println(result); // nullObject result2 = eat2.invoke(d, "骨头"); // 狗吃骨头System.out.println(result2); // 吃的很开心!}

六、 反射的作用

6.1 绕过编译阶段为集合添加数据

绕过泛型约束:泛型只是在编译阶段可以约束集合只能操作某种数据类型,编译成Class文件后,进入运行阶段的时候,泛型会自动擦除。

反射是作用在运行时的技术,此时集合的泛型将不能产生约束了,此时是可以为集合存入其他任意类型的元素。

举例:

public class Test {public static void main(String[] args) throws Exception {        // 需求:反射实现泛型擦除后,加入其他类型的元素        ArrayList<String> lists1 = new ArrayList<>();        ArrayList<Integer> lists2 = new ArrayList<>();        System.out.println(lists1.getClass() ==  lists2.getClass());  // true  ArrayList.class        ArrayList<Integer> lists3 = new ArrayList<>();        lists3.add(23);        lists3.add(22);        // lists3.add("黑马"); // 报错        Class c = lists3.getClass(); // ArrayList.class  ===> public boolean add(E e)        // 定位类对象 c 中的 add 方法        Method add = c.getDeclaredMethod("add", Object.class); // 第二个参数代表此时 add方法中参数是任意类型        boolean rs = (boolean) add.invoke(lists3, "黑马");        System.out.println(rs); // true        System.out.println(lists3); // [23, 22, 黑马]}}

举例2:变量被赋值后,泛型也会被擦除

public class Test2 {    public static void main(String[] args) {        // 需求:反射实现泛型擦除后,加入其他类型的元素        ArrayList<Integer> list1 = new ArrayList<>();        list1.add(23);        list1.add(22);        // list.add("黑马"); // 报错        ArrayList list2 = list1;        list2.add("白马");        list2.add(false);        System.out.println(list2);  // [23, 22, 白马, false]    }}

6.2 通用框架的底层原理

需求:给定任意一个对象,在不清楚对象字段的情况可以,可以把对象的字段名称和对应值存储到文件中去。

public class mybatisUtil {        public static void save(Object obj){        try (                PrintStream ps = new PrintStream(new FileOutputStream("day11-oop/src/data.txt", true));                ){            // 提取到这个对象的全部成员变量,只有反射可以解决            Class c = obj.getClass();  //   c.getSimpleName() 获取当前类名   c.getName() 获取全限名:包名+类名            ps.println("================" + c.getSimpleName() + "================");            // 提取到它全部成员变量            Field[] fields = c.getDeclaredFields();            // 获取成员变量的信息            for (Field field : fields) {                field.setAccessible(true);                String name = field.getName();                String value = field.get(obj) + "";                ps.println(name + " ==> " + value);            }        } catch (Exception e) {            e.printStackTrace();        }    }}
public class Test {    public static void main(String[] args) {        Student s = new Student();        s.setName("猪八戒");        s.setClassName("西天跑路1班");        s.setAge(1000);        s.setHobby("吃,睡");        s.setSex('男');        MyBatisUtil.save(s);        Teacher t = new Teacher();        t.setName("波仔");        t.setSex('男');        t.setSalary(6000);        MyBatisUtil.save(t);    }}

测试结果:

在这里插入图片描述


文章参考:Java入门基础视频教程,java零基础自学就选黑马程序员Java入门教程(含Java项目和Java真题)

来源地址:https://blog.csdn.net/weixin_43819566/article/details/131318002

--结束END--

本文标题: Java 基础进阶篇(十七):反射概述及获取对象的方式

本文链接: https://lsjlt.com/news/421756.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作