Java Inner Class Tutorial: Types, Examples, and Rules
An inner class is a class defined inside another class. It sounds simple, but Java has four different kinds, and each one has its own rules. This guide walks through all four types with code, output, and the rules that interviewers ask about.
Nested Inner Class
- A class defined inside a class is called an inner class.
// outer class or top-level class
class A {
// inner class
class B {
}
}
- Inner classes are used to organize a class's code.
class A {
class Logic {
// business logic here..
}
class View {
// design here..
}
}
- An inner class can itself contain another class, called a nested inner class.
// outer class
class A {
// inner class
class B {
// nested inner class
class C {
}
}
}
- Inner classes remove naming conflicts between classes.
class A {
class B {
class C {
}
}
class D {
class C {
}
}
}
- Inner classes can be private, protected, default, public, static, final, abstract, and so on.
class A {
private class B {
}
protected class C {
}
public class D {
}
final class E {
}
abstract class F {
}
}
- An inner class can access the private fields of the outer class.
class A {
private int i = 10;
class B {
void show() {
System.out.println(i);
}
}
public static void main(String[] h) {
// create outer class object
A a = new A();
// create inner class object through outer reference
B b = a.new B();
b.show();
}
}
/* Note: Inner class B is non-static, so first we
need to create an instance of the outer class,
then use the outer reference to create an inner
class object. Otherwise there is a compile-time error. */
Output is : 10
- A private field of one inner class can be accessed from another inner class inside the same outer class, through an object.
class A {
class B {
private int i = 10;
}
class C {
void show() {
System.out.println(new B().i);
}
}
public static void main(String[] h) {
A a = new A();
C c = a.new C();
c.show();
// OR we can also call like below:
new A().new C().show();
}
}
Output is : 10
- A class or interface can be an inner class, and an interface can also have an interface or class as an inner class.
class A {
interface B {
}
class G {
}
}
OR
interface C {
class F {
}
interface D {
}
}
- A member interface can only be defined inside a top-level class or interface, or in a static inner class.
class A {
interface T { // this is possible
}
class B {
interface C { // compile-time error
}
}
void show() {
interface G { // compile-time error
}
}
}
- The compiler creates a separate .class file for every inner class.
class A {
class B {
}
static class C {
}
void show() {
class F {
}
}
}
// When you compile, the compiler creates four .class files:
// A.class, A$B.class, A$C.class, and A$1F.class.
Types of inner class
There are 4 types of inner class:
- Non-Static Inner class
- Static Inner class
- Local Inner class
- Anonymous Inner class
1. Non-Static Inner class
- A class defined inside a class without the
statickeyword is called a non-static inner class.
class A {
// non-static inner class
class B {
}
}
- A non-static inner class must be initialized through an outer reference to access its properties.
class A {
void say() {
System.out.println("Hey I am outer class method");
}
class B {
void show() {
System.out.println("Hey I am non-static inner class method");
}
}
public static void main(String[] h) {
A a = new A();
a.say();
B b = a.new B();
b.show();
}
}
Output is : Hey I am outer class method
Output is : Hey I am non-static inner class method
- The
thiskeyword andOuter.thisremove naming conflicts between variables in nested inner classes.
class A {
int i = 1;
class B {
int i = 2;
class C {
int i = 3;
class D {
int i = 4;
void show() {
int i = 5;
System.out.println(i); // 5
System.out.println(this.i); // 4
System.out.println(C.this.i); // 3
System.out.println(B.this.i); // 2
System.out.println(A.this.i); // 1
}
}
}
}
}
- A non-static inner class cannot have static members except constant variables (static final).
class A {
class B {
final static int i = 10; // only this is allowed
static void show() {} // not allowed
static int k = 100; // not allowed
}
}
2. Static Inner class
- A class defined inside a class with the
statickeyword is called a static inner class.
class A {
// static inner class
static class B {
}
}
- A static inner class can be accessed through the outer class name.
class A {
static class B {
static void show() {
System.out.println("Hey I am static inner class");
}
}
public static void main(String[] h) {
A.B.show();
}
}
- A static inner class can also have non-static properties.
class A {
static class B {
int i = 100;
void show() {
System.out.println(i);
}
}
public static void main(String[] h) {
A.B a = new A.B();
a.show();
}
}
Output is : 100
- A static inner class can also have its own
mainmethod.
class A {
static class B {
public static void main(String[] h) {
System.out.println("Hello static inner class");
}
}
}
// compile by
javac A.java
// run by
java A$B
Output is : Hello static inner class
3. Local Inner class
- A local inner class is defined inside a method, constructor, or block.
class A {
void show() {
// local inner class
class B {
}
}
}
- A local inner class cannot be declared private, static, protected, or public.
class A {
void show() {
// local inner class
private class B { // compile-time error
}
protected class B { // compile-time error
}
public class B { // compile-time error
}
}
}
- A local inner class can only be accessed within the method, constructor, or block body where it is defined.
class A {
void show() {
// local inner class
class B {
void goo() {
System.out.println("Hey I am local inner class");
}
}
B b = new B();
b.goo();
}
public static void main(String[] h) {
A a = new A();
a.show();
}
}
Output is : Hey I am local inner class
4. Anonymous Inner class
- An anonymous inner class is a class that has no name.
- It is a shorthand form of a local inner class.
- It can create an object of an interface, an abstract class, or a normal class.
- It is generated at runtime.
- It can be passed as an argument to a method.
- Its .class file is named
OuterClass$1.class.
Example using a local inner class:
interface B {
void add(int i, int j);
}
class A {
void show(int i, int j) {
class D implements B {
public void add(int i, int j) {
System.out.println(i + j);
}
}
D d = new D();
d.add(i, j);
}
public static void main(String[] h) {
new A().show(2, 2);
}
}
Output is : 4
Example using an anonymous inner class:
interface B {
void add(int i, int j);
}
class A {
public static void main(String[] h) {
// this is the syntax of an anonymous inner class
B b = new B() {
public void add(int i, int j) {
System.out.println(i + j);
}
};
b.add(2, 2);
}
}
// The anonymous class is generated at runtime when the object is created.
// The anonymous .class name is A$1.class
Output is : 4
Example using a lambda expression:
interface B {
void add(int i, int j);
}
class A {
public static void main(String[] h) {
B b = (i, j) -> System.out.println(i + j);
b.add(2, 2);
}
}
Output is : 4
Summary
You now know the four types of inner classes, when each one runs, and the rules that break if you get them wrong. If you remember one thing, remember this: non-static inner classes need an outer object, static inner classes do not, local inner classes live inside a method, and anonymous inner classes have no name.
If you want to go deeper, try compiling a class with all four types and look at the generated .class files. The naming pattern (Outer$Inner.class, Outer$1.class) will make the compiler's behavior concrete.
No comments:
Post a Comment