Programming Tutorials Browser Tutorials Articles Struts Tutorials Hibernate Tutorials

  Tutorial: Java performance programming, Part 2: The cost of casting - JavaWorld December 1999

Java performance programming, Part 2: The cost of casting - JavaWorld December 1999

Tutorial Details:

Java performance programming, Part 2: The cost of casting
Java performance programming, Part 2: The cost of casting
By: By Dennis M. Sosnoski
Reduce overhead and execution errors through type-safe code
or this second article in our series on Java performance, the focus shifts to casting -- what it is, what it costs, and how we can (sometimes) avoid it. This month, we start off with a quick review of the basics of classes, objects, and references, then follow up with a look at some hardcore performance figures (in a sidebar , so as not to offend the squeamish!) and guidelines on the types of operations that are most likely to give your Java Virtual Machine (JVM) indigestion. Finally, we finish off with an in-depth look at how we can avoid common class-structuring effects that can cause casting.
Java performance programming: Read the whole series!
Part 1. Learn how to reduce program overhead and improve performance by controlling object creation and garbage collection
Part 2. Reduce overhead and execution errors through type-safe code
Part 3. See how collectionsalternatives measure up in performance, and find out how to get the most out of each type
Object and reference types in Java
Last month , we discussed the basic distinction between primitive types and objects in Java. Both the number of primitive types and the relationships between them (particularly conversions between types) are fixed by the language definition. Objects, on the other hand, are of unlimited types and may be related to any number of other types.
Each class definition in a Java program defines a new type of object. This includes all the classes from the Java libraries, so any given program may be using hundreds or even thousands of different types of objects. A few of these types are specified by the Java language definition as having certain special usages or handling (such as the use of java.lang.StringBuffer for java.lang.String concatenation operations). Aside from these few exceptions, however, all the types are treated basically the same by the Java compiler and the JVM used to execute the program.
If a class definition does not specify (by means of the extends clause in the class definition header) another class as a parent or superclass, it implicitly extends the java.lang.Object class. This means that every class ultimately extends java.lang.Object , either directly or via a sequence of one or more levels of parent classes.
Objects themselves are always instances of classes, and an object's type is the class of which it's an instance. In Java, we never deal directly with objects, though; we work with references to objects. For example, the line:
java.awt.Component myComponent;
does not create an java.awt.Component object; it creates a reference variable of type java.lang.Component . Even though references have types just as objects do, there is not a precise match between reference and object types -- a reference value may be null , an object of the same type as the reference, or an object of any subclass (i.e., class descended from) the type of the reference. In this particular case, java.awt.Component is an abstract class, so we know that there can never be an object of the same type as our reference, but there can certainly be objects of subclasses of that reference type.
Polymorphism and casting
The type of a reference determines how the referenced object -- that is, the object that is the value of the reference -- can be used. For instance, in the example above, code using myComponent could invoke any of the methods defined by the class java.awt.Component , or any of its superclasses, on the referenced object.
However, the method actually executed by a call is determined not by the type of the reference itself, but rather by the type of the referenced object. This is the basic principle of polymorphism -- subclasses can override methods defined in the parent class in order to implement different behavior. In the case of our example variable, if the referenced object was actually an instance of java.awt.Button , the change in state resulting from a setLabel("Push Me") call would be different from that resulting if the referenced object were an instance of java.awt.Label .
Besides class definitions, Java programs also use interface definitions. The difference between an interface and a class is that an interface only specifies a set of behaviors (and, in some cases, constants), while a class defines an implementation. Since interfaces do not define implementations, objects can never be instances of an interface. They can, however, be instances of classes that implement an interface. References can be of interface types, in which case the referenced objects may be instances of any class that implements the interface (either directly or through some ancestor class).
Casting is used to convert between types -- between reference types in particular, for the type of casting operation in which we're interested here. Upcast operations (also called widening conversions in the Java Language Specification) convert a subclass reference to an ancestor class reference. This casting operation is normally automatic, since it's always safe and can be implemented directly by the compiler.
Downcast operations (also called narrowing conversions in the Java Language Specification) convert an ancestor class reference to a subclass reference. This casting operation creates execution overhead, since Java requires that the cast be checked at runtime to make sure that it's valid. If the referenced object is not an instance of either the target type for the cast or a subclass of that type, the attempted cast is not permitted and must throw a java.lang.ClassCastException .
The instanceof operator in Java allows you to determine whether or not a specific casting operation is permitted without actually attempting the operation. Since the performance cost of a check is much less than that of the exception generated by an unpermitted cast attempt, it's generally wise to use an instanceof test anytime you're not sure that the type of a reference is what you'd like it to be. Before doing so, however, you should make sure that you have a reasonable way of dealing with a reference of an unwanted type -- otherwise, you may as well just let the exception be thrown and handle it at a higher level in your code.
Casting caution to the winds
Casting allows the use of generic programming in Java, where code is written to work with all objects of classes descended from some base class (often java.lang.Object , for utility classes). However, the use of casting causes a unique set of problems. In the next section we'll look at the impact on performance, but let's first consider the effect on the code itself. Here's a sample using the generic java.lang.Vector collection class:
private Vector someNumbers;
...
public void doSomething() {
...
int n = ...
Integer number = (Integer) someNumbers.elementAt(n);
...
}
This code presents potential problems in terms of clarity and maintainability. If someone other than the original developer were to modify the code at some point, he might reasonably think that he could add a java.lang.Double to the someNumbers collections, since this is a subclass of java.lang.Number . Everything would compile fine if he tried this, but at some indeterminate point in execution he'd likely get a java.lang.ClassCastException thrown when the attempted cast to a java.lang.Integer was executed for his added value.
The problem here is that the use of casting bypasses the safety checks built into the Java compiler; the programmer ends up hunting for errors during execution, since the compiler won't catch them. This is not disastrous in and of itself, but this type of usage error often hides quite cleverly while you're testing your code, only to reveal itself when the program is put into production.
Not surprisingly, support for a technique that would allow the compiler to detect this type of usage error is one of the more heavily requested enhancements to Java. There's a project now in progress in the Java Community Process that's investigating adding just this support: project number JSR-000014, Add Generic Types to the Java Programming Language (see the Resources section below for more details.) In the continuation of this article, coming next month, we'll look at this project in more detail and discuss both how it's likely to help and where it's likely to leave us wanting more.
The performance issue
It's long been recognized that casting can be detrimental to performance in Java, and that you can improve performance by minimizing casting in heavily used code. Method calls, especially calls through interfaces, are also often mentioned as potential performance bottlenecks. The current generation of JVMs have come a long way from their predecessors, though, and it's worth checking to see how well these principles hold up today.
For this article, I developed a series of tests to see how important these factors are to performance with current JVMs. The test results are summarized into two tables in the sidebar , Table 1 showing method call overhead and Table 2 casting overhead. The full source code for the test program is also available online (see the Resources section below for more details).
To summarize these conclusions for readers who don't want to wade through the details in the tables, certain types of method calls and casts are still fairly expensive, in some cases taking nearly as long as a simple object allocation. Where possible, these types of operations should be avoided in code that needs to be optimized for performance.
In particular, calls to overridden methods (methods that are overridden in any loaded class, not just the actual class of the object) and calls through interfaces are considerably more costly than simple method calls. The HotSpot Server JVM 2.0 beta used in the test will even convert man


 

Read Tutorial at: Click here to view the tutorial

Rate Tutorial:
Java performance programming, Part 2: The cost of casting - JavaWorld December 1999

View Tutorial:
Java performance programming, Part 2: The cost of casting - JavaWorld December 1999

Related Tutorials:

3D graphics programming in Java, Part 3: OpenGL
3D graphics programming in Java, Part 3: OpenGL
 
Accelerate your RMI programming
Accelerate your RMI programming
 
I want my AOP!, Part 1
I want my AOP!, Part 1
 
Cache SOAP services on the client side
Cache SOAP services on the client side
 
Step into the J2EE architecture and process
Step into the J2EE architecture and process
 
I want my AOP!, Part 3
I want my AOP!, Part 3
 
J2SE 1.4 breathes new life into the CORBA community, Part 1
J2SE 1.4 breathes new life into the CORBA community, Part 1
 
Check out three collections libraries
Check out three collections libraries
 
Attack of the clones
Attack of the clones
 
Fixing the Java Memory Model, Part 1
JSR 133, which has been active for nearly three years, has recently issued its public recommendation on what to do about the Java Memory Model (JMM).
 
JView 2004 - J2EE Performance Management Software - Version 1.4
JView 2004 Enterprise Edition available now! JView 2004 is the leading J2EE Production Performance Monitor and Java Performance Tuning solution, providing precise real-time performance metrics to assist you in ensuring your performance requirements a
 
JView 2004 2.1 Released - J2EE Performance Profiler
JView 2004 J2EE Performance Tuning and Monitoring Enterprise Edition Trial Download
 
Comparing The Performance of J2EE Servers
Performance ReportThe standardization of the application server, thanks to Sun\'s J2EE specifications, has spawned a wealth of implementations. There are offerings from big players such as Sun, IBM, BEA and Oracle as well as numerous offerings from low-co
 
JDBC scripting, Part 2
JDBC scripting, Part 2 Programming and Java scripting in JudoScript Summary JudoScript is a rich functional scripting language, and an easy and powerful general programming and Java scripting language. JudoScript's power comes from its synergy of
 
Annotations in Tiger, Part 1: Add metadata to Java code
Annotations, a new feature in J2SE 5.0 (Tiger), brings a much-needed metadata facility to the core Java language. In this first of a two-part series, author Brett McLaughlin explains why metadata is so useful, introduces you to annotations in the Java lan
 
Access Windows Performance Monitor counters from Java, Part 1
Access Windows Performance Monitor counters from Java, Part 1 Use a simple Java API to gather valuable performance statistics Summary Windows NT, 2000, 2003, and XP contain a utility called the Performance Monitor that provides a rich array of perform
 
A well-behaved Jetspeed portlet
This article presents a working example of how to construct a Jetspeed portlet that runs efficiently, adheres to the Model 2 architecture, and, by not interfering with additional portlets, plays well with others. In addition, I demonstrate some simple way
 
Introduction to Servlets, JSP, and Servlet Engines
Servlets are the Java Technologies' answer to CGI programming. They are programs which run on the server side and generate dynamic content. Why would one prefer to use Servlets over traditional CGI programming?
 
Using and Programming Generics in J2SE 5.0
Generics, one of the most frequently requested language extensions to the Java programming language, have been added in J2SE 5.0. This article provides an introduction to programming with generics.
 
New Technical Articles: 64-bit Programming on Solaris 10 OS for x86 Platforms
Four technical articles describe the new Sun Studio 10 software's 64-bit programming features on the Solaris 10 OS for x86 and AMD64 platforms. Important issues regarding the AMD64 ABI (Application Binary Interface), debugging, migration to 64-bits, and p
 
Site navigation
 

 

Send your comments, Suggestions or Queries regarding this site at roseindia_net@yahoo.com.

Copyright © 2006. All rights reserved.