笔记

way

JAVA调用重写的祖父方法

本打算继承一个API中的Parent类(Parent继承自GrandParent类),重写其中的service方法,copy了Parent的service方法。不过发现Parent的service中也有super.service方法。当时考虑直接调用GrandParent的service方法。。。未遂(包括反射也不行)。正好看到老外写的一篇文章,翻译:
在Son类里面写一个test方法:
public void test() {
 
super.test();
 
this.test();
}
反编译之后:
public void test()
    {
    
//    0    0:aload_0         
    
//    1    1:invokespecial   #2   <Method void Parent.test()>
    
//    2    4:aload_0         
    
//    3    5:invokevirtual   #3   <Method void test()>
    
//    4    8:return          
    }
使用ASM可以完成对GrandParent方法的调用
public class GrandParent {
    
public void test() {
            System.out.println(
"test of GrandParent");
    }
}

public class Parent extends GrandParent{
    
public void test() {
        System.out.println(
"test of Parent");
    }
}

public class Son extends Parent{
    
public void test() {
        System.out.println(
"test of Son");
    }
}
调用Son实例的test方法只会执行Son的test方法。而ASM可以修改class,先写一个Example类继承Son,重写test方法

 1 import java.io.FileOutputStream;
 2  
 3 import org.objectweb.asm.ClassWriter;
 4 import org.objectweb.asm.MethodVisitor;
 5 import org.objectweb.asm.Opcodes;
 6  
 7 public class ASMByteCodeManipulation extends ClassLoader implements Opcodes {
 8  
 9  public static void main(String args[]) throws Exception {
10   ClassWriter cw = new ClassWriter(0);
11   cw.visit(V1_1, ACC_PUBLIC, "Example"null"Son"null);
12  
13   // creates a MethodWriter for the (implicit) constructor
14   MethodVisitor mw = cw.visitMethod(ACC_PUBLIC, "<init>""()V"null,null);
15   mw.visitVarInsn(ALOAD, 0);
16   mw.visitMethodInsn(INVOKESPECIAL, "Son""<init>""()V");
17   mw.visitInsn(RETURN);
18   mw.visitMaxs(11);
19   mw.visitEnd();
20  
21   // creates a MethodWriter for the 'test' method
22   mw = cw.visitMethod(ACC_PUBLIC, "test""()V"nullnull);
23   mw.visitFieldInsn(GETSTATIC, "java/lang/System""out","Ljava/io/PrintStream;");
24   mw.visitLdcInsn("test of AI3");
25   mw.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream""println",
26     "(Ljava/lang/String;)V");
27   //Call test() of GrandParent
28   mw.visitVarInsn(ALOAD, 0);
29   mw.visitMethodInsn(INVOKESPECIAL, "GrandParent""test""()V");
30   //Call test() of GrandParent
31   mw.visitVarInsn(ALOAD, 0);
32   mw.visitMethodInsn(INVOKESPECIAL, "Parent""test""()V");
33   //Call test() of GrandParent
34   mw.visitVarInsn(ALOAD, 0);
35   mw.visitMethodInsn(INVOKESPECIAL, "Son""test""()V");
36   mw.visitInsn(RETURN);
37   mw.visitMaxs(21);
38   mw.visitEnd();
39  
40   byte[] code = cw.toByteArray();
41   FileOutputStream fos = new FileOutputStream("Example.class");
42   fos.write(code);
43   fos.close();
44  
45   ASMByteCodeManipulation loader = new ASMByteCodeManipulation();
46   Class<?> exampleClass = loader.defineClass("Example", code, 0,
47     code.length);
48   Object obj = exampleClass.newInstance();
49   exampleClass.getMethod("test"null).invoke(obj, null);
50  
51  }
52 }
输出:
test of AI3
test of GrandParent
test of Parent
test of Son
看看怎样实现的,11行定义一个新的类Example继承Son。22行,Example重写test方法,先打印“test of AI3”,再分别在29、32、35行调用GrandParent、Parent、Son的test方法。
 main方法中,45行创建Example的实例,再用反射调他的test方法。
使用invokespecial这种方式也有局限,只能从子类调用。否则报错:
Exception in thread "main" java.lang.VerifyError: (class: Example, method: test1 signature: (LAI2;)V) Illegal use of nonvirtual function call

posted on 2012-05-31 11:23 yuxh 阅读(2027) 评论(0)  编辑  收藏 所属分类: jdkwork


只有注册用户登录后才能发表评论。


网站导航:
 

导航

<2012年5月>
293012345
6789101112
13141516171819
20212223242526
272829303112
3456789

统计

常用链接

留言簿

随笔分类

随笔档案

收藏夹

博客

搜索

最新评论

阅读排行榜

评论排行榜