0% found this document useful (0 votes)
6 views

corejavaInterviewQuestions1

Uploaded by

tellapuri.naresh
Copyright
© © All Rights Reserved
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
6 views

corejavaInterviewQuestions1

Uploaded by

tellapuri.naresh
Copyright
© © All Rights Reserved
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 14

Core java Interview Questions

=============================

In Java 8, static and default methods were introduced to interfaces to enhance the
flexibility and functionality of interfaces while maintaining backward
compatibility with older versions of Java. These additions address several design
and practical needs:

### Default Methods

#### Purpose and Use

1. **Backward Compatibility**:
- When new methods are added to an existing interface, all implementing classes
must implement those new methods. This can be problematic for large codebases or
third-party libraries. Default methods allow new methods to be added to interfaces
without breaking existing implementations.

2. **Providing Common Functionality**:


- Default methods enable interfaces to provide default implementations for
methods, which can be used by all implementing classes. This promotes code reuse
and reduces boilerplate code.

3. **Multiple Inheritance of Behavior**:


- Interfaces in Java support multiple inheritance of type but not behavior.
Default methods allow interfaces to provide behavior, giving some of the benefits
of multiple inheritance without the associated complexity.

#### Example

```java
interface MyInterface {
void existingMethod();

// Default method
default void newDefaultMethod() {
System.out.println("Default implementation");
}
}

class MyClass implements MyInterface {


@Override
public void existingMethod() {
System.out.println("Existing method implementation");
}

// Optionally, override the default method


@Override
public void newDefaultMethod() {
System.out.println("Overridden default implementation");
}
}

public class Main {


public static void main(String[] args) {
MyClass myClass = new MyClass();
myClass.existingMethod();
myClass.newDefaultMethod(); // Uses overridden version
}
}
```

### Static Methods

#### Purpose and Use

1. **Utility or Helper Methods**:


- Static methods in interfaces allow utility or helper methods to be defined in
the interface itself, rather than requiring them to be placed in a separate utility
class. This can improve code organization and clarity.

2. **Accessing Methods Without Instances**:


- Static methods can be called without needing an instance of the implementing
class. This is useful for methods that do not rely on instance-specific data.

3. **Interface-specific Behavior**:
- Static methods in interfaces can encapsulate behavior that is specific to the
interface, which can be accessed in a type-safe manner.

#### Example

```java
interface MyUtilityInterface {
// Static method
static void utilityMethod() {
System.out.println("Utility method in interface");
}
}

public class Main {


public static void main(String[] args) {
// Call the static method directly from the interface
MyUtilityInterface.utilityMethod();
}
}
```

### Summary

The introduction of default and static methods in interfaces in Java 8 was driven
by the need to:

- **Enhance Interface Functionality**: Allow interfaces to include method


implementations, enabling more versatile and powerful design patterns.
- **Improve Backward Compatibility**: Allow existing interfaces to be extended with
new methods without breaking existing implementations.
- **Provide Utility Methods**: Facilitate the inclusion of utility methods directly
in interfaces, improving code organization.

These changes make interfaces in Java more flexible and powerful, enabling
developers to write more maintainable and expressive code.
In Java, the `Set` interface represents a collection that does not allow duplicate
elements and does not guarantee any specific order of elements. Unlike lists, sets
are non-indexed, meaning you cannot access elements by their position.

### Example of Using a Set in Java

Here's an example demonstrating the basic usage of a `Set` in Java:


```java
import java.util.HashSet;
import java.util.Set;

public class SetExample {


public static void main(String[] args) {
// Creating a Set
Set<String> mySet = new HashSet<>();

// Adding elements to the Set


mySet.add("Apple");
mySet.add("Banana");
mySet.add("Orange");
mySet.add("Mango");
mySet.add("Apple"); // Duplicate element

// Printing the Set


System.out.println("Set elements:");
for (String element : mySet) {
System.out.println(element);
}

// Checking if an element is present in the Set


if (mySet.contains("Banana")) {
System.out.println("Banana is in the Set");
}

// Removing an element from the Set


mySet.remove("Orange");

// Printing the Set after removal


System.out.println("Set elements after removal:");
for (String element : mySet) {
System.out.println(element);
}
}
}
```

### Explanation

1. **Creating a Set:**
```java
Set<String> mySet = new HashSet<>();
```
This line creates a `HashSet` instance which implements the `Set` interface.
`HashSet` is one of the common implementations of the `Set` interface.

