编程技术是改变世界的力量。
本站
当前位置:网站首页 > 后端语言 > 正文

Java基础:反射 java反射的步骤原理

gowuye 2024-04-04 11:57 10 浏览 0 评论

反射的作用

Java反射描述的是,在运行状态中:

1、对于任意一个类,都能够知道这个类的所有属性和方法

2、对于任意一个类,都能够调用它的任意一个属性和方法

之所以强调属性、方法,是因为属性、方法是开发者对于一个类最关注的两个部分。实际上通过反射,不仅仅可以获知类的属性、方法,还可以获知类的父类、接口、包等信息

至于反射的原理,不难,Java类加载机制一文中讲到了,一个类在加载的时候,会在内存中生成一个代表这个.class文件的java.lang.Class对象,.classs文件里面就包含了描述这个类的信息的一切内容。至于.class文件,是由Java编译器(注意是Java编译器,指的不仅仅是Javac)编译而来的,是编译原理的领域;.class文件结构,网上很多讲解了,比如类文件结构,这里就不讲了。

其实本文只是总结性的,并没有任何复杂或者难以理解的知识点,关注点只是希望用到的时候有个地方可以方便地查看而已。

本文用到的实体类

定义一下本文用到的实体类,尽量把这个实体类的内容定义得全一些,以期能说明问题:

package com.xrq.test19;
import java.io.Serializable;
import java.util.List;
@SuppressWarnings("serial")
public class Reflection implements Cloneable, Serializable
{
 private String str;
 private double d;
 public boolean b;
 public static short s; 
 
 public Reflection()
 {
 
 }
 
 public Reflection(String str)
 {
 this.str = str;
 }
 
 public Reflection(String str, double d, boolean b)
 {
 this.str = str;
 this.d = d;
 this.b = b;
 }
 
 private void privateMethod()
 {
 
 }
 
 public String publicMethod()
 {
 privateMethod();
 return null;
 }
 
 public String publicMethod(int i)
 {
 return null;
 }
 
 public String publicMethod(int i, double d, List<String> l)
 {
 return "Reflection.publicMethod(int i, double d), i = " + i + ", d = " + d;
 }
 
 public static int returnOne()
 {
 return 1;
 }
 
 public String toString()
 {
 return "str = " + str + ", d = " + d + ", b = " + b;
 }
}

Class和ClassLoader

和此java.lang.Class相关的Class和ClassLoader对象。测试代码为:

public static void main(String[] args) throws Exception
{
 Class<?> c = Class.forName("com.xrq.test19.Reflection");
 Reflection[] rs = new Reflection[2];
 
 System.out.println("Class.getClass():" + c.getClass()); // 获取java.lang.Class的Class对象
 System.out.println("Class.getClassLoader():" + c.getClassLoader()); // 获取类的加载器
 System.out.println("Class.getSuperclass():" + c.getSuperclass()); // 获取父类Class对象
 System.out.println("Class.getInterfaces():" + c.getInterfaces()[0] + ", " + c.getInterfaces()[1]); // 获取类的接口列表,注意返回的是一个数组
 System.out.println("Class.getgetComponentType():" + rs.getClass().getComponentType()); // 获取该数组的Class对象
 
 Reflection r = (Reflection)c.newInstance(); // 根据Class实例化出一个类实例来,默认调用无参构造方法
 System.out.println("Class.newInstance():" + r);
}

运行结果:

Class.getClass():class java.lang.Class
Class.getClassLoader():sun.misc.Launcher$AppClassLoader@63c78e57
Class.getSuperclass():class java.lang.Object
Class.getInterfaces():interface java.lang.Cloneable, interface java.io.Serializable
Class.getgetComponentType():class com.xrq.test19.Reflection
Class.newInstance():str = null, d = 0.0, b = false

Package

Package对象包含有关Java包的实现和规范的版本信息。测试代码为:

