java - dalvik Java 如何使用反射调用父类(super class)方法?

标签 java android reflection

我的情况: 我想通过扩展 TextView 覆盖 TextView 中的隐藏方法,并调用它的 super 方法。

public class MyTextView extends TextView {
    protected void makeNewLayout(int wantWidth, int hintWidth,
                                 BoringLayout.Metrics boring,
                                 BoringLayout.Metrics hintBoring,
                                 int ellipsisWidth, boolean bringIntoView) {
        // omit try catch for simple
        Method method = Class.forName("android.widget.TextView").getDeclaredMethod("makeNewLayout", int.class, int.class, BoringLayout.Metrics.class, BoringLayout.Metrics.class, int.class, boolean.class);
        method.setAccessible(true);
        method.invoke(this, wantWidth, hintWidth, boring, hintBoring, ellipsisWidth, bringIntoView);
    }
}

问题是我自己定义的makeNewLayout被调用了,method.invoke被执行了,但是调用的方法是MyTextView::makeNewLayout不是 TextView::makeNewLayout,它是一个死递归调用。

我怎样才能实现它?

PS:makeNewLayout是一个隐藏函数,所以不能直接用super.makeNewLayout(...)调用

看来java/android不可能轻松完成这种工作。 Java 太安全了,无法破解。

最佳答案

android 8.0以下有一个解决方案,如果你能接受打包一些*.so库。 JNI 接口(interface)中有一系列调用非虚拟方法 ( https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/functions.html#CallNonvirtual_type_Method_routines ) 像这样使用它:

在java中声明:

public native void callNonvirtualVoidMethodHelper(Object obj, String classNameOfMethod, String methodName, String methodSignature);

在cpp中的实现:

extern "C"
JNIEXPORT
void JNICALL
Java_yourpackage_yourclass_callNonvirtualVoidMethodHelper(
    JNIEnv *env,
    jobject /* this */,
    jobject obj,
    jstring classNameOfMethod,
    jstring methodName,
    jstring methodSignature) {
    const char *classNameStr = env->GetStringUTFChars(classNameOfMethod, JNI_FALSE);
    const char *methodNameStr = env->GetStringUTFChars(methodName, JNI_FALSE);
    const char *methodSignatureStr = env->GetStringUTFChars(methodSignature, JNI_FALSE);
    jclass classOfMethod = env->FindClass(classNameStr);
    jmethodID method = env->GetMethodID(classOfMethod, methodNameStr, methodSignatureStr);
    env->CallNonvirtualVoidMethod(obj, classOfMethod, method);
}

在java中使用它:

callNonvirtualVoidMethodHelper(new SubClass(),
        "some/package/SuperClass", // specify the class of non-virtual method
        "foo",
        "()V"); // method signature

或者在android 8.0以上运行时使用MethodHandle(引用:https://stackoverflow.com/a/15674467/2300252)。

关于java - dalvik Java 如何使用反射调用父类(super class)方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32711203/

相关文章:

java - 发送通知到通知栏

java - "Unfortunately, <App Name> has stopped."常见无法解释的错误

android - FLAG_ACTIVITY_NEW_TASK 和 FLAG_ACTIVITY_CLEAR_TASK 行为怪异

go - 使用反射附加到结构中的 slice 字段

c# - 如何从 EventInfo 中获取委托(delegate)对象?

java - 如何使用sqlite制作android测验应用程序?

java - 格式:String 无法转换为 String[]

java - 如何找出每个对象在 ArrayList<Object> 中的类型?

java - 如何通过关闭一个阶段并返回到上一个阶段的值而不打开一个新阶段?

java - 整数和字符串 TCP 连接