stub包
若干年前,我用eclipse开发安卓,反编译jar的时候发现android.jar内部的东西,所有方法都只有一个实现:
throw new RuntimeException("Stub!");
当时我还只会写几个activity,完全是懵逼状态,这样的实现到底能干什么?
后来查阅了一系列资料,明白了这个jar只是用于编译的,程序打包成apk的时候并不会把这个jar打进去,而编译时只需要类结构并不需要管里面的实现,当然,我们并不会去在电脑上实际运行它。
那么到了实际运行时这些类是如何获取的呢?我觉得,真正具有完整实现的android.jar里面的东西当然在安卓设备里,让我们验证一下:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ClassLoader classLoader = getClass().getClassLoader();
while (classLoader != null){
Log.e("classloader",classLoader.getClass().getName());
classLoader = classLoader.getParent();
}
try {
Class activityThreadClass = Class.forName("android.app.ActivityThread");
Log.e("classloader",String.format("ActivityThread is loaded by %s", activityThreadClass.getClassLoader()));
Log.e("classloader",String.format("Handler is loaded by %s", Handler.class.getClassLoader()));
Log.e("classloader",String.format("MainActivity is loaded by %s", getClass().getClassLoader()));
Log.e("classloader",String.format("Application is loaded by %s", getApplication().getClass().getClassLoader()));
Log.e("classloader",String.format("CommonTabLayout is loaded by %s", CommonTabLayout.class.getClassLoader()));
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
以上代码,先循环取父加载器,看系统中有几种java类加载器,然后分别取了我们自定义的类、第三方库的类、系统类进行输入看是哪种类加载器加载的它。输出结果如下:

可以看到,系统类是由BootClassLoader预先加载的,第三方库的类(打到了apk包里)和我们自定义的类(也在apk里)是由PathClassLoader加载的。当然,类加载器在jni层还有其他的,我们用java代码访问不到而已。
我们程序在用到系统类的时候,根据类加载器的双亲委派模式,向上查找,由BootClassLoader返回预先加载的类供我们使用,这里的类已经不是stub实现的假类了。
无法查看的类
首先说说只存在于安卓环境的类,上文我们提到了android.jar是个用于编译的stub包,所以有些只在安卓系统框架中发挥作用,在开发中无法用到的类,其实是没必要打进这个包里的,比如com.android.internal包下的类等,但在实际运行时一样由BootClassLoader加载,所以能够在运行时通过反射正常访问。
然后说说@hide
这个东西是谷歌官方为了隐藏某些类或者方法不让外部能访问到所以弄出来的,比如ActivityThread这个类,就被标注了@hide,如果想访问只能通过反射,有的版本IDE跳转至定义功能也无法跳转至@hide标注的部分,所以有些人想到了办法,反正编译时用的也是stub包,我们自己打一个,把hide全去掉,再把上面说的只存在于安卓环境下的类从安卓环境(比如手机)里提取出来,也打进去。这样不就可以美美哒为所欲为了么。
我想说的是,如果为了更方便地看源码,那是不错的,但是如果你用这个绕开限制直接访问它们,那就相当于在天台拆除所有栏杆(因为在有些文章里看到这样就可以不用反射直接用这些类所以加一下这个说明)。
谷歌爸爸不让你访问的东西那是一定有他的道理的,也许你在某个版本的安卓下玩火没什么事,但是下个版本可能人家就禁用了这种本来就不提倡的行为,到时候你的app各种崩溃岂不蛋疼?
所以还是老老实实的吧。。
最后,附上一个不缺类的改造包的github地址:
改造包地址
网友评论