Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to apply Java reflection Mechanism

2025-01-17 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article mainly explains "how to apply Java reflection mechanism". Friends who are interested may wish to have a look. The method introduced in this paper is simple, fast and practical. Let's let the editor take you to learn how to apply the Java reflection mechanism.

Reflection foundation

P.S.: this article requires readers to have some understanding of the API of the reflection mechanism. If you have not touched it before, it is recommended to take a look at the Quick Start of the official document first.

Before applying the reflection mechanism, let's first look at how to get the corresponding reflection class Class of an object. In Java, we have three ways to get the reflection class of an object.

Through the getClass method

In Java, every Object has a getClass () method, and we can get the corresponding reflection class of this object through the getClass method:

String s = "http://www.ziwenxie.site"; Class c = s.getClass ()

Through the forName method

We can also call the static method forName () of the Class class:

Class c = Class.forName ("java.lang.String")

Use .class

Or we can use .class directly:

Class c = String.class

Get type information

At the beginning of the article, we mentioned that one of the great benefits of reflection is that it allows us to get the type information of the object at run time. Let's take a look at it with an example.

First, we create a new interface A under the typeinfo.interfacea package:

Package typeinfo.interfacea; public interface A {void f ();}

Then we create a new class C under the typeinfo.packageaccess package, which implements interface A, and we also create several additional methods for testing. Note that the permissions of the following methods are different.

Package typeinfo.packageaccess; import typeinfo.interfacea.A; class C implements A {public void f () {System.out.println ("public C.F ()");} public void g () {System.out.println ("public C.g ()");} protected void v () {System.out.println ("protected C.v ()");} void u () {System.out.println ("package C.u ()") } private void w () {System.out.println ("private C.W ()");}} public class HiddenC {public static A makeA () {return new C ();}}

We use several new API in the callHiddenMethod () method, where getDeclaredMethod () is used to get a method declared by the Class class referring to the object itself according to the method name, and then we can trigger the relevant method of the object by calling the invoke () method:

Package typeinfo; import typeinfo.interfacea.A; import typeinfo.packageaccess.HiddenC; import java.lang.reflect.Method; public class HiddenImplementation {public static void main (String [] args) throws Exception {AA = HiddenC.makeA (); a.f (); System.out.println (a.getClass (). GetName ()); / / Oops! Reflection still allows us to call g (): callHiddenMethod (a, "g"); / / And even methods that are less accessible! CallHiddenMethod (a, "u"); callHiddenMethod (a, "v"); callHiddenMethod (a, "w");} static void callHiddenMethod (Object a, String methodName) throws Exception {Method g = a.getClass () .getDeclaredMethod (methodName); g.setAccessible (true); g.invoke (a);}}

We can see from the output that we are free to call either the public,default,protect or the private method through the reflection class. Of course, we are only here to show the power of reflection, in the actual development of this technique is still not recommended.

Public C.F () typeinfo.packageaccess.C public C.g () package C.U () protected C.v () private C.w ()

We just tested the Method object above, and after interested readers are familiar with the reflected API, they might as well test the Filed, so we won't repeat it here.

Using dynamic Agent to realize aspect-oriented programming

AOP is one of the powerful features provided by Spring. AOP means aspect-oriented programming, which means to separate the code that has nothing to do with the business. When we need to add related transactions, we don't want to change the business itself. What are the advantages of aspect-oriented programming compared to object-oriented programming? let's take a look at an example. For beginners, they often write code like this:

Public class Example1 {public void execute () {/ / logging Logger logger = Logger.getLog (...); / / performance statistics PerformanceUtil.startTimer (...) / / permission check if (! user.hasPrevilege ()) {/ / throw exception} / / execute real business executeTransaction (); PerformanceUtil.endTimer ();}}

Although the only business we really want to perform above is executeTransaction (), the log, performance, and permission-related code almost masks the real business code. And in the future, if we have an Example2, it also needs to implement the same log, performance, permission code. In this way, when we need to add relevant logic checks in the future, we need all Example for refactoring, which obviously does not conform to one of the basic object-oriented principles-encapsulating changes.

The above scenario can be solved using both the template method and the decorator pattern, which is implemented through dynamic proxies in Spring. Let's use an example to simulate the AOP implementation in Spring.

The business we want to achieve is the time the program executes when counting employees' salaries and checking the permissions of users. First, let's implement the Salary class, which contains some business logic to count employees' salaries:

