Pushing Java Envelope – Part 1: Java Class File

 

 

For a few days, I am working on Java to get OCA certificate. To be honest, my initial thinking was that, with a little bit of study, I would easily pass it. However, when I started to practice, I understood that the exam tries to trick you while asking fundamentals of Java. It also makes us double think on the aspects of the programming language that we all took for granted. As I dive deeper, I found many things that Java permits but we do not use that much. In this post, I will start with basics and present codes that emphasis each point.

Java Class File

In Java, every application has one or many classes, since everything depend on them. The basic class file presents the fields, methods of the class. Also, we can learn how to initialize an object of that class by the same file. The interesting point is, there may be more than one class in a file. I am not talking about inner classes. What I mean is, in the same file, there can be more than one class definition independent of each other. Here is an example MultipleClasses.java file content that is perfectly valid:

public class MultipleClasses {
  int a = 5;
  private Helper helper = new Helper();

public static void main(String[] args) {
MultipleClasses mc = new MultipleClasses();
System.out.println(mc.helper.getB());
}
}
class Helper {
  private int b;
 
public int getB() {
return this.b;
}

public static void main(String[] args) {
System.out.println("How may I help you?");
MultipleClasses mc = new MultipleClasses();
System.out.println(mc.a);
}
}

Now let’s move step by step and see what happens. First, compiling the code. Since the file name is MultipleClasses.java, we will run:

javac MultipleClasses.java

Multiple Class Files

It compiles and generates 2 .class files! One is MultipleClasses.class and the other one is Helper.class. If we had gone with the inner classes, what we would have gotten was again two classes but the latter one being MulitpleClasses$Helper.class. Here we understand that the two classes in the same file are totally different classes. We can add as many classes as possible in the same file, generating .class files for each. This result is exactly the same when we have files dedicated to each class. Each class has its own main() method so we can run MultipleClass and Helper with the java command.

When we run MultipleClass, the main() of that class takes control. It creates a MultipleClasses object. For that, the control is transferred to the instance initializer. We see that the package-private field a is set to integer literal 5. Also, another Helper object is created and set to the private field helper. That means, the control is now inside Helper instance initializer. There, we only reset the private integer field b to 0 and return to the MultipleClasses instance initializer. Since there is nothing to be left in the MultipleClasses instance initializer, it returns to the main() method.

The objects are ready so we can print the b field of helper. One of the important points here is that, we cannot access private fields of helper object from MultipleClass. There will be a compile-time error if we try to directly access the private b field inside the Helper object from MultipleClass object. That’s why I added the public getB() method to Helper class. We expected to and now see a 0 (zero) on the screen.

MulipleClasses Stack

Following the same procedure, we can also generate the output of java Helper command. We again start with the main() method but this time, it is the main() method of Helper class. It prints “How may I help you?” in a new line first. After that, it creates a new instance of MultipleClasses. The control is transferred to its instance initializer. It sets 5 to package-private field a. Again, another Helper object is created and set to the private field helper. That means, the control is now inside Helper instance initializer. There, we only reset the private integer field b to 0 and return to the MultipleClasses instance initializer. It has nothing else to do, just returns back to main() method of Helper class. Here we will print the a field of newly created MultipleClasses object, which is named as mc. The small but significant change is that, for that field we DO NOT NEED a public getter to access. That is because that field is package-private.

Helper Running Stack

So the output of the Helper will be “How may I help you?” followed by 5 (five).

Multiple Java Runs

 

Restrictions

In Java, we can make the top-level classes either public or package-private (i.e. by not writing anything before class className). With more than one top-level classes in the same file, all classes can be package-private. In that case, we can give ANY name to the class file. I mean, really ANY NAME WE WANT. It does not have to be a class name. Java does not care the name of the java class file when there is no public class inside the .java file. The following, slightly modified example is just OK with the file name What.java

class MultipleClasses {
  int a = 5;
private Helper helper = new Helper();

public static void main(String[] args) {
MultipleClasses mc = new MultipleClasses();
System.out.println(mc.helper.getB());
}
}
class Helper {
private int b;

public int getB() {
return this.b;
}

public static void main(String[] args) {
System.out.println("How may I help you?");
MultipleClasses mc = new MultipleClasses();
System.out.println(mc.a);
}
}

As you can see, there is NO class named as What but the file name is What.java. 

If we want to make the classes inside the Java file public, that drastically changes everything. First, there can only be one public class per file. We cannot make both MultipleClasses and Helper public. Also, the public one now dictates the name of the Java class file. The very first example above illustrates that case. MultipleClasses is public so the name of the file must be MultipleClasses.java.

Packaging

There are many clues that takes us to the point that these classes inside the same class file are actually classes in the same package. To verify this, I created two more simple classes with their own class files. One of them, InPackage, will share the same package with MultipleClasses and Helper. The other one, OutPackage, will be totally out of their package. Also, I will modify MultipleClasses and Helper, so that each of them will try to access InPackage class.

There are two packages: experiment and other. MultipleClasses and Helper classes are in the same file, MultipleClasses.java. They are also in the experiment package. They both initialize an instance of InPackage class, which is in the InPackage.java file. The InPackage class also initializes one object from each. The key point is that, none of the java files import anything. That’s all below:

package experiment;
public class MultipleClasses {
int a = 5;
private Helper helper = new Helper();

public static void main(String[] args) {
MultipleClasses mc = new MultipleClasses();
System.out.println(mc.helper.getB());
InPackage inPackage = new InPackage();
System.out.println(inPackage.c);
}
}
class Helper {
private int b;

public int getB() {
return this.b;
}

public static void main(String[] args) {
System.out.println("How may I help you?");
MultipleClasses mc = new MultipleClasses();
System.out.println(mc.a);
InPackage inPackage = new InPackage();
System.out.println(inPackage.c);
}
}

The code for the simple InPackage class is here:

package experiment;
class InPackage {
int c = 3;
  public static void main(String[] args) {
Helper helper = new Helper();
System.out.println(helper.getB());
MultipleClasses mc = new MultipleClasses();
System.out.println(mc.a);
}
}

Packages

As you can see, these three classes belong to the same package. My aim is to show that, these can access each other without importing any other package. After comping two files, I run each class and get the outputs. You can see them below:

3 Classes Run

Without importing any other class, we can safely use each of them in their respective main() methods. See also that, both MultipleClasses and Helper access directly to the package-private field (c) of InPackage class, whereas the InPackage class can access the package-private field (a) of MultipleClasses. These show that all three classes belong to the same package.

Now let’s turn out attention to the OutPackage class. It exists inside the package named other. I will compile this class first without an import statement, then with it.

package other;
// import experiment.*;
public class OutPackage {
  public static void main(String[] args) {
Helper helper = new Helper();
System.out.println(helper.getB());
MultipleClasses mc = new MultipleClasses();
System.out.println(mc.a);
  }
}

When we comment out the import statement, the code does not compile since it cannot find anything about MultipleClasses and Helper.

Without Import Statement

When we import those two classes, the compiler still complains but for a different reason. It now knows about the classes but it also knows that Helper class is only package-private, which prohibits its direct use from a different package.

With Import Statement

Hence, we are sure that putting more than one class inside a single .java file makes them share the same package.

2 Responses to “Pushing Java Envelope – Part 1: Java Class File”

  1. corejavatraininginhyderabad Says:

    Hi,
    Very nice and informative article. Thanks for sharing this article. Keep posting.

  2. javatogo Says:

    Good info, helped me crack an interview question

Leave a comment