Enumeration, dynamic proxy principle, enumeration dynamic proxy

Source: Internet
Author: User

Enumeration, dynamic proxy principle, enumeration dynamic proxy

Some time ago in the dota group, a buddy went out for an interview and reviewed the interview questions.

As an Android player, when talking about enumeration, it must be:

Enumeration should not be used on Android, occupying the memory, instead of using the @ XXXDef annotation, balabala...

The answer is fascinating.

I did not expect the interviewer to ask:

What is the principle of enumeration? How much memory does it occupy?

I am panic when I hear this. I have never understood it.

The first question is as follows (yes, there is a second question ).

Nature of enumeration

Well written.

Next, let's briefly describe an enumeration class:

public enum Animal {    DOG,CAT}

Looking at this code, we can't see how it works. However, we should all know that the class file will be generated after the java class is compiled.

The closer it is to the underlying layer, the more likely it is to be exposed.

We first get Animal. class through javac, and then use the javap command to see:

javap Animal.class

Output:

public final class Animal extends java.lang.Enum {  public static final Animal DOG;  public static final Animal CAT;  public static Animal[] values();  public static Animal valueOf(java.lang.String);  static {};}

In fact, we have already roughly understood the nature of enumeration. In fact, the enumerated Animal class we wrote inherits from Enum, and each enumerated object is a static final class object.

I also want to know more details, such as when our object is initialized.

We can add the-c parameter to decompile the code.

You can use javap-help to view the meaning of all parameters.

javap -c Animal.class

Output:

public final class Animal extends java.lang.Enum {  public static final Animal DOG;  public static final Animal CAT;  public static Animal[] values();    Code:       0: getstatic     #1                  // Field $VALUES:[LAnimal;       3: invokevirtual #2                  // Method "[LAnimal;".clone:()Ljava/lang/Object;       6: checkcast     #3                  // class "[LAnimal;"       9: areturn  public static Animal valueOf(java.lang.String);    Code:       0: ldc           #4                  // class Animal       2: aload_0       3: invokestatic  #5                  // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;       6: checkcast     #4                  // class Animal       9: areturn  static {};    Code:       0: new           #4                  // class Animal       3: dup       4: ldc           #7                  // String DOG       6: iconst_0       7: invokespecial #8                  // Method "
 
  ":(Ljava/lang/String;I)V      10: putstatic     #9                  // Field DOG:LAnimal;      13: new           #4                  // class Animal      16: dup      17: ldc           #10                 // String CAT      19: iconst_1      20: invokespecial #8                  // Method "
  
   ":(Ljava/lang/String;I)V      23: putstatic     #11                 // Field CAT:LAnimal;      26: iconst_2      27: anewarray     #4                  // class Animal      30: dup      31: iconst_0      32: getstatic     #9                  // Field DOG:LAnimal;      35: aastore      36: dup      37: iconst_1      38: getstatic     #11                 // Field CAT:LAnimal;      41: aastore      42: putstatic     #1                  // Field $VALUES:[LAnimal;      45: return}
  
 

Now you can analyze the code.

However, this code also seems a headache. Let's take a look at it first:

Static code:

0: new           #4                  // class Animal3: dup4: ldc           #7                  // String DOG6: iconst_07: invokespecial #8                  // Method "
 
