类层次结构的规模对Java性能有何影响?

8

我有一个继承另一个类的类,该类再继承另一个类...以此类推。

当一个类的层次结构有100层时,与只有10级层次结构的类相比,其执行速度有多慢(以百分比计算)?


24
如果你的应用程序有100个级别的类层级结构,我怀疑性能将是你最不用担心的问题。 - Gareth Davis
1
请参阅:what-is-the-max-level-of-inheritance-in-java。 - jmj
你真正需要问的问题应该是:“我有一个层次结构,深度超过十二层 - 我做错了什么?如何改进我的设计?” - cthulhu
我知道。我参与了一个大型的Documentum定制项目,其中有很多Java代码,并且非常烦恼于非常深的层次结构。这个项目通常有20个层级深度。 - qwazer
4个回答

11

让我们试一下:

class T1 {}
class T2 extends T1{}
class T3 extends T2{}
class T4 extends T3{}
class T5 extends T4{}
class T6 extends T5{}
class T7 extends T6{}
class T8 extends T7{}
class T9 extends T8{}
class T10 extends T9{}
class T11 extends T10{}
class T12 extends T11{}
class T13 extends T12{}
class T14 extends T13{}
class T15 extends T14{}
class T16 extends T15{}
class T17 extends T16{}
class T18 extends T17{}
class T19 extends T18{}
class T20 extends T19{}
class T21 extends T20{}
class T22 extends T21{}
class T23 extends T22{}
class T24 extends T23{}
class T25 extends T24{}
class T26 extends T25{}
class T27 extends T26{}
class T28 extends T27{}
class T29 extends T28{}
class T30 extends T29{}
class T31 extends T30{}
class T32 extends T31{}
class T33 extends T32{}
class T34 extends T33{}
class T35 extends T34{}
class T36 extends T35{}
class T37 extends T36{}
class T38 extends T37{}
class T39 extends T38{}
class T40 extends T39{}
class T41 extends T40{}
class T42 extends T41{}
class T43 extends T42{}
class T44 extends T43{}
class T45 extends T44{}
class T46 extends T45{}
class T47 extends T46{}
class T48 extends T47{}
class T49 extends T48{}
class T50 extends T49{}
class T51 extends T50{}
class T52 extends T51{}
class T53 extends T52{}
class T54 extends T53{}
class T55 extends T54{}
class T56 extends T55{}
class T57 extends T56{}
class T58 extends T57{}
class T59 extends T58{}
class T60 extends T59{}

我能够实例化T53,但从T54开始会抛出StackOverflowError错误。

new T54();

Exception in thread "main" java.lang.StackOverflowError
    at java.lang.ref.Reference.<init>(Reference.java:216)
    at java.lang.ref.FinalReference.<init>(FinalReference.java:16)
    at java.lang.ref.Finalizer.<init>(Finalizer.java:66)
    at java.lang.ref.Finalizer.register(Finalizer.java:72)
    at java.lang.Object.<init>(Object.java:20)
    at java.io.InputStream.<init>(InputStream.java:28)
    at java.io.FileInputStream.<init>(FileInputStream.java:96)
    at sun.misc.URLClassPath$FileLoader$1.getInputStream(URLClassPath.java:1005)
    at sun.misc.Resource.cachedInputStream(Resource.java:61)
    at sun.misc.Resource.getByteBuffer(Resource.java:144)
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:256)
    at java.net.URLClassLoader.access$000(URLClassLoader.java:58)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:197)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClassCond(ClassLoader.java:632)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:616)
    at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141)
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:283)
    at java.net.URLClassLoader.access$000(URLClassLoader.java:58)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:197)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:248)

这是使用默认的JVM堆栈大小完成的。

对于100级别的层次结构,您需要更大的堆栈。 (您可以使用Xss增加堆栈大小。)


1
你可能可以在循环中先模糊类加载:for(String name:listOfClassNames)Class.forName(name);……并不是一个可持续的解决方案。 - Gareth Davis

9
“好的JVM”(不管这是什么意思)会缓存方法解析的结果。因此,性能影响只会发生一次,即使那次也可能很小。然而,在对象创建时,每个扩展类的一个实例也将被创建,每个超类的构造函数都将被调用,这可能会在创建具有大型层次结构的大量对象时产生更大的影响。
我必须同意Jon Skeet的观点(谁不会呢),因为这个问题听起来像是存在一些严重的设计问题或者代码生成器失控了。这就像是问“一个数据库表支持多少列”。如果超出了合理范围,你可能做错了什么。

不是真的 - 虽然超类构造函数代码可能会被执行,但只会创建一个新实例(超类构造函数在派生类的实例下面起作用)。 - mikera
2
很难想象每个构造函数都做一些无法内联的事情。如果构造函数可以内联(彼此之间),那么成本可能不会那么大。 - Peter Lawrey
@Peter:是的,JIT可能会这样做。也许吧。我对JIT了解得不够。 - musiKk
JIT 将会内联简单的方法调用 (包括构造函数),如果这样的调用足够频繁 (通常 10K 次就足够了)。然而,安卓虚拟机可能会有不同的行为。 ;) - Peter Lawrey

7

这将取决于你的JVM,你执行的确切操作,是否重写了各种方法等。

然而,我更关注的是设计和可读性的影响,而不是性能影响。这真的是你能想出的最好设计吗?它解决了什么问题,不能用不同的方法更好地解决吗?


3
根据Java2完全参考书作者Herbert Schildr的说法: 然而,您可以继承任意数量的类,但Java类继承超过5级并不是更可取的选择。这将始终降低性能。 我也同意Jon Skeet的答案。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接