10 Common Questions about Java Fundamentals (Part 1)
Tags: java, interview, fundamental
Published: 2023-10-10 02:53:13

After every interview I participate in, I always save the technical questions as notes, and re-read them to remember knowledge. So today, I want to share them so everyone can read and best prepare for their interview.

## 1. Enum in Java
In Java, an **enum** (short for **enumeration**) is a special data type that allows you to define a collection of constants. It is used to represent a fixed set of predefined values or options. Enumerations in Java are declared using the enum keyword.
`enum.name()` vs `enum.toString()` vs `Enum.valueOf()`

In Java, the both are used to obtain a string representation of an enum constant, but they are not exactly the same.
enum.name() is an instance method defined in the Enum class, returns the name of the enum constant as declared in the enum definition.

`enum.toString()` also returns the name of the enum constant, just like `enum.name()`.

However, the behavior of enum.toString() can be overridden for each enum constant if you want to provide a custom string representation for that constant.

`Enum.valueOf()` is a static method defined in the Enum class, and it is used to retrieve an enum constant from its name as a string.

In summary, `Enum.valueOf()` is used to get the enum constant by providing its name as a string, while enum.name() is used to obtain the name of an enum constant that the method is called on. Both methods can be helpful depending on the scenario you are dealing with.

## 2. String in Java
In Java, String is a class that represents a sequence of characters. It’s is immutable and you can not be changed content of String.

### 2.1. == vs equals()
In Java, the == operator is used to compare the object reference of two objects, while the equals() method is used to compare the contents of two objects. For example:

```Java
String s1 = "hello";
String s2 = "hello";
String s3 = new String("hello");

System.out.println(s1 == s2); // true
System.out.println(s1 == s3); // false
System.out.println(s1.equals(s2)); // true
System.out.println(s1.equals(s3)); // true
```

In the example above, s1 and s2 are both references to the same string in memory, so `s1 == s2` is true. s3 is a new string object with the same contents as s1, so `s1 == s3` is `false`. However, `s1.equals(s2`) and s1.equals(s3) are both true, because equals() compares the contents of the strings.

### 2.2. String vs StringBuilder
In Java, String objects are immutable, which means that once a String object is created, its contents cannot be changed. If you need a mutable string, you can use the StringBuilder class instead. For example:

```Java
StringBuilder sb = new StringBuilder("hello");
sb.append(" world");
String s = sb.toString(); // "hello world"
```

### 2.3. concat()
The `concat()` method can be used to concatenate two strings together. For example:

```Java
String s1 = "hello";
String s2 = " world";
String s3 = s1.concat(s2); // "hello world"
```

### 2.4. StringPool in Java
In Java, the StringPool (also known as the String Constant Pool) is a special memory area in the Java Virtual Machine (JVM) that stores a pool of unique string literals. It is a mechanism used to optimize memory and improve the performance of string handling in Java applications.

In Java, when you create a string using double quotes (“…”) and assign it to a variable, the JVM automatically checks the StringPool to see if an identical string already exists in the pool. If string content exists, they will reference into variable, if not, they will created new object.

It ensures that multiple references to the same string literal point to the same memory location, saving memory and reducing object creation overhead.

```Java
String str1 = "Hello"; // A new string "Hello" is created and added to the StringPool.
String str2 = "Hello"; // JVM looks in the StringPool and finds an existing "Hello" string, so str2 points to the same location as str1.
```

Using the StringPool can be beneficial in scenarios where you have a large number of identical or similar string literals in your code, as it helps to reduce memory consumption and improve performance by minimizing redundant string objects.

### 2.5. StringBuffer vs StringBuilder
In Java, both StringBuffer and StringBuilder are mutable string classes. The difference is that StringBuffer is thread-safe, while StringBuilder is not.

If you need to modify a string in a multi-threaded environment, you should use StringBuffer. Otherwise, you should use StringBuilder.

In summary, String is a class that represents a sequence of characters in Java. It is important to know the differences between `==` operator and `equals()` method, as well as to understand the differences between String and StringBuilder or StringBuffer.

## 3. Thread Safety in Java
Thread safety is an important concept in Java programming, especially in multi-threaded environments. It refers to the ability of a program to function correctly and consistently when multiple threads are executing parallel.

In Java, there are several ways to achieve thread safety. One way is to use synchronized blocks or methods to ensure that only one thread can access a particular block of code at a time. For example:

```Java
public synchronized void incrementCounter() {
    counter++;
}
```
In the example above, the `synchronized` keyword ensures that only one thread can execute the `incrementCounter() `method at a time. This helps to prevent race conditions and other concurrency issues.

Another way to achieve thread safety in Java is to use thread-safe data structures. For example, the `java.util.concurrent` package provides several thread-safe collections, such as `ConcurrentHashMap` and `ConcurrentLinkedQueue`.

It is important to note that achieving thread safety in Java can come at a performance cost. Synchronization and other thread-safety measures can introduce overhead and slow down the program’s execution. Therefore, it is important to carefully consider the trade-offs between thread safety and performance when designing and implementing a Java program.

## 4. Functional Interfaces in Java
A functional interface in Java is an interface that has only one abstract method. This means that a functional interface can be look like as a lambda expression or method reference.

Functional interfaces are used in Java 8 and later versions to implement lambda expressions and method references.

For example, the `java.util.function` package in Java 8 defines several built-in functional interfaces, such as `Predicate`, `Consumer`, and `Function`.

Here is an example of a simple functional interface that takes two integers and returns their sum:

```Java
@FunctionalInterface
public interface Popo {
    int sum(int a, int b);
}
```

In this example, the IntSum interface has only one abstract method, `sum()`, which takes two integers as arguments and returns their sum.

This interface can be used to create lambda expressions that implement the `sum()` method. For example:

```Java
Popo popo = (a, b) -> a + b;
int result = popo.sum(5, 10); // result = 15
```

In this example, the lambda expression `(a, b) -> a + b` implements the `sum()` method defined in the `IntSum` interface.

The lambda expression is then assigned to a variable of type IntSum, which can be used to call the `sum()` method with different arguments.

Functional interfaces are a powerful feature in Java that allow for concise and flexible code. They are often used in conjunction with lambda expressions and method references to implement functional programming concepts in Java.

5. Stack vs Heap in Java

![Stack vs Heap in Java](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f5yjj0jkzl4rkgfux9t2.png)

### What is the Stack?

The stack is a region of memory where method invocations and local variables are stored. Each time a method is called, a new frame is added to the stack. When the method finishes executing, its frame is removed from the stack.

### What is the Heap?

The heap is a region of memory where objects are stored. When an object is created, it is allocated on the heap. The object remains on the heap until it is no longer referenced by any other objects or variables.

Java’s garbage collector is responsible for identifying and freeing unused objects in the Heap.

### What are the differences between Stack and Heap?

- The stack is used for method invocations and local variables, while the heap is used for object allocation.
- The stack is much smaller than the heap.
- The stack is organized in a Last-In-First-Out (LIFO) manner, while the heap is not.
- Access to the stack is much faster than access to the heap.

In summary, the stack and the heap are two different regions of memory used in Java. The stack is used for method invocations and local variables, while the heap is used for object allocation. Access to the stack is faster than access to the heap, but the heap can store much larger amounts of data.