  ":(Ljava/lang/String;I)V10: putstatic     #9                  // Field DOG:LAnimal;
  
 
  • 123456

The general meaning is new Animal (String, int), and then assign a value to our static constant DOG.

Okay. Don't read it. It's so annoying. Let's think about it. If we can understand this bytecode, there are rules. As long as there are rules, there must be tools similar to the translation class, which can be directly converted into java code.

Yes, for example, jad:

Download a copy first, very small:

The command is also very simple. Execute:

./jad -sjava Animal.class

The java file is generated in the current directory.

The output is as follows:

public final class Animal extends Enum{    public static Animal[] values()    {        return (Animal[])$VALUES.clone();    }    public static Animal valueOf(String s)    {        return (Animal)Enum.valueOf(Animal, s);    }    private Animal(String s, int i)    {        super(s, i);    }    public static final Animal DOG;    public static final Animal CAT;    private static final Animal $VALUES[];    static     {        DOG = new Animal("DOG", 0);        CAT = new Animal("CAT", 1);        $VALUES = (new Animal[] {            DOG, CAT        });    }}

At this point, I believe you know the enumerated classes we have compiled:

public enum Animal {    DOG,CAT}

The final generation is such a class, so we will understand the corresponding methods. In addition, how do you use such a class, compared with the memory of two static INT constants, is certainly much more.

Secondly, we can also answer by the way why the enumerated object is a singleton.

In addition, the readObject and clone methods are implemented in the Enum class. You can see at a glance.

This article is not intended to discuss the enumeration principle, but to show you that many similar things like "syntactic sugar" can follow these ideas to understand its principles.

Let's look at another one, which sounds a little more advanced:

Dynamic proxy dynamic proxy

This is also famous for its wide fit.

Q: What is the principle of fit? A: Based on Dynamic proxy, and then balabal... Q: What is the principle of dynamic proxy? A :...

We start with a simple example.

Let's write an interface:

public interface IUserService{    void login(String username, String password);}

Then, use the dynamic proxy to generate a proxy object and call the login method:

import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.util.Arrays;public class Test{    public static void main(String[] args){        IUserService userService = (IUserService) Proxy.newProxyInstance(IUserService.class.getClassLoader(),                new Class[]{IUserService.class},                new InvocationHandler() {                    @Override                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {                        System.out.println("method = " + method.getName() +" , args = " + Arrays.toString(args));                        return null;                    }                });        System.out.println(userService.getClass());        userService.login("zhy","123");    }}

Well, this should be the simplest example of dynamic proxy.

When we investigate the userService. login method, you will find that the InvocationHandler's invoke method is called and relevant information is output.

Why is it so amazing?

We have written an interface to generate an object for this interface, and then we can intercept its methods.

Continue Viewing:

FirstJavac Test. java to get the class file.

Then call:

java Test

Output:

class com.sun.proxy.$Proxy0method = login , args = [zhy, 123]

We can see that when we call the login method, invoke intercepts our method, parameters, and other information.

The principle of adaptive fit is actually like this. We Intercept methods and parameters, splice them into a normal Okhttp request based on our annotations on the method, and then execute them.

I want to know the principle. Based on our enumeration experience, I 'd like to see this.

Com. sun. proxy. $ Proxy0 // full path of userService object output

How can I obtain the class file of this class?

In the first line of the main method, add:

System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");  

Then re-compile and execute the command, and you will see it in the current directory.

MacBook-Pro:tmp zhanghongyang01$ tree .├── IUserService.class├── IUserService.java├── Test$1.class├── Test.class├── Test.java└── com    └── sun        └── proxy            └── $Proxy0.class3 directories, 6 files

Then, you wantJavap-c ~~

Let's take out the jad we just downloaded.

Run:

./jad -sjava com/sun/proxy/\$Proxy0.class 

In the same directory of jad, you will find the java file of Proxy0:

package com.sun.proxy;import IUserService;import java.lang.reflect.*;public final class $Proxy0 extends Proxy implements IUserService{ public $Proxy0(InvocationHandler invocationhandler) { super(invocationhandler); } public final void login(String s, String s1) { super.h.invoke(this, m3, new Object[] { s, s1 }); } private static Method m3; static { m3 = Class.forName("IUserService").getMethod("login", new Class[] { Class.forName("java.lang.String"), Class.forName("java.lang.String") }); }}

For ease of understanding, some equals, hashCode, and other methods are deleted.

As you can see, we actually generate a class that implements IUserSevice for us. We call its login method, which is actually called:

 super.h.invoke(this, m3, new Object[] { s, s1 }); 

M3 is our login method, initialized in the static block. The rest are our input parameters.

Let's see what super. h is:

package java.lang.reflect;public class Proxy{ protected InvocationHandler h;}

Is the InvocationHandler object we have created.

Looking at this class and thinking about the login method, why do you still find it strange to call back the InvocationHandler's invoke method ~~

Well, in fact, this guy has been interviewing for a long time and finally finished writing it out. I hope you will have some gains ~

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.