← Back to list

Core Java Interview Questions Asked in TCS (2026 Complete Guide)

TCS is one of the largest Java employers in India. Here are the exact questions asked across TCS technical rounds — with the answers that…

Vighneshwar Bhat · 2026-04-24 17:26 · 0 claps · 13.2 min read
#java #tcs-hackquest #interview #backend #programming
Open on Medium ↗
Wiki topics: 💻 · Programming 🌐 · Web Development

Core Java Interview Questions Asked in TCS (2026 Complete Guide)

TCS is one of the largest Java employers in India. Here are the exact questions asked across TCS technical rounds — with the answers that get you selected.

TCS (Tata Consultancy Services) conducts one of the most structured interview processes in the Indian IT industry. Every year, thousands of Java developers — freshers and experienced alike — walk into TCS interviews hoping to clear the technical round.

The good news: TCS follows a predictable pattern. The technical interview for Java developers consistently covers the same core topics — OOP concepts, String handling, Collections, Exception Handling, Multithreading, and JDBC. Once you know what they ask and what depth they expect, you can prepare with precision.

This guide is built from actual TCS interview experiences reported by candidates across fresher and 1–3 years experience roles. Every question here has been asked in a TCS technical round. Read it, understand the answers deeply, and walk in confident.

The TCS Interview Process — What to Expect

Before the questions, understand the structure:

Step 1 — TCS NQT (National Qualifier Test): Online aptitude test covering Verbal, Reasoning, Numerical, Programming Logic, and Coding sections. Clearing NQT is the entry point.

Step 2 — Technical Interview (TR): 30–60 minutes. Core Java, Data Structures, DBMS, and project discussion. This is where Java questions are concentrated.

Step 3 — Managerial Round (MR): Situational questions, project depth, team scenarios. Some Java design questions appear here.

Step 4 — HR Round: Salary, relocation, company knowledge.

This guide focuses on the Technical Round — where Java knowledge is tested.

📘 [Java Backend Interview Questions]

It covers 300+ questions across all experience levels, with detailed explanations, common follow-up questions, and the reasoning interviewers are actually looking for.

📘 [Complete Backend Interview Questions]

It covers 1000+ core Java, collections, concurrency, JVM internals, Spring, design patterns, and system design — with the kind of detailed explanations that don’t just help you pass interviews, but make you a better Java developer.

Section 1: OOP Concepts — Always Asked First

TCS interviewers almost always open with OOP. These questions appear in 90%+ of TCS Java interviews.

Q1. What are the four pillars of OOP? Explain each with a real-world example.

This is the most asked opening question in TCS Java interviews. Do not just list the four words — explain each with a concrete example.

Encapsulation — hiding internal data:

Wrapping data (variables) and methods together inside a class and controlling access using access modifiers.

public class BankAccount {
    private double balance; // hidden from outside

    public void deposit(double amount) {
        if (amount > 0) balance += amount;
    }

    public double getBalance() {
        return balance; // controlled access
    }
}
// Nobody can directly access or modify balance — they go through methods

Real-world example: An ATM machine. You interact through buttons (methods). You cannot directly touch the cash vault (private data).

Abstraction — hiding complexity:

Showing only what is necessary, hiding how it works internally.

abstract class Vehicle {
    abstract void start(); // what it does — not how

    public void refuel() {
        System.out.println("Refuelling vehicle");
    }
}

class Car extends Vehicle {
    @Override
    void start() {
        System.out.println("Car starts with key ignition");
    }
}

Real-world example: Driving a car. You know the steering wheel turns the car. You do not know the mechanical steering system inside.

Inheritance — reusing parent class features:

A child class inherits properties and methods from a parent class, reducing code duplication.

class Animal {
    String name;
    void eat() { System.out.println(name + " is eating"); }
}

class Dog extends Animal {
    void bark() { System.out.println(name + " is barking"); }
}

Dog dog = new Dog();
dog.name = "Tommy";
dog.eat();  // inherited from Animal
dog.bark(); // Dog's own method

