前言
这是记录自己在学习java反射的一篇文章,有很多不足的地方还请师傅们指教。
反射原理:
反射是java的一个特性,通过反射,java可以动态的加载未知的外部对象,从而生成字节码进行加载使用。
java反射函数(自己学习到的那几个):
forName,newInstance,getMethod,invoke这里我们分别来看它们的函数原型,然后再一个一个实现。
forName方法原型:
public static Class<?> forName(@NonNls() String className)
throws ClassNotFoundException{
Class<?> caller = Reflection.getCallerClass();
return forName0(className, initialize:true, ClassLoader.getClassLoader(caller),caller);
}
可以看见 forName 是一个Class<?> 类对象接受一个 String类型且参数名为className 可以知道这个参数传入的是一个类名。forName方法的作用就是读取className外部传入的类。
forName使用方法:
public class forname\_test {
public static void main(String []args) throws Exception{
Class<?> class1=Class.forName("test");//动态加载类
Class<?> class2=Class.forName("java.lang.Runtime");
System.out.println(class1.getName());
System.out.println(class2.getName());
}
}
输出结果为:test,java.lang.Runtime 我们使用Class<?> class来获取Class.forName(String)的返回值,getName方法来获取类的名字从输出结果,以及语法没有报错来看,test,java.lang.Runtime 的的确确被加载了。
newInstance方法原型:
public T newInstance()
throws InstantiationException,IllegalAccessException
{
if (System.getSecurityManager()!=null){
checkMemberAccess(Member.PUBLIC,Reflection.getCallerClass(),checkProxyInterfaces:false);
}
if (cachedConstructor == null){
if (this == Class.class){
throw new IllegalAccessException(
"Can not call newInstance() on the Class for java.lang.Class"
);
}
try {
Class<?>[] empty = {};
final Constructorc=getConstructor0(empty, Member.DECLARED);
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction(){
public Void run() {
c.setAccessible(true);
return null;
}
});
cachedConstructor = c;
} catch (NoSuchMethodException e){
throw (InstantiationException)
new InstantiationException(getName()).initCause(e);
}
}
ConstructortmpConstructor = cachedConstructor;
int modifiers = tmpConstructor.getModifiers();
if (!Reflection.quickCheckMemberAccess(this, modifiers)) {
Class<?> caller = Reflection.getCallerClass();
if (newInstanceCallerCache != caller) {
Reflection.ensureMemberAccess(caller, this, null, modifiers);
newInstanceCallerCache = caller;
}
}
// Run constructor
try {
return tmpConstructor.newInstance((Object[])null);
} catch (InvocationTargetException e) {
Unsafe.getUnsafe().throwException(e.getTargetException());
// Not reached
return null;
}
}
函数原型很长。。。首先 public T 一个泛型方法 ,检测java安全管理器是否启动,启动执行checkMemberAccess,后面的就是获取该类的所有构造函数了。通常用来实例化类。
newInstance使用方法:
我们来接着上个forName的例子来进一步的使用newInstance,看看newInstance是怎么和forName配合使用的。
<br>
public class forname\_test {
public static void main(String []args) throws Exception{
Class<?> class1=Class.forName("test");
Class<?> class2=Class.forName("java.lang.Runtime");
System.out.println(class1.getName());
System.out.println(class2.getName());
Object object1=class1.newInstance();
System.out.println(object1);
}
}
输出结果为:test,java.lang.Runtime,test@1b6d3586,从Object object1=class1.newInstance();可以看出class1.newInstance()返回一个对象,对类实例化成对象。
getMothd方法原型:
public Method getMethod(@NonNls() String name,Class<?>... parameterTypes)
throws NoSuchMethodException,SecurityException {
checkMemberAccess(Member.PUBLIC,Reflection.getCallerClass(),checkProxyInterfaces: true);
Method method = getMethod0(name,parameterTypes,includeStaticMethods:true);
if(method == null){
throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes)); }
return method;
}
该方法参数name 要获得方法的名字,parameterTypes按声明顺序标识该方法形参类型。作用是获得对象所声明的公开方法。
getMothd使用方法:
import java.lang.reflect.Method;
public class forname\_test {
public static void main(String []args) throws Exception{
Class<?> class1=Class.forName("test"); //动态加载test类
Object object1= class1.newInstance(); //实例化class1类成对象
Class[] parameterTypes;
for(Method m1:class1.getMethods()){ //获取所有的public方法,自身声明的,父类的,接口实现的。
System.out.println(m1);
}
}
}
invoke方法原型:
public Object invoke(Object obj, Object... args)
throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException
{
if (!override) {
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, clazz, obj, modifiers);
}
}
MethodAccessor ma = methodAccessor; // read volatile
if (ma == null) {
ma = acquireMethodAccessor();
}
return ma.invoke(obj, args);
}
作用:调用Method类代表的方法,可以把方法参数化。
invoke使用方法:
import java.lang.reflect.Method;
public class forname\_test {
public static void main(String []args) throws Exception{
Class<?> class1=Class.forName("test"); //动态加载类
Object object1= class1.newInstance(); //实例化class1后的的object1对象
Method method1=class1.getMethod("fun1"); //从类中加载方法fun1给method1
method1.invoke(object1); //哪个对象要调用这个方法method1呢? 答案是object1这个对象通过invoke去调用method1
}
}
利用反射执行命令:
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class forname\_test{
public static void main(String[] args) throws Exception{
Class<?> class1=Class.forName("java.lang.Runtime"); //动态加载类
Constructor<?> con1=class1.getDeclaredConstructor(); //获得构造器
con1.setAccessible(true); //设置暴力访问,跳过修饰符检查
Object object = con1.newInstance(); //实例化对象。
Method method1=class1.getMethod("exec",String.class); //获取的exec方法
method1.invoke(object,"calc.exe"); //调用invoke函数,执行calc.exe
}
}
来源:freebuf.com 2021-03-07 16:23:27 by: mengmeng1
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END
喜欢就支持一下吧
请登录后发表评论
注册