Class Level Modifiers
- whether this class can be accessed from anywhere are not.
- whether child class creation or not.
- whether object creation is possible or not.
the only applicable modifiers for top-level classes are-:
But for inner classes, the applicable modifiers are:
Access Specifiers vs Access Modifiers
In older languages like C++:
public, protected, default, and private are considered as access specifiers,
and the remaining are considered as modifiers.
In Java:
All are considered as modifiers. There is no term like "specifier".
Example:
private class Test {
public static void main(String... args) {
System.out.print("Hello");
}
}
Compile-time error: modifier private not allowed here
Top-Level Modifiers
public
public classes: If a class is declared public, we can access that class from anywhere.
Example:
package pack1;
class A {
public static void m() {
System.out.print("Hello");
}
}
Command for run: javac -d . A.java
package pack2;
class B {
public static void main(String[] args) {
A a = new A();
a.m();
}
}
Command for run: javac -d . B.java
Compile-time error
If class A is not public, then while compiling class B we will get a compile-time error saying: "pack1.A is not public in pack1 and cannot be accessed from outside the package."
*/
Example:
package pack1;
public class A {
public static void m() {
System.out.print("Hello");
}
}
Command for run: javac -d . A.java
package pack2;
import pack1.A;
class B {
public static void main(String[] args) {
A a = new A();
a.m();
}
}
Command for run: javac -d . B.java
Run command: java pack2.B
Output: Hello
default
default classes: If a class is declared as default, we can access that class only within the current package. From outside the package, we cannot access it. Hence, default access is known as package-level access.
Example:
package pack1;
class A {
public static void m() {
System.out.print("Hello");
}
}
Command for run: javac -d . A.java
package pack2;
import pack1.A;
class B {
public static void main(String[] args) {
A a = new A();
a.m();
}
}
Command for run: javac -d . B.java
Compile-time error: because A is a default class, we cannot access it outside the package.
Final
Final modifier: final is a modifier applicable for classes, methods, and variables.
Final method: Whatever method the parent has is available to the child through inheritance. If the child is not satisfied with the parent method implementation, the child is allowed to redefine that method. This process is called overriding.
If the parent class method is declared as final, then we cannot override that method in the child class because its implementation is final.
Example:
class P {
public void property() {
System.out.print("Cash land Gold");
}
public final void marry() {
System.out.print("Sobha");
}
}
class A extends P {
public void marry() {
System.out.print("Rita");
}
}
Compile-time error: marry() in A cannot override marry() in P; overridden method is final.
Final class: If a class is declared as final, we cannot extend its functionality. This means we cannot create a child class, as inheritance is not possible for final classes.
Example:
final class A {
}
class B extends A {
}
Commands:
javac A.java
javac B.java
Compile Error: cannot inherit from final class A (class B extends A)
Note:
- Every method present inside a final class is always final by default, but every variable present inside a final class need not be final.
- The main advantage of the final keyword is that we can achieve security and provide unique implementation.
- The main disadvantage of the final keyword is that we miss key OOP features like inheritance (because of final classes) and polymorphism (because of final methods). Hence, if there is no specific requirement, it is not recommended to use the final keyword.
Example:
final class A {
static int x = 10;
public static void main(String... args) {
x = 888;
System.out.print(x);
}
}
Output: 888
Abstract
The abstract is a modifier applicable for classes and methods but not for variables.
Abstract method:
Even though we do not know the implementation, still we can declare a method with the abstract modifier. For an abstract method, only declaration is available but not implementation. Hence, abstract method declaration should end with a semicolon.
Child class is responsible to provide implementation for parent class abstract methods.
By declaring an abstract method in the parent class, we can provide guidelines to child classes such that which methods are compulsory for implementation.
The abstract method never talks about implementation. If any modifier talks about implementation, then it forms an illegal combination with the abstract modifier.
Syntax:
public abstract void m(); // valid
public abstract void m() {} // invalid
Example:
abstract class Vehicle {
public abstract int getNoOfWheel();
}
class Bus extends Vehicle {
public int getNoOfWheels() {
return 6;
}
}
class Bike extends Vehicle {
public int getNoOfWheels() {
return 2;
}
}
The following are various illegal combinations of modifiers for methods with respect to abstract.
Example:
abstract final void m();
Compile-time error: illegal combination of modifiers abstract and final.
Abstract class:
For any Java class, if we are not allowed to create an object (because of partial implementation), such a class should be declared with the abstract modifier. That is, for abstract classes, instantiation is not possible.
Abstract class vs Abstract method:
-
If a class contains at least one abstract method, then we must declare the class as abstract;
otherwise we will get a compile-time error.
Reason: If a class contains at least one abstract method, then implementation is not complete, and hence object creation is not recommended. To restrict object instantiation, the class must be abstract. - Even if a class does not contain any abstract method, still we can declare it as abstract if we do not want instantiation. That is, an abstract class can contain zero abstract methods also.
Examples:
- HTTP Servlet class is abstract but it does not contain any abstract method.
- Every adapter class is recommended to be declared as abstract, but it does not contain any abstract method.
Example Program:
abstract class Test {
public static void main(String... args) {
Test t = new Test(); // not allowed
}
}
Compile-time error: Test is abstract and cannot be instantiated
Some more examples:
Case 1:
class P {
public void m();
}
Compile-time error: missing body or declare method abstract
Case 2:
class P {
public abstract void m() {}
}
Compile-time error: abstract method cannot have a body
Case 3:
class P {
public abstract void m();
}
Compile-time error: P is not abstract and does not override abstract method m()
Case 4 (Valid):
abstract class P {
public abstract void m();
}
// This is valid
If we are extending an abstract class, then for each and every abstract method of the parent class we should provide implementation. Otherwise, we have to declare the child class as abstract. In this case, the next-level child class is responsible to provide the implementation.
Example:
abstract class P {
public abstract void m();
public abstract void m1();
}
class C extends P {
public void m() {}
}
Compile-time error: C is not abstract and does not override abstract method m1() in P.
Final vs Abstract
- Abstract methods must be overridden in child classes to provide implementation, whereas final methods cannot be overridden. Hence, final and abstract combination is illegal for methods.
- Final classes cannot be extended, whereas abstract classes must be extended to provide implementation. Hence, final and abstract combination is illegal for classes.
- Abstract classes can contain final methods, whereas final classes cannot contain abstract methods.
Example:
abstract class P {
public final void m1() {
}
}
// valid
final class P {
public abstract void m1();
}
// invalid
Note: It is highly recommended to use abstract modifiers because it promotes several OOP features like inheritance and polymorphism.
strictfp (Strict Floating Point)
- Introduced in JDK 1.2
- We can declare strictfp for classes and methods but not for variables.
- Usually, the result of floating-point arithmetic varies from platform to platform. If we want platform-independent results for floating-point arithmetic, we should use the strictfp modifier.
strictfp method:
If a method is declared as strictfp, all floating-point calculations in that method must follow IEEE 754 standards, so we get platform-independent results.
The abstract modifier never talks about implementation, whereas strictfp always deals with implementation. Hence, abstract strictfp combination is illegal for methods.
Example:
public abstract strictfp void m(); // invalid
Compile-time error: illegal combination of modifiers abstract and strictfp
strictfp class:
If a class is declared as strictfp, then every floating-point calculation inside all its concrete methods follows IEEE 754 standards, ensuring platform-independent results.
We can declare abstract strictfp combination for a class. This combination is legal for classes but illegal for methods.
Example:
abstract strictfp class Test {
}
Member Modifiers (Method or Variable Level Modifiers)
Public members:
If a member is declared as public, then we can access that member from anywhere. But the corresponding class should be visible. That is, before checking member visibility, we have to check class visibility.
Example:
package pack1;
class A {
public void m() {
System.out.print("Hello");
}
}
package pack2;
import pack1.A;
class B {
public static void main(String... args) {
A a = new A();
a.m();
}
}
Compile-time error: pack1.A is not public in pack1; cannot be accessed from outside the package.
In the above example, even though m() is public, we cannot access it from outside the package because the corresponding class is not public. That is, only when both class and method are public, we can access them outside the package.
Default members:
If a member is declared as default, then we can access that member only within the current package. From outside the package, we cannot access it. Hence, default access is also known as package-level access.
Private members:
If a member is private, then we can access it only within the class. From outside the class, we cannot access it.
Abstract methods must be available to child classes for implementation, whereas private methods are not available to child classes. Hence, private abstract combination is illegal for methods.
Protected members:
If a member is declared protected, then we can access it anywhere within the current package. Outside the package, it can be accessed only in child classes.
Within the current package, we can access protected members either using parent reference or child reference.
But outside the package, protected members can be accessed only in child classes, and we must use child references only. Parent references cannot be used to access protected members outside the package.
Protected = default + child access
Example (Same Package):
package pack1;
public class A {
protected void m1() {
System.out.print("Hello");
}
}
class B extends A {
public static void main(String... args) {
A a = new A();
a.m1(); // valid
B b = new B();
b.m1(); // valid
A aa = new B();
aa.m1(); // valid
}
}
Example (Different Package):
package pack2;
import pack1.A;
class C extends A {
public static void main(String... args) {
A a = new A();
a.m1(); // invalid
C c = new C();
c.m1(); // valid
A ac = new C();
ac.m1(); // invalid
}
}
We can access protected members from outside the package only in child classes, and we should use the child class reference only.
For example:
From class D, if we want to access, we should use D class reference only.
package pack1;
public class A {
protected void m1() {
System.out.print("Hello");
}
}
class B extends A {
public static void main(String... args) {
A a = new A();
a.m1(); // valid
B b = new B();
b.m1(); // valid
A aa = new B();
aa.m1(); // valid
}
}
package pack2;
class C extends A { }
class D extends C {
public static void main(String... args) {
A a = new A();
a.m1(); // invalid
A ac = new C();
ac.m1(); // invalid
A a1 = new D();
a1.m1(); // invalid
C c = new C();
c.m1(); // invalid
C c1 = new D();
c1.m1(); // invalid
D d = new D();
d.m1(); // valid
}
}
compile time error → m1() has protected access in pack1.A
Summary Table:
The most restricted access modifier is private.
The most accessible modifier is public.
Recommended: variables → private, methods → public.
private < default < protected < public
| Visibility | Public | Private | Protected | Default |
|---|---|---|---|---|
| Within same class | ✔ Allowed | ✔ Allowed | ✔ Allowed | ✔ Allowed |
| Child class (same package) | ✔ Allowed | ✖ Not Allowed | ✔ Allowed | ✔ Allowed |
| Non-child class (same package) | ✔ Allowed | ✖ Not Allowed | ✔ Allowed | ✔ Allowed |
| Child class (outside package) | ✔ Allowed | ✖ Not Allowed |
✔ Allowed (use child reference only) |
✖ Not Allowed |
| Non-child class (outside package) | ✔ Allowed | ✖ Not Allowed | ✖ Not Allowed | ✖ Not Allowed |
1 Comments
hello
ReplyDeleteHello