Polymorphism — one name, many forms:

The same method name behaves differently based on the object or parameters.

Runtime polymorphism (overriding):

class Shape {
    void draw() { System.out.println("Drawing a shape"); }
}
class Circle extends Shape {
    @Override
    void draw() { System.out.println("Drawing a circle"); }
}
class Rectangle extends Shape {
    @Override
    void draw() { System.out.println("Drawing a rectangle"); }
}

Shape s = new Circle();
s.draw(); // "Drawing a circle" — decided at runtime

Compile-time polymorphism (overloading):

class Calculator {
    int add(int a, int b) { return a + b; }
    double add(double a, double b) { return a + b; }
    int add(int a, int b, int c) { return a + b + c; }
}

Q2. What is the difference between method overloading and method overriding?

TCS asks this in almost every interview. Know both the definition and the table.

Method Overloading:

  • Same class, same method name, different parameters
  • Resolved at compile time (static polymorphism)
  • Return type can differ (but not alone)
  • Access modifier can be anything
class MathUtils {
    int multiply(int a, int b) { return a * b; }
    double multiply(double a, double b) { return a * b; }
    int multiply(int a, int b, int c) { return a * b * c; }
}

Method Overriding:

  • Parent-child relationship, same method name, same parameters
  • Resolved at runtime (dynamic polymorphism)
  • Return type must be same or covariant
  • Access modifier cannot be more restrictive than parent
class Parent {
    public void display() { System.out.println("Parent"); }
}
class Child extends Parent {
    @Override
    public void display() { System.out.println("Child"); } // overrides
}

Feature Overloading Overriding Class Same class Parent-child Parameters Must differ Must be same Return type Can differ Must be same/covariant Resolution Compile time Runtime @Override Not needed Recommended static methods Can be overloaded Cannot be overridden (hidden) private methods Can be overloaded Cannot be overridden final methods Can be overloaded Cannot be overridden

Q3. What is the difference between an abstract class and an interface? (TCS asks this every time)

This is the single most repeated question in TCS Java interviews.

Abstract Class:

abstract class Animal {
    String name;                    // instance variable — allowed
    static int count = 0;          // static variable — allowed

    Animal(String name) {           // constructor — allowed
        this.name = name;
    }

    abstract void makeSound();      // abstract method — no body

    void breathe() {               // concrete method — has body
        System.out.println(name + " is breathing");
    }
}

class Dog extends Animal {
    Dog(String name) { super(name); }

    @Override
    void makeSound() { System.out.println("Woof!"); }
}

Interface:

interface Flyable {
    int MAX_HEIGHT = 10000;        // public static final — always
    void fly();                    // public abstract — always
    default void land() {          // default method (Java 8+)
        System.out.println("Landing...");
    }
    static void checkWeather() {   // static method (Java 8+)
        System.out.println("Checking weather");
    }
}

class Bird implements Flyable {
    @Override
    public void fly() { System.out.println("Bird is flying"); }
}

The comparison table TCS expects:

Feature Abstract Class Interface Keyword abstract class interface Inheritance extends (single) implements (multiple) Variables Any type public static final only Constructor Yes No Methods Abstract + concrete Abstract + default + static Access modifiers Any public only Speed Slightly faster Slightly slower Use case Is-a relationship Can-do capability

When to use which:

  • Abstract class: When related classes share common state and behavior (e.g., Animal for Dog, Cat)
  • Interface: When unrelated classes share a capability (e.g., Serializable for any class)

Q4. What is the difference between this and super keyword?

**this keyword:**

class Employee {
    String name;
    int salary;

    Employee(String name, int salary) {
        this.name = name;       // distinguish field from parameter
        this.salary = salary;
    }

    void display() {
        System.out.println(this.name); // refers to current object
    }

    Employee copy() {
        return this; // returns current object reference
    }
}

**super keyword:**

class Person {
    String name = "Person";
    Person(String name) {
        this.name = name;
        System.out.println("Person constructor");
    }
    void display() { System.out.println("Person: " + name); }
}

