Day1

反射

基本参考Java核心技术的反射部分和p神Java安全漫谈 跟着写写 顺带熟悉Java语法了

1.常用的一些方法的tiplist

获取class实例:

  • Class.forName(类全名)
  • 类型.class 如果没导包,则要用类全名 这个只是类的一个属性 其实不属于反射
  • 实例.getClass()

感觉forName好用些
根据JDK源码可知,forName方法其实是Class这个类的一个静态方法,而getClass是继承自Object的方法,所以对Class实例也是适用的,可以有希望用来bypass一些沙盒。
比如这样
System.out.println(int.class.forName("top.p3rh4ps.learning.Test1"));
再比如这样
System.out.println("".getClass().forName("top.p3rh4ps.learning.Test1"));
另外一提 打印的时候打印的其实是getName方法返回的结果 即打印的是它属于哪个类的class实例꒰⑅•ᴗ•⑅꒱

获取method

  • 如果要指定方法的参数的话 传的参必须是class实例
  • getMethod 和getDeclaredMethod的区别:
    getMethod不会获取private方法
    getDeclaredMethod会获取所有方法

    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
        Class clazz = Class.forName("top.p3rh4ps.learning.Test1");
        Object o=clazz.newInstance();
        var method=clazz.getDeclaredMethod("test");
        method.setAccessible(true);
        method.invoke(o);
    }
    }

    改成getMethod的话 会报找不到方法的错误
    具体区别:

    getDeclaredMethod:获取当前类的所有声明的方法,包括public、protected和private修饰的方法。需要注意的是,这些方法一定是在当前类中声明的,从父类中继承的不算,实现接口的方法由于有声明所以包括在内。
    getMethod:获取当前类和父类的所有public的方法。这里的父类,指的是继承层次中的所有父类。比如说,A继承B,B继承C,那么B和C都属于A的父类。

    一个能获取当前类所有方法 但是获取不到继承关系的
    一个能获取继承关系的所有public方法 获取不到private和protected
    获取类的所有声明方法并遍历:

    public class Test3 {
    public static void main(String[] args) throws ClassNotFoundException {
        ArrayList<Method> list = new ArrayList<Method>();
        Method[] methods = Class.forName("top.p3rh4ps.learning.Test1").getDeclaredMethods();
        for(Method a:methods){
            System.out.println(a);
        }
        for(Method test:Class.forName("top.p3rh4ps.learning.Test1").getDeclaredMethods()){
            list.add(test);
        }
        for(Method test:list){
            System.out.println(test);
        }
    }
    }

    调用有参数的方法

    public static void test() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
        Class clazz = Class.forName("Helloworld");
        clazz.getMethod("test2",int.class).invoke(123);
        Method method = clazz.getDeclaredMethod("test2",int.class);
        method.setAccessible(true);
        method.invoke(clazz.newInstance(),123);
    }

获取实例

  • Class.newInstance() 用Class实例调用无参构造器,没有无参构造器的时候会报错
  • getConstructor().newInstance() 同样的,参数类型用class实例写在前面 具体参数写在后面,跟调用方法是一样的

反射执行一个ProcessBuilder

   Class clazz = Class.forName("java.lang.ProcessBuilder");
   clazz.getDeclaredMethod("start").invoke(clazz.getConstructor(String[].class).newInstance(((Object)new String[]{"cmd.exe","/c","calc.exe"})));
   clazz.getDeclaredMethod("start").invoke(clazz.getConstructor(String[].class).newInstance(new String[][]{{"cmd.exe","/c","calc.exe"}}));

上面的是自己写的 下面的是p神文章里的 不太明白为什么我的必须显式转换成Object才能不报错
问了大师傅,大师傅说因为反射给可变参数传参时候会自动把数组展开,转成object是为了告诉它不要展开,这么一想还挺合理,毕竟二维展开一层就是一维了。
然后队里的师傅找到了正解文章
https://www.jianshu.com/p/8d7d09500fc8

反射使用Runtime执行命令

Method m = Runtime.class.getDeclaredMethod("exec", String.class);
m.invoke(Runtime.getRuntime(), "calc.exe");

Runtime是单例模式,构造方法是private的 可以用getRuntime来获取一个Runtime实例执行
也可以用getConstructor 把构造方法设置为可访问来获得实例。

分类: 技术

0 条评论

发表评论

电子邮件地址不会被公开。 必填项已用*标注