资源描述:
《java重写方法与初始化的隐患》由会员上传分享,免费在线阅读,更多相关内容在应用文档-天天文库。
1、虽然文章标题是Java,但几乎所有面向对象设计的语言都遵守这个初始化流程,感谢廖祜秋liaohuqiu_秋百万指出,之前忘记提这个了.前言drakeet写了个和RecyclerView相关的GenerousRecyclerView, 原文提到了写这个的目的.因为需要知道ViewGroup的clipToPadding属性,所以调用了ViewGroup.getClipToPadding,但这个方法是APIlevel21引入的.我看了一下代码,ViewGroup是通过调用setClipToPadding完成相
2、关内容初始化的,setClipToPadding在APIlevel1就有了,也就是说我们只要监视setClipToPadding的调用,就能知道ViewGroup的clipToPadding状态.如此巧妙,如果我告诉drakeet,说不定就能引起他的注意,出任CEO,走上人生巅峰.如果你已经知道我要说什么了,可以鄙视我.问题简单还原一下问题,我们有一个类SuperClass123456789101112public class SuperClass{ private int mSuperX;
3、 public SuperClass(){ setX(99); } public void setX(int x){ mSuperX=x; }}现在我们想随时知道mSuperX是什么值,不用反射,因为父类从不直接修改mSuperX的值,总是通过setX来改,那么最简单的方法就是继承SuperClass,重写setX方法,监听它的改变就好.下面是我们的子类SubClass:1234567891011121314151617public class Sub
4、Class extends SuperClass{ private int mSubX= 1; public SubClass(){} @Override public void setX(int x){ super.setX(x); mSubX=x; System.out.println("SubXisassigned" +x); } public void printX(){ System.out.p
5、rintln("SubX=" +mSubX); }}我使用mSubX来跟踪mSuperX因为在ViewGroup中,clipToPadding默认值是true(为了简化问题,把它当成boolean,实际并不是),而ViewGroup初始化有可能不调用setClipToPadding,此时是默认值,为了模拟这种情况,将mSubX初始化为1.最后在main里调用:123456public class Main{ public static void main(String[]args){
6、 SubClasssc= new SubClass(); sc.printX(); }}很多人,包括我,认为终端输出的结果应该是:12SubXisassigned 99SubX= 99然而真正运行后输出的是:12SubXisassigned 99SubX= 1 实际分析要想知道发生了什么,最简单的方法就是看看到底程序到底是怎么执行的,比如单步调试,或者直接一点,看看Java字节码.下面是Main的字节码123456789Compiledfrom "Main.java"publi
7、c class bugme.Main{ ...... public static void main(java.lang.String[]); Code: 0: new #2 //classbugme/SubClass 3:dup 4:invokespecial#3 //Methodbugme/SubClass."":()V .
8、..... 10}这是直接用javap反编译.class文件得到的.虽说同样是Java写的,用apktool反编译APK文件(其中的dex文件)得到的smali代码和JavaBytecode明显长得不一样.字节码乍一看怪怪的,只要知道它隐含了一个栈和局部变量表就好懂了.这段代码首先new一个SubClass实例,把引用入栈, dup是把栈顶复制一份入栈, invokespecial#3将栈顶元素出栈并调用它的某个方法,这个方法具体是什么要看