zoukankan      html  css  js  c++  java
  • # JDK7+ MethodHandle

    简单例子

    import java.lang.invoke.MethodHandle;
    import java.lang.invoke.MethodHandles;
    import java.lang.invoke.MethodType;
    
    public class MHT {
    
        private String name;
    
        // 构造方法
        public MHT(String name) {
            this.name = name;
        }
    
        // 公共方法
        public String publicTest() {
            return name + "'publicTest";
        }
    
        // 静态方法
        public static String publicStaticTest() {
            return "'publicStaticTest";
        }
    
        // 私有方法
        private String test(int param) {
            switch (param) {
                case 1:
                    return "suych1";
                case 2:
                    return "suych2";
                case 3:
                    return "suych3";
                default:
                    return "suych4";
            }
        }
    
        // Get方法
        public String getName() {
            return name;
        }
    
        // Set方法
        public void setName(String name) {
            this.name = name;
        }
    
        public static void main(String[] args) throws Throwable {
            // 构造方法
            MethodType mtConstructor = MethodType.methodType(void.class, String.class);  //返回值类型,参数类型
            MethodHandle mhConstructor = MethodHandles.lookup().findConstructor(MHT.class, mtConstructor);
            MHT businessHandle = ( MHT ) mhConstructor.invokeExact("suych");
            System.out.println(businessHandle.getName());
    
            // 公共方法
            MethodType mtPublic = MethodType.methodType(String.class);  //返回值类型
            MethodHandle mhPublic = MethodHandles.lookup().findVirtual(MHT.class, "publicTest", mtPublic);
            String resultPublic = ( String ) mhPublic.invokeExact(businessHandle);
            System.out.println(resultPublic);
    
            // 静态方法
            MethodType mtPublicStatic = MethodType.methodType(String.class);
            MethodHandle mhPublicStatic = MethodHandles.lookup().findStatic(MHT.class, "publicStaticTest",
                    mtPublicStatic);
            String resultPublicStatic = ( String ) mhPublicStatic.invokeExact();
            System.out.println(resultPublicStatic);
    
            // 私有方法
            MethodType mtPrivate = MethodType.methodType(String.class, int.class); //返回值类型,参数类型
            MethodHandle mhPrivate = MethodHandles.lookup().findSpecial(MHT.class, "test", mtPrivate,
                    MHT.class);
            String resultPrivate = ( String ) mhPrivate.invokeExact(businessHandle, 1);
            System.out.println(resultPrivate);
    
            // Set方法
            MethodHandle mhSet = MethodHandles.lookup().findSetter(MHT.class, "name", String.class);
            mhSet.invokeExact(businessHandle, "A");
            System.out.println(businessHandle.name);
    
            // Get方法
            MethodHandle mhGet = MethodHandles.lookup().findGetter(MHT.class, "name", String.class);
            String resultGet = ( String ) mhGet.invokeExact(businessHandle);
            System.out.println(resultGet);
    
        }
    
    }
    

    输出:

    suych   构造方法输出
    suych'publicTest   公共方法输出
    'publicStaticTest   静态方法输出
    suych1	 私有方法输出
    A	Set方法输出
    A	Get方法输出
    

    基于MethodHandle实现的调用Runtime执行系统命令

    import java.io.InputStream;
    import java.lang.invoke.MethodHandle;
    import java.lang.invoke.MethodHandles;
    import java.lang.invoke.MethodType;
    import java.util.Scanner;
    
    /**
     * @author yz
     */
    public class MethodHandlesTest {
    
        public static void main(String[] args) {
            try {
                String               str          = "arp -a";
                Class                runtimeClass = Runtime.class;
                MethodHandles.Lookup lookup       = MethodHandles.lookup();
    
                // Runtime rt = Runtime.getRuntime()
                MethodHandle methodHandle = lookup.findStatic(
                        runtimeClass, "getRuntime", MethodType.methodType(runtimeClass)
                );
    
                // 获取Runtime的exec方法
                MethodHandle execMethod = lookup.findVirtual(
                        runtimeClass, "exec", MethodType.methodType(Process.class, new Class[]{
                                String.class
                        })
                );
    
                // 获取Process的getInputStream方法
                MethodHandle inputStreamMethod = lookup.findVirtual(
                        Process.class, "getInputStream", MethodType.methodType(InputStream.class)
                );
    
                // 调用Runtime.getRuntime().exec(xxx).getInputStream()
                InputStream in = (InputStream) inputStreamMethod.invoke(
                        execMethod.invoke(methodHandle.invoke(), str)
                );
    
                // 输出InputStream内容到
                Scanner scanner = new Scanner(in).useDelimiter("\A");
                System.out.println(scanner.hasNext() ? scanner.next() : "");
            } catch (Throwable t) {
                t.printStackTrace();
            }
        }
    
    }
    

    Alt text

    JAVA反射修改private,final值

    FinalName.java

    class FinalName {
        public final String name="init";
    }
    

    PrivateName.java

    class PrivateName {
        private String name = "init";
        public String getName() {
            return name;
        }
    }
    

    Test.java

    import java.lang.reflect.Field;
    
    public class Test {
        public static void main(String[] args) throws Exception {
            PrivateName privateName = new PrivateName();
            FinalName finalName = new FinalName();
    //        System.out.println(finalName.name);
            modify(privateName, "name", "private change");
            modify(finalName, "name", "final change");
            System.out.println(privateName.getName());
            System.out.println(finalName.name);
        }
        public static void modify(Object object, String fieldName, Object newFieldValue) throws Exception {
            Field field = object.getClass().getDeclaredField(fieldName);
            field.setAccessible(true);
            field.set(object, newFieldValue);
            System.out.println(field.get(object));
        }
    }
    

    输出结果,private修饰的变量结果已经被修改,但是final修改正常但是获取的依然是原先的值,这是因为内联优化。

    private change
    final change
    private change
    init
    

    如果将FinalName.java修改为通过构造方法给final修饰的属性赋值。

    class FinalName {
        public final String name;
    
        FinalName(String name) {
            this.name = name;
        }
    }
    FinalName Finalname = FinalName("aaaaaa");
    

    再次运行Test.java,发现final修饰的变量已经被修改。

    private change
    final change
    private change
    final change
    

    总结:private修饰的变量可以通过反射的方法将值修改,需要设置访问权限为true。field.setAccessible(true);
    final修饰的变量如果是直接赋值,则对属性值进行修改无效。如果是通过构造方法修改属性的值,则可以通过反射的方法修改final修饰的变量。

    通过反射方式执行命令。

    import java.io.InputStream;
    import java.lang.reflect.Method;
    import java.util.Scanner;
    public class ReflectionTest {
    
        public static void exec() {
            try {
                System.out.println(Runtime.class.getMethod("exec", String.class).invoke(Runtime.class.getMethod("getRuntime").invoke(null), "curl -i localhost:8000"));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        public static void main(String[] args) {
            try {
                String str = "arp -a";
    
                // java.lang.Runtime
                String runtime = new String(new byte[]{106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 82, 117, 110, 116, 105, 109, 101});
    
                // Runtime.class
                Class<?> c = Class.forName(runtime);
    
                // 获取getRuntime方法,Runtime.getRuntime()
                Method m1 = c.getMethod(new String(new byte[]{103, 101, 116, 82, 117, 110, 116, 105, 109, 101}));
    
                // 获取Runtime的exec方法,rt.exec(xxx)
                Method m2 = c.getMethod(new String(new byte[]{101, 120, 101, 99}), String.class);
    
                // Runtime.getRuntime().exec(str)
                Object obj2 = m2.invoke(m1.invoke(null), str);
    
                // 获取命令执行结果Process类的getInputStream()方法
                Method m = obj2.getClass().getMethod(new String(new byte[]{103, 101, 116, 73, 110, 112, 117, 116, 83, 116, 114, 101, 97, 109}));
                m.setAccessible(true);
    
                // process.getInputStream()
                InputStream in = (InputStream) m.invoke(obj2, new Object[]{});
    
                // 输出InputStream内容到
                Scanner scanner = new Scanner(in).useDelimiter("\A");
                System.out.println(scanner.hasNext() ? scanner.next() : "");
            } catch (Throwable t) {
                t.printStackTrace();
            }
        }
    
    }
    

    看下为什么获取命令执行结果Process类的getInputStream()方法访问权限需要设置true。
    跟入java.lang.ProcessImpl类
    Alt text
    getInputStream方法返回stdout_stream是私有变量
    Alt text
    Alt text
    注释掉,则会报下面这样的错误
    Alt text

    参考链接:
    https://docs.oracle.com/javase/7/docs/api/java/lang/invoke/MethodType.html
    https://mp.weixin.qq.com/s/mlqjOlhefcsO9z51cw4S7w
    https://blog.csdn.net/yhd723948277/article/details/82661870

  • 相关阅读:
    UVA 401 回文词
    n的阶乘分解成素数幂的积
    DSSM问答匹配模型
    Enhanced LSTM for Natural Language Inference
    Bidirectional LSTM-CRF Models for Sequence Tagging
    Attention Is All You Need 学习笔记
    BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding
    C++学习笔记(四)
    C++学习笔记(三)
    java学习笔记(七)
  • 原文地址:https://www.cnblogs.com/afanti/p/11090072.html
Copyright © 2011-2022 走看看