class Employee extends Person {
    String department;

    Employee(String name, String dept) {
        super(name);            // calls Person constructor — MUST be first line
        this.department = dept;
        System.out.println("Employee constructor");
    }

    void display() {
        super.display();        // calls Person's display()
        System.out.println("Dept: " + department);
    }
}

Q5. Can we achieve multiple inheritance in Java? How?

Java does NOT support multiple inheritance through classes — to avoid the Diamond Problem:

class A { void show() }
         /                       \
  class B extends A         class C extends A
  { void show() }           { void show() }
         \                       /
          class D extends B, C  ← AMBIGUOUS! Which show()?
          // Java does NOT allow this

Java achieves multiple inheritance through interfaces:

interface Swimmer {
    default void swim() { System.out.println("Swimming"); }
}

interface Runner {
    default void run() { System.out.println("Running"); }
}

class Triathlete implements Swimmer, Runner {
    // inherits both swim() and run()
    // if both had same default method, must override to resolve conflict
}

Triathlete t = new Triathlete();
t.swim(); // Swimming
t.run();  // Running

Section 2: String Handling — TCS Favourite Topic

TCS loves String questions. They appear in almost every technical round.

Q6. Why is String immutable in Java? What are its benefits?

String is immutable — once created, its value cannot be changed.

String s = "Hello";
s.concat(" World"); // creates NEW string — s is unchanged
System.out.println(s); // "Hello" — still original

s = s.concat(" World"); // now s points to new string "Hello World"

Why immutable — three reasons TCS expects:

1. String Pool (Memory efficiency): The JVM maintains a String Pool. Immutability allows safe sharing of the same String object across multiple references. If String were mutable, one reference changing it would corrupt all others.

String a = "TCS";
String b = "TCS";
// a and b point to SAME object in pool — safe only because String is immutable
System.out.println(a == b); // true

2. Thread Safety: Immutable objects are inherently thread-safe. Multiple threads can share the same String without synchronization.

3. Security: Strings are used as parameters in class loading, network connections, file paths. If they could be changed after a security check, attackers could exploit the window between check and use (TOCTOU attack).

Q7. What is the String Pool? What is intern()?

The String Pool (also called String Constant Pool) is a special area in the heap where Java stores String literals to avoid creating duplicate objects.

String s1 = "Java";           // stored in pool
String s2 = "Java";           // reuses same pool object
String s3 = new String("Java"); // new object on heap — NOT in pool

System.out.println(s1 == s2);  // true  — same pool reference
System.out.println(s1 == s3);  // false — different objects
System.out.println(s1.equals(s3)); // true — same content

// intern() — moves string to pool or returns existing pool reference
String s4 = s3.intern();
System.out.println(s1 == s4); // true — s4 now points to pool object

Q8. What is the difference between String, StringBuilder, and StringBuffer?

TCS loves this question. Know all three thoroughly.

// String — immutable
String s = "Hello";
s += " World"; // creates NEW object every time — old "Hello" becomes garbage
// 1000 concatenations = 1000 objects — very inefficient in loops

// StringBuilder — mutable, NOT thread-safe, FAST
StringBuilder sb = new StringBuilder("Hello");
sb.append(" World");     // modifies same object — efficient
sb.insert(5, ",");       // Hello, World
sb.reverse();            // dlroW ,olleH
sb.delete(0, 5);         // ,olleH
System.out.println(sb.toString());

// StringBuffer — mutable, thread-safe (synchronized), slightly slower
StringBuffer sbf = new StringBuffer("Hello");
sbf.append(" World"); // synchronized — safe across threads

Feature String StringBuilder StringBuffer Mutable? No Yes Yes Thread-safe? Yes (immutable) No Yes Performance Slowest (new object) Fastest Moderate Use case Fixed text Single-thread ops Multi-thread ops Since Java 1.0 Java 1.5 Java 1.0

