Java for Automation Tester
What is a method?
A method in Java is a named block of code that performs a task (computes a value, updates state, does I/O). Methods are the building blocks of behavior in classes and interfaces.
Think of a method as “a function attached to a type” (object-oriented).
A method has:
Modifiers (public, private, static, final, abstract, synchronized, native, etc.)
Return type (can be any type or
void)Name
Parameter list (zero or more parameters)
throwsclause (optional checked exceptions it may throw)Body
{ ... }(except abstract methods, which have no body)
Why methods?
Reuse code (DRY)
Encapsulate behavior & hide implementation
Organize program logic into small understandable units
Enable polymorphism (different implementations in subclasses)
Allow separation of interface (what) and implementation (how)
How to declare & call a method — basic syntax
// instance method
public int add(int a, int b) {
return a + b;
}
// static method
public static void greet(String name) {
System.out.println("Hello, " + name);
}
Call:
MyClass obj = new MyClass();
int sum = obj.add(2,3); // instance call
MyClass.greet("Sam"); // static call
Method components explained
Access modifiers:
public,protected, (package-private default),private.Non-access modifiers:
static,final,abstract,synchronized,native,strictfp.Return type: type or
void.Name: must be a valid identifier.
Parameters: typed
(Type name, ...).Throws:
throws IOException.Body: code block.
abstractmethods omit body.
Types of methods (common kinds)
Instance method — operates on an object (uses
this).Static method — belongs to the class, not an instance.
Abstract method — declared in abstract class (no body).
Default & static methods in interfaces (Java 8+).
Private methods in interfaces (Java 9+).
Synchronized method — acquires a lock when executing.
Native method — implemented in other language (C/C++) using JNI.
Final method — cannot be overridden.
Declaration examples (various kinds)
public class Example {
// instance
public int square(int x) { return x*x; }
// static
public static void log(String s) { System.out.println(s); }
// synchronized
public synchronized void increment() { /* thread-safe */ }
// final
public final void cannotOverride() { }
// abstract (in abstract class)
public abstract void doWork();
// native
public native long getNativeTime();
// varargs
public int sum(int... nums) { /* treat nums as int[] */ return 0; }
}
Parameters — call-by-value (important!)
Java is always pass-by-value:
For primitive parameters (e.g.,
int) the actual primitive value is copied.For object references, the reference is copied (so both caller and method refer to the same object), but the reference itself is passed by value — reassigning that parameter inside the method does not change the caller’s reference.
Examples:
void modifyInt(int x) { x = 10; } // caller unchanged
void modifyPerson(Person p) { p.name = "X"; } // caller's object's field changes
void reassignPerson(Person p) { p = new Person("Y"); } // caller's ref unchanged
Swap example that fails for primitives:
void swap(int a, int b) { int t=a; a=b; b=t; } // doesn't swap caller ints
But you can swap wrapped values by mutating object fields.
Varargs
Syntax Type... name (treated as array)
public void printAll(String... items) {
for (String s : items) System.out.println(s);
}
Return types and signatures
The method signature in Java (for overloading) is method name + parameter types. Return type is NOT part of the signature. So you cannot overload by only changing return type.
Overriding requires same signature (name + param types); return type can be covariant (a subtype of the parent's return type).
Example — invalid (compiler error):
int foo() { ... }
long foo() { ... } // ERROR: duplicate method foo()
Covariant return example — valid:
class A { Number get() { ... } }
class B extends A { @Override Integer get() { ... } } // OK
Overloading vs Overriding
Overloading: multiple methods in same class (or subclass) with same name but different parameter lists.
Overriding: subclass provides new implementation for inherited method with same signature.
Overloading resolution (compile-time) considers types, boxing, widening and varargs — it can be subtle and sometimes ambiguous.
Example of overriding (polymorphism / dynamic dispatch):
class Animal { void speak() { System.out.println(".."); } }
class Dog extends Animal { @Override void speak() { System.out.println("woof"); } }
Animal a = new Dog();
a.speak(); // prints "woof" — runtime dispatch to Dog.speak()
Notes:
privateandstaticmethods are not polymorphic — they cannot be overridden (static methods are hidden).Overriding method cannot reduce visibility (
public->privateis illegal).Checked-exception rule: overriding method cannot throw broader checked exceptions.
Exceptions in method signature
- Use
throwsfor checked exceptions.
public void read() throws IOException { /* may throw */ }
throwactually throws an exception instance inside the method.Overriding rule: subclass method can't declare new checked exceptions not declared in the parent (unless they are subclasses).
Constructors vs Methods
Constructors have no return type and must match class name. They initialize objects.
Constructors are invoked using
newand are not inherited; they useinvokespecialat JVM level.
The main method
Java program entry point:
public static void main(String[] args) { /* ... */ }
// or
public static void main(String... args) { /* ... */ }
The JVM looks for public static void main(String[]). If not present (or signature differs), you get NoSuchMethodError when launching.
Generics & generic methods
You can declare methods with their own type parameters:
public static <T> T pickFirst(T[] arr) { return arr.length>0 ? arr[0] : null; }
Lambdas & method references (Java 8+)
Lambdas implement a functional interface (single abstract method).
List<String> l = List.of("a","b");
l.sort(String::compareToIgnoreCase); // method reference
Consumer<String> c = s -> System.out.println(s); // lambda
Supplier<Date> sd = Date::new; // constructor reference
Reflection & invoking methods at runtime
You can discover and invoke methods using java.lang.reflect.Method:
Method m = MyClass.class.getMethod("greet", String.class);
m.invoke(myInstance, "Alex"); // may throw InvocationTargetException, IllegalAccessException
Reflection can access private methods with setAccessible(true) (subject to security/module rules).
JVM-level details (brief, but important)
The JVM stores methods as
method_infostructures in the class file. Each has a descriptor describing parameter and return types: e.g.(ILjava/lang/String;)Vmeans(int, String)->void.Invocation bytecodes:
invokestatic— static methodsinvokevirtual— most instance method calls (virtual dispatch)invokeinterface— interface method callsinvokespecial— private, constructors,supercallsinvokedynamic— used for lambdas and dynamic call sites (bootstrap mechanism)
Method call creates a stack frame: local variables and operand stack. Recursion uses frames; deep recursion →
StackOverflowError.The JVM imposes a limit on method code size: the
Codeattribute of a method in a class file must be ≤ 65535 bytes. (If your method exceeds that, you must split it.)The compiler sometimes emits bridge methods (synthetic methods) to support generics/covariant returns and maintain binary compatibility after type erasure.
The JIT compiler can inline frequently used small methods for performance;
final/privatemake inlining easier but JVM does aggressive optimizations anyway.
Concurrency-related method behavior
synchronizedmethod locksthisfor instance methods, or theClassobject forstatic synchronizedmethods.Consider locking granularity — synchronized on smaller objects when possible.
Use
java.util.concurrent.locks.Lockfor more flexible behavior.
Annotations on methods
You can annotate methods: @Override, @Deprecated, custom annotations, @SafeVarargs (for varargs + generics), etc. Retention policy determines runtime visibility.
Common pitfalls & gotchas
Return type not part of signature — can't overload only by return type.
Calling instance method on
null=>NullPointerException:MyClass x = null; x.instanceMethod(); // NPE at runtimeYou can call a static method through a null reference (compiles), but it's strongly discouraged:
MyClass m = null; m.staticMethod(); // works — resolved as MyClass.staticMethod()Overloading ambiguity with autoboxing and varargs:
void f(int x) {} void f(Integer x) {} // ambiguous if you pass nullRecursion without base-case →
StackOverflowError.Large methods: hard to read and may exceed bytecode size limit; split into smaller methods.
Exposure of internals: returning internal mutable objects exposes state.
Best practices
Keep methods small and single-purpose (SRP).
Use clear verb-based names:
calculateTax,isEmpty,loadFromFile.Prefer immutability / avoid side effects when possible.
Validate parameters early (
Objects.requireNonNull).Document behavior, especially for nullability and thread-safety.
Prefer
Optional<T>for "no value" result when appropriate (API choice).Use interfaces and default methods for evolving APIs carefully.
Use
finalfor parameters and methods where it improves clarity.
Quick cheat-sheet (summary)
Signature =
name + parameter types(not return)Invocation opcodes:
invokestatic— staticinvokevirtual— normal instance (virtual dispatch)invokeinterface— interface methodsinvokespecial— private/constructors/superinvokedynamic— lambdas/dynamic
Pass-by-value always — object references are copied, not the object
Overloading resolved at compile time; overriding resolved at runtime
JVM method code size ≤ 65535 bytes
Covariant returns allowed for overriding
Overriding cannot reduce visibility, cannot add broader checked exceptions
Practical examples (short)
Overloading:
void print(Integer i) { System.out.println("Integer"); }
void print(int i) { System.out.println("int"); }
print(5); // prints "int"
print(null); // compile-time error: ambiguous between Integer and int? (null matches reference type)
Overriding & exceptions:
class Parent { void m() throws IOException {} }
class Child extends Parent {
@Override
void m() throws FileNotFoundException { } // OK: narrower checked exception
}
Reflection:
import java.lang.reflect.*;
Method m = String.class.getMethod("toUpperCase");
String s = (String) m.invoke("hello"); // returns "HELLO"
Lambda & method ref:
List<String> names = List.of("bob","Ann");
names.sort(String::compareToIgnoreCase);
Runnable r = () -> System.out.println("hi");
🔹 What is a Constructor?
A constructor in Java is a special method-like block used to initialize objects when they are created using the new keyword.
Key differences from methods:
Same name as the class.
No return type (not even
void).Automatically called by JVM when an object is created.
Purpose: set initial state of an object.
🔹 Why do we need Constructors?
To provide default values to object fields.
To allow different ways of initializing objects (overloading constructors).
To enforce rules/validation at the time of object creation.
To hide object creation logic (with
privateconstructors in Singleton / Factory pattern).
🔹 How to declare and use a Constructor
class Car {
String brand;
int speed;
// Constructor
Car(String b, int s) {
brand = b;
speed = s;
}
}
public class Main {
public static void main(String[] args) {
Car c = new Car("Tesla", 100); // Constructor called here
System.out.println(c.brand + " runs at " + c.speed);
}
}
Output:
Tesla runs at 100
🔹 Types of Constructors
1. Default constructor (no-arg, provided by compiler if none exists)
class Bike {
Bike() { // default constructor
System.out.println("Bike is created");
}
}
If no constructor is written, Java creates a hidden default constructor:
Bike() { super(); }
2. No-arg constructor (explicitly written by programmer)
class Bike {
Bike() {
System.out.println("Custom no-arg constructor");
}
}
3. Parameterized constructor
class Student {
String name;
int age;
Student(String n, int a) {
name = n;
age = a;
}
}
4. Constructor overloading
Multiple constructors in the same class with different parameter lists.
class Person {
String name;
int age;
Person() { name = "Unknown"; age = 0; }
Person(String n) { name = n; age = 18; }
Person(String n, int a) { name = n; age = a; }
}
5. Copy constructor (Java doesn’t provide it, but you can write one)
class Point {
int x, y;
Point(int a, int b) { x=a; y=b; }
Point(Point p) { x = p.x; y = p.y; } // copy constructor
}
6. Private constructor
- Used in Singleton pattern or Factory methods.
class Singleton {
private static Singleton instance;
private Singleton() {} // private constructor
public static Singleton getInstance() {
if (instance == null) instance = new Singleton();
return instance;
}
}
🔹 Rules about Constructors
Name must match class name.
Cannot have return type (not even
void).Can have modifiers:
public,protected,private,default.Can call another constructor using
this(...).First line of a constructor must be:
this(...)(to call another constructor of the same class), orsuper(...)(to call parent constructor).
If not written, compiler insertssuper();automatically.
Constructors are not inherited.
Can be overloaded but not overridden.
Can throw exceptions.
class Test {
Test() throws IOException { /* ... */ }
}
🔹 Constructor Chaining
Within the same class — use this()
class A {
A() {
this(10); // calls parameterized constructor
System.out.println("Default constructor");
}
A(int x) {
System.out.println("Parameterized constructor: " + x);
}
}
With parent class — use super()
class Parent {
Parent() { System.out.println("Parent constructor"); }
}
class Child extends Parent {
Child() {
super(); // calls Parent constructor
System.out.println("Child constructor");
}
}
🔹 Constructor vs Method
| Feature | Constructor | Method |
| Name | Same as class | Any name (identifier rules) |
| Return type | None (not even void) | Must have return type |
| Called by | JVM automatically via new | Explicitly by user |
| Purpose | Initialize object | Define object behavior |
| Inheritance | Not inherited | Inherited |
| Overloading | Allowed | Allowed |
| Overriding | Not allowed | Allowed |
🔹 JVM-level Details
When you call
new Car(), the JVM does:Allocate memory for object on heap.
Initialize fields with default values (
0,null,false).Call the constructor (using
invokespecialbytecode).Return the reference to the object.
Every constructor must call a parent constructor (
super()), directly or indirectly.If no constructor exists in parent, compiler inserts
super()call toObject().
🔹 Common Pitfalls
Forgetting to initialize fields (constructor should set them).
Using heavy logic inside constructors (bad practice → slow object creation).
Recursive constructor calls → compilation error.
class A { A() { this(); } // ERROR: recursive constructor invocation }Private constructor without factory → object creation impossible.
Not handling exceptions properly in constructor.
Thinking constructors are methods — they are not.
🔹 Best Practices
Keep constructors simple (only initialization).
Use constructor overloading for flexibility.
If many parameters → prefer Builder pattern.
Use
this(...)andsuper(...)wisely to avoid duplicate code.Use immutability: make fields
finaland initialize in constructor.Use
@ConstructorPropertiesfor frameworks (Spring, Jackson, etc.).
🔹 Example (Complete)
class Employee {
String name;
int id;
// default constructor
Employee() {
this("Unknown", 0); // calls parameterized constructor
}
// parameterized constructor
Employee(String n, int i) {
name = n;
id = i;
}
// copy constructor
Employee(Employee e) {
this.name = e.name;
this.id = e.id;
}
void display() {
System.out.println("Employee: " + name + " (" + id + ")");
}
}
public class Main {
public static void main(String[] args) {
Employee e1 = new Employee(); // default
Employee e2 = new Employee("Alice", 101); // parameterized
Employee e3 = new Employee(e2); // copy
e1.display();
e2.display();
e3.display();
}
}
Output:
Employee: Unknown (0)
Employee: Alice (101)
Employee: Alice (101)
✅ So, in short:
A constructor is a special method-like block used to initialize an object’s state when created. It can be default, parameterized, overloaded, private, or copy. JVM ensures one constructor in the inheritance chain is always called.
What is a method?
A method in Java is a named block of code that performs a task (computes a value, updates state, does I/O). Methods are the building blocks of behavior in classes and interfaces.
Think of a method as “a function attached to a type” (object-oriented).
A method has:
Modifiers (public, private, static, final, abstract, synchronized, native, etc.)
Return type (can be any type or
void)Name
Parameter list (zero or more parameters)
throwsclause (optional checked exceptions it may throw)Body
{ ... }(except abstract methods, which have no body)
Why methods?
Reuse code (DRY)
Encapsulate behavior & hide implementation
Organize program logic into small understandable units
Enable polymorphism (different implementations in subclasses)
Allow separation of interface (what) and implementation (how)
How to declare & call a method — basic syntax
// instance method
public int add(int a, int b) {
return a + b;
}
// static method
public static void greet(String name) {
System.out.println("Hello, " + name);
}
Call:
MyClass obj = new MyClass();
int sum = obj.add(2,3); // instance call
MyClass.greet("Sam"); // static call
Method components explained
Access modifiers:
public,protected, (package-private default),private.Non-access modifiers:
static,final,abstract,synchronized,native,strictfp.Return type: type or
void.Name: must be a valid identifier.
Parameters: typed
(Type name, ...).Throws:
throws IOException.Body: code block.
abstractmethods omit body.
Types of methods (common kinds)
Instance method — operates on an object (uses
this).Static method — belongs to the class, not an instance.
Abstract method — declared in abstract class (no body).
Default & static methods in interfaces (Java 8+).
Private methods in interfaces (Java 9+).
Synchronized method — acquires a lock when executing.
Native method — implemented in other language (C/C++) using JNI.
Final method — cannot be overridden.
Declaration examples (various kinds)
public class Example {
// instance
public int square(int x) { return x*x; }
// static
public static void log(String s) { System.out.println(s); }
// synchronized
public synchronized void increment() { /* thread-safe */ }
// final
public final void cannotOverride() { }
// abstract (in abstract class)
public abstract void doWork();
// native
public native long getNativeTime();
// varargs
public int sum(int... nums) { /* treat nums as int[] */ return 0; }
}
Parameters — call-by-value (important!)
Java is always pass-by-value:
For primitive parameters (e.g.,
int) the actual primitive value is copied.For object references, the reference is copied (so both caller and method refer to the same object), but the reference itself is passed by value — reassigning that parameter inside the method does not change the caller’s reference.
Examples:
void modifyInt(int x) { x = 10; } // caller unchanged
void modifyPerson(Person p) { p.name = "X"; } // caller's object's field changes
void reassignPerson(Person p) { p = new Person("Y"); } // caller's ref unchanged
Swap example that fails for primitives:
void swap(int a, int b) { int t=a; a=b; b=t; } // doesn't swap caller ints
But you can swap wrapped values by mutating object fields.
Varargs
Syntax Type... name (treated as array)
public void printAll(String... items) {
for (String s : items) System.out.println(s);
}
Return types and signatures
The method signature in Java (for overloading) is method name + parameter types. Return type is NOT part of the signature. So you cannot overload by only changing return type.
Overriding requires same signature (name + param types); return type can be covariant (a subtype of the parent's return type).
Example — invalid (compiler error):
int foo() { ... }
long foo() { ... } // ERROR: duplicate method foo()
Covariant return example — valid:
class A { Number get() { ... } }
class B extends A { @Override Integer get() { ... } } // OK
Overloading vs Overriding
Overloading: multiple methods in same class (or subclass) with same name but different parameter lists.
Overriding: subclass provides new implementation for inherited method with same signature.
Overloading resolution (compile-time) considers types, boxing, widening and varargs — it can be subtle and sometimes ambiguous.
Example of overriding (polymorphism / dynamic dispatch):
class Animal { void speak() { System.out.println(".."); } }
class Dog extends Animal { @Override void speak() { System.out.println("woof"); } }
Animal a = new Dog();
a.speak(); // prints "woof" — runtime dispatch to Dog.speak()
Notes:
privateandstaticmethods are not polymorphic — they cannot be overridden (static methods are hidden).Overriding method cannot reduce visibility (
public->privateis illegal).Checked-exception rule: overriding method cannot throw broader checked exceptions.
Exceptions in method signature
- Use
throwsfor checked exceptions.
public void read() throws IOException { /* may throw */ }
throwactually throws an exception instance inside the method.Overriding rule: subclass method can't declare new checked exceptions not declared in the parent (unless they are subclasses).
Constructors vs Methods
Constructors have no return type and must match class name. They initialize objects.
Constructors are invoked using
newand are not inherited; they useinvokespecialat JVM level.
The main method
Java program entry point:
public static void main(String[] args) { /* ... */ }
// or
public static void main(String... args) { /* ... */ }
The JVM looks for public static void main(String[]). If not present (or signature differs), you get NoSuchMethodError when launching.
Generics & generic methods
You can declare methods with their own type parameters:
public static <T> T pickFirst(T[] arr) { return arr.length>0 ? arr[0] : null; }
Lambdas & method references (Java 8+)
Lambdas implement a functional interface (single abstract method).
List<String> l = List.of("a","b");
l.sort(String::compareToIgnoreCase); // method reference
Consumer<String> c = s -> System.out.println(s); // lambda
Supplier<Date> sd = Date::new; // constructor reference
Reflection & invoking methods at runtime
You can discover and invoke methods using java.lang.reflect.Method:
Method m = MyClass.class.getMethod("greet", String.class);
m.invoke(myInstance, "Alex"); // may throw InvocationTargetException, IllegalAccessException
Reflection can access private methods with setAccessible(true) (subject to security/module rules).
JVM-level details (brief, but important)
The JVM stores methods as
method_infostructures in the class file. Each has a descriptor describing parameter and return types: e.g.(ILjava/lang/String;)Vmeans(int, String)->void.Invocation bytecodes:
invokestatic— static methodsinvokevirtual— most instance method calls (virtual dispatch)invokeinterface— interface method callsinvokespecial— private, constructors,supercallsinvokedynamic— used for lambdas and dynamic call sites (bootstrap mechanism)
Method call creates a stack frame: local variables and operand stack. Recursion uses frames; deep recursion →
StackOverflowError.The JVM imposes a limit on method code size: the
Codeattribute of a method in a class file must be ≤ 65535 bytes. (If your method exceeds that, you must split it.)The compiler sometimes emits bridge methods (synthetic methods) to support generics/covariant returns and maintain binary compatibility after type erasure.
The JIT compiler can inline frequently used small methods for performance;
final/privatemake inlining easier but JVM does aggressive optimizations anyway.
Concurrency-related method behavior
synchronizedmethod locksthisfor instance methods, or theClassobject forstatic synchronizedmethods.Consider locking granularity — synchronized on smaller objects when possible.
Use
java.util.concurrent.locks.Lockfor more flexible behavior.
Annotations on methods
You can annotate methods: @Override, @Deprecated, custom annotations, @SafeVarargs (for varargs + generics), etc. Retention policy determines runtime visibility.
Common pitfalls & gotchas
Return type not part of signature — can't overload only by return type.
Calling instance method on
null=>NullPointerException:MyClass x = null; x.instanceMethod(); // NPE at runtimeYou can call a static method through a null reference (compiles), but it's strongly discouraged:
MyClass m = null; m.staticMethod(); // works — resolved as MyClass.staticMethod()Overloading ambiguity with autoboxing and varargs:
void f(int x) {} void f(Integer x) {} // ambiguous if you pass nullRecursion without base-case →
StackOverflowError.Large methods: hard to read and may exceed bytecode size limit; split into smaller methods.
Exposure of internals: returning internal mutable objects exposes state.
Best practices
Keep methods small and single-purpose (SRP).
Use clear verb-based names:
calculateTax,isEmpty,loadFromFile.Prefer immutability / avoid side effects when possible.
Validate parameters early (
Objects.requireNonNull).Document behavior, especially for nullability and thread-safety.
Prefer
Optional<T>for "no value" result when appropriate (API choice).Use interfaces and default methods for evolving APIs carefully.
Use
finalfor parameters and methods where it improves clarity.
Quick cheat-sheet (summary)
Signature =
name + parameter types(not return)Invocation opcodes:
invokestatic— staticinvokevirtual— normal instance (virtual dispatch)invokeinterface— interface methodsinvokespecial— private/constructors/superinvokedynamic— lambdas/dynamic
Pass-by-value always — object references are copied, not the object
Overloading resolved at compile time; overriding resolved at runtime
JVM method code size ≤ 65535 bytes
Covariant returns allowed for overriding
Overriding cannot reduce visibility, cannot add broader checked exceptions
Practical examples (short)
Overloading:
void print(Integer i) { System.out.println("Integer"); }
void print(int i) { System.out.println("int"); }
print(5); // prints "int"
print(null); // compile-time error: ambiguous between Integer and int? (null matches reference type)
Overriding & exceptions:
class Parent { void m() throws IOException {} }
class Child extends Parent {
@Override
void m() throws FileNotFoundException { } // OK: narrower checked exception
}
Reflection:
import java.lang.reflect.*;
Method m = String.class.getMethod("toUpperCase");
String s = (String) m.invoke("hello"); // returns "HELLO"
Lambda & method ref:
List<String> names = List.of("bob","Ann");
names.sort(String::compareToIgnoreCase);
Runnable r = () -> System.out.println("hi");
This is extensive but not absolutely exhaustive (there are JVM implementation details, compiler flags, and historical corner-cases I didn’t expand into pages of bytecode). If you want I can:
give a printable one-page cheat-sheet,
provide interactive examples / exercises,
show how the JVM compiles a method to bytecode and explain the
method_infoentries,or deep-dive into method invocation bytecode and JIT inlining behavior with examples.
Which of those next would be most useful to you?
You said:
What is constuctor also give indetails
ChatGPT said:
Perfect — let’s go in detail about Constructors in Java (same as I did for methods).
I’ll cover what, why, how, when, types, rules, JVM-level details, pitfalls, and best practices with examples.
🔹 What is a Constructor?
A constructor in Java is a special method-like block used to initialize objects when they are created using the new keyword.
Key differences from methods:
Same name as the class.
No return type (not even
void).Automatically called by JVM when an object is created.
Purpose: set initial state of an object.
🔹 Why do we need Constructors?
To provide default values to object fields.
To allow different ways of initializing objects (overloading constructors).
To enforce rules/validation at the time of object creation.
To hide object creation logic (with
privateconstructors in Singleton / Factory pattern).
🔹 How to declare and use a Constructor
class Car {
String brand;
int speed;
// Constructor
Car(String b, int s) {
brand = b;
speed = s;
}
}
public class Main {
public static void main(String[] args) {
Car c = new Car("Tesla", 100); // Constructor called here
System.out.println(c.brand + " runs at " + c.speed);
}
}
Output:
Tesla runs at 100
🔹 Types of Constructors
1. Default constructor (no-arg, provided by compiler if none exists)
class Bike {
Bike() { // default constructor
System.out.println("Bike is created");
}
}
If no constructor is written, Java creates a hidden default constructor:
Bike() { super(); }
2. No-arg constructor (explicitly written by programmer)
class Bike {
Bike() {
System.out.println("Custom no-arg constructor");
}
}
3. Parameterized constructor
class Student {
String name;
int age;
Student(String n, int a) {
name = n;
age = a;
}
}
4. Constructor overloading
Multiple constructors in the same class with different parameter lists.
class Person {
String name;
int age;
Person() { name = "Unknown"; age = 0; }
Person(String n) { name = n; age = 18; }
Person(String n, int a) { name = n; age = a; }
}
5. Copy constructor (Java doesn’t provide it, but you can write one)
class Point {
int x, y;
Point(int a, int b) { x=a; y=b; }
Point(Point p) { x = p.x; y = p.y; } // copy constructor
}
6. Private constructor
- Used in Singleton pattern or Factory methods.
class Singleton {
private static Singleton instance;
private Singleton() {} // private constructor
public static Singleton getInstance() {
if (instance == null) instance = new Singleton();
return instance;
}
}
🔹 Rules about Constructors
Name must match class name.
Cannot have return type (not even
void).Can have modifiers:
public,protected,private,default.Can call another constructor using
this(...).First line of a constructor must be:
this(...)(to call another constructor of the same class), orsuper(...)(to call parent constructor).
If not written, compiler insertssuper();automatically.
Constructors are not inherited.
Can be overloaded but not overridden.
Can throw exceptions.
class Test {
Test() throws IOException { /* ... */ }
}
🔹 Constructor Chaining
Within the same class — use this()
class A {
A() {
this(10); // calls parameterized constructor
System.out.println("Default constructor");
}
A(int x) {
System.out.println("Parameterized constructor: " + x);
}
}
With parent class — use super()
class Parent {
Parent() { System.out.println("Parent constructor"); }
}
class Child extends Parent {
Child() {
super(); // calls Parent constructor
System.out.println("Child constructor");
}
}
🔹 Constructor vs Method
| Feature | Constructor | Method |
| Name | Same as class | Any name (identifier rules) |
| Return type | None (not even void) | Must have return type |
| Called by | JVM automatically via new | Explicitly by user |
| Purpose | Initialize object | Define object behavior |
| Inheritance | Not inherited | Inherited |
| Overloading | Allowed | Allowed |
| Overriding | Not allowed | Allowed |
🔹 JVM-level Details
When you call
new Car(), the JVM does:Allocate memory for object on heap.
Initialize fields with default values (
0,null,false).Call the constructor (using
invokespecialbytecode).Return the reference to the object.
Every constructor must call a parent constructor (
super()), directly or indirectly.If no constructor exists in parent, compiler inserts
super()call toObject().
🔹 Common Pitfalls
Forgetting to initialize fields (constructor should set them).
Using heavy logic inside constructors (bad practice → slow object creation).
Recursive constructor calls → compilation error.
class A { A() { this(); } // ERROR: recursive constructor invocation }Private constructor without factory → object creation impossible.
Not handling exceptions properly in constructor.
Thinking constructors are methods — they are not.
🔹 Best Practices
Keep constructors simple (only initialization).
Use constructor overloading for flexibility.
If many parameters → prefer Builder pattern.
Use
this(...)andsuper(...)wisely to avoid duplicate code.Use immutability: make fields
finaland initialize in constructor.Use
@ConstructorPropertiesfor frameworks (Spring, Jackson, etc.).
🔹 Example (Complete)
class Employee {
String name;
int id;
// default constructor
Employee() {
this("Unknown", 0); // calls parameterized constructor
}
// parameterized constructor
Employee(String n, int i) {
name = n;
id = i;
}
// copy constructor
Employee(Employee e) {
this.name = e.name;
this.id = e.id;
}
void display() {
System.out.println("Employee: " + name + " (" + id + ")");
}
}
public class Main {
public static void main(String[] args) {
Employee e1 = new Employee(); // default
Employee e2 = new Employee("Alice", 101); // parameterized
Employee e3 = new Employee(e2); // copy
e1.display();
e2.display();
e3.display();
}
}
Output:
Employee: Unknown (0)
Employee: Alice (101)
Employee: Alice (101)
✅ So, in short:
A constructor is a special method-like block used to initialize an object’s state when created. It can be default, parameterized, overloaded, private, or copy. JVM ensures one constructor in the inheritance chain is always called.
Do you want me to also give you a side-by-side comparison of constructor invocation vs method invocation at JVM bytecode level (like invokespecial vs invokevirtual)? That’s a deeper dive into how the JVM actually executes constructors.
You said:
What is block in details
ChatGPT said:
Great question 👍 Let’s go in detail about Blocks in Java.
(Blocks are often overlooked, but they’re very important for scope, initialization, and readability.)
🔹 What is a Block?
A block in Java is a group of zero or more statements enclosed in curly braces { }.
It defines a scope (lifetime and visibility of variables) and can also be used to initialize data.
🔹 Types of Blocks in Java
There are mainly 4 kinds of blocks:
1. Normal (Local) Block
A block inside a method, loop, or control statement.
Used to limit variable scope and improve readability.
class Test {
public static void main(String[] args) {
{ // local block
int x = 10;
System.out.println("Inside block: " + x);
}
// System.out.println(x); ❌ Error: x not visible here
}
}
✅ Use-case: free memory sooner by limiting variable scope.
2. Instance Initialization Block (IIB)
Declared inside a class but outside any method/constructor.
Runs every time an object is created, before the constructor.
Executed after field initializers and before constructor body.
class Example {
int x;
// Instance Initialization Block
{
x = 100;
System.out.println("Instance block executed");
}
Example() {
System.out.println("Constructor executed");
}
}
public class Main {
public static void main(String[] args) {
new Example();
new Example();
}
}
Output:
Instance block executed
Constructor executed
Instance block executed
Constructor executed
✅ Use-case: shared initialization code among multiple constructors.
3. Static Initialization Block (SIB)
Declared with
static { }.Runs only once when the class is loaded into memory (by JVM).
Used to initialize static variables or perform one-time setup.
class Demo {
static int count;
static {
count = 10;
System.out.println("Static block executed");
}
public static void main(String[] args) {
System.out.println("Main executed");
System.out.println("Count = " + count);
}
}
Output:
Static block executed
Main executed
Count = 10
✅ Use-case:
Load configuration (DB connections, files).
Initialize static variables.
Logging setup.
4. Synchronized Block
A block of code inside a method synchronized using an object lock.
Used for thread-safety (only one thread executes the block at a time for that object).
class Counter {
private int count = 0;
public void increment() {
synchronized(this) { // lock on 'this'
count++;
}
}
public int getCount() { return count; }
}
✅ Use-case: critical sections in multi-threaded programs.
🔹 Execution Order of Blocks
For a class with static block, instance block, and constructor, the order is:
Static block (runs once, when class is loaded)
Instance block (runs every time before constructor)
Constructor
Example:
class Order {
static { System.out.println("1. Static block"); }
{ System.out.println("2. Instance block"); }
Order() { System.out.println("3. Constructor"); }
}
public class Main {
public static void main(String[] args) {
new Order();
new Order();
}
}
Output:
1. Static block
2. Instance block
3. Constructor
2. Instance block
3. Constructor
🔹 Nested Blocks
Blocks can be nested within each other, creating scopes inside scopes:
class Nested {
public static void main(String[] args) {
int a = 10;
{
int b = 20;
{
int c = 30;
System.out.println(a + b + c);
}
// c not visible here
}
// b not visible here
}
}
🔹 Anonymous Block (inside objects)
You can also write anonymous inner classes with blocks:
Runnable r = new Runnable() {
{ System.out.println("Anonymous block in anonymous class"); }
public void run() { System.out.println("Run method"); }
};
r.run();
🔹 Special Notes
Multiple static blocks are allowed, executed top-to-bottom when class loads.
Multiple instance blocks are allowed, executed top-to-bottom before constructor.
A static block cannot access non-static members (no object yet).
An instance block can access both static and instance members.
A synchronized block can lock on
this, a class object (ClassName.class), or any custom object.
🔹 Block vs Method vs Constructor
| Feature | Block (Normal/IIB/SIB) | Constructor | Method |
| Name | No name | Same as class | Any valid identifier |
| Return type | No | No | Yes (or void) |
| Execution | Auto by JVM (based on type) | Auto by new keyword | Manual (explicit call) |
| Purpose | Scope, init, sync, control | Object initialization | Object behavior definition |
| Overloading | No | Yes | Yes |
| Overriding | No | No | Yes |
🔹 Best Practices
Use normal/local blocks only to reduce variable scope.
Use instance blocks sparingly; constructors are usually clearer.
Use static blocks for complex static initialization only.
Use synchronized blocks instead of whole methods if you want fine-grained locking.
Keep blocks small and readable.
✅ Quick Summary
Block = code inside
{}.Normal/local block → limit scope.
Instance block (IIB) → runs before constructor for each object.
Static block (SIB) → runs once when class loads.
Synchronized block → thread-safety.
Execution order: Static block → Instance block → Constructor.
🔹 Execution Flow (when we create an object)
Class Loading Phase
Static variables → initialized with default values.
Static Block(s) executed (once per class load).
Object Creation Phase (
newkeyword)Instance variables → initialized with default values.
Instance variable initializers (explicit assignments).
Instance Block(s) executed (top-to-bottom).
Constructor executed.
🔹 Diagram
┌─────────────────────┐
│ Class Loaded │
│ (by JVM, once) │
└─────────┬───────────┘
│
┌─────────▼───────────┐
│ Static Block(s) │ (only once)
└─────────┬───────────┘
│
▼
┌─────────────────────┐
│ new Object() │
└─────────┬───────────┘
│
┌─────────▼───────────┐
│ Instance Vars = 0 │ (default values)
└─────────┬───────────┘
│
┌─────────▼───────────┐
│ Instance Initializer │ (field assignments)
└─────────┬───────────┘
│
┌─────────▼───────────┐
│ Instance Block(s) │ (every time)
└─────────┬───────────┘
│
┌─────────▼───────────┐
│ Constructor │
└─────────────────────┘
🔹 Example Code to Match Flow
class Order {
static { System.out.println("1. Static block"); }
{ System.out.println("2. Instance block"); }
Order() { System.out.println("3. Constructor"); }
}
public class Main {
public static void main(String[] args) {
new Order();
new Order();
}
}
🔹 Output
1. Static block
2. Instance block
3. Constructor
2. Instance block
3. Constructor
✅ In short:
Static block → runs once (class loading).
Instance block → runs every object creation (before constructor).
Constructor → runs last, after instance blocks.
🔹 What is OOPS?
Object-Oriented Programming System (OOPS) is a programming paradigm based on the concept of objects.
Objects = entities that combine state (data/fields) and behavior (methods).
In Java, everything (except primitives) is an object.
OOP helps structure software around real-world models.
🔹 Why OOPS?
Models real-world entities (Car, Student, BankAccount).
Encapsulation of data → hides implementation.
Reuse through inheritance → reduces code duplication.
Polymorphism → flexible, extensible behavior.
Abstraction → focus on what, not how.
Maintainability & scalability for large projects.
🔹 4 Main Pillars of OOP (Core Principles)
1. Encapsulation (Data Hiding)
Wrapping fields + methods together in a class.
Fields often kept
private; accessed via getters/setters.Helps control how data is modified.
class Account {
private double balance;
public void deposit(double amt) {
if (amt > 0) balance += amt;
}
public double getBalance() {
return balance;
}
}
✅ Why: Protects internal state, enforces rules.
2. Inheritance (Code Reuse)
Mechanism to acquire properties and behavior of another class.
extends→ class inheritance,implements→ interface inheritance.
class Animal {
void eat() { System.out.println("Eating"); }
}
class Dog extends Animal {
void bark() { System.out.println("Barking"); }
}
Usage:
Dog d = new Dog();
d.eat(); // inherited
d.bark();
✅ Why: Avoids duplicate code, establishes is-a relationship.
⚠️ Java supports single inheritance of classes, but multiple inheritance via interfaces.
3. Polymorphism (Many Forms)
Two types:
a) Compile-time polymorphism (Method Overloading)
Same method name, different parameter list.
class MathUtil {
int add(int a, int b) { return a+b; }
double add(double a, double b) { return a+b; }
}
b) Runtime polymorphism (Method Overriding / Dynamic Dispatch)
Subclass provides new implementation.
class Animal {
void sound() { System.out.println("Some sound"); }
}
class Dog extends Animal {
@Override void sound() { System.out.println("Woof"); }
}
Animal a = new Dog();
a.sound(); // Woof (decided at runtime)
✅ Why: Flexibility & extensibility.
4. Abstraction (Hiding Implementation)
Hides how things work, only shows what is available.
Achieved via abstract classes & interfaces.
abstract class Shape {
abstract void draw(); // abstract method
}
class Circle extends Shape {
void draw() { System.out.println("Drawing Circle"); }
}
Usage:
Shape s = new Circle();
s.draw(); // abstraction: we don’t care *how* it draws
✅ Why: Focus on essential details, ignore complexity.
🔹 OOPS Features in Java
Class → blueprint for objects.
class Car { String color; void drive() {} }Object → instance of a class.
Car c = new Car();Inheritance →
extends,implements.Polymorphism → Overloading & Overriding.
Abstraction → abstract classes & interfaces.
Encapsulation → data hiding via private + getter/setter.
Association → relationship between classes (HAS-A).
Aggregation (weak HAS-A, independent objects).
Composition (strong HAS-A, dependent objects).
class Engine {}
class Car { Engine e = new Engine(); } // composition
- Message Passing → objects communicate by calling methods.
🔹 Special OOP Concepts in Java
a) Constructors (object initialization)
- Default, parameterized, copy constructors.
b) this keyword
Refers to current object.
Used for disambiguation, constructor chaining.
c) super keyword
Refers to parent class.
Used for parent constructor/method/field access.
d) Method Overloading vs Overriding
Overloading → compile-time (same name, diff params).
Overriding → runtime (same signature, subclass implementation).
e) final keyword
final class→ cannot be extended.final method→ cannot be overridden.final variable→ constant.
f) abstract vs interface
Abstract class → can have both abstract & concrete methods.
Interface → pure abstraction (Java 8+ allows default & static methods).
g) Object Class
Superclass of all classes in Java.
Methods:
toString(),equals(),hashCode(),clone(),finalize().
h) Inner Classes
- Member inner, static nested, local inner, anonymous inner.
🔹 OOPS at JVM Level
Objects → stored in Heap.
References → stored in Stack.
Method calls → handled via:
invokevirtual→ polymorphic instance method calls.invokestatic→ static methods.invokespecial→ constructors, private, super methods.invokeinterface→ interface methods.
Dynamic dispatch (polymorphism) → JVM decides method at runtime by looking at the actual object.
🔹 Pitfalls / Misconceptions
Java doesn’t support multiple inheritance of classes (diamond problem) → use interfaces.
Constructors are not methods (no return type, not inherited).
Overloading ≠ Overriding.
Encapsulation ≠ Abstraction → Encapsulation hides data, Abstraction hides implementation.
Java is not 100% OOP (because of primitives).
🔹 Best Practices in OOP (Java)
Follow SOLID principles:
Single Responsibility Principle
Open/Closed Principle
Liskov Substitution Principle
Interface Segregation Principle
Dependency Inversion Principle
Use composition over inheritance when possible.
Keep fields private and expose through methods.
Keep classes small and cohesive.
Favor interfaces and abstractions for loose coupling.
Avoid deep inheritance chains (hard to maintain).
Use design patterns (Singleton, Factory, Builder, Strategy, Observer).
🔹 Quick Example — OOP in Action
// Abstraction + Inheritance + Polymorphism + Encapsulation
abstract class Shape {
private String color; // encapsulation
Shape(String color) { this.color = color; }
public String getColor() { return color; }
abstract double area(); // abstraction
}
class Circle extends Shape {
private double radius;
Circle(String color, double r) {
super(color); this.radius = r;
}
@Override double area() { return Math.PI * radius * radius; }
}
class Rectangle extends Shape {
private double w, h;
Rectangle(String color, double w, double h) {
super(color); this.w = w; this.h = h;
}
@Override double area() { return w * h; }
}
public class Main {
public static void main(String[] args) {
Shape s1 = new Circle("Red", 5); // polymorphism
Shape s2 = new Rectangle("Blue", 4, 6);
System.out.println(s1.getColor() + " Circle Area: " + s1.area());
System.out.println(s2.getColor() + " Rectangle Area: " + s2.area());
}
}
Output:
Red Circle Area: 78.53981633974483
Blue Rectangle Area: 24.0
✅ In short:
Java OOP = Classes + Objects + 4 Pillars (Encapsulation, Inheritance, Polymorphism, Abstraction) + additional features (association, composition, message passing). It models real-world entities, makes code reusable, scalable, and maintainable.
🔹 OOPS 4 Pillars Diagram
┌─────────────────────────┐
│ OOPS (Java) │
│ Object-Oriented │
│ Programming System │
└───────────┬────────────┘
│
┌───────────────────┼───────────────────┐
│ │ │
▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ Encapsulation │ │ Inheritance │ │ Polymorphism │
│ (Data Hiding) │ │ (Code Reuse) │ │ (Many Forms) │
└───────┬───────┘ └───────┬───────┘ └───────┬───────┘
│ │ │
Private fields + `extends` / a) Compile-time
Getter/Setter `implements` (Overloading)
Example: Example: b) Runtime
Account balance Dog extends (Overriding)
Animal
│ │ │
└─────────────┬─────┴───────────────┐
│ │
▼ ▼
┌────────────────────┐ ┌───────────────┐
│ Abstraction │ │ Others │
│ (Hides Impl.) │ │ Assoc/Comp. │
└────────────────────┘ │ Message Pass │
│ └───────────────┘
Abstract class / Interface
Example: Shape → Circle/Rect
🔹 One-line memory trick
👉 “Encapsulation hides, Inheritance reuses, Polymorphism flexes, Abstraction simplifies.”
🔹 Quick Example Mapping
Encapsulation → private
balanceinAccount.Inheritance →
Dog extends Animal.Polymorphism →
sound()overridden inDog.Abstraction →
Shapeas abstract class, concrete subclasses.
🚗 OOPS Pillars → Car Analogy
┌────────────────────────────┐
│ CAR (Object) │
└───────────┬────────────────┘
│
┌─────────────────────────┼─────────────────────────┐
│ │ │
▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ Encapsulation │ │ Inheritance │ │ Polymorphism │
│ (Hide Engine) │ │ Car IS-A │ │ Drive works │
│ Engine parts │ │ Vehicle │ │ differently │
│ are private │ │ Truck, Bike │ │ Auto vs Manual│
│ but Start() │ │ also extend │ │ Overloading & │
│ is public │ │ Vehicle │ │ Overriding │
└───────────────┘ └───────────────┘ └───────────────┘
│
▼
┌───────────────┐
│ Abstraction │
│ CarInterface │
│ start(), stop()│
│ driver uses it │
│ no idea of impl│
└───────────────┘
🔹 Explanation with Car Example
Encapsulation (Data Hiding)
A car’s engine is hidden inside.
You can’t directly access pistons or fuel injection system.
Instead, you use public methods like
startCar(),accelerate().👉 In Java: private variables + getters/setters.
Inheritance (Code Reuse)
Caris a subclass of Vehicle.Other vehicles like
Truck,Bikealso inheritVehicle.Common features (wheels, fuel, move()) come from
Vehicle.👉 In Java:
class Car extends Vehicle.
Polymorphism (Many Forms)
drive()works differently:Manual Car → gear + clutch.
Automatic Car → no clutch.
start()could be:Key ignition.
Push button.
👉 In Java: Overloading (
start(int key)vsstart(String keyless)) and Overriding (Car.start()vsTruck.start()).
Abstraction (Hiding Implementation)
As a driver, you only know what to do (press accelerator, brake).
You don’t care how engine burns fuel internally.
👉 In Java:
interface Vehicle { void start(); void stop(); }.
🔹 Quick Java Mapping with Car
// Abstraction
interface Vehicle {
void start();
void stop();
}
// Inheritance + Polymorphism
class Car implements Vehicle {
private Engine engine; // Encapsulation
Car() { engine = new Engine(); }
@Override
public void start() {
System.out.println("Car starting with button ignition.");
}
@Override
public void stop() {
System.out.println("Car stopping.");
}
}
class Truck implements Vehicle {
@Override
public void start() {
System.out.println("Truck starting with heavy-duty ignition.");
}
@Override
public void stop() {
System.out.println("Truck stopping with air brakes.");
}
}
// Encapsulated class
class Engine {
private int horsepower = 120;
void ignite() { System.out.println("Engine ignited with " + horsepower + " HP"); }
}
public class Main {
public static void main(String[] args) {
Vehicle v1 = new Car(); // Polymorphism
Vehicle v2 = new Truck();
v1.start(); // Car's implementation
v2.start(); // Truck's implementation
}
}
Output:
Car starting with button ignition.
Truck starting with heavy-duty ignition.
✅ With this Car analogy, you can easily explain OOP in interviews in a way that’s simple, memorable, and practical.