Java基础:反射

Java基础:反射实际上通过反射,不仅仅可以获知类的属性、方法,还可以获知类的父类、接口、包等信息至于反射的原理,不难。

大家好,欢迎来到IT知识分享网。

反射的作用

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语言修饰符,详细看下每个修饰符对应的枚举值:

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

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

Java基础:反射

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/45364.html

(0)
上一篇 2024-04-20 21:26
下一篇 2024-04-21 08:45

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信