views:

147

answers:

7

Is there a guarantee that (the default, system) Java class loader doesn't attempt to load classes that aren't referred to in the code being run? A couple of examples of what I mean:

  • I'm using a framework.jar which I know to contain references to another library.jar's classes in it, but I'm using only such part of the framework that doesn't contain those references. Is it safe to leave library.jar out?
  • Static blocks are run when a class is first loaded. If no running code contains references to a specific class, is it sure that it's static block is not run?

Quickly testing it seems to work as assumed above, and it wouldn't make much sense to load unused classes anyway, but is there any guarantee on this?

Addition: It seems that my "static blocks are run when a class is first loaded" statement above is somewhat incorrect. It's definitely possible to load classes (one thing) without running them (another thing). So I'm interested in both cases; guarantees about classes not getting loaded, and not getting run.

+6  A: 

There is no such guarantee wrt the loading of the classes.

However, you are guaranteed that static blocks won't be run prematurely. The events that trigger class initialization are specified in JLS 12.4.1.

A class or interface type T will be initialized immediately before the first occurrence of any one of the following:

  • T is a class and an instance of T is created.
  • T is a class and a static method declared by T is invoked.
  • A static field declared by T is assigned.
  • A static field declared by T is used and the field is not a constant variable (§4.12.4).
  • T is a top-level class, and an assert statement (§14.10) lexically nested within T is executed.
Stephen C
+1  A: 

I don't think there's any such guarantee. For one thing, I've seen code scanners which do things like processing annotations from whole package hierarchies/JARs during application startup; they'd violate that assumption right away.

Why does this matter? You're usually after highly controllable system loading so anything where would matter would be somewhere where you'd want to force it anyway…

Donal Fellows
+1  A: 

The thing that pulls in classes is the references to them from Java byte code (which again may pull in other classes). If the classes you run, do not have any reference to class X, it will not be loaded.

Note however that there is newer ways to register e.g. services through META-INF. Those classes need to be loaded too.

You can always run with "-verbose" to see the classes as they load - the order clearly shows that they are loaded when needed.

Thorbjørn Ravn Andersen
AFAIK, it's not just the "reference" which matters here, but also the use. As long as a class is not used (i.e. referenced in an executing bytecode instruction) it isn't loaded. Of course, this is not guaranteed by the spec but any self-respecting JVM behaves this way.
sasuke
+2  A: 

The java specification states

The loading process is implemented by the class ClassLoader and its subclasses. Different subclasses of ClassLoader may implement different loading policies. In particular, a class loader may cache binary representations of classes and interfaces, prefetch them based on expected usage, or load a group of related classes together.

So the classloader is free to prefetch classfiles.

A class or interface type T will be initialized immediately before the first occurrence of any one of the following:

  • T is a class and an instance of T is created.
  • T is a class and a static method declared by T is invoked.
  • A static field declared by T is assigned.
  • A static field declared by T is used and the reference to the field is not a compile-time constant (§15.28). References to compile-time constants must be resolved at compile time to a copy of the compile-time constant value, so uses of such a field never cause initialization.

The static blocks will be executed only when the class is first used.

josefx
+1 for "prefetch them on expected usage, or load a group of related classes together". So there are definitely no guarantees about not loading anything.
Joonas Pulakka
+1  A: 

If you are not using reflection, then you can statically check which classes are used using a dead-code removal tool, such as ProGuard. It will analyse your code and determine all the classes used. On the basis of that, it removes unused code, including unused code in libraries.

If your code or libraries use reflection to load classes, then you will need to run a full coverage test of your application and log all the classes loaded, which you instruct ProGuard to keep.

mdma
I think Joonas project has a dependency on framework.jar which has a dependency on library.jar. Joonas believes nonetheless that his project is not dependent on library.jar. Can ProGuard really verify that assertion?
emory
A: 

There are no such guarantees as other posters have mentioned. But your question and your concern don't follow from each other. For you to leave library.jar out, you don't need such guarantees.

There are a number of frameworks that discover the presence or absence of other frameworks during runtime. Ex: Commons-logging discovers a bunch of other frameworks. Spring web flow discovers what the scripting framework is (is it OGNL for instance) during runtime. These frameworks are obviously compiled using all dependent frameworks but they dont have to exist during runtime.

Hence it is perfectly acceptable to leave library.jar out during runtime.

raja kolluru
A: 

Yes.

Think about the following. If you add the following code to that library.jar class:

 public ShutDown {static { System.exit(-1); }}

That code won't be loaded automatically by the default system, because none of the existing code has a reference or knows about the ShutDown class, nor had a way to load it, and the Java class loader don't just go around trying to load random classes from the jar.

The way classes are loaded are described in the previous answers, if you review them carefully none of them include a "If there is a class in the jar it would be loaded" of some sort.

OscarRyz