preface

Only a bald head can be strong.

Star: github.com/ZhongFuChen…

Today I’ll write briefly about Reflection in Java. I didn’t intend to write about reflection, but many readers have asked me: “Your knowledge seems to lack reflection. Can you fix it?”

I’m a little free this weekend, so I’ll write about my simple understanding of reflection. This is the entry article, there is no advanced knowledge points, I hope to be helpful to the new. If there are any mistakes in this article, please kindly point them out in the comments section

I have written about all the common and important knowledge points in Java (now I have more than 200 original technical articles). If you want to read it, you can follow my GitHub to get all my original articles.

A preface,

When you learn the basics of Java, you will usually learn reflection. When I first learned about reflection, I didn’t understand what it was for. I learned some APIS and found: “Why should it go around getting the Class object and then calling the Class object method to create the object when I can just create it myself? Isn’t that unnecessary?”

I’m sure many of you have this idea when you first learn reflexes (I can’t believe I’m the only one who’s so stupid!!).

In addition, when searching for relevant information, it is usually only a series of APIS to explain reflection, always do not understand what reflection is used, this article will tell you. Think it’s good. Give me a thumbs up

Introduce the Class object

Let’s start with a piece of code:

public class Demo {
    // create a Student class
    class Student{}public static void main(String[] args) {
        // Change Object to Student
        Object o = newObject(); Student s = (Student) o; }}Copy the code

When we write this code in the IDE, there will be no errors. But when we execute it, we’ll know it’s going to fail.

So how does “Java” (essentially the JVM) know if we’re writing strong turns? You can rely on the Class object to help you decide.