2. **Adding Elements:**
```java
mySet.add("Apple");
mySet.add("Banana");
mySet.add("Orange");
mySet.add("Mango");
mySet.add("Apple"); // Duplicate element
```
Elements are added to the set using the `add` method. Note that adding a
duplicate element ("Apple") does not affect the set, as sets do not allow
duplicates.

3. **Iterating Over the Set:**


```java
for (String element : mySet) {
System.out.println(element);
}
```
Since `Set` is non-indexed, you can't access elements by index. Instead, you can
use an enhanced for loop to iterate over the elements.

4. **Checking for an Element:**


```java
if (mySet.contains("Banana")) {
System.out.println("Banana is in the Set");
}
```
The `contains` method checks if a specific element is present in the set.

5. **Removing an Element:**
```java
mySet.remove("Orange");
```
The `remove` method removes a specified element from the set.

### Output

The output of the above program will be something like this (note that the order of
elements in a `HashSet` is not guaranteed):

```
Set elements:
Apple
Banana
Orange
Mango
Banana is in the Set
Set elements after removal:
Apple
Banana
Mango
```

### Key Points

- **Non-indexed:** You cannot access elements by their position in a set.


- **No duplicates:** A set does not allow duplicate elements.
- **Unordered:** The order of elements in a set is not guaranteed (especially in
`HashSet`). If you need a specific order, you might use `LinkedHashSet` or
`TreeSet`.

By using sets, you can ensure the uniqueness of elements and perform set operations
efficiently.
Using immutable classes provided by the JDK as keys in a `Map` is a good practice
because immutable objects are inherently thread-safe and their hash codes do not
change, which ensures consistent behavior of the `Map`. Common immutable classes in
Java include `String`, `Integer`, `Long`, `Double`, `BigDecimal`, `BigInteger`, and
more.
Here's an example demonstrating the use of `String` and `Integer` (both immutable
classes) as keys in a `Map`:

### Example Using `String` and `Integer` as Keys

```java
import java.util.HashMap;
import java.util.Map;

public class ImmutableMapExample {


public static void main(String[] args) {
// Create a Map with String keys
Map<String, String> stringKeyMap = new HashMap<>();

// Add some key-value pairs to the map


stringKeyMap.put("Key1", "Value1");
stringKeyMap.put("Key2", "Value2");
stringKeyMap.put("Key3", "Value3");

// Print the Map


System.out.println("Map with String keys:");
for (Map.Entry<String, String> entry : stringKeyMap.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}

// Create a Map with Integer keys


Map<Integer, String> integerKeyMap = new HashMap<>();

// Add some key-value pairs to the map


integerKeyMap.put(1, "One");
integerKeyMap.put(2, "Two");
integerKeyMap.put(3, "Three");

// Print the Map


System.out.println("Map with Integer keys:");
for (Map.Entry<Integer, String> entry : integerKeyMap.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}

// Retrieve a value using a key


String value = stringKeyMap.get("Key1");
System.out.println("Value for 'Key1' in stringKeyMap: " + value);

// Check if a key is present


boolean hasKey = integerKeyMap.containsKey(2);
System.out.println("integerKeyMap contains key 2: " + hasKey);
}
}
```

### Explanation

1. **Using `String` as Keys:**

```java
Map<String, String> stringKeyMap = new HashMap<>();
stringKeyMap.put("Key1", "Value1");
stringKeyMap.put("Key2", "Value2");
stringKeyMap.put("Key3", "Value3");
```

In this example, `String` objects are used as keys. Since `String` is immutable,
it is a good choice for keys in a `Map`. We add key-value pairs to the map and
print the map's contents.

2. **Using `Integer` as Keys:**

```java
Map<Integer, String> integerKeyMap = new HashMap<>();
integerKeyMap.put(1, "One");
integerKeyMap.put(2, "Two");
integerKeyMap.put(3, "Three");
```

Similarly, `Integer` objects are used as keys in another map. `Integer` is also
immutable, making it suitable for use as a key in a `Map`.

3. **Retrieving Values and Checking Keys:**

```java
String value = stringKeyMap.get("Key1");
System.out.println("Value for 'Key1' in stringKeyMap: " + value);

boolean hasKey = integerKeyMap.containsKey(2);


System.out.println("integerKeyMap contains key 2: " + hasKey);
```

The example demonstrates how to retrieve values using keys and check for the
presence of a key in the map.

