Java programming offers a flexible structure for organizing classes and utilizing import statements efficiently. Let’s delve into the various aspects of class organization, naming conventions, and import statements in Java.
Java Class Organization and Naming Conventions
Any Java class can contain any number of Java classes, and we can give any name to it, whether it is the containing class name or any other user-defined name. For example:
class A {
// Class A implementation
}
class B {
// Class B implementation
}
class C {
// Class C implementation
}
Case 1: Here we can take any name like A.java, B.java, C.java, or amol.java, so there are no restrictions.
Case 2: If we declare a class with the public modifier, then the class name should match that of the file. For instance, in the above example, if public class B
is declared, then the class name should be B.java
; otherwise, we will get a compilation error: “class B is public, should be declared file name as B.java.”
Case 3: If a class contains multiple public classes, then at most one public class name should match the file name. For example, if public class B
and public class C
are present in the above code, then the file name should be C.java. Otherwise, we will get a compilation error: “class C is public, declare file name as C.java.”
Execution Behavior
In Java, a single source file can accommodate multiple classes, each with its main
method. For example:
class A {
public static void main(String args[]) {
System.out.println("A class main");
}
}
class B {
public static void main(String args[]) {
System.out.println("B class main");
}
}
class C {
public static void main(String args[]) {
System.out.println("C class main");
}
}
class D {
}
When running Java programs with multiple classes, the behavior varies based on the class invoked:
If the above class is named “amol.java,” it compiles with that name, but different source files are generated for each class name, such as A.java, B.java, C.java, and D.java. However, when we run with different class names, we get different output:
java A –> output: A class main
java B –> output: B class main
java C –> output: C class main
java D –> Runtime Error: NoSuchMethodError exception
java amol –> Runtime Error: NoClassDefFoundError
It is highly recommended to have only one class per source file and name the program the same as the class name. This practice improves readability and maintainability. This practice also aids in avoiding issues like the one encountered with java D
. Additionally, importing statements in the class should be written so that there is no need to write the fully qualified name.
Import Statements
Import statements in Java facilitate the use of classes and packages within the code. There are two types of import statements:
- Explicit Import: Imports a specific class or interface ->
import java.util.ArrayList;
- Implicit Import: Imports all classes within a package ->
import java.util.*;
Resolving Class Names
While resolving class names, the compiler always gives precedence in the following manner:
- Explicit class import take precedence
- Classes present in the current working directory (default package) are considered next.
- Implicit class import are checked last.
We don’t require import statements for the java.lang package and the default package (CWD – current working directory).
Static Import Statements
Import statements are a concept at the compiler level and have no effect on execution time.
A key difference between the #include
statement in C and the import statement in Java is their behavior:
- The
#include
statement in C is a static include type, loading all required classes at the beginning, which can lead to unnecessary memory usage and reduced performance. - The import statement in Java is a dynamic include type, loading classes on demand or “on the fly,” reducing memory usage and improving performance.
According to Sun Microsystems, static import statements reduce code length and enhance code readability. However, some programmers argue that it decreases readability and increases complexity.
In Java, without static imports, we can use class names with static methods like Math.sqrt()
and Math.random()
. With static imports, we can directly use methods without the class name, by using the import static
statement. For instance, import static java.lang.Math.sqrt;
allows us to use sqrt(10)
directly without the class name.
import static java.lang.Math.sqrt;
public class Example {
public static void main(String[] args) {
System.out.println(sqrt(10));
}
}
Static import statements provide a way to access static members of a class directly without qualifying the class name. This can enhance code readability but may increase complexity.
System.out.println()
The System.out.println()
method in Java can be dissected as follows:
System
: This is a class present in thejava.lang
package.out
: It’s a static variable within theSystem
class, of the typePrintStream
.println()
: This is a method present in thePrintStream
class.
While resolving static members, in the case of static statements, the compiler will always consider the following order:
- Current class static members
- Explicit static import
- Implicit static import.
Also,
There are two types of static import:
- Explicit static import
- Implicit static import.
Java Package
In Java, a package is a group of interrelated classes and interfaces bundled into a single unit. The structure of a Java source file typically includes:
- Package statement: This appears at most once and defines the package of the file’s contents.
- Import statements: Any number of import statements can be included to import classes from other packages.
- Class, interface, or enum declarations: There can be any number of these declarations within the source file.
Conclusion
Understanding Java class structure and import statements is crucial for writing efficient and maintainable code. By organizing classes logically and utilizing import statements effectively, developers can improve code readability and performance in Java applications.