TCS trick question: "Which is faster — StringBuilder or StringBuffer?" Answer: StringBuilder — because it has no synchronization overhead. Use StringBuffer only when multiple threads access the same buffer.

Q9. What are common String methods? (TCS asks you to write code)

String str = "  Hello TCS World  ";

// Length
str.length();                    // 20 (including spaces)

// Case
str.toUpperCase();               // "  HELLO TCS WORLD  "
str.toLowerCase();               // "  hello tcs world  "

// Trim and Strip
str.trim();                      // "Hello TCS World" (removes leading/trailing spaces)
str.strip();                     // Java 11+ — Unicode-aware trim

// Contains, StartsWith, EndsWith
str.contains("TCS");             // true
str.trim().startsWith("Hello");  // true
str.trim().endsWith("World");    // true

// indexOf, lastIndexOf
str.indexOf("o");                // first occurrence index
str.lastIndexOf("o");            // last occurrence index

// Substring
str.trim().substring(6);         // "TCS World"
str.trim().substring(6, 9);      // "TCS"

// Replace
str.replace("TCS", "Infosys");   // "  Hello Infosys World  "
str.replaceAll("\\s+", " ");     // replaces multiple spaces with one

// Split
String csv = "Java,Python,C++";
String[] langs = csv.split(","); // ["Java", "Python", "C++"]

// charAt and toCharArray
str.charAt(7);                   // 'H' (after spaces)
char[] chars = "Java".toCharArray();

// equals and compareTo
"TCS".equals("tcs");             // false — case sensitive
"TCS".equalsIgnoreCase("tcs");   // true
"Apple".compareTo("Banana");     // negative — A comes before B

// String.format and valueOf
String formatted = String.format("Name: %s, Score: %d", "Rahul", 95);
String num = String.valueOf(42); // "42"
int n = Integer.parseInt("42");  // 42

// Java 11+ methods
"  ".isBlank();                  // true — empty or whitespace only
"Hello\nWorld".lines()           // Stream of lines
    .collect(Collectors.toList());
"Java".repeat(3);                // "JavaJavaJava"

Q10. Write a Java program to reverse a String without using reverse().

TCS commonly asks this as a coding question in TR.

// Method 1 — Using charAt loop (most common answer)
public static String reverseString(String str) {
    String reversed = "";
    for (int i = str.length() - 1; i >= 0; i--) {
        reversed += str.charAt(i);
    }
    return reversed;
}

// Method 2 — Using StringBuilder (more efficient)
public static String reverseEfficient(String str) {
    StringBuilder sb = new StringBuilder();
    for (int i = str.length() - 1; i >= 0; i--) {
        sb.append(str.charAt(i));
    }
    return sb.toString();
}

// Method 3 — Using char array
public static String reverseCharArray(String str) {
    char[] chars = str.toCharArray();
    int left = 0, right = chars.length - 1;
    while (left < right) {
        char temp = chars[left];
        chars[left] = chars[right];
        chars[right] = temp;
        left++;
        right--;
    }
    return new String(chars);
}

// Method 4 — Using recursion
public static String reverseRecursive(String str) {
    if (str.isEmpty()) return str;
    return reverseRecursive(str.substring(1)) + str.charAt(0);
}

TCS follow-up: "Check if a String is a palindrome."

public static boolean isPalindrome(String str) {
    str = str.toLowerCase().replaceAll("\\s+", "");
    int left = 0, right = str.length() - 1;
    while (left < right) {
        if (str.charAt(left) != str.charAt(right)) return false;
        left++; right--;
    }
    return true;
}

Section 3: Exception Handling

Q11. What is the exception hierarchy in Java?

Throwable
    ├── Error (JVM-level, do NOT catch)
    │     ├── OutOfMemoryError
    │     ├── StackOverflowError
    │     └── VirtualMachineError
    └── Exception
          ├── Checked Exceptions (must handle)
          │     ├── IOException
          │     ├── SQLException
          │     ├── ClassNotFoundException
          │     └── FileNotFoundException
          └── RuntimeException (unchecked)
                ├── NullPointerException
                ├── ArrayIndexOutOfBoundsException
                ├── ClassCastException
                ├── ArithmeticException (/ by zero)
                ├── NumberFormatException
                └── IllegalArgumentException