### Key Points

- **Immutability:** Using immutable keys ensures that the key's hash code remains
consistent, preventing potential issues with retrieving or storing values in the
map.
- **Thread-Safety:** Immutable objects are inherently thread-safe, making them
suitable for use in concurrent environments.
- **Built-in hashCode() and equals():** Immutable classes like `String` and
`Integer` have well-defined `hashCode()` and `equals()` methods, ensuring correct
behavior when used as keys in a `Map`.

By using immutable classes as keys in a `Map`, you can avoid the complexity and
potential pitfalls of implementing `hashCode()` and `equals()` methods yourself.
In Java, if you store a key-value pair in a `HashMap` where the key is `null`, and
then retrieve the value associated with the `null` key, it will print the
corresponding value stored for the `null` key.

### Example

Here's a simple example to demonstrate storing and retrieving a value using a


`null` key in a `HashMap`:

```java
import java.util.HashMap;
import java.util.Map;

public class HashMapNullKeyExample {


public static void main(String[] args) {
// Create a HashMap
Map<String, String> hashMap = new HashMap<>();

// Put a null key with a value


hashMap.put(null, "NullKeyExample");

// Put some other key-value pairs


hashMap.put("Key1", "Value1");
hashMap.put("Key2", "Value2");

// Retrieve the value associated with the null key


String nullKeyValue = hashMap.get(null);

// Print the value associated with the null key


System.out.println("Value for null key: " + nullKeyValue);

// Print the entire map to see all key-value pairs


System.out.println("HashMap contents: " + hashMap);
}
}
```

### Output

When you run the above program, you will see the following output:

```
Value for null key: NullKeyExample
HashMap contents: {null=NullKeyExample, Key1=Value1, Key2=Value2}
```

### Explanation

- **Storing a null key:**


```java
hashMap.put(null, "NullKeyExample");
```
Here, a key-value pair is added to the `HashMap` where the key is `null` and the
value is `"NullKeyExample"`.

- **Retrieving the value associated with the null key:**


```java
String nullKeyValue = hashMap.get(null);
```
The `get` method is called with `null` as the key, which retrieves the value
associated with the `null` key, which is `"NullKeyExample"`.

- **Printing the value associated with the null key:**


```java
System.out.println("Value for null key: " + nullKeyValue);
```
This prints the value stored for the `null` key.

- **Printing the entire map:**


```java
System.out.println("HashMap contents: " + hashMap);
```
This prints all key-value pairs in the `HashMap`, showing that it can store a
`null` key and its corresponding value alongside other key-value pairs.
### Summary

When you store a key-value pair in a `HashMap` where the key is `null`, and you
retrieve the value using the `null` key, it will print the corresponding value
associated with the `null` key. In this example, it prints `"NullKeyExample"`.
In Java, a functional interface is an interface that has exactly one abstract
method. Functional interfaces are intended to be used with lambda expressions and
method references, allowing a more concise and functional style of programming.

### Key Characteristics of Functional Interfaces:


1. **Single Abstract Method (SAM):** A functional interface must have exactly one
abstract method.
2. **Default Methods:** It can have any number of default methods.
3. **Static Methods:** It can have any number of static methods.
4. **`Object` Methods:** It can also have methods from the `Object` class (like
`toString()`, `equals()`, `hashCode()`), which do not count as abstract methods.

### Variables and Constructors in Functional Interfaces:


- **Instance Variables:** Functional interfaces cannot have instance variables.
They can only have `static` and `final` variables (implicitly `final`).
- **Constructors:** Functional interfaces do not have constructors because they
cannot be instantiated directly. Instead, they are typically implemented using
lambda expressions or method references.

### Example of a Functional Interface:

Here's an example demonstrating the components of a functional interface:

```java
@FunctionalInterface
interface MyFunctionalInterface {
// Single abstract method
void singleAbstractMethod();

// Default method
default void defaultMethod() {
System.out.println("Default method in functional interface");
}

// Static method
static void staticMethod() {
System.out.println("Static method in functional interface");
}

// Implicitly final static variable


static final int CONSTANT = 42;
}

public class FunctionalInterfaceExample {


public static void main(String[] args) {
// Implementing the functional interface using a lambda expression
MyFunctionalInterface example = () -> System.out.println("Lambda expression
implementation");

// Calling the single abstract method


example.singleAbstractMethod();

// Calling the default method


example.defaultMethod();

// Calling the static method


MyFunctionalInterface.staticMethod();

// Accessing the static final variable


System.out.println("Constant value: " + MyFunctionalInterface.CONSTANT);
}
}
```

