继承的方法是否会计入 Android 中的 Dex 方法限制?

2022-09-01 19:28:59

Dalvik对单个文件中可以拥有的方法数量有这个众所周知的限制(其中约65,536个)。我的问题是继承的(但不是被覆盖的)方法是否计入此限制。.dex

为了使事情具体化,假设我有:

public class Foo {
  public int foo() {
    return 0;
  }
}

public class A extends Foo { }
public class B extends Foo { }
public class C extends Foo { }

出于 65,536 方法限制的目的,这算作添加一个方法还是添加 4 个?(或者,我猜,为了得出合乎逻辑的结论,这是否算作1种方法或52种方法,考虑到这也带来了12种方法)。java.lang.Object

作为背景,我有一些具有一些共性的生成类,并且我也遇到了方法限制,所以我想知道是否值得尝试将其中一些抽象到类层次结构中以购买一些时间。


答案 1

继承但未重写的方法仅在被引用(调用)时才计入方法限制。

在您的示例中,假设您有以下代码段

public class main {
    public static void main(String[] args) {
        Foo foo = new A();
        foo.foo();
    }
}

在本例中,您指的是 Foo.foo(),由于显式定义,它已经具有引用。假设这 5 个类是 dex 文件中唯一的类,则总共将有 2 个方法引用*。一个用于 main.main(String[]),另一个用于 Foo.foo()。

相反,假设您有以下代码

public class main {
    public static void main(String[] args) {
        A a = new A();
        a.foo();

        B b = new B();
        b.foo();

        C c = new C();
        c.foo();
    }
}

在这种情况下,由于实际上引用了每个子类的 foo 方法,因此它们将计入您的方法限制。您的 dex 文件将有 5 个方法引用*。

  • main.main(String[])
  • Foo.foo()
  • A.foo()
  • B.foo()
  • C.foo()

* 此计数不是很准确,它没有考虑在后台添加到每个类的构造函数方法。每个构造函数调用其超类的构造函数,因此我们也有一个对 Object 构造函数的引用,每种情况下总共有 6 个额外的方法引用,分别给出 8 和 11 的方法计数。


如有疑问,您可以尝试各种方案,并使用 baksmali 的原始转储功能来查看 dex 文件中的方法列表实际包含的内容。

例如:

javac *.java
dx --dex --output=temp.dex *.class
baksmali -N -D temp.dump temp.dex

然后,在转储文件中,查找“method_id_item部分”。这是应用 64k 限制的方法引用的列表。


答案 2

推荐