Skip to content

This is my personal notebook for Java concept checks and quick revisions. Whenever I revisit Java, I update or add more content here — it's a growing space where I capture what I’m learning, revising, or preparing for. If you notice any mistakes or have suggestions, feel free to fork the repo and contribute — I’ll happily review and merge !

Notifications You must be signed in to change notification settings

AthiraThulasi/Java-Interview-Notebook

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

25 Commits
 
 

Repository files navigation

Java Concepts Check !

If two interfaces have the same default method and a class implements both, what happens? How can this conflict be resolved?

If two interfaces (A and B) have the same default method and a class implements both, the compiler will throw an error because of ambiguity.

To fix it, the class must override the method !

Inside the override -

(1) we can choose to call a specific interface’s default implementation using InterfaceName.super.method() 

OR 

(2) write our own logic.

interface A {
    default void show() {
        System.out.println("A's show()");
    }
}

interface B {
    default void show() {
        System.out.println("B's show()");
    }
}

class Test implements A, B {
    @Override
    public void show() { // one override method handles both interface defaults.

        // explicitly call A's version
        A.super.show();

        // explicitly call B's version
        B.super.show();

        // custom logic
        System.out.println("Test class's own show()");
    }
}

public class Main {
    public static void main(String[] args) {
        Test t = new Test();
        t.show();
    }
}

Execution flow


A.super.show(); → prints A's show()

B.super.show(); → prints B's show()

System.out.println("Test class's own show()"); → prints Test class's own show()

What is method overloading in Java?

> Method overloading means creating MULTIPLE METHODS with SAME NAME but DIFFERENT PARAMETERS in the SAME CLASS.

> It helps you perform similar actions with different inputs.

> This is also called COMPILE TIME POLYMORPHISM! 

NOTES : > We must write the return type in every method.

      > Java ignores it while checking if two methods are overloaded.
      
      > Overloading depends only on METHOD NAME, NUM OF PARAMETERS, TYPE and ORDER  not on RETURN TYPE.
class Calculator {

    int sum(int a, int b) { // 2 parameters - int
        return a + b;
    }

    int sum(int a, int b, int c) { // 3 parameters - int
        return a + b + c;

    double sum(int a, double b, int c) { int & double
        return a + b + c;
    }
}

If a method involves both int and double parameters, what should the return type be?

When a method involves both int and double parameters, any arithmetic operation between them results in a double value. 

This is because Java automatically promotes the smaller data type (int, 4 bytes) to the larger one (double, 8 bytes) to avoid data loss.

So, the return type should be double.

If we try to return this double result using int as the return type, Java will throw a "possible lossy conversion" error.

That's because an int can only hold whole numbers and has less storage — using it would risk losing the decimal part of the result.

 NOTES: 
 
 > In Java, when we mix different data types (like int and double) > Java automatically promotes the smaller type to the larger one — this is called implicit type casting (or widening).

> But if we try to store a larger type (like double) into a smaller one (like int), we must use explicit type casting, or Java will give a lossy conversion error.   

double sum(int a, double b, int c) {
    return a + b + c; //  correct - result is double
}

int sum(int a, double b, int c) {
    return a + b + c; //  Error: lossy conversion from double to int
}

int sum(int a, double b, int c) {
    return (int)(a + b + c); //  Works if we cast, but decimal is lost

}

What is method overriding and when is it used?

> Method overriding happens when a child class (subclass) gives its own version of a method that already exists in the parent class (superclass) — using the same method name and signature.

> It happens between a parent and child class using inheritance, and is used to achieve runtime polymorphism.

NOTES:

   > Overriding = child redefines the parent method

   > Inheriting = child uses the parent method as-is
class Animal {. // Parent class
    void sound() {
        System.out.println("Animal makes a sound");
    }
}

class Dog extends Animal { // child class
    @Override
    void sound() {
        System.out.println("Dog barks");
    }
}

What is the difference between == and .equals() in Java?

== compares object references (memory addresses)

.equals() compares values (contents)

NOTES:

== compares values for primitives( int, float,double)

== compares memory addresses for objects (String, Integer etc)

.equals() compares content for objects

.equals() does not exist for primitives
// For Non -Primitives

String a = "Java"; // Stored in String Intern Pool
String b = new String("Java"); // Object created in Heap

a == b        //   false → different memory locations
a.equals(b)   //   true  → same content
// For Primitives

int a = 5; // For primitive Types > == compares actual values
int b = 5;  // No .equals() method for primitives

System.out.println(a == b); //  true → because 5 == 5

What is a static variable and a static method? Can static methods be overridden?

 > static variable → belongs to the class, shared across all objects.

    > There is only ONE COPY of it, and it's shared by all instances (objects) of that class.

 > static method → belongs to the class, not tied to objects.

 > Static methods cannot be overridden, only hidden.