### Explanation:
1. **Single Abstract Method:** The `MyFunctionalInterface` has a single abstract
method named `singleAbstractMethod()`.
2. **Default Method:** It has a default method `defaultMethod()` which provides a
default implementation.
3. **Static Method:** It includes a static method `staticMethod()` that can be
called without an instance of the interface.
4. **Static Final Variable:** It has a `static final` variable `CONSTANT` which is
implicitly `final`.

### Summary:
- **Variables:** Functional interfaces can have `static` and `final` variables.
- **Constructors:** Functional interfaces do not have constructors since they
cannot be instantiated directly.
- **Methods:** Besides the single abstract method, functional interfaces can have
default and static methods, as well as methods from the `Object` class.

Functional interfaces are a key feature in Java for enabling functional programming
constructs and are commonly used with lambda expressions and method references.
In Java, you can customize the sorting order of elements in a `TreeSet` by
providing a custom comparator. This is particularly useful when you want to sort
elements in a way that differs from their natural ordering.

### Example: Custom Sorting with `TreeSet`

Let's create an example where we have a `TreeSet` of `Person` objects, and we want
to sort these objects based on their age in descending order.

1. **Define the `Person` class:**


```java
public class Person {
private String name;
private int age;

public Person(String name, int age) {


this.name = name;
this.age = age;
}

public String getName() {


return name;
}

public int getAge() {


return age;
}

@Override
public String toString() {
return "Person{name='" + name + "', age=" + age + "}";
}
}
```

2. **Create the `TreeSet` with a custom comparator:**


```java
import java.util.Comparator;
import java.util.TreeSet;

public class TreeSetCustomSortExample {


public static void main(String[] args) {
// Custom comparator to sort Person objects by age in descending order
Comparator<Person> ageComparator = new Comparator<Person>() {
@Override
public int compare(Person p1, Person p2) {
return Integer.compare(p2.getAge(), p1.getAge());
}
};

// Create a TreeSet with the custom comparator


TreeSet<Person> persons = new TreeSet<>(ageComparator);

// Add Person objects to the TreeSet


persons.add(new Person("Alice", 30));
persons.add(new Person("Bob", 25));
persons.add(new Person("Charlie", 35));
persons.add(new Person("Dave", 28));

// Print the TreeSet


System.out.println("Persons sorted by age (descending):");
for (Person person : persons) {
System.out.println(person);
}
}
}
```

### Explanation:

1. **Person Class:**
- A simple class with `name` and `age` fields.
- It includes a constructor, getter methods, and an overridden `toString` method
for easy printing.

2. **Custom Comparator:**
- A `Comparator` is defined to compare `Person` objects by age in descending
order.
- The `compare` method uses `Integer.compare(p2.getAge(), p1.getAge())` to
achieve this.

3. **TreeSet with Custom Comparator:**


- A `TreeSet` is created with the custom comparator.
- `Person` objects are added to the `TreeSet`. The `TreeSet` uses the custom
comparator to sort the objects.

4. **Printing the TreeSet:**


- The elements of the `TreeSet` are printed, showing the `Person` objects sorted
by age in descending order.

### Output:
When you run the above code, the output will be:
```
Persons sorted by age (descending):
Person{name='Charlie', age=35}
Person{name='Alice', age=30}
Person{name='Dave', age=28}
Person{name='Bob', age=25}
```

This example demonstrates how to use a custom comparator to sort elements in a


`TreeSet` according to a specified order, in this case, by age in descending order.
In Java, the `static` keyword is not applicable to constructors. Constructors are
special methods used to initialize objects, and they cannot be static for several
reasons:

1. **Constructors are Meant to Initialize Instances:**


- Constructors are designed to create and initialize instances of a class. A
`static` keyword denotes that a method or variable belongs to the class itself, not
to instances of the class. Thus, making a constructor static would contradict its
fundamental purpose.

2. **Instance Context:**
- Constructors are inherently tied to instance creation. They are called when an
object of the class is instantiated using the `new` keyword. A `static` context
means there is no instance involved, which makes it nonsensical to have a static
constructor.

3. **Object Lifecycle:**
- The lifecycle of an object begins with the constructor. Since static methods
can be called without creating an instance of the class, a static constructor would
not fit into the lifecycle model of object-oriented programming in Java.