Public interface SalaryInterface {public void doSalary ();} public class Salary implements SalaryInterface {public void doSalary () {...}}

We implement the dynamic proxy through InvocationHandler. In the future, before we call the relevant methods of obj, we will proxy through the invoke method instead of calling the obj method directly.

Public class SimpleProxy implements InvocationHandler {private Object obj; private Object advice; / / bind proxy object public Object bind (Object obj, Advice advice) {this.obj = obj; this.advice = advice Return Proxy.newProxyInstance (obj.getClass (). GetClassLoader (), obj.getClass (). GetInterfaces (), this)} / / implement proxy public Object invoke (Object proxy, Method method, Object [] args) throws Throwalbe {Object result = null; try {advice.before (); result = method.invoke (obj, args); advice.after () } catch (Exception e) {e.printStackTrace ();} return result}}

Simulate the Advice interface in Spring:

Public interface Advice {public void before (); public void after ();}

Implement TimeAdvice to count the execution time of the program:

Public class TimeAdvice implements Advice {long startTime; long endTime; @ Override public void before () {startTime = System.nanoTime (); / / get start time} @ Override public void after () {endTime = System.nanoTime (); / / get end time}}

The client call code is as follows:

Public class Client {public static void main (String [] args) {SimpleProxy = new SimpleProxy (); SalaryInterface salaryInterface = (SalaryInterface) simpleProxy.bind (new Salary (), new TimeAdvice ()); salaryInterface.doSalary ();}}

If we need to add permission control now, let's implement the ControlAdvie class:

Public class ControlAdvice implements Advice {@ Override public void before () {if (...) {...} else {...} @ Override public void after () {...}}

Our client code only needs to be changed to simpleProxy.bind (new Salary (), new ControlAdvie), while SimpleProxy itself does not need to make any changes.

Combined with annotations

The reflection mechanism is also widely used in unit testing frameworks such as Junit, that is, through annotations. Let's briefly learn how to obtain the annotation information of related methods through the reflection mechanism. For example, we have a business scenario in which when a user changes his or her password, in order to ensure the security of the password, we require the user's new password to meet some conditions, such as containing at least one non-numeric character, not the same as the previous password, and so on.

Import java.lang.annotation.* @ Target (ElementType.METHOD) @ Retention (RetentionPolicy.RUNTIME) public @ interface UserCase {public int id (); public String description () default "no description";}

The following is the implementation of our utility class for detecting passwords:

Public class PasswordUtils {@ UserCase (id=47, description= "Password must contain at least one numeric") public boolean validatePassword (String password) {return (password.matches ("\\ w*\\ d\\ w*"));} @ UserCase (id=48) public String encryptPassword (String password) {return new StringBuilder (password). Reverse (). ToString () } @ UserCase (id=49, description= "New passwords can't equal previously used ones") public boolean checkForNewPassword (List prevPasswords, String password) {return! prevPasswords.contains (password);}}

With reflection, we can write clearer test code, where the getDeclaredMethods () method can get the relevant methods declared by the relevant objects themselves, and getAnnotation () can get the specified annotations of the Method objects.

Public class UseCaseTracker {public static void trackUseCases (List useCases, Class cl) {for (Method m: cl.getDeclaredMethods ()) {UseCase uc = m.getAnnotation (UseCase.class); if (uc! = null) {System.out.println ("Found UseCase:" + uc.id () + "+ uc.description ()); useCases.remove (new Integer (uc.id () } for (int I: useCases) {System.out.println ("Warning: Missing use case-" + I);} public static void main (String [] args) {List useCases = new ArrayList (); Collections.addAll (useCases, 47, 48, 49, 50); trackUseCases (userCases, PasswordUtils.class);}}

Resolve generic erasure

Now there is a business scenario where we have a generic collection class List, Integer > {private Class baseType; public TypeCounter (Class baseType) {this.baseType = baseType;} public void count (Object obj) {Class type = obj.getClass () If (! baseType.isAssignableFrom (type)) {throw new RuntimeException (obj + "incorrect type" + type + ", should be type or subtype of" + baseType);} countClass (type);} private void countClass (Class type) {Integer quantity = get (type); put (type, quantity = = null? 1: quantity + 1); Class superClass = type.getSuperclass () If (superClass! = null & & baseType.isAssignableFrom (superClass)) {countClass (superClass);}} @ Override public String toString () {StringBuilder result = new StringBuilder ("{"); for (Map.Entry)

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report