 NOTE: Static members are loaded into memory ONLY ONCE 
              — when the class is loaded .
              — and are shared across all objects.


  (Static Members - static variables, methods, blocks, and nested classes)

What is a constructor? Can it be inherited?

> A constructor is a special method with same name as class name!

> Constructors initialize instance variables when an object is created.

> It cannot be inherited, but the subclass can call the superclass constructor using super().

How is memory managed for static vs instance variables?

static variables are stored in the Method Area (or Class Area).

They are loaded once when the class is loaded into memory and are shared across all objects.

instance variables are stored in the heap, and every object gets its own copy.

Can an interface have a constructor?

No, interfaces cannot have constructors.

Because objects can't be created from interfaces directly.

Interfaces are meant to be implemented by classes, and only those classes can define constructors.

What happens if we don't call super() explicitly in a constructor?

If the parent class has only a parameterized constructor and we don’t explicitly call super(args) in the child constructor, Java throws a compile-time error:

Error - constructor Parent in class Parent cannot be applied to given types.

 But if the parent has a no-arg constructor - Java automatically inserts a call to super() in the first line of the child constructor.

 ##  If class B extends class A, and both have a method show(), which one is called when wewrite A obj = new B()?

```java
 class A {
    void show() {
        System.out.println("Show from A");
    }
}

class B extends A {
    void show() {
        System.out.println("Show from B");
    }
}

public class Main {
    public static void main(String[] args) {
        A obj = new B(); // Parent reference, Child object
        obj.show();      // Output: Show from B
    }
}
The reference type is the parent, but the object type is the child.

At compile time: Java checks if the reference type (A) has the method show() -  Yes, it exists → So no compile-time error.

At runtime: Java looks at the actual object (new B()) >> Since B overrides the show() method, Java calls the child class's version.

Even though obj is of type A, the show() method from class B is called — because the actual object is of type B - This is runtime polymorphism (also called dynamic method dispatch).

What are the 4 pillars of OOPS in Java?

(1) Encapsulation (2) Abstraction (3) Inheritance (4) Polymorphism

What is Encapsulation?

Encapsulation protects the instance variables from invalid value assignments, which is achieved through public getter and setter methods by writing the validation logic.

Prevents illegal access or modification of data.
public class Student {
    private String name; // Encapsulated variable

    public void setName(String name) { // setter
        this.name = name;
    }

    public String getName() { // getter
        return name;
    }
}

Difference Between Abstract Class and Interface

|| Feature                | Abstract Class                             | Interface                                            |
| ----------------------- | ------------------------------------------ | ---------------------------------------------------- |
|  Keyword                | `abstract`                                 | interface / implements                               |
|  Object Creation        | Cannot create object                       |  Cannot create object                                |
|  Constructor.           | Can have constructors                      |  Cannot have constructors                            |
|  Methods.               | Can have `abstract` and `concrete` methods | Can have `abstract`, `default`, and `static` methods |
| Inheritance.            | Use `extends`                              | Use `implements`                                     |
| Abstraction Type        | Partial abstraction                        | Full abstraction                                     |
| Inheritance Support     | Single inheritance only.                   | Multiple inheritance via interfaces.                 |

Why abstract class achieve only partial abstraction?

Abstraction = Hiding implementation details and showing only the essential features (the “what”, not the “how”).

An abstract class provides partial abstraction because it can contain both abstract (unimplemented) and concrete (implemented) methods.

What is Partial Abstraction?

It can have - (1) abstract methods (no body) and (2) concrete methods (with body).

That means - some behavior is already defined, and some must be provided by child classes.

So it's partially abstract — not everything is hidden or forced to be implemented
abstract class Vehicle {
    abstract void start(); // no body — abstract

    void fuelType() {      // has body — concrete
        System.out.println("Petrol or Diesel");
    }
}

This is partial abstraction, because:

One method (start()) is abstractchild must override it

One method (fuelType()) is already implemented - So the child class only needs to implement part of the logic.

How Interface achieve full abstraction?

Interface Vehicle {
    void start();      // abstract
    void fuelType();   // abstract

}
This is full abstraction because: There is no implementation at all (before Java 8). 

An interface provides full abstraction (before Java 8) because it only contains method declarations and no implementation.The implementing class must define everything

After Java 8  default and static methods are introduced - Still Interface is considered to provide full abstraction -

The reason is — interface is primarily meant to define only abstract behavior without implementation.

The default and static methods are optional utility methods that do not break the purpose of abstraction.

(1) Unlike abstract classes, interfaces:

(2) Cannot have instance variables

(3) Cannot have constructors

(4) And cannot be instantiated directly.

So while technically it has some implementation now, it still enforces no object creation and no concrete state, which qualifies it as full abstraction in the design sense.

Encapsulation Coding Challenge

Challenge 1 – Bank Account Security

Problem: Create a class BankAccount with:

A private variable balance.

A setter deposit(double amount) → only accept if amount > 0.

A setter withdraw(double amount) → only allow if amount <= balance.

A getter getBalance() → to check balance.

Main Method Goal: Deposit 500, withdraw 200, withdraw 400 → observe validations.
package Encapsulation;

public class BankAccount {

    private double balance;
    
        // Only one private variable is enough
    

        // Deposit method
        public void deposit(double amount) {
            if (amount > 0) {
                balance += amount; // increase balance
                System.out.println("Deposited: " + amount);
            } else {
                System.out.println("Invalid deposit amount!");
            }
        }

        // Withdraw method
        public void withdraw(double amount) {
            if (amount > 0 && amount <= balance) {
                balance -= amount; // decrease balance
                System.out.println("Withdrawn: " + amount);
            } else {
                System.out.println("Insufficient balance!");
            }
        }

        // Getter for balance
        public double getBalance() {
            return balance;
        }
    }

Runner class for deposit and withdrawal!

package Encapsulation;

public class BankAccountRunner {
    public static void main(String[] args){
                BankAccount account = new BankAccount(); // create object

                account.deposit(500);   // Deposit 500
                account.withdraw(200);  // Withdraw 200
                account.withdraw(400);  // Withdraw 400 -> should fail

                System.out.println("Final Balance: " + account.getBalance());
            }
}

TakeAway:

Usually we create getters and setters from our instance variables!

But here in your BankAccount case, depositAmount and withdrawAmount are temporary inputs, not state that belongs to the object.

The real state of the account is just the balance.

deposit(500) → means “add 500 to balance.”

withdraw(200) → means “subtract 200 from balance.”

Since depositAmount and withdrawAmount don’t need to be remembered, WE don’t create them as instance variables.   We just use them as method parameters.

so, We only need one variable: balance, because that’s the actual state of the account.

Encapsulation principle → only keep variables that represent the state of the object.

In short: Balance is state, deposit/withdraw are actions (method parameters), so we don’t store them as separate variables.

Challenge 2 – Read-Only Student Record

Problem:Create a class Student with: Private variables: name, rollNo.

Constructor to initialize them.

Only getters (no setters).

Main Method Goal: Create student object and print details.

Try modifying → should not be allowed.
package Encapsulation;

public class Student {

    private int rollnumber;
    private String name;

    public Student(int rollnumber, String name) {
        this.rollnumber = rollnumber;
        this.name = name;
    }

    public int getRollnumber() {
        return rollnumber;
    }

    public String getName() {
        return name;
    }
}

Student Runner

package Encapsulation;

public class StudentRunner {
    public static void main (String[] args){
        Student s1  = new Student(45,"Athira");


        // Print details
        System.out.println("Roll No: " + s1.getRollnumber());
        System.out.println("Name: " + s1.getName());

        //  Try modifying 
         s1.rollnumber = 100;    
        //java error: rollnumber has private access in Encapsulation.Student
        // s1.name = "New Name";   // ERROR → private variable

        //  No setter available
        // s1.setName("New Name"); // ERROR → no method defined

        // ✅ Values remain unchanged
        System.out.println("After trying modification:");
        System.out.println("Roll No: " + s1.getRollnumber());
        System.out.println("Name: " + s1.getName());
    }

}

Take Away

Setter = lets you modify/change the variable.

Getter = only allows you to read/access the variable.

In our example, we only gave getters and no setters.So:

    We can read the student’s details (via getName(), getRollnumber() 

    We cannot modify them (because no setName() or setRollnumber() 

Which statement is true and Why?

Integer x = 1000; 
Integer y = 1000;
System.out.print(x==y);

Integer a = 100;
Integer b = 100;
System.out.print(a==b);

Explanation

Integer x = 1000; 
Integer y = 1000;

Interger is a wrapper class (Wrapper class is an object representation of primitive type)

Java caches Integer objects only in the range -128 to 127.

Since 1000 is outside that range, new objects are created.

When we write Integer x = 1000; → autoboxing happens.

Java calls Integer.valueOf(1000).

Integer.valueOf() checks the Integer cache (not the general heap) 

- Cache range = -128 to 127.

If the number is inside that range → it returns the same cached object.

If outside → it creates a new Integer object on the heap.

x == y → false
Integer a = 100; 
Integer b = 100;

System.out.print(a == b);

Value 100 is inside the cache range (-128 to 127).

So, a and b point to the same cached object.

a and b themselves (the references) are stored on the stack (as local variables).

The actual Integer object (with value 100) is stored in the heap (cached region).

Both a and b reference the same object.

a == b → true

About

This is my personal notebook for Java concept checks and quick revisions. Whenever I revisit Java, I update or add more content here — it's a growing space where I capture what I’m learning, revising, or preparing for. If you notice any mistakes or have suggestions, feel free to fork the repo and contribute — I’ll happily review and merge !

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published