Java有反射为什么还要封装_Java中为什么需要反射?反射要解决什么问题?

一、反射的概述

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象.

以上的总结就是什么是反射

反射就是把java类中的各种成分映射成一个个的Java对象

例如:一个类有:成员变量、方法、构造方法、包等等信息,利用反射技术可以对一个类进行解剖,把个个组成部分映射成一个个对象。(其实:一个类中这些成员方法、构造方法、在加入类中都有一个类来描述)

如图是类的正常加载过程:反射的原理在与class对象。

熟悉一下加载的时候:Class对象的由来是将class文件读入内存,并为之创建一个Class对象。

83e4916ae7fb5db4f869e4cc53195781.png

Java中编译类型有两种:

静态编译:在编译时确定类型,绑定对象即通过。

动态编译:运行时确定类型,绑定对象。动态编译最大限度地发挥了Java的灵活性,体现了多态的应用,可以减低类之间的耦合性。

Java反射是Java被视为动态(或准动态)语言的一个关键性质。这个机制允许程序在运行时透过Reflection APIs取得任何一个已知名称的class的内部信息,包括其modifiers(诸如public、static等)、superclass(例如Object)、实现之interfaces(例如Cloneable),也包括fields和methods的所有信息,并可于运行时改变fields内容或唤起methods。

Reflection可以在运行时加载、探知、使用编译期间完全未知的classes。即Java程序可以加载一个运行时才得知名称的class,获取其完整构造,并生成其对象实体、或对其fields设值、或唤起其methods。

反射(reflection)允许静态语言在运行时(runtime)检查、修改程序的结构与行为。

在静态语言中,使用一个变量时,必须知道它的类型。在Java中,变量的类型信息在编译时都保存到了class文件中,这样在运行时才能保证准确无误;换句话说,程序在运行时的行为都是固定的。如果想在运行时改变,就需要反射这东西了。

实现Java反射机制的类都位于java.lang.reflect包中:

Class类:代表一个类

Field类:代表类的成员变量(类的属性)

Method类:代表类的方法

Constructor类:代表类的构造方法

Array类:提供了动态创建数组,以及访问数组的元素的静态方法

一句话概括就是使用反射可以赋予jvm动态编译的能力,否则类的元数据信息只能用静态编译的方式实现,例如热加载,Tomcat的classloader等等都没法支持。

三、使用

先创建一个对象

package com.example.jdk8demo;

import com.alibaba.fastjson.JSON;

public class Student {

private String name;

private Integer age;

private Status status;

public String name1;

public Integer age1;

private String getName1(){

return this.name1;

}

private String setName(String name){

this.name = name;

return "调用setName成功,设置为"+this.name;

}

private String setName1(String name){

this.name1 = name;

return "调用setName1成功,设置为"+this.name1;

}

public Student(String name,Integer age){

this.name = name;

this.age = age;

}

public Student(){

}

public Student(String name,Integer age, Status status){

this.name = name;

this.age = age;

this.status = status;

}

public String getName() {

return name;

}

public Integer getAge() {

return age;

}

public Status getStatus(){

return status;

}

public enum Status{

FREE,

BUSY,

VOCATION

}

}

反射使用:

(1)获取反射对象

package com.example.jdk8demo;

import com.alibaba.fastjson.JSON;

import lombok.extern.slf4j.Slf4j;

import org.junit.jupiter.api.Test;

import org.springframework.boot.test.context.SpringBootTest;

import java.lang.reflect.Constructor;

import java.lang.reflect.Field;

import java.lang.reflect.Method;

@SpringBootTest

@Slf4j

class FanSheTest {

@Test

public void test() throws Exception{

//获取反射对象

Student student = new Student();

Class studentClass1 = student.getClass();

log.info("student.getClass()反射结果{}",studentClass1.getName());

Class studentClass2 = Student.class;

log.info("Student.class反射结果{}",studentClass2.getName());

log.info("Student.class==student.getClass()结果{}",studentClass1==studentClass2);

Class studentClass3 = Class.forName("com.example.jdk8demo.Student");

log.info("Class.forName反射结果{}",studentClass3.getName());

log.info("Student.class==Class.forName结果{}",studentClass3==studentClass2);

}

测试结果:

c573ffbab6aff1a6890ba899268b673e.png

由测试结果可见,三种方式得到的结果是一致的

(2)获取相关内容

//获取构造函数集合

Constructor[] cons = studentClass1.getConstructors();

log.info("反射获取所有构造函数{}", JSON.toJSONString(cons));

//获取无参构造

Constructor con = studentClass1.getConstructor();

log.info("反射获取无参构造函数{}", JSON.toJSONString(con));

//获取有参构造

Constructor con1 = studentClass1.getConstructor(String.class, Integer.class);

log.info("反射获取有参构造函数{}", JSON.toJSONString(con));

//获取公有字段,此处字段必须是public修饰,否则会报错

Field field = studentClass1.getField("name1");

log.info("公有字段{}", JSON.toJSONString(con));

(3)动态调用方法

//获取私有方法

Method setName1 = studentClass1.getDeclaredMethod("setName1", String.class);

setName1.setAccessible(true);

String s = (String)setName1.invoke(Student.class.newInstance(),"lcl");

log.info("========={}", s);

//获取公有方法

Method setName = studentClass1.getDeclaredMethod("setName", String.class);

String ss = (String)setName1.invoke(Student.class.newInstance(),"mm");

log.info("========={}", ss);

测试结果:

a9e0d5ef8dd85a82da173ee6932ba11b.png

这里需要特别说明,如果动态调用的是私有方法,则需要使用 setName1.setAccessible(true);  进行解绑操作,才可以使用invoice方法调用。

来源:https://www.cnblogs.com/liconglong/p/13036388.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值