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

这篇具有很好参考价值的文章主要介绍了Java 基础进阶篇(十七):反射概述及获取对象的方式。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


一、反射概述

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

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

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

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

java反射获取对象,JavaSE,java,开发语言,反射

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


二、反射获取类对象

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

java反射获取对象,JavaSE,java,开发语言,反射

java反射获取对象,JavaSE,java,开发语言,反射

三种方式:

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);
    }
}

三、反射获取构造器对象

步骤:

java反射获取对象,JavaSE,java,开发语言,反射
获取构造器的方法:
java反射获取对象,JavaSE,java,开发语言,反射

Constructor类中用于创建对象的方法:
java反射获取对象,JavaSE,java,开发语言,反射

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

举例:

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;
	}
	...
}
@Test
public 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
}

@Test
public void getDeclaredConstructors(){
    // 1. 第一步:获取类对象
    Class c = Student.class;
    
    // 2. 提取类中的全部构造方法
    Constructor[] constructors = c.getDeclaredConstructors();
    
    // 3. 遍历构造器
    // 拿到所有的构造器
    for (Constructor con : constructors) {
        System.out.println(con.getName() + " ==> " + con.getParameterCount());
    }
}

暴力反射举例:

@Test
public 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}
}

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

步骤:
java反射获取对象,JavaSE,java,开发语言,反射

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

Class类中用于获取成员变量的方法:
java反射获取对象,JavaSE,java,开发语言,反射

Field类中用于取值、赋值的方法:
java反射获取对象,JavaSE,java,开发语言,反射
注:某成员变量是非public的,需要打开权限(暴力反射),然后再取值、赋值。

举例:

public class Student {
    private String name;
    private int age;
    public static String schoolName;
    public static final String  COUNTTRY = "中国";
	....
}
@Test
public void getDeclaredField() throws Exception {
	// 1. 第一步:获取类对象
	Class c = Student.class;
	
	// 2. 第二步:根据名称定位某个成员变量
	Field f = c.getDeclaredField("age");
	System.out.println(f.getName() +" ===> " + f.getType()); // age ===> int
}
 
@Test
public 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 ...
	}
}

暴力反射举例:

@Test
public 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);
}

五、反射获取方法对象

步骤:
java反射获取对象,JavaSE,java,开发语言,反射

获取成员方法的方法:
java反射获取对象,JavaSE,java,开发语言,反射

Method类中用于触发执行的方法:
java反射获取对象,JavaSE,java,开发语言,反射
注:某成员方法是非 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("狗在睡觉!");
    }
}
@Test
public 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 ...
}

暴力反射举例:

@Test
public 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); // null
	
	Object 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反射获取对象,JavaSE,java,开发语言,反射


文章参考:Java入门基础视频教程,java零基础自学就选黑马程序员Java入门教程(含Java项目和Java真题)文章来源地址https://www.toymoban.com/news/detail-730429.html

到了这里,关于Java 基础进阶篇(十七):反射概述及获取对象的方式的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java反射:探索对象创建与类信息获取

    🎉欢迎来到Java学习路线专栏~Java反射:探索对象创建与类信息获取 ☆* o(≧▽≦)o *☆嗨~我是IT·陈寒🍹 ✨博客主页:IT·陈寒的博客 🎈该系列文章专栏:Java学习路线 📜其他专栏:Java学习路线 Java面试技巧 Java实战项目 AIGC人工智能 数据结构学习 🍹文章作者技术和水平有限

    2024年02月09日
    浏览(28)
  • 【Java反射】反射获取Class、Constructor、Field、Method的方式

    如下是相应的获取方式 总结: 首先获取对象的Class,然后通过getXXX方法获取,带Declared可以通过setAccessible获取私有XXX

    2024年02月02日
    浏览(34)
  • 【Java 基础篇】Java反射:深入了解Class对象

    Java是一门强类型语言,它要求在编译时知道所有的类和对象类型。然而,有时候我们需要在运行时动态地获取和操作类的信息,这就是Java反射的用武之地。本文将深入探讨Java反射,特别是与Class对象相关的内容。 反射是一种机制,允许我们在运行时检查、获取和操作类的信

    2024年02月06日
    浏览(35)
  • Java SE 学习笔记(十七)—— 单元测试、反射

    开发好的系统中存在很多方法,如何对这些方法进行测试? 以前我们都是将代码全部写完再进行测试。其实这样并不是很好。在以后工作的时候,都是写完一部分代码,就测试一部分。这样,代码中的问题可以得到及时修复。也避免了由于代码过多,从而无法准确定位到错误

    2024年02月06日
    浏览(37)
  • 【Java 进阶篇】Java Request 获取请求参数的通用方式详解

    在Java Web开发中,获取HTTP请求的参数是一项基本任务。请求参数可以包含在URL中,也可以包含在请求体中,例如表单提交时的参数。在Java中,可以使用 HttpServletRequest 对象来获取HTTP请求的参数。本文将详细解释如何使用Java获取HTTP请求的参数,包括通用的方式以及示例代码。

    2024年02月05日
    浏览(34)
  • Java list 根据id获取对象 有哪几种方式

    在 Java 中,有以下几种方法来根据 ID 获取列表中的对象: 循环遍历列表:遍历整个列表,比较每个对象的 ID 和目标 ID,如果匹配,就返回该对象。 使用 Stream API:使用 Java 8 的 Stream API 操作列表,并使用 filter() 方法筛选出具有指定 ID 的对象。 使用 Map:将对象存储在 Map 中

    2024年02月11日
    浏览(36)
  • java基础入门-05-【面向对象进阶(static&继承)】

    类的定义格式如下: 例如: 例如: 1.3.1 封装的步骤 1.使用 private 来修饰成员变量。 2.使用 public 修饰getter和setter方法。 1.3.2 封装的步骤实现 private修饰成员变量 public修饰getter和setter方法 1.4.1 构造方法的作用 在创建对象的时候,给成员变量进行初始化。 初始化即赋值的意

    2024年02月03日
    浏览(48)
  • GO基础进阶篇 (十二)、反射

    Go语言中的反射是指在程序运行时检查程序的结构,比如变量的类型、方法的签名等。Go语言的反射包是reflect。通过反射,你可以动态地检查类型信息、获取字段和方法、调用方法等。 反射可以在运行时动态获取变量的各种信息,比如变量的类型、值等 如果是结构体,还可以

    2024年02月02日
    浏览(35)
  • java通过反射创建反射对象三种的方法

    目录 前言: 代码部分: computer类: 1.类名.class创建反射对象: 2.对象.getclass创建反射对象: 3.Class.forName(\\\"\\\")创建反射对象: JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态

    2024年02月14日
    浏览(31)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包