Those of you who read my article on the JVM probably know the loading process of an object. If you haven’t, you can read it again. Here’s a refresher for you:

  • After a. Java file is successfully compiled by using the javac command, a. Class file is generated

  • When we perform an initialization (it could be new, it could be subclass initialization, it could be reflection… The.class file is loaded into the JVM through the class loader

  • Loading the.class file loader into the JVM takes several steps, including loading, wiring, and initialization

  • At load time, an object of the Java.lang. Class Class is created in the Java heap, and this Class object represents class-related information.

Since the Class object represents information about the Class, I can find anything in the Class object. Let’s open the IDE and look at the methods inside:

The Class object is then used to determine the true type of the object.

Three, reflection introduction

Reflection is all about Class objects and the java.lang.reflect library, the various apis

For example, the Method/Field/Constructor shown in the screenshot above is under the java.lang.Reflect class library, which is not difficult to learn, so I haven’t written about reflection.

I’m not saying I can remember all of these apis, but there are many, many API tutorials on the web and they are easy enough to understand. At the time of entry, in fact, to master the following kinds of also about:

  • Know several ways to get Class objects
  • Create objects from Class objects, get constructors, member variables, methods
  • The reflected API modifies the value of a member variable and calls a method
/* The following is my first reflection notes, should help you, I will not post code. */ To use reflection, I first need to get the class file object. 1: getClass() Method of the Object class 2: static properties of the data type class 3: static methods of the class: Public static Class class.forname (String className) -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- for the member variable and using 1: Constructor Object 3: Object obj = constructive.newinstance () Field Field = class.getField (" specify variable name ") Field. Set (obj,"") assigns a value to the field field of an obj object if a private or default modified member variable is needed. 1: class.getDeclaredField () retrieves this member variable. 2:setAccessible() Violent access -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- by reflection method 1: call members get Class object 2: through the Class object for the Constructor object 3: Constructor. NewInstance () to create objects. 4: ------getMethod(" Method name "); Invoke: getDeclaredMethod(); setAccessiable();Copy the code

Trust me, go to a search engine and you’ll get it. The reflection API is not that hard to learn, and people don’t understand reflection because they don’t know what reflection does, so I’m going to talk about it.

Why is reflection needed

When I first learned Java, I found it hard to understand why reflection was necessary, because without a certain amount of code, it was hard to understand why I had to go around in circles with reflection.

I now think there are two main reasons for using reflection:

  • Improve program flexibility
  • The implementation details are shielded to make it easier for users to use

I have always emphasized in my articles that before learning a certain technology, one must understand why one should learn it. Therefore, my articles usually spend a long range on why.

Let me give you some examples to help you understand

4.1 Case 1 (JDBC)

I believe you have written JDBC code, I posted a short paragraph, you can review:

Class.forName("com.mysql.jdbc.Driver");

// Get the object connected to the database -Connetcion
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/java3y"."root"."root");

// Get the statement object to execute the SQL statement
statement = connection.createStatement();

// Execute the SQL statement to get the result set
resultSet = statement.executeQuery("SELECT * FROM users");
Copy the code

Why did it change to the following form?

// Get the read stream of the configuration file
InputStream inputStream = UtilsDemo.class.getClassLoader().getResourceAsStream("db.properties");

Properties properties = new Properties();
properties.load(inputStream);

// Get configuration file information
driver = properties.getProperty("driver");
url = properties.getProperty("url");
username = properties.getProperty("username");
password = properties.getProperty("password");

// Load the driver class
Class.forName(driver);
Copy the code

The reason is simple: people don’t want to change the code. As long as there are changes, I write in the configuration inside, isn’t it sweet? If one day, my username, password, URL or even database changes, I can modify the configuration to achieve.

I don’t need to touch any of my code, just change the configuration, which provides flexibility.

Some people might say, “Well, that still needs to change. I can change code pretty quickly, and you can change configuration too.”

In fact, it’s different. Let me give you an example:

  • Write a JDBC component and write all the configuration in the code, such as the above driver/username/ database connection number, etc. Now I’m out of the three and on the run.
  • Aobing came to take over the code of Three Crooked, Aobing just began to take over the project, the company said to change the database. Ao third say to the leader: this trifle, I change configuration good, a few minutes finish matter.
  • Ao third looked for a long time did not find the configuration of the place, because the code written by three crooked smelly and rotten, looking for a long time to find the entrance and the corresponding position.

Changing the code is riskier than changing the configuration, even if you don’t know the implementation of the code.

And this can be done by matching, probably internally by reflection.

It says maybe, but not quite. Some of the configurable parameters may just be configurations, independent of reflection. But in the JDBC example above, the driver is loaded by reflection.

4.2 Case 2 (SpringMVC)

I believe that you have learned servlets before learning SpringMVC, if not, I suggest you read my article and review again.

When I was learning MVC framework, what impressed me most was that I used to need various getParameter(), but now I can just fill in the value by specifying the field name of JavaBean.

Let’s go to code. Here’s where we were with servlets:

// Get the value from the HTML name attribute
String username = request.getParameter("username");
String password = request.getParameter("password");
String gender = request.getParameter("gender");

// Check box and drop box have multiple values, get multiple values
String[] hobbies = request.getParameterValues("hobbies");
String[] address = request.getParameterValues("address");

// Get the value of the text field
String description = request.getParameter("textarea");

// Get the value of the hidden field
String hiddenValue = request.getParameter("aaa");
Copy the code

How we learned about SpringMVC:

@RequestMapping(value = "/save")
@ResponseBody
public String taskSave(PushConfig pushConfig) {
     // Use it directly
	   String name= pushConfig.getName();
}
Copy the code

Why does SpringMVC do that? It’s actually done by reflection.

I’m sure you’ve had the same experience:

  • If the property name of your JavaBean does not match the name of the parameter passed in, the “auto assembly” has failed. Because reflection can only find field names based on parameter names, if inconsistent, then definitelysetI won’t go in. So the assembly failed

If we use frameworks, why do we write Javabeans, keep the field name the same as the parameter name, and get the corresponding value “automatically”? That’s the benefit of reflection.

The implementation details are shielded to make it easier for users to use

Do we write much reflection code?

Most programmers write business code, and most programmers maintain old systems. In fact, we don’t often write reflective code ourselves.

You can see from the top, when do you write reflection? When writing our own components/frameworks. If you’re looking for a place to practice reflection, I think custom annotations are a good choice.

There are a lot of ways to use annotations these days, mainly because they are clear and simple (no more against a bunch of XML files, hahaha ~).

When I first learned to write a paragraph, can be a simple reference, ideas are similar. Here’s what it looks like (using custom annotations to add permissions to different interfaces)

@permission("Add category")
/* Add category */ void addCategory(Category category);

/* Find the category */
void findCategory(String id);

@permission("Lookup category")
/* Check the category */ List<Category> getAllCategory(a);
Copy the code

Return a proxy Service object to handle custom annotations:

public class ServiceDaoFactory {

    private static final ServiceDaoFactory factory = new ServiceDaoFactory();

    private ServiceDaoFactory(a) {}public static ServiceDaoFactory getInstance(a) {
        return factory;
    }


    // Determine whether the user has permissions
    public <T> T createDao(String className, Class<T> clazz, final User user) {

        System.out.println("Added category in!");

        try {
            // Get the type of the class
            final T t = (T) Class.forName(className).newInstance();
            // Return a dynamic proxy object
            return (T) Proxy.newProxyInstance(ServiceDaoFactory.class.getClassLoader(), t.getClass().getInterfaces(), new InvocationHandler() {

                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, PrivilegeException {
                    // What method is called by the user
                    String methodName = method.getName();
                    System.out.println(methodName);

                    // Get the actual method called by the user, pay attention to the arguments!!
                    Method method1 = t.getClass().getMethod(methodName,method.getParameterTypes());

                    // Check for annotations on methods
                    permission permis = method1.getAnnotation(permission.class);

                    // If the annotation is empty, this means that the method does not need permissions, just call the method
                    if (permis == null) {
                        return method.invoke(t, args);
                    }

                    // If the annotation is not empty, get the permission on the annotation
                    String privilege = permis.value();

                    // Set the user's permission.
                    Privilege p = new Privilege();
                    p.setName(privilege);

                    // Check whether the user has logged in
                    if (user == null) {

                        // The exception thrown here is a proxy object, sun will automatically convert to a run-time exception thrown, so on the Servlet we use getCause() to determine whether it is the exception, so as to make the corresponding prompt.
                        throw new PrivilegeException("Excuse me, please log in first.");
                    }

                    // The user has logged in, check whether the user has permission
                    Method m = t.getClass().getMethod("findUserPrivilege", String.class);
                    List<Privilege> list = (List<Privilege>) m.invoke(t, user.getId());

                    // Check if the permissions set contains the permissions required by the method. Use the contains method to override hashCode and equals() in the Privilege object
                    if(! list.contains(p)) {// The exception thrown here is a proxy object, sun will automatically convert to a run-time exception thrown, so on the Servlet we use getCause() to determine whether it is the exception, so as to make the corresponding prompt.
                        throw new PrivilegeException("You do not have permission, please contact the administrator!");
                    }

                    // When executing this command, you already have permission, so you can release it
                    returnmethod.invoke(t, args); }}); }catch (Exception e) {
            new RuntimeException(e);
        }
        return null; }}Copy the code

The last

This reflection article is not quite the same as the reflection article on the web, which usually describes how the reflection API is used. If you think it’s good, give me a thumbs up 👍. If you want to see other knowledge points, you can leave a message to me, I can consider writing it down.

I’ve already written about loading JVM classes, annotations, dynamic proxies, SpringMVC, and JDBC. If you want to read this article, you can search GitHub for related keywords.

If you want to follow my updated articles and shared dry goods in real time, you can follow my official account “Java3y”.

  • 🔥Java beautiful brain map
  • 🔥Java Learning path
  • 🔥 Develop common tools

Reply “888” under the public number to obtain!!

This has been included in my GitHub featured articles, welcome to Star: github.com/ZhongFuChen…

Ask for praise ask for attention ️ ask for share 👥 ask for a message 💬 for me really very useful!!