您的位置:首页技术文章
文章详情页

android-studio - Android 反射获取方法 ClassNotFoundException

浏览:40日期:2024-08-16 14:49:08

问题描述

我是想获取Bundle中持有的mMap集合.在bundle类中,有getMap()方法可以获取,但是被标记为hide,所以我用反射去取.

ArrayMap<String, Object> metaMap= null;try { Class ownerClass = Class.forName(Bundle.class.getName()); Class superclass = ownerClass.getSuperclass(); Method[] declaredMethods = superclass.getDeclaredMethods();// getMapMethod.setAccessible(true);// metaMap= (ArrayMap<String, Object>) getMapMethod.invoke(metaData); Log.e('test','superclass: '+superclass.getName()); declaredMethods.toString();} catch (ClassNotFoundException e) { e.printStackTrace();}

这是我测试的代码,之前是直接调方法,然后抛异常了.于是我就打印了所有的方法:

0 = {Method@4216} 'public void android.os.BaseBundle.clear()'1 = {Method@4217} 'public boolean android.os.BaseBundle.containsKey(java.lang.String)'2 = {Method@4218} 'public java.lang.Object android.os.BaseBundle.get(java.lang.String)'3 = {Method@4219} 'public boolean android.os.BaseBundle.getBoolean(java.lang.String)'4 = {Method@4220} 'public boolean android.os.BaseBundle.getBoolean(java.lang.String,boolean)'5 = {Method@4221} 'public [Z android.os.BaseBundle.getBooleanArray(java.lang.String)'6 = {Method@4222} 'byte android.os.BaseBundle.getByte(java.lang.String)'7 = {Method@4223} 'java.lang.Byte android.os.BaseBundle.getByte(java.lang.String,byte)'8 = {Method@4224} '[B android.os.BaseBundle.getByteArray(java.lang.String)'9 = {Method@4225} 'char android.os.BaseBundle.getChar(java.lang.String)'10 = {Method@4226} 'char android.os.BaseBundle.getChar(java.lang.String,char)'11 = {Method@4227} '[C android.os.BaseBundle.getCharArray(java.lang.String)'12 = {Method@4228} 'java.lang.CharSequence android.os.BaseBundle.getCharSequence(java.lang.String)'13 = {Method@4229} 'java.lang.CharSequence android.os.BaseBundle.getCharSequence(java.lang.String,java.lang.CharSequence)'14 = {Method@4230} '[Ljava.lang.CharSequence; android.os.BaseBundle.getCharSequenceArray(java.lang.String)'15 = {Method@4231} 'java.util.ArrayList android.os.BaseBundle.getCharSequenceArrayList(java.lang.String)'16 = {Method@4232} 'java.lang.ClassLoader android.os.BaseBundle.getClassLoader()'17 = {Method@4233} 'public double android.os.BaseBundle.getDouble(java.lang.String)'18 = {Method@4234} 'public double android.os.BaseBundle.getDouble(java.lang.String,double)'19 = {Method@4235} 'public [D android.os.BaseBundle.getDoubleArray(java.lang.String)'20 = {Method@4236} 'float android.os.BaseBundle.getFloat(java.lang.String)'21 = {Method@4237} 'float android.os.BaseBundle.getFloat(java.lang.String,float)'22 = {Method@4238} '[F android.os.BaseBundle.getFloatArray(java.lang.String)'23 = {Method@4239} 'public int android.os.BaseBundle.getInt(java.lang.String)'24 = {Method@4240} 'public int android.os.BaseBundle.getInt(java.lang.String,int)'25 = {Method@4241} 'public [I android.os.BaseBundle.getIntArray(java.lang.String)'26 = {Method@4242} 'java.util.ArrayList android.os.BaseBundle.getIntegerArrayList(java.lang.String)'27 = {Method@4243} 'public long android.os.BaseBundle.getLong(java.lang.String)'28 = {Method@4244} 'public long android.os.BaseBundle.getLong(java.lang.String,long)'29 = {Method@4245} 'public [J android.os.BaseBundle.getLongArray(java.lang.String)'30 = {Method@4246} 'public java.lang.String android.os.BaseBundle.getPairValue()'31 = {Method@4247} 'java.io.Serializable android.os.BaseBundle.getSerializable(java.lang.String)'32 = {Method@4248} 'short android.os.BaseBundle.getShort(java.lang.String)'33 = {Method@4249} 'short android.os.BaseBundle.getShort(java.lang.String,short)'34 = {Method@4250} '[S android.os.BaseBundle.getShortArray(java.lang.String)'35 = {Method@4251} 'public java.lang.String android.os.BaseBundle.getString(java.lang.String)'36 = {Method@4252} 'public java.lang.String android.os.BaseBundle.getString(java.lang.String,java.lang.String)'37 = {Method@4253} 'public [Ljava.lang.String; android.os.BaseBundle.getStringArray(java.lang.String)'38 = {Method@4254} 'java.util.ArrayList android.os.BaseBundle.getStringArrayList(java.lang.String)'39 = {Method@4255} 'public boolean android.os.BaseBundle.isEmpty()'40 = {Method@4256} 'public boolean android.os.BaseBundle.isParcelled()'41 = {Method@4257} 'public java.util.Set android.os.BaseBundle.keySet()'42 = {Method@4258} 'public void android.os.BaseBundle.putAll(android.os.PersistableBundle)'43 = {Method@4259} 'void android.os.BaseBundle.putAll(android.util.ArrayMap)'44 = {Method@4260} 'public void android.os.BaseBundle.putBoolean(java.lang.String,boolean)'45 = {Method@4261} 'public void android.os.BaseBundle.putBooleanArray(java.lang.String,boolean[])'46 = {Method@4262} 'void android.os.BaseBundle.putByte(java.lang.String,byte)'47 = {Method@4263} 'void android.os.BaseBundle.putByteArray(java.lang.String,byte[])'48 = {Method@4264} 'void android.os.BaseBundle.putChar(java.lang.String,char)'49 = {Method@4265} 'void android.os.BaseBundle.putCharArray(java.lang.String,char[])'50 = {Method@4266} 'void android.os.BaseBundle.putCharSequence(java.lang.String,java.lang.CharSequence)'51 = {Method@4267} 'void android.os.BaseBundle.putCharSequenceArray(java.lang.String,java.lang.CharSequence[])'52 = {Method@4268} 'void android.os.BaseBundle.putCharSequenceArrayList(java.lang.String,java.util.ArrayList)'53 = {Method@4269} 'public void android.os.BaseBundle.putDouble(java.lang.String,double)'54 = {Method@4270} 'public void android.os.BaseBundle.putDoubleArray(java.lang.String,double[])'55 = {Method@4271} 'void android.os.BaseBundle.putFloat(java.lang.String,float)'56 = {Method@4272} 'void android.os.BaseBundle.putFloatArray(java.lang.String,float[])'57 = {Method@4273} 'public void android.os.BaseBundle.putInt(java.lang.String,int)'58 = {Method@4274} 'public void android.os.BaseBundle.putIntArray(java.lang.String,int[])'59 = {Method@4275} 'void android.os.BaseBundle.putIntegerArrayList(java.lang.String,java.util.ArrayList)'60 = {Method@4276} 'public void android.os.BaseBundle.putLong(java.lang.String,long)'61 = {Method@4277} 'public void android.os.BaseBundle.putLongArray(java.lang.String,long[])'62 = {Method@4278} 'void android.os.BaseBundle.putSerializable(java.lang.String,java.io.Serializable)'63 = {Method@4279} 'void android.os.BaseBundle.putShort(java.lang.String,short)'64 = {Method@4280} 'void android.os.BaseBundle.putShortArray(java.lang.String,short[])'65 = {Method@4281} 'public void android.os.BaseBundle.putString(java.lang.String,java.lang.String)'66 = {Method@4282} 'public void android.os.BaseBundle.putStringArray(java.lang.String,java.lang.String[])'67 = {Method@4283} 'void android.os.BaseBundle.putStringArrayList(java.lang.String,java.util.ArrayList)'68 = {Method@4284} 'void android.os.BaseBundle.readFromParcelInner(android.os.Parcel)'69 = {Method@4285} 'public void android.os.BaseBundle.remove(java.lang.String)'70 = {Method@4286} 'void android.os.BaseBundle.setClassLoader(java.lang.ClassLoader)'71 = {Method@4287} 'public int android.os.BaseBundle.size()'72 = {Method@4288} 'void android.os.BaseBundle.typeWarning(java.lang.String,java.lang.Object,java.lang.String,java.lang.ClassCastException)'73 = {Method@4289} 'void android.os.BaseBundle.typeWarning(java.lang.String,java.lang.Object,java.lang.String,java.lang.Object,java.lang.ClassCastException)'74 = {Method@4290} 'synchronized void android.os.BaseBundle.unparcel()'75 = {Method@4291} 'void android.os.BaseBundle.writeToParcelInner(android.os.Parcel,int)'76 = {Method@4292} 'private void android.os.BaseBundle.readFromParcelInner(android.os.Parcel,int)'

我在源码中看到的方法如下:(只复制了方法名.)

BaseBundleBaseBundleBaseBundleBaseBundleBaseBundleBaseBundleBaseBundleclearcontainsKeygetgetBooleangetBooleangetBooleanArraygetBytegetBytegetByteArraygetChargetChargetCharArraygetCharSequencegetCharSequencegetCharSequenceArraygetCharSequenceArrayListgetClassLoadergetDoublegetDoublegetDoubleArraygetFloatgetFloatgetFloatArraygetIntgetIntgetIntArraygetIntegerArrayListgetLonggetLonggetLongArraygetMapgetPairValuegetSerializablegetShortgetShortgetShortArraygetStringgetStringgetStringArraygetStringArrayListisEmptyisEmptyParcelisParcelledkeySetputAllputAllputBooleanputBooleanArrayputByteputByteArrayputCharputCharArrayputCharSequenceputCharSequenceArrayputCharSequenceArrayListputDoubleputDoubleArrayputFloatputFloatArrayputIntputIntArrayputIntegerArrayListputLongputLongArrayputSerializableputShortputShortArrayputStringputStringArrayputStringArrayListreadFromParcelInnerreadFromParcelInnerremovesetClassLoadersetShouldDefusesizetypeWarningtypeWarningunparcelwriteToParcelInner

其中,isParcelled(),getPairValue()也是被标记为hide,但是却能获取到.想问问是为什么?

我猜测是sdk版本原因,我的手机是sdk = 23,我编译的版本为25,我猜测那几个没获取到的方法是23之后添加的,不知有没有什么可以查看sdk版本差异测方法,或者是其他的原因.

问题解答

回答1:

我对比了下 Api23和Api25两个的Bundle源码,没有关于getMap的明显信息,然后又对比了下Api16和Api25两个的Bundle源码,发现端倪,如下图黄色块标注:android-studio - Android 反射获取方法 ClassNotFoundException我们可以看到Api25上,Bundle extends BaseBundle,而Api16却没有,而且两边采用的数据结构也发生了变化。

我们看下Api25上的BaseBundle,确实有getMap :

/** @hide */ArrayMap<String, Object> getMap() { unparcel(); return mMap;}

然后我们在看下在Api23的BaseBundle里面搜getMap,结果如下:android-studio - Android 反射获取方法 ClassNotFoundException很明显,在Api23上,无论是Bundle,还是它的父类BaseBundle,都是不存在getMap方法的,所以反射也调不到。

回答2:

@hide 属于一个javadoc的标签, Bundle源码在编译成jar包的时候会把@hide标记过的方法 排除掉, 生成的jar包是给开发者使用的, 所以在IDE中我们是没办法直接通过bundle对象的引用去直接调用到bundle类hide起来的方法的, 这个跟sdk编译的版本是没差别的。等到后期你熟悉了android的整体后, 可以自己尝试着编译一下android源码生成自己的android.jar包, 打个比方说, 这边做camera开发比较多, 而camera不少方法都被hide了 我们又不想每次都通过反射去调用hide方法, 于是乎, 我们自己编译了一套完整的android.jar包, 在camera中被hide的方法就可以在 ide中直接调用到了。

相关文章: