Programming Tutorials Browser Tutorials Articles Struts Tutorials Hibernate Tutorials

  Tutorial: A primordial interface? - JavaWorld March 2001

A primordial interface? - JavaWorld March 2001

Tutorial Details:

A primordial interface?
A primordial interface?
By: By Wm. Paul Rogers
Investigate Java's elusive primordial interface
ection 8.1.3 of the Java Language Specification ( JLS ) states, "The class java.lang.Object ... is the primordial class and has no direct superclass." That means java.lang.Object serves as the root class for all Java class hierarchies. The single-rooted implementation inheritance hierarchy guarantees that every runtime object has a concrete implementation for all java.lang.Object type operations. Furthermore, the JLS clearly dismisses the existence of a similar primordial interface. Section 9.1.3 states, "There is no analogue of the class Object for interfaces; that is, while every class is an extension of class Object , there is no single interface of which all interfaces are extensions."
Nonetheless, this article investigates the fact that the Java language acts as if a primordial interface does indeed exist. To lay the foundation necessary for understanding the existence of a tacit primordial interface, I first present a conceptual, type-oriented view of Java objects.
Conceptual goggles
Figure 1 shows a UML class diagram for the simple class and type hierarchy used as this article's example. The diagram models two classes, one interface, and three type declarations. For brevity and clarity, the diagram and following discussion does not include the requisite root java.lang.Object class.
Figure 1. UML class diagram for the example code
I purposely keep simple the concrete implementation of each class. The following code implements the class Base :
public class Base
{
public String m1()
{
return "Base.m1()";
}
public String m2( String s )
{
return "Base.m2( " + s + " )";
}
private String p()
{
return "Base.p()";
}
}
As detailed in "Thanks Type and Gentle Class" , every class declaration provides implementation code and declares a user-defined data type. Here class Base implements two public methods, m1() and m2(String) , and a private method, p() . Type Base declares two operations, m1() and m2(String) . Figure 2 depicts a conceptual view of the following Java code:
Base base = new Base();
System.out.println( base.m1() ); // Prints "Base.m1()"
System.out.println( base.m2( "base" ) ); // Prints "Base.m2( base )"
System.out.println( base.p() ); // Compile-time error
System.out.println( base.m() ); // Compile-time error
Figure 2. Base reference attached to Base object
The first statement in the code above attaches a type Base reference to an object instantiated with class Base . The Base type reference acts as conceptual goggles for viewing the underlying Base class object. The reference type effectively shields the Base object, permitting interaction only through messages adhering to declared Base type operations. The designer of class Base explicitly declared that type Base would only permit operations m1() and m2(String) . So while the second and third lines of code pass compile-time type checking, the fourth and fifth lines result in compile-time errors. In declaring method p() private, the designer has hidden that implementation. At compile time, the type checker polices the code and censors the attempt to send a p() message to the Base object through a Base reference. Note that the Base object is fully capable of handling the message. As for calling method m() , the type checker also rejects that attempt, which is fortunate since the Base object is not prepared to receive that message. Importantly, when viewed through a Base reference, method p() is as invisible as a nonexistent method.
That conceptual view can be extended to include implementation inheritance as well. The code below declares type IType and implements class Derived :
public interface IType
{
String m2( String s );
String m3();
}
public class Derived
extends Base
implements IType
{
public String m1()
{
return "Derived.m1()";
}
public String m3()
{
return "Derived.m3()";
}
}
Class Derived provides implementation for methods m1() and m3() . As a subclass of Base , Derived inherits implementation for m1() and m2(String) , though it overrides the m1() implementation. Since p() was declared private, Derived does not inherit that method's implementation.
Type Derived explicitly declares two operations, m1() and m3() . As a subtype of Base , Derived inherits operations m1() and m2(String) and, as a subtype of IType , it inherits operations m2(String) and m3() . So m1() , m2(String) , and m3() make up the set of operations for type Derived . Note that inheriting operation m2(String) along multiple lines of the type hierarchy does not cause any difficulties. That is not true of multiple implementation inheritance, which Java does not allow.
This code attaches three separate reference types to a newly created Derived object:
Derived derived = new Derived();
Base base = derived;
IType iType = derived;
Figure 3 depicts the conceptual view of the first statement.
Figure 3. Derived reference attached to Derived object
The second and third statements in the code above attach Base and IType references to the existing Derived object. The type checker verifies that those attachments conform to the declared type hierarchy. Figure 4 depicts the resulting conceptual view of those statements.
Figure 4. Base and IType references attached to Derived object
Figures 3 and 4 reveal an important fact: the type of attached reference does not affect the mapping from the Derived object to the actual implementation code prescribed by the class inheritance hierarchy. The reference type does, however, significantly impact the accessibility to the methods of the underlying Derived object. The code below illustrates that impact:
// Call methods through Derived reference
System.out.println( derived.m1() );
System.out.println( derived.m2( "derived" ) );
System.out.println( derived.m3() );
// Call methods through Base reference
System.out.println( base.m1() );
System.out.println( base.m2( "base" ) );
System.out.println( base.m3() ); // Compile-time error
// Call methods through IType reference
System.out.println( iType.m1() ); // Compile-time error
System.out.println( iType.m2( "iType" ) );
System.out.println( iType.m3() );
Since the references are attached to the same object, each section of the above code attempts access to the exact same object methods. The access, however, is not uniform. The Base type reference restricts the call to m3() , whereas the IType type reference restricts the call to m1() . Importantly, the underlying runtime Derived object is fully capable of receiving either message. Type-imposed restrictions, applied at compile time, invalidate both attempts. From the type checker's point of view, the underlying object's actual capabilities are not relevant. The type checker rigidly enforces the restrictions imposed by the compile-time reference type and remains unconcerned with the actual object. In fact, at compile time, the type checker can't even be sure what that underlying object's capabilities may be. It can only provide a compile-time guarantee that runtime implementation code for each operation of the attached reference type will be accessible.
Primordial interface
The previous discussion and figures omitted the presence of the primordial Object class. That class, however, plays an integral part in every Java class hierarchy. By leaving out the optional extends clause, class Base implicitly extends Object and, therefore, subclasses and subtypes Object . Using an attached IType reference, Figure 5 includes the Object class and the requisite changes to the Derived object.
Figure 5. Derived references attached to Derived object, version 2
Of course, the methods of class Object aren't aa() , bb() , etc. As of Java 2 Platform, Standard Edition, Version 1.3, type Object declares nine operations: equals(Object) , getClass() , hashCode() , notify() , notifyAll() , toString() , wait() , wait(long) , and wait(long,int) . Figure 5 does not show all the methods or the actual names. It does show an IType reference unaffected by the additional implementation code and object mappings. Just as an IType reference can't view the m1() method, neither should it see any of the public methods of Object . The following code, however, reveals a slight surprise:
System.out.println( derived.equals( base ) );
System.out.println( iType.equals( base ) ); // This is legal!
The first statement is type conformant. Since Derived subtypes Base , which subtypes Object , a reference of type Derived may access operations declared by type Object . So a Derived reference may access the equals(Object) method. (That is not shown in Figure 5, which applies to the second code statement.)
The second statement, however, should arguably cause a compile-time error. Type IType does not include operation equals(Object) . It is not sufficient that the Derived object happens to possess a mapping for that method. It maps m1() too, but the IType reference can't access method m1() .
How can we reconcile the apparent discrepancy? We could certainly argue that no harm has resulted. Since every object must be instantiated from a concrete class, and every class must descend from the primordial class Object , we know that at runtime the equals(Object) method call will not fail since implementation for that method exists in class Object . Nevertheless, that argument appeals to runtime issues and type conformance occurs at compile time. How does the compiler, acting as type checker, allow type IType to include operations neither declared by it or any of its supertypes? In our example, IType has no supertypes.
Figure 6 illustrates the conceptual view you actually receive for an IType reference attached to a Derived object. The Java type system grants the IType reference access to all operations defined by type Object .
Figure 6. Derived references attached to Derived object, version 3
To resolve that access in


 

Read Tutorial at: Click here to view the tutorial

Rate Tutorial:
A primordial interface? - JavaWorld March 2001

View Tutorial:
A primordial interface? - JavaWorld March 2001

Related Tutorials:

Integrating Databases
Integrating Databases
 
3D graphics programming in Java, Part 3: OpenGL
3D graphics programming in Java, Part 3: OpenGL
 
How to write a Java Card applet: A developer's guide
How to write a Java Card applet: A developer's guide
 
The basics of Java class loaders
The basics of Java class loaders
 
Connect the enterprise with the JCA, Part 1
Connect the enterprise with the JCA, Part 1
 
XSLT blooms with Java
XSLT blooms with Java
 
Java security evolution and concepts, Part 5
Java security evolution and concepts, Part 5
 
Cache SOAP services on the client side
Cache SOAP services on the client side
 
Check out three collections libraries
Check out three collections libraries
 
Sun boosts
Sun boosts enterprise Java
 
Servlet 2.4: What's in store
Servlet 2.4: What's in store
 
Jini Starter Kit 2.0 tightens Jini's security framework
Jini Starter Kit 2.0 tightens Jini's security framework
 
Good article
Good article
 
Use AOP to maintain legacy Java applications
Use AOP to maintain legacy Java applications This artical shows you how to use aspect-oriented programming (AOP) to gain an unprecedented view into the inner workings of even the most opaque of legacy applications. Please note that this article assume
 
Improving JSF by Dumping JSP
Improving JSF by Dumping JSP After a long wait and high expectations, JavaServer Faces (JSF) 1.0 was finally released on March 11, 2004. JSF introduces an event-driven component model for web application development, similar in spirit and function to t
 
Software Download Central compatible.
GNU getopt - Java port A while back I found myself in need of a Java command line option parser. Unsatisfied with free versions I was able to find on the net, I volunteered to port the GNU getopt family of functions from C to Java. The current release
 
IberAgents
Introduction IberAgents is a web application framework that enables the creation of SOAP-interoperable components in Java, with life cycle management and remote configuration. Development started in 2001; we now have a mature, solid open-source platform
 
Struts, JavaServer Faces, and Java Studio Creator:
The Evolution of Web Application Frameworks Sun Microsystems' Craig McClanahan, the creator of the Apache Struts Framework, co-specification lead for JavaServer Faces 1.0, and prime architect for Sun Java Studio Creator's new release, explains all three.
 
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
 
Solaris 10 OS Certification Beta Exams
If you are an expert in system and network administration, you can get involved in the creation of three new Solaris 10 certification exams. These Beta exams count toward official Solaris Certification and allow you to provide comments and technical feedb
 
Site navigation
 

 

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

Copyright © 2006. All rights reserved.