public static void main(String[] args) throws Exception
{
 Class<?> c = Class.forName("com.xrq.test19.Reflection");
 Package p = c.getPackage();
 System.out.println("Package.toString():" + p.toString()); //toString()
 System.out.println("Package.getName():" + p.getName()); // 获取包名 
 System.out.println("Package.getImplementationTitle():" + p.getImplementationTitle()); // 获取包标题
 System.out.println("Package.getImplementationVendor():" + p.getImplementationVendor()); // 获取提供该实现的组织、供应商或公司的名称
 System.out.println("Package.getImplementationVersion():" + p.getImplementationVersion()); // 获取该实现的版本
 System.out.println("Package.isSealed():" + p.isSealed()); // 获取包是否密封的

运行结果:

Package.toString():package com.xrq.test19
Package.getName():com.xrq.test19
Package.getImplementationTitle():null
Package.getImplementationVendor():null
Package.getImplementationVersion():null
Package.isSealed():false

Field

提供有关类或接口的单个字段的信息,以及对它的动态访问权限。测试代码为:

public static void main(String[] args) throws Exception
{
 Class<?> c = Class.forName("com.xrq.test19.Reflection");
 Reflection r = new Reflection();
 Field f0 = c.getField("b"); 
 Field f1 = c.getDeclaredField("d");
 Field[] fs0 = c.getFields();
 Field[] fs1 = c.getDeclaredFields();
 
 System.out.print("Class.getFields():"); // 获取类中所有public字段,顺序即public的Field定义的顺序
 for (Field f : fs0)
 System.out.print(f + "\t");
 
 System.out.println();
 System.out.print("Class.getDeclaredFields():"); // 获取类中任意访问权限的字段,顺序即所有Field定义的顺序
 for (Field f : fs1)
 System.out.print(f + "\t");
 
 System.out.println();
 System.out.println("Class.getField(String name):" + f0); // 根据name获取类中一个访问权限为public的字段
 System.out.println("Class.getDeclaredField(String name):" + f1); // 根据name获取类中一个任意访问权限的字段
 
 System.out.println();
 System.out.println("Field.getName():" + f0.getName()); // 获取字段名
 System.out.println("Field.getType():" + f0.getType()); // 获取类的类型
 System.out.println("Field.getBoolean():" + f0.getBoolean(r)); // 获取某个实例对象该Field的值,什么类型的Field就是getXXX(Object obj)
 System.out.println("Field.getModifiers():" + f0.getModifiers()); // 以整数形式返回此Field对象的Java语言修饰符,如public、static、final等
 System.out.println("Field.isAccessible():" + f0.isAccessible()); // 返回Field的访问权限,对private的Field赋值,必须要将accessible设置为true,如下
 
 System.out.println();
 f1.setAccessible(true);
 System.out.println("Before setB():" + r);
 f1.setDouble(r, 1.1);
 System.out.println("After setB():" + r); // 向对象的指定Field设定值
}

运行结果:

Class.getFields():public boolean com.xrq.test19.Reflection.b public static short com.xrq.test19.Reflection.s 
Class.getDeclaredFields():private java.lang.String com.xrq.test19.Reflection.str private double com.xrq.test19.Reflection.d public boolean com.xrq.test19.Reflection.b public static short com.xrq.test19.Reflection.s 
Class.getField(String name):public boolean com.xrq.test19.Reflection.b
Class.getDeclaredField(String name):private double com.xrq.test19.Reflection.d
Field.getName():b
Field.getType():boolean
Field.getBoolean():false
Field.getModifiers():1
Field.isAccessible():false
Before setB():str = null, d = 0.0, b = false
After setB():str = null, d = 1.1, b = false

Constructor

提供关于类的单个构造方法的信息以及对它的访问权限。测试代码为:

public static void main(String[] args) throws Exception
{
 Class<?> c = Class.forName("com.xrq.test19.Reflection");
 Constructor<?> constructor = c.getConstructor(String.class);
 Constructor<?>[] constructors = c.getConstructors();
 
 System.out.println("Class.getConstructor(Class<?>... parameterTypes):" + constructor); // 获取指定参数列表的构造函数
 System.out.print("Class.getConstructors():"); // 获取所有的构造函数
 
 for (Constructor<?> con : constructors)
 System.out.print(con + "\t");
 System.out.println("\n");
 
 System.out.println("Constructor.getName():" + constructor.getName()); // 获取构造函数名,没什么意义,肯定是和类同名
 System.out.println("Constructor.getModifiers():" + constructor.getModifiers()); // 获取以整数形式返回的此Constructor对象的Java语言修饰符,如public、static、final等
 System.out.println("Constructor.isAccessible():" + constructor.isAccessible()); // 获取该Constructor的访问权限
 System.out.println("Constructor.getParameterTypes():" + constructor.getParameterTypes()[0]); // 获取Constructor的参数类型,是个数组
 System.out.println("Constructor.isVarArgs():" + constructor.isVarArgs()); // 获取此Constructor中是否带了可变数量的参数,即例如"String... str"类型的参数
 
 System.out.println();
 Reflection r = (Reflection)constructor.newInstance("123"); // 根据指定的构造方法实例化出一个类的实例来,重要
 System.out.println("Constructor.newInstance():" + r);
}

运行结果:

Class.getConstructor(Class<?>... parameterTypes):public com.xrq.test19.Reflection(java.lang.String)
Class.getConstructors():public com.xrq.test19.Reflection(java.lang.String) public com.xrq.test19.Reflection(java.lang.String,double,boolean) public com.xrq.test19.Reflection() 
Constructor.getName():com.xrq.test19.Reflection
Constructor.getModifiers():1
Constructor.isAccessible():false
Constructor.getParameterTypes():class java.lang.String
Constructor.isVarArgs():false
Constructor.newInstance():str = 123, d = 0.0, b = false

Method

提供关于类或接口上单独某个方法(以及如何访问该方法)的信息,所反映的方法可能是类方法或实例方法。测试代码为:

public static void main(String[] args) throws Exception
{
 Reflection r = new Reflection();
 Class<?> c = Class.forName("com.xrq.test19.Reflection");
 Method md0 = c.getMethod("publicMethod", int.class, double.class, List.class);
 Method md1 = c.getDeclaredMethod("privateMethod", new Class[0]);
 Method[] ms0 = c.getMethods();
 Method[] ms1 = c.getDeclaredMethods();
 
 System.out.println("Method.getMethod():" + md0); // 根据方法名和参数列表获取指定的public方法
 System.out.println("Method.getDeclaredMethod():" + md1); // 根据方法名和参数列表获取指定的任意访问权限的方法,但不包括继承的方法
 
 System.out.print("Method.getMethods():"); // 获取此类包括其父类中所有的public方法
 for (Method m : ms0)
 System.out.print(m + "\t");
 System.out.println();
 
 System.out.print("Method.getDeclaredMethods():"); // 返回此类中所有的方法(无访问权限限制),但不包括继承的方法
 for (Method m : ms1)
 System.out.print(m + "\t");
 System.out.println("\n");
 
 System.out.println("Method.getName():" + md0.getName()); // 获取方法的名字
 System.out.println("Method.isAccessible():" + md0.isAccessible()); // 获取方法的访问属性
 System.out.println("Method.isVarArgs():" + md0.isVarArgs()); // 获取方法是否带有可变数量的参数
 System.out.println("Method.getReturnType():" + md0.getReturnType()); // 获取方法的返回类型
 System.out.println("Method.getParameterTypes():" + md0.getParameterTypes()[0] + ", " + md0.getParameterTypes()[1] + ", " + md0.getParameterTypes()[2]); // 获取方法的参数类型,数组形式,注意一下和下面的方法的区别
 System.out.println("Method.getGenericParameterTypes():" + md0.getGenericParameterTypes()[0] + ", " + md0.getGenericParameterTypes()[1] + ", " + md0.getGenericParameterTypes()[2]); // 获取方法的参数化(带泛型)类型,数组形式
 
 System.out.println();
 System.out.println(md0.invoke(r, 1, 2.2, new ArrayList<String>())); // 反射调用方法,重要
}

运行结果:

Method.getMethod():public java.lang.String com.xrq.test19.Reflection.publicMethod(int,double,java.util.List)
Method.getDeclaredMethod():private void com.xrq.test19.Reflection.privateMethod()
Method.getMethods():public java.lang.String com.xrq.test19.Reflection.toString() public java.lang.String com.xrq.test19.Reflection.publicMethod(int) public java.lang.String com.xrq.test19.Reflection.publicMethod(int,double,java.util.List) public java.lang.String com.xrq.test19.Reflection.publicMethod() public static int com.xrq.test19.Reflection.returnOne() public final void java.lang.Object.wait() throws java.lang.InterruptedException public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException public native int java.lang.Object.hashCode() public final native java.lang.Class java.lang.Object.getClass() public boolean java.lang.Object.equals(java.lang.Object) public final native void java.lang.Object.notify() public final native void java.lang.Object.notifyAll() 
Method.getDeclaredMethods():public java.lang.String com.xrq.test19.Reflection.toString() public java.lang.String com.xrq.test19.Reflection.publicMethod(int) public java.lang.String com.xrq.test19.Reflection.publicMethod(int,double,java.util.List) public java.lang.String com.xrq.test19.Reflection.publicMethod() private void com.xrq.test19.Reflection.privateMethod() public static int com.xrq.test19.Reflection.returnOne() 
Method.getName():publicMethod
Method.isAccessible():false
Method.isVarArgs():false
Method.getReturnType():class java.lang.String
Method.getParameterTypes():int, double, interface java.util.List
Method.getGenericParameterTypes():int, double, java.util.List<java.lang.String>
Reflection.publicMethod(int i, double d), i = 1, d = 2.2

Modifier枚举值列表

Field、Constructor、Method中都有getModifiers()方法,返回的是表示此对象的Java语言修饰符,详细看下每个修饰符对应的枚举值:

也就是说如果一个方法是"public static final synchronized"的,那么这个方法的getModifiers()返回的应该是1 + 8 + 16 + 32 = 57,有兴趣的可以自己试验一下。

那如果反过来,我有一个值是X,如何通过X知道它是哪种访问权限的呢?个人的方法是(写一个完整的版本,现实中可以用if...else简化算法):

1、X先和00000001,也就是1做"&"运算,X&1,非0就是public;

2、X再和00000010,也就是2做"&"运算,X&2,非0就是private;

3、X最后和00000100,也就是4做"&"运算,X&4,非0就是protected

其它几位也都是一样的判断方式。

相关推荐

嵌入式C语言中常量的应用实例(嵌入式c语言中常量的应用实例是什么)

常量,我们都知道,就是数值保持不变的量。在C语言中,常量一旦初始化了,它的值将在整个程序运行周期内,不允许发生任何变化。常量与变量是相对的,我们实际项目中经常会用到它。定义常量的两种方式C语言中主要有...

C语言编程基础知识汇总学习,适合初学者!更新常量知识

(二)整型常量整型常量有3种形式:十进制整型常量、八进制整型常量和十六进制整型常量。(注意:c语言中没有直接表示二进制的整型常量,在c语言源程序中不会出现二进制。)书写方式如下:十进制整型常量:123...

【C语言】第二章第六节:字符串常量

第二章第六节:字符串常量。下表C语言中的常用转义字符。·字符形式功能:ASCIl码(十进制形式)。→\t水平制表(横向跳格:跳到下一个tab位置)。→\b退格8。→\r回车(不换行,光标移到本行行首)...

「GCTT 出品」Go 系列教程——5. 常量

这是我们Golang系列教程的第五篇。定义在Go语言中,术语”常量”用于表示固定的值。比如5、-89、IloveGo、67.89等等。看看下面的代码:varaint=50v...

每日C语言-常量指针、指针常量、指向常量的指针常量

一、常量指针1)什么是常量指针?通过该指针不可以修改其所指向存储单元中的值指针本身即地址可以被修改2)定义:类型说明符const*指针变量;类型说明符表示指针所指向存储单元中的值得数据类型指针...

