Home  >  Article  >  Java  >  Java principle—reflection mechanism

Java principle—reflection mechanism

黄舟
黄舟Original
2016-12-13 14:06:041143browse

Learning: Java Principle - Reflection Mechanism

1. What is reflection:
The concept of reflection was first proposed by Smith in 1982. It mainly refers to the ability of a program to access, detect and modify its own state or behavior. The introduction of this concept quickly triggered research on applied reflectivity in the field of computer science. It was first adopted in the field of programming language design, and has achieved results in Lisp and object-oriented. Among them, LEAD/LEAD++, OpenC++, MetaXa and OpenJava are languages ​​based on the reflection mechanism. Recently, reflection mechanisms have also been applied to windowing systems, operating systems, and file systems.

Reflection itself is not a new concept, although computer science has given new meaning to the concept of reflection. In computer science, reflection refers to a class of applications that are self-describing and self-controlling. That is to say, this type of application uses a certain mechanism to realize the description (self-representation) and monitoring (examination) of its own behavior, and can adjust or modify the status and results of the behavior described by the application based on the status and results of its own behavior. related semantics.

2. What is class reflection in Java:
Reflection is one of the features of the Java program development language. It allows the running Java program to check itself, or "self-audit", and directly operate the internals of the program. Properties and methods. This capability of Java is not used much in practical applications, but this feature does not exist at all in other programming languages. For example, in Pascal, C, or C++ there is no way to obtain information about function definitions in a program.
Reflection is the key to Java being regarded as a dynamic (or quasi-dynamic) language. It allows the program to obtain the internal information of any class with a known name during execution through the Reflection APIs, including package, type parameters, superclass, implemented interfaces, inner classes, outer Class, fields, constructors, methods, modifiers, and can generate instances, change fields content, or invoke methods during execution.

3. Necessary classes for Java class reflection:
There are not many classes required for Java class reflection. They are: Field, Constructor, Method, Class, and Object. Below I will make a simple summary of these classes. illustrate.
Field class: Provides information about the properties of a class or interface, as well as dynamic access to it. The reflected field may be a class (static) attribute or instance attribute. A simple understanding can be seen as a class that encapsulates the attributes of the reflective class.
Constructor class: Provides information about a single constructor method of a class and access to it. This class is different from the Field class. The Field class encapsulates the properties of the reflection class, while the Constructor class encapsulates the construction method of the reflection class.
Method class: Provides information about a single method on a class or interface. The reflected methods may be class methods or instance methods (including abstract methods). This class is not difficult to understand. It is a class used to encapsulate reflection class methods.
Class: Instances of classes represent classes and interfaces in a running Java application. An enumeration is a class and an annotation is an interface. Each array belongs to a class that is mapped to a Class object, which is shared by all arrays with the same element type and dimension.
Object class: Every class uses Object as its super class. All objects (including arrays) implement the methods of this class.

4. What can Java’s reflection class do:
After reading so much above, I think you are impatient. You think I am wasting your time, so okay! Below we will use some simple examples to illustrate it.
First, let’s take a look at what we can get through Java’s reflection mechanism.
First, let’s write a class:

java code

 java.awt.event.ActionListener;  
import java.awt.event.ActionEvent;  
class A extends Object implements ActionListener{  
private int a = 3;  
public Integer b = new Integer(4);  
public A(){}  
public A(int id,String name){}  
public int abc(int id,String name){return 0;}  
public void actionPerformed(ActionEvent e){}  
}

You may be confused by my class. If you can’t see what I want to do, then don’t look at this class. This class is for testing. , you know that it inherits the Object class, has an interface ActionListener, two properties int and Integer, two constructors and two methods, this is enough.
Next, we use class A as a reflection class to learn some information in class A. First, let’s take a look at the attributes and attribute values ​​​​in the reflection class.

java code

