July 13, 2020
Hot Topics:

Java Performance & Security: Dynamically Loaded Classes

  • By Matt Weisfeld
  • Send Email »
  • More Articles »

This series, The Object-Oriented Thought Process, is intended for someone just learning an object-oriented language and who wants to understand the basic concepts before jumping into the code, or someone who wants to understand the infrastructure behind an object-oriented language he or she is already using. These concepts are part of the foundation that any programmer will need to make the paradigm shift from procedural programming to object-oriented programming.

Click here to start at the beginning of the series.

In keeping with the code examples used in the previous articles, Java will be the language used to implement the concepts in code. One of the reasons that I like to use Java is because you can download the Java compiler for personal use at the Sun Microsystems Web site http://java.sun.com/. You can download the standard edition, J2SE 5.0, at http://java.sun.com/j2se/1.5.0/download.jsp to compile and execute these applications. I often reference the Java J2SE 5.0 API documentation and I recommend that you explore the Java API further. Code listings are provided for all examples in this article as well as figures and output (when appropriate). See the first article in this series for detailed descriptions for compiling and running all the code examples.

This column covers the topic of Java Class verification security. Here, you explore the concept of dynamically loaded classes, a very basic aspect of security that a Java developer needs to consider for performance and security reasons.

Dynamically Loaded Classes

As is often the case, a specific system's strength can also be a glaring weakness, or at least a vulnerability. This statement is true in one very important aspect of the Java language as well as the .NET model: their ability to load classes dynamically.

Before the widespread acceptance of object-oriented language development platforms, it was common for applications to be compiled and then statically linked. This model is still in place today for many development paradigms. When coding in the C programming language, for example, you would create (edit) the code, compile it, and then link it. The linking process would create a static, executable application that could then be run on the native machine.

Diagram 1: Static Edit/Compile/Link/Execute Model.

The term "native machine" is an important point here. When you create a Windows EXE file, that file is native to the Windows environment and cannot be transported to a UNIX or Mac platform, at least not without a simulator.

This is an advantage in the sense that the entire application can be packaged in a single executable file. The problem, besides that transportability issue, is that the executable has everything included in the file, including the kitchen sink. In short, you must include everything you potentially need in that executable file. If you need to rebuild or redeploy any part of the executable, you must re-link the entire application, create a new executable, and deploy it at all locations.

The bytecode model deals with things differently. Rather than statically link everything and create a single application, each module creates its own class (the bytecodes) and these classes are dynamically loaded when needed. This is of particular importance when you consider that so many applications are now being run over networks. Just consider the size of some Windows EXE files and you can see that transporting them over a network is not always practical.

Diagram 2: Dynamic Compile/Interpret Model (bytecodes).

However, if you simply load a main application with a small footprint, and then only request the code that the application actually needs (and when it needs it), you have a much more efficient model. Take a look at an example of this dynamic loading.

Dynamic loading

You can use the code example from the previous article on Controlling Access to a Class. In this case, you will use only two of the classes, AccountList and CheckingAccount.

Listing 1: Simple Application

class AccountList {

   public static void main(String args[]) {

      CheckingAccount myList = new CheckingAccount();


class CheckingAccount {

   protected String accountNumber;
   protected double accountBalance = 1000000.00;


When these classes are compiled, you can then invoke the main class and execute the application. When you inspect the directory (in this case, right off the C: drive) where the application resides (see Figure 1), you see that there are indeed two class files, AccountList.class and CheckingAccount.class.

Figure 1: Individual Class Files.

An important thing to understand here is that the main application class AccountList actually creates a CheckingAccount object.

CheckingAccount myList = new CheckingAccount();

This line is the point when the Virtual Machine actually goes looking for the CheckingAccount class. What happens if the CheckingAccount class is not there? Delete it from the directory. If you then run the application, you get the following error, as seen in Figure 2.

Figure 2: Class CheckingAccount missing.

As you can see, when the main class, AccountList, is loaded and executed, it complains when it can't find the CheckingAccount class. This is because CheckingAccount is literally not there. In fact, the error occurs because AccountList, after it starts, cannot find the CheckingAccount class when it attempts to load it. How can you prove this? Take out the line of code where you create the CheckingAccount object: Listing 2.

Listing 2: No Object Created

class AccountList {

   public static void main(String args[]) {


In this example, when the AccountList class is loaded, it does not require the services of the CheckingAccount class. Thus, there is no error generated, as seen in Figure 3.

Figure 3: Class CheckingAccount not needed.

This is an important concept; the classes are not loaded until they are actually needed. Dynamic loading of classes can greatly increase the performance of applications. This includes reducing the flow of bytes over networks as well as keeping memory footprints to a minimum.

Page 1 of 3

This article was originally published on January 5, 2007

Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Thanks for your registration, follow us on our social networks to keep up-to-date