C语言-符号常量、常变量、变量之我见

更新内容:新增音频。音频和文章一起更配oHello,大家好,又和大家见面了~~相信很多朋友们听了C语言的“符号常量”、“常变量”、“变量”后还是对这三者一脸懵逼吧。不管老师怎么歇斯底里地讲解,同学们迷...

零基础带你学习C语言:四:探索常量与变量

前言常量与变量学习;一:分析:short、float、long类型#include<stdio.h>intmain(){shortage=18;floatweight=12...

C语言中是如何定义常量的?那定义字符串呢?

常量有整型常量、浮点型常量、字符型常量及字符串常量。‘常量定义是指定义符号常量,用一个标识符来代表一个常量,通过宏定义预处理指令来实现。常量的定义:#definecount60这就定义了一个常量...

C语言符号常量的优点,会是那几点?

符号常量是一个常量,是不变量,所以,在编译的时候,就把符号常量出现的地方,替换为符号常量对应的常量。符号常量一般用户定义一个全局使用的数据,而且要改变该数据的时候,只需要改变符号常量的值,代码中引用符...

嵌入式开发- C语言数据类型-常量(c语言嵌入式是干嘛的)

基本数据类型的常量-掌握**整型常量:**常量是指在程序运行期间其数值不发生变化的数据。整型常量通常简称为整数整数可以是十进制数、八进制数、十六进制数八进制06334十六进制0xd1...