import java.lang.reflect.*;  
class B{  
public static void main(String args[]){  
A r = new A();  
Class temp = r.getClass();  
try{  
System.out.println("反射类中所有公有的属性");  
Field[] fb =temp.getFields();  
for(int j=0;j<fb.length;j++){  
Class cl = fb[j].getType();  
System.out.println("fb:"+cl);  
}  
  
System.out.println("反射类中所有的属性");  
Field[] fa = temp.getDeclaredFields();  
for(int j=0;j<fa.length;j++){  
Class cl = fa[j].getType();  
System.out.println("fa:"+cl);  
}  
System.out.println("反射类中私有属性的值");  
Field f = temp.getDeclaredField("a");  
f.setAccessible(true);  
Integer i = (Integer)f.get(r);  
System.out.println(i);  
}catch(Exception e){  
e.printStackTrace();  
}  
}  
  
}

这里用到了两个方法,getFields()、getDeclaredFields(),它们分别是用来获取反射类中所有公有属性和反射类中所有的属性的方法。另外还有getField(String)和getDeclaredField(String)方法都是用来过去反射类中指定的属性的方法,要注意的是getField方法只能取到反射类中公有的属性,而getDeclaredField方法都能取到。
这里还用到了Field 类的setAccessible方法,它是用来设置是否有权限访问反射类中的私有属性的,只有设置为true时才可以访问,默认为false。另外 Field类还有set(Object AttributeName,Object value)方法,可以改变指定属性的值。

下面我们来看一下如何获取反射类中的构造方法

java 代码

import java.lang.reflect.*;  
public class SampleConstructor {  
public static void main(String[] args) {  
A r = new A();  
printConstructors(r);  
}  
  
public static void printConstructors(A r) {  
Class c = r.getClass();  
//获取指定类的类名  
String className = c.getName();  
try {  
//获取指定类的构造方法  
Constructor[] theConstructors = c.getConstructors();  
for(int i=0; i<theConstructors.length; i++) {  
//获取指定构造方法的参数的集合  
Class[] parameterTypes = theConstructors[i].getParameterTypes();  
  
System.out.print(className + "(");  
  
for(int j=0; j<parameterTypes.length; j++)  
System.out.print(parameterTypes[j].getName() + " ");  
  
System.out.println(")");  
  
}  
}catch(Exception e) {  
e.printStackTrace();  
}  
}  
}

这个例子很简单,只是用getConstructors()方法获取了反射类的构造方法的集合,并用Constructor类的getParameterTypes()获取该构造方法的参数。

下面我们再来获取一下反射类的父类(超类)和接口

java 代码

import java.io.*;  
import java.lang.reflect.*;  
  
public class SampleInterface {  
public static void main(String[] args) throws Exception {  
A raf = new A();  
printInterfaceNames(raf);  
}  
  
public static void printInterfaceNames(Object o) {  
Class c = o.getClass();  
//获取反射类的接口  
Class[] theInterfaces = c.getInterfaces();  
for(int i=0; i<theInterfaces.length; i++)  
System.out.println(theInterfaces[i].getName());  
//获取反射类的父类(超类)  
Class theSuperclass = c.getSuperclass();  
System.out.println(theSuperclass.getName());  
}  
}

这个例子也很简单,只是用Class类的getInterfaces()方法获取反射类的所有接口,由于接口可以有多个,所以它返回一个 Class数组。用getSuperclass()方法来获取反射类的父类(超类),由于一个类只能继承自一个类,所以它返回一个Class对象。

下面我们来获取一下反射类的方法

java 代码

import java.lang.reflect.*;  
public class SampleMethod {  
  
public static void main(String[] args) {  
A p = new A();  
printMethods(p);  
}  
  
public static void printMethods(Object o) {  
Class c = o.getClass();  
String className = c.getName();  
Method[] m = c.getMethods();  
for(int i=0; i<m.length; i++) {  
//输出方法的返回类型  
System.out.print(m[i].getReturnType().getName());  
//输出方法名  
System.out.print(" "+m[i].getName()+"(");  
//获取方法的参数  
Class[] parameterTypes = m[i].getParameterTypes();  
for(int j=0; j<parameterTypes.length; j++){  
System.out.print(parameterTypes[j].getName());  
if(parameterTypes.length>j+1){  
System.out.print(",");  
}  
}  
  
System.out.println(")");  
}  
  
}  
  
}

