corejavaInterviewQuestions1
corejavaInterviewQuestions1
=============================
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:
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.
#### Example
```java
interface MyInterface {
void existingMethod();
// Default method
default void newDefaultMethod() {
System.out.println("Default implementation");
}
}
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");
}
}
### Summary
The introduction of default and static methods in interfaces in Java 8 was driven
by the need to:
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.
### 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.
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
```
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`:
```java
import java.util.HashMap;
import java.util.Map;
### Explanation
```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.
```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`.
```java
String value = stringKeyMap.get("Key1");
System.out.println("Value for 'Key1' in stringKeyMap: " + value);
The example demonstrates how to retrieve values using keys and check for the
presence of a key in the map.
- **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
```java
import java.util.HashMap;
import java.util.Map;
### 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
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.
```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");
}
### 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.
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.
@Override
public String toString() {
return "Person{name='" + name + "', age=" + age + "}";
}
}
```
### 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.
### 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}
```
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.
```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);
### 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()`.
- **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:
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.
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.
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:
### Example
```java
public class Example {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
```
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.
### 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.