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 条评论