### Example to Illustrate Constructors and `static` Methods

Here's an example to illustrate the use of constructors and `static` methods in a


class:

```java
public class Example {
// Instance variable
private int value;

// Constructor
public Example(int value) {
this.value = value;
}

// Instance method
public void displayValue() {
System.out.println("Value: " + value);
}

// Static method
public static void staticMethod() {
System.out.println("This is a static method.");
}
public static void main(String[] args) {
// Creating an instance of the Example class
Example example = new Example(42);

// Calling the instance method


example.displayValue();

// Calling the static method


Example.staticMethod();
}
}
```

### Explanation:

1. **Constructor:**
- The `Example` class has a constructor `Example(int value)` that initializes
the instance variable `value`.
- This constructor is called when a new object of `Example` is created using
`new Example(42)`.

2. **Instance Method:**
- The `displayValue` method is an instance method that prints the value of the
instance variable `value`.
- This method is called on the instance `example` using
`example.displayValue()`.

3. **Static Method:**
- The `staticMethod` method is a static method that prints a message.
- This method can be called without creating an instance of the class using
`Example.staticMethod()`.

### Key Points:

- **Static Keyword:**
- The `static` keyword is used for methods and variables that belong to the class
rather than any particular instance.
- Static methods and variables can be accessed without creating an instance of
the class.

- **Constructors:**
- Constructors are used to initialize new objects and cannot be static.
- They are called when a new instance of the class is created.

### Summary:

The `static` keyword cannot be applied to constructors because constructors are


inherently tied to the instance creation process. Static methods and variables
belong to the class itself, whereas constructors are designed to initialize
individual instances of a class.
In Java, `.class` files, which are the compiled bytecode of Java source files, are
not stored directly in Java memory. Instead, they are typically stored on the file
system in the file structure of the project. However, when a Java program is run,
these `.class` files are loaded into memory by the Java Virtual Machine (JVM).

### Storage on the File System

When you compile a Java source file (with a `.java` extension) using the Java
compiler (`javac`), the output is a bytecode file with a `.class` extension. These
`.class` files are usually stored in the same directory as the source files, or in
a separate `bin` or `out` directory, depending on the build configuration.

### Loading into Memory

When a Java program is executed, the JVM loads the necessary `.class` files into
memory. This process involves several steps:

1. **Class Loading:**
- The JVM loads the `.class` files from the file system into memory. The class
loader subsystem is responsible for finding and loading the class files.

2. **Class Linking:**
- This step includes:
- **Verification:** Ensures that the bytecode is valid and does not violate
Java's security constraints.
- **Preparation:** Allocates memory for static variables and initializes them
to their default values.
- **Resolution:** Converts symbolic references into actual references.

3. **Class Initialization:**
- The static initializers and static blocks of the class are executed to
initialize the static variables.

### In-Memory Storage

Once loaded, the class files are stored in different areas of the JVM memory,
primarily in the **Method Area** (part of the heap in older JVMs, and part of the
Metaspace in newer JVMs starting from Java 8). Here is a breakdown:

- **Method Area (or Metaspace in Java 8 and later):**


- Stores class structures such as the runtime constant pool, field and method
data, and the code for methods.

### Example

Let's illustrate this with a simple example:

```java
public class Example {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
```

### Compilation and Execution

1. **Compilation:**
```bash
javac Example.java
```
This command compiles the `Example.java` file and produces `Example.class`.

2. **Execution:**
```bash
java Example
```
This command starts the JVM, which loads the `Example.class` file from the file
system into memory, and executes the `main` method.

### Memory Layout in JVM

When the `Example.class` is loaded into the JVM:

- The **Class Loader** loads `Example.class` into the JVM.


- The **Method Area** (or **Metaspace**) stores the class metadata and bytecode.
- **Heap Memory** is used for the objects created by the program.
- **Stack Memory** is used for method invocations and local variables.
- **PC Registers** and **Native Method Stacks** are also used by the JVM.

### Summary

- **File System:** `.class` files are stored in the file system after compilation.
- **JVM Memory:** When executed, the `.class` files are loaded into the JVM memory,
primarily into the Method Area (or Metaspace in newer versions of Java).

This separation allows the JVM to efficiently manage class loading, linking, and
initialization, ensuring that the bytecode can be executed securely and
effectively.

You might also like