Q12. What is the difference between throw and throws?

**throw** — used to explicitly throw an exception from inside a method:

public void validateAge(int age) {
    if (age < 18) {
        throw new IllegalArgumentException("Age must be 18+"); // explicit throw
    }
}

**throws** — used in the method signature to declare that the method may throw a checked exception:

public void readFile(String path) throws IOException, FileNotFoundException {
    // method may throw these — caller must handle
    FileReader fr = new FileReader(path);
}

// Caller must handle:
try {
    readFile("data.txt");
} catch (IOException e) {
    e.printStackTrace();
}

throw throws Used inside method body Used in method signature Throws one exception instance Declares multiple exception types Followed by an exception object Followed by exception class names throw new Exception() void method() throws Exception

Q13. What is the difference between final, finally, and finalize()?

TCS asks this in almost every interview — the three confusingly similar words.

**final — keyword:**

final int MAX = 100;        // constant — cannot reassign
final class Utility { }     // cannot be extended/subclassed
final void display() { }    // cannot be overridden in subclass

**finally — block:**

try {
    int result = 10 / 0; // ArithmeticException
} catch (ArithmeticException e) {
    System.out.println("Exception caught: " + e.getMessage());
} finally {
    System.out.println("Finally always executes"); // always runs
    // Use for: closing connections, releasing resources
}

**finalize() — method:**

class Resource {
    @Override
    protected void finalize() throws Throwable {
        System.out.println("Garbage collector is cleaning up");
        // Called by GC before object is collected
        // DEPRECATED since Java 9 — unreliable, avoid using
    }
}

TCS follow-up: "Does finally always execute?" Answer: Almost always. Exceptions: System.exit() is called inside try/catch, JVM crashes, or the thread is killed. In normal flow — yes, always.

Q14. Can we have multiple catch blocks? What is multi-catch?

// Multiple catch blocks — most specific first
try {
    String s = null;
    int[] arr = new int[5];

    s.length();        // NullPointerException
    arr[10] = 1;       // ArrayIndexOutOfBoundsException
    int x = 10 / 0;   // ArithmeticException

} catch (NullPointerException e) {
    System.out.println("Null pointer: " + e.getMessage());
} catch (ArrayIndexOutOfBoundsException e) {
    System.out.println("Array index: " + e.getMessage());
} catch (ArithmeticException e) {
    System.out.println("Arithmetic: " + e.getMessage());
} catch (Exception e) {
    // Most general — always last
    System.out.println("General exception: " + e.getMessage());
}

// Multi-catch (Java 7+) — handle multiple exceptions the same way
try {
    // risky code
} catch (NullPointerException | ArrayIndexOutOfBoundsException e) {
    System.out.println("Caught: " + e.getMessage());
}

TCS rule: Always catch more specific exceptions before general ones. Catching Exception first makes lower catches unreachable — compile error.

Section 4: Collections

Q15. What is the difference between ArrayList and LinkedList? When do you use each?

(See full explanation in collections section — TCS asks the same comparison.)

TCS shortcut answer:

  • ArrayList — fast random access O(1), slow insert/delete in middle O(n). Use for read-heavy operations.
  • LinkedList — slow random access O(n), fast insert/delete at ends O(1). Use for frequent insertions/deletions.
  • In practice: use ArrayList by default.

Q16. What is the difference between HashMap and TreeMap?

// HashMap — no order, O(1) operations
Map<String, Integer> hashMap = new HashMap<>();
hashMap.put("Banana", 2);
hashMap.put("Apple", 1);
hashMap.put("Cherry", 3);
System.out.println(hashMap); // {Apple=1, Cherry=3, Banana=2} — random