这个例子并不难,它只是获得了反射类的所有方法,包括继承自它父类的方法。然后获取方法的返回类型、方法名和方法参数。

接下来让我们回过头来想一想,我们获取了反射类的属性、构造方法、父类、接口和方法,可这些东西能帮我们做些什么呢!!
下面我写一个比较完整的小例子,来说明Java的反射类能做些什么吧!!

java 代码

import java.lang.reflect.Constructor;  
import java.lang.reflect.Method;  
  
public class LoadMethod {  
public Object Load(String cName,String MethodName,String[] type,String[] param){  
Object retobj = null;  
try {  
//加载指定的Java类  
Class cls = Class.forName(cName);  
  
//获取指定对象的实例  
Constructor ct = cls.getConstructor(null);  
Object obj = ct.newInstance(null);  
  
//构建方法参数的数据类型  
Class partypes[] = this.getMethodClass(type);  
  
//在指定类中获取指定的方法  
Method meth = cls.getMethod(MethodName, partypes);  
  
//构建方法的参数值  
Object arglist[] = this.getMethodObject(type,param);  
  
//调用指定的方法并获取返回值为Object类型  
retobj= meth.invoke(obj, arglist);  
  
}  
catch (Throwable e) {  
System.err.println(e);  
}  
return retobj;  
}  
  
//获取参数类型Class[]的方法  
public Class[] getMethodClass(String[] type){  
Class[] cs = new Class[type.length];  
for (int i = 0; i < cs.length; i++) {  
if(!type[i].trim().equals("")||type[i]!=null){  
if(type[i].equals("int")||type[i].equals("Integer")){  
cs[i]=Integer.TYPE;  
}else if(type[i].equals("float")||type[i].equals("Float")){  
cs[i]=Float.TYPE;  
}else if(type[i].equals("double")||type[i].equals("Double")){  
cs[i]=Double.TYPE;  
}else if(type[i].equals("boolean")||type[i].equals("Boolean")){  
cs[i]=Boolean.TYPE;  
}else{  
cs[i]=String.class;  
}  
}  
}  
return cs;  
}  
  
//获取参数Object[]的方法  
public Object[] getMethodObject(String[] type,String[] param){  
Object[] obj = new Object[param.length];  
for (int i = 0; i < obj.length; i++) {  
if(!param[i].trim().equals("")||param[i]!=null){  
if(type[i].equals("int")||type[i].equals("Integer")){  
obj[i]= new Integer(param[i]);  
}else if(type[i].equals("float")||type[i].equals("Float")){  
obj[i]= new Float(param[i]);  
}else if(type[i].equals("double")||type[i].equals("Double")){  
obj[i]= new Double(param[i]);  
}else if(type[i].equals("boolean")||type[i].equals("Boolean")){  
obj[i]=new Boolean(param[i]);  
}else{  
obj[i] = param[i];  
}  
}  
}  
return obj;  
}  
}

这是我在工作中写的一个实现Java在运行时加载指定的类,并调用指定方法的一个小例子。这里没有main方法,你可以自己写一个。
Load方法接收的五个参数分别是,Java的类名,方法名,参数的类型和参数的值。

结束语:
Java 语言反射提供一种动态链接程序组件的多功能方法。它允许程序创建和控制任何类的对象,无需提前硬编码目标类。这些特性使得反射特别适用于创建以非常普通的方式与对象协作的库。Java reflection 非常有用,它使类和数据结构能按名称动态检索相关信息,并允许在运行着的程序中操作这些信息。Java 的这一特性非常强大,并且是其它一些常用语言,如 C、C++、Fortran 或者 Pascal 等都不具备的。

但反射有两个缺点。第一个是性能问题。用于字段和方法接入时反射要远慢于直接代码。性能问题的程度取决于程序中是如何使用反射的。如果它作为程序运行中相对很少涉及的部分,缓慢的性能将不会是一个问题。即使测试中最坏情况下的计时图显示的反射操作只耗用几微秒。仅反射在性能关键的应用的核心逻辑中使用时性能问题才变得至关重要。


Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn