Understanding Classes in Java

Introduction

After gathering some insight into Java Reference Types in the previous posts, now understanding classes in Java has become easier.

We need to understand how a Reference Type comes to existence and more. Apart from that we must also learn about Interfaces and Enums which are the building blocks of any written program.

A Class in Java

A class declaration defines a new reference type and describes its implementation. A class contains members which are enclosed in the body of the class. Members may also be inherited from a Super Class or Interfaces.

A member can be a field, a method, a class (nested class) or an interface. Apart from the members, a class may also contain static or instance initializer and constructors.

A word about initializers

Initializers are optional code blocks which can be written in any class (concrete or abstract). These code blocks need not necessarily initialize anything but can execute any valid statement.

Static Initializer : Blocks of executable code that may be used to help initialize a class. There can be multiple such blocks in the class and they are meant to be executed in the order of their declaration. All such blocks will be executed only once per class while the class initialization process.

Instance Initializer : Blocks of executable code that may be used to help initialize an instance of the class. There can be multiple such blocks and they are executed in the order of their declaration. All such block will be executed once per instance creation. They are executed before the execution of code block present in the constructor of the class.

You can think of the instance initializer code as the piece of code inserted in a constructor just after the call to super().
The below two code segments can be considered equivalent.
Code Block 1

Code Block 2

Why is this even important?

Any complex operation which we want to do before executing the constructor code can be done in this block. Also, in scenarios where there is no constructor possible (as in anonymous classes) we can use this block for initialization of few instance variables if we do not want them to have their respective default values.

Also, if there are multiple constructors and we do not want chaining of constructor and still want to write a common piece of initialization code which needs to be executed on each instance creation, then this is the right place to do so.

Example Code for static and instance initializer

Here is the output of the above program:

Categorizing Classes

We can categorize classes in various ways, based on how they are declared and used. Here are three different categories:

  • Named classes and Anonymous classes : Any class which is declared using the class keyword is a named class. It basically means that the name of the class can be used as reference type. Anonymous classes on the other hand will not have any name. They are defined on the fly as per requirement. They have many other features as well, which we can discuss in a dedicated section for Anonymous classes
  • Top Level classes and Nested classes : A class, which is not a member of any other class is called a top level class, whereas a class which is enclosed in another top level class is called a nested class. We can declare multiple level of nesting, and theoretically there is no limit.
  • Abstract classes and Concrete classes : A class with incomplete definition is called an abstract class. An abstract class may have behaviors which are not clearly defined. That means, few or all methods may not have definition or body. In such scenarios the class must be qualified with a keyword abstract and so should be the methods without body. Any class which is not an abstract class is concrete.

How are classes stored?

A class is always stored in a Compilation Unit and these units are enclosed in a structure called package. Packages are nested structures like the nested directories in an operating system.

Packages can be stored in a Local File System, a Distributed File System or a Database Table. It is the internal implementation of Java (which is specific to the File Systems) which creates physical files for each compilation units.

However, when it comes to the Local File Systems, then Java dictates a rule where it allows one declared Type with access modifier public per physical unit (called file). However, you can have few more classes without the access modifier public in the same physical file.

This means, on local file system only one public class can exist in a physical .java file.

When the compilation units are stored in distributed file systems or database tables, then also the above rule is honored while de-serializing them back while compilation and creation of class files.

Note : A class must always be a part of a package. Although Java provides an option to write classes which can exist without a package, but it is only recommended for small test programs.

You can read my answer regarding packaging on Quora

Conclusion

No discussion about Java Classes can be complete without discussing the Production Rule for Class Declaration. According to JLS here is the production:

NormalClassDeclaration:
ClassModifiersopt class Identifier TypeParametersopt Superopt Interfacesopt ClassBody

The production opens room for a lot of discussion, in fact each of the words in the production deserves a discussion so let us continue this in the next post. We will try to understand the exact meaning of this statement and that can solve all the mysteries about access modifiers and many more questions related to other OOP concepts.

Don’t forget to subscribe to TechieMe to get updates on latest posts.