// TreeMap — sorted by key, O(log n) operations
Map<String, Integer> treeMap = new TreeMap<>();
treeMap.put("Banana", 2);
treeMap.put("Apple", 1);
treeMap.put("Cherry", 3);
System.out.println(treeMap); // {Apple=1, Banana=2, Cherry=3} — sorted

Feature HashMap TreeMap Order No ordering Sorted by key Performance O(1) average O(log n) Null key One allowed Not allowed Implementation Hash table Red-black tree Use case General purpose Sorted key-value pairs

Q17. What is the difference between Iterator and ListIterator?

List<String> list = new ArrayList<>(List.of("TCS", "Infosys", "Wipro"));

// Iterator — forward only, works on any Collection
Iterator<String> it = list.iterator();
while (it.hasNext()) {
    String s = it.next();
    if (s.equals("Infosys")) it.remove(); // safe removal
}

// ListIterator — bidirectional, only for List
ListIterator<String> lit = list.listIterator();
while (lit.hasNext()) {
    String s = lit.next();
    lit.set(s.toUpperCase()); // can replace element
}
while (lit.hasPrevious()) {
    System.out.println(lit.previous()); // traverse backward
}

Section 5: Multithreading Basics

Q18. What is multithreading? How do you create a thread in Java?

Multithreading allows a Java program to execute multiple threads simultaneously, improving performance and responsiveness.

Two ways to create a thread:

Method 1 — Extend Thread class:

java

class MyThread extends Thread {
    private String taskName;

    MyThread(String name) { this.taskName = name; }

    @Override
    public void run() {
        for (int i = 1; i <= 5; i++) {
            System.out.println(taskName + " - Count: " + i);
            try { Thread.sleep(500); } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }
}

MyThread t1 = new MyThread("Thread-1");
MyThread t2 = new MyThread("Thread-2");
t1.start(); // starts new thread — calls run() in new thread
t2.start(); // do NOT call run() directly — that runs in current thread

Method 2 — Implement Runnable interface (preferred):

java

class MyTask implements Runnable {
    private String taskName;

    MyTask(String name) { this.taskName = name; }

    @Override
    public void run() {
        System.out.println(taskName + " running in " + Thread.currentThread().getName());
    }
}

Thread t1 = new Thread(new MyTask("Task-1"));
Thread t1Lambda = new Thread(() -> System.out.println("Lambda task")); // Java 8
t1.start();
t1Lambda.start();

Why Runnable is preferred:

  • Java allows only single class inheritance — if you extend Thread, you cannot extend any other class
  • Runnable separates task from thread mechanism
  • Works naturally with ExecutorService thread pools

Q19. What is synchronization? Why is it needed?

Without synchronization, multiple threads accessing shared data simultaneously can produce inconsistent results.

java

// WITHOUT synchronization — race condition
class Counter {
    int count = 0;
    void increment() { count++; } // read-modify-write — not atomic
}

Counter c = new Counter();
Thread t1 = new Thread(() -> { for(int i=0; i<1000; i++) c.increment(); });
Thread t2 = new Thread(() -> { for(int i=0; i<1000; i++) c.increment(); });
t1.start(); t2.start();
t1.join(); t2.join();
System.out.println(c.count); // NOT always 2000 — race condition

java

// WITH synchronization — thread safe
class SynchronizedCounter {
    int count = 0;

    synchronized void increment() { // only one thread at a time
        count++;
    }
}
// OR
void increment() {
    synchronized(this) { count++; }
}

메타데이터
post_id
e7d82c24e37c
slug
core-java-interview-questions-asked-in-tcs-2026-complete-guide-e7d82c24e37c
url
https://medium.com/@sparsh187/core-java-interview-questions-asked-in-tcs-2026-complete-guide-e7d82c24e37c
canonical_url
https://medium.com/@sparsh187/core-java-interview-questions-asked-in-tcs-2026-complete-guide-e7d82c24e37c
author_url
https://medium.com/@sparsh187
status
ok
fetched_at
2026-06-25 12:15:08