c语言解剖课:只读变量、常量、字面量傻傻分不清?

写在前面本篇主题的缘起,是因为一个计算机专业的大学生在和我讨论c语言问题时,说const常量如何如何,我说变量被const修饰了,还是变量,不是“常量”。他给了我一个截图:他说大模型都是这样回答的,变...

C/C++编程笔记:C数组、字符串常量和指针!三分钟弄懂它

想弄懂C语言中数组和指针的关系吗?这篇文章就占据你三分钟时间,看完你肯定会有收获!数组数组声明为数据类型名称[constant-size],并将一个数据类型的一个或多个实例分组到一个可寻址的位...

C语言入门到精通【第008讲】——C语言常量

C语言常量常量是固定值,在程序执行期间不会改变。这些固定的值,又叫做字面量。常量可以是任何的基本数据类型,比如整数常量、浮点常量、字符常量,或字符串字面值,也有枚举常量。常量就像是常规的变量,只不过常...

这是C语言无法修改得东西,C语言基础教程之常量解析

常量是指程序在执行期间不会改变的固定值。这些固定值也称为文字。常量可以是任何基本数据类型,如整数常量,浮点常量,字符常量或字符串文字,还有枚举常量。常量被视为常规变量,除了它们的值在定义后无法修改。整...

C语言中的单精度、双精度、常量等都有什么意思?

刚接触C语言时,对于常量,变量,浮点,单精度,双精度等问题的理解,大都很模糊不清,其实在程序运行过程中,其值不能改变的量称为常量。如12、0、-3为整型常量,4.6、-1.23为实型常量,'a'、'...

取消回复欢迎 发表评论: