JavaRush /Java блог /Random UA /Кава-брейк #92. 20 часто задаваних питань на співбесідах ...

Кава-брейк #92. 20 часто задаваних питань на співбесідах з Java

Стаття з групи Random UA
Джерело: Dev.to Здрастуйте, колеги-розробники, я склав список основних питань на співбесіді з Java, які повинен знати кожен кодер.

1. Як у Java реверсувати рядок без використання методів reverse()?

Відповідь: Java не має стандартного методу reverse() , хоча метод reverse() існує в декількох бібліотеках, таких як StringBuffer або StringBuilder . Тому питання про реверсування масиву часто зустрічається на інтерв'ю. Нижче наводиться простий алгоритм, який можна використовуватиме реверсування масиву.
public class StringReverse {

    public static void main(String[] args) {

        String str = "Flexiple";
        System.out.println(reverse(str));
    }

    public static String reverse(String in) {
        if (in == null)
            throw new IllegalArgumentException("Null is not valid");

        StringBuilder out = new StringBuilder();

        char[] chars = in.toCharArray();

        for (int i = chars.length - 1; i >= 0; i--)
            out.append(chars[i]);

        return out.toString();
    }
}

2. Напишіть фрагмент коду для реалізації послідовності Фібоначчі з використанням рекурсії

Відповідь: Нижче наведений фрагмент коду реалізує послідовність Фібоначчі з використанням рекурсії. Це питання також дуже поширене на співбесідах з Java.
public class FibonacciNumbers {
    public static int fibonacci(int n) {
        if (n <= 1)
            return n;
        return fibonacci(n - 1) + fibonacci(n - 2);
    }


    public static void main(String args[]) {
        int n = 10;
        System.out.println(fibonacci(n));
    }
}

3. Як у Java видаляються пробіли з рядка?

Відповідь: Метод strip() — це рядковий метод, який видаляє всі початкові та кінцеві прогалини. Strip() використовує в собі метод Character.isWhitespace() для перевірки прогалин. Він визначає пробіли за допомогою символів Unicodes та є рекомендованим способом видалення пробілів. Також можна використовувати альтернативні методи stripLeading() та stripTrailing() . Вони допоможуть, якщо ви хочете видалити лише початкові або кінцеві пробіли відповідно. Наведений нижче код є прикладом використання методу strip() .
String s = "  flexiple ";

s = s.strip();

System.out.println(s);

4. Що викликає тупиковий (deadlock) сценарій? Напишіть код для створення deadlock

Відповідь: Сценарій взаємоблокування (deadlock) виникає, коли два потоки вимагають однакових блокувань для виконання. Ці сценарії виникають, коли обидва потоки отримали одне блокування і очікують на отримання іншого блокування. Однак, оскільки обидва потоки чекають на виконання іншого, вони блокують один одного, викликаючи взаємоблокування. Багатопотокові програми страждають від блокування, оскільки ключове слово synchronized використовується для забезпечення потокової безпеки методів. Це означає, що лише один потік може заблокувати та використовувати синхронізований метод. Інші потоки повинні дочекатися завершення потоку. Наведений нижче код створює два потоки, які перебувають у взаємоблокуванні.
class Util
{
    static void sleep(long millis)
    {
        try
        {
            Thread.sleep(millis);
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }
    }
}
class Shared
{
    synchronized void test1(Shared s2)
    {
        System.out.println("test1-begin");
        Util.sleep(1000);

        s2.test2();
        System.out.println("test1-end");
    }

    synchronized void test2()
    {
        System.out.println("test2-begin");
        Util.sleep(1000);

        System.out.println("test2-end");
    }
}

class Thread1 extends Thread
{
    private Shared s1;
    private Shared s2;

    public Thread1(Shared s1, Shared s2)
    {
        this.s1 = s1;
        this.s2 = s2;
    }

    @Override
    public void run()
    {
        s1.test1(s2);
    }
}

class Thread2 extends Thread
{
    private Shared s1;
    private Shared s2;

    public Thread2(Shared s1, Shared s2)
    {
        this.s1 = s1;
        this.s2 = s2;
    }

    @Override
    public void run()
    {
        s2.test2(s1);
    }
}

public class Deadlock
{
    public static void main(String[] args)
    {
        Shared s1 = new Shared();

        Shared s2 = new Shared();

        Thread1 t1 = new Thread1(s1, s2);
        t1.start();

        Thread2 t2 = new Thread2(s1, s2);
        t2.start();

        Util.sleep(2000);
    }
}

5. Напишіть Java-код для друку дати у визначеному форматі

Відповідь: Клас SimpleDateFormat допомагає перетворювати дати з одного формату на інший. Цей метод також дозволяє користувачам використовувати строковий формат дати та змінювати його до бажаного формату. Наведений нижче код перетворює дату у стандартний формат: ДД/ММ/РРРР
import java.text.SimpleDateFormat;
import java.util.Date;
public class CurrentDateTimeExample2 {
public static void main(String[] args) {
    SimpleDateFormat formatter = new SimpleDateFormat("DD/MM/YYYY HH:mm:ss");
    Date date = new Date();
    System.out.println(formatter.format(date));
}
}
Фрагмент коду для перетворення дати в ММ/ДД/РРРР:
import java.text.SimpleDateFormat;
import java.util.Date;
public class CurrentDateTimeExample2 {
public static void main(String[] args) {
    SimpleDateFormat formatter = new SimpleDateFormat("MM/DD/YYYY HH:mm:ss");
    Date date = new Date();
    System.out.println(formatter.format(date));
}
}

6. Як відсортувати HashMap за його значеннями?

Відповідь: HashMaps використовується для реалізації інтерфейсів map. Вони дають можливість користувачам зберігати пари ключ-значення (key-value), проте ключі мають бути унікальними. HashMaps не є впорядкованими колекціями і їх сортування немає сенсу, але оскільки сортування хеш-карт може бути досить складним, вони є поширеним питанням на співбесідах з Java. У наведеному нижче коді показано реалізацію HashMaps .
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

public class SortHashMap {

    public static void main(String[] args) {
        Map scores = new HashMap<>();

        scores.put("John", 6);
        scores.put("Carol", 8);
        scores.put("Martin", 9);
        scores.put("Mona", 7);
        scores.put("Eric", 5);

        System.out.println(scores);

        scores = sortByValue(scores);

        System.out.println(scores);

    }

    private static Map sortByValue(Map scores) {
        Map sorted = new LinkedHashMap<>();

        Set> entrySet = scores.entrySet();
        System.out.println(entrySet);

        List> entryList = new ArrayList<>(entrySet);
        System.out.println(entryList);

        entryList.sort((x, y) -> x.getValue().compareTo(y.getValue()));
        System.out.println(entryList);

        for (Entry e : entryList)
            sorted.put(e.getKey(), e.getValue());

        return sorted;
    }

}

7. Що робить метод forEach()? Поясніть на прикладі

Відповідь: forEach() — це метод, який використовується для перебору об'єктів Java. Але на відміну від інших циклів, тут лічильник циклу не оголошується і не ініціалізується, а скоріше передається змінна як ітерована (iterable). Отже, forEach() зазвичай використовується з масивами чи класами колекцій. Синтаксис:
for (type var : array)
{
    statements using var;
}
Приклад використання forEach() :
class ExampleForEach
{
    public static void main(String[] arg)
    {
        {
            int[] scores = { 10, 13, 9, 11, 11};

            int highest_score = maximum(scores);
            System.out.println(highest_scores);
        }
    }
    public static int maximum(int[] numbers)
    {
        int max = numbers[0];

        // for each loop
        for (int n : numbers)
        {
            if (n > max)
            {
                max = n;
            }
        }
    return max;
    }
}

8. Що таке функціональні інтерфейси та як вони створюються?

Відповідь: Інтерфейс, що містить лише один абстрактний метод, називається функціональним інтерфейсом. Згодом функціональні інтерфейси можуть мати лише одну функцію, однак вони можуть містити декілька методів за промовчанням. Java 8 лямбда-вирази можуть використовуватися для створення екземплярів функціональних інтерфейсів, що значно спрощує роботу. Приклади функціональних інтерфейсів: ActionListener , Comparable . Ось код, який використовується визначення функціонального інтерфейсу.
@FunctionalInterface
interface Foo {
    void test();
}

9. Опишіть навантаження (Overloading) на прикладі

Відповідь: Перевантаження (Overloading) — це процес дозволу кількох методів з тим самим ім'ям, але різняться залежно від своїх сигнатур, типу даних чи кількості параметрів. Перевантаження дозволяє користувачу повторно використовувати один метод, а не створювати та запам'ятовувати кілька методів. Коротше кажучи, навантаження пов'язані з поліморфізмом часу компіляції. Приклад коду навантаження методу:
public class Sum {

    public int sum(int x, int y)
    {
        return (x + y);
    }

    public int sum(int x, int y, int z)
    {
        return (x + y + z);
    }

    public double sum(double x, double y)
    {
        return (x + y);
    }

    public static void main(String args[])
    {
        Sum s = new Sum();
        System.out.println(s.sum(10, 20));
        System.out.println(s.sum(10, 20, 30));
        System.out.println(s.sum(10.5, 20.5));
    }
}

10. Опишіть перевизначення (Overriding) з прикладу

Відповідь: Перевизначення (Overriding) — це функція Java, яка дозволяє підкласам або дочірнім класам надавати окрему реалізацію для існуючого методу в батьківському класі. Коли метод підкласу має те саме ім'я, параметр і тип значення, що повертається, що і батьківський клас, цей метод перевизначає метод в батьківському класі. І версія викликаного методу визначає, який метод буде виконано. Перевизначення - це спосіб досягти поліморфізму під час виконання. Приклад коду перевизначення методу:
class Parent {
    void show()
    {
        System.out.println("Parent's show()");
    }
}

class Child extends Parent {
    @Override
    void show()
    {
        System.out.println("Child's show()");
    }
}

class Main {
    public static void main(String[] args)
    {
        Parent obj1 = new Parent();
        obj1.show();

        Parent obj2 = new Child();
        obj2.show();
    }
}

11. Що таке бінарний пошук? А як це реалізовано?

Відповідь: Алгоритм двоичного (бінарного) пошуку використовується для пошуку значення у відсортованому масиві чи типі колекції. Цей метод пошуку значно швидший, ніж методи лінійного пошуку. Бінарний пошук розбиває масив на дрібніші набори, а потім застосовує правила для перевірки ключа введення. Етапи реалізації двійкового (бінарного) пошуку:
  • Відсортуйте масив за зростанням.
  • Знайдіть середнє значення масиву та порівняйте його з ключем.
  • Якщо ключ дорівнює середньому значенню, поверніть true.
  • Якщо false, перевірте, чи ключ більше або менше середнього значення.
  • Далі на основі результату перевірте ключ у верхній чи нижній половині відповідно.
  • Ітеруйте та порівняйте кожне значення з ключем.
Фрагмент коду з реалізацією двійкового пошуку:
import java.util.Scanner;

public class BinarySearch {

    public static void main(String[] args) {

        Scanner commandReader = new Scanner(System.in);
        System.out.println("Enter total number of elements : ");
        int length = commandReader.nextInt();
        int[] input = new int[length];

        System.out.printf("Enter %d integers %n", length);
        for (int i = 0; i < length; i++) {
            input[i] = commandReader.nextInt();
        }

        System.out.println("Please enter number to be searched in array
                                    (sorted order)");
        int key = commandReader.nextInt();

        int index = performBinarySearch(input, key);

        if (index == -1) {
            System.out.printf("Sorry, %d is not found in array %n", key);
        } else {
            System.out.printf("%d is found in array at index %d %n", key,
                                                         index);
        }

        commandReader.close();

    }


    public static int performBinarySearch(int[] input, int number) {
        int low = 0;
        int high = input.length - 1;

        while (high >= low) {
            int middle = (low + high) / 2;
            if (input[middle] == number) {
                return middle;
            } else if (input[middle] < number) {
                low = middle + 1;
            } else if (input[middle] > number) {
                high = middle - 1;
            }
        }
        return -1;
    }

}

12. Які найкращі методи запобігання взаємоблокуванню (deadlocks) у Java?

Відповідь:
  • Вкладені блокування (Nesting Locks): основна причина взаємоблокування - це коли блокування передаються кільком потокам. Уникнення блокування кількох потоків у випадку, якщо потік із блокуванням вже існує, може допомогти запобігти взаємоблокуванню.
  • Використання Thread.join() : взаємоблокування можуть виникати, коли потік очікує ресурс з іншого потоку. Однак у таких випадках Thread.join() можна використовувати з максимальним часом виконання.
  • Використання блокування лише за потреби: Практикуйте у використанні блокування лише на елементах, коли це необхідно. Непотрібні блокування – основна причина тупикових ситуацій.

13. Напишіть код для реалізації LRU-кешування на Java

Відповідь: LRU означає кеш-пам'ять, яка найменше використовувалася. Схема кешування LRU використовується видалення останнього використаного кеша. Цей процес відбувається, коли існуючий кеш заповнений, а нова сторінка, на яку є посилання, відсутня у існуючому кеші. У наведеному нижче коді показано реалізацію:
import java.util.Deque;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Iterator;

public class LRUCache {

    private Deque doublyQueue;

    private HashSet hashSet;

    private final int CACHE_SIZE;

    LRUCache(int capacity) {
        doublyQueue = new LinkedList<>();
        hashSet = new HashSet<>();
        CACHE_SIZE = capacity;
    }

    public void refer(int page) {
        if (!hashSet.contains(page)) {
            if (doublyQueue.size() == CACHE_SIZE) {
                int last = doublyQueue.removeLast();
                hashSet.remove(last);
            }
        }
        else {/* The found page may not be always the last element, even if it's an
            intermediate element that needs to be removed and added to the start
            of the Queue */
            doublyQueue.remove(page);
        }
        doublyQueue.push(page);
        hashSet.add(page);
    }

    public void display() {
        Iterator itr = doublyQueue.iterator();
        while (itr.hasNext()) {
            System.out.print(itr.next() + " ");
        }
    }

    public static void main(String[] args) {
        LRUCache cache = new LRUCache(4);
        cache.refer(1);
        cache.refer(2);
        cache.refer(3);
        cache.refer(1);
        cache.refer(4);
        cache.refer(5);
        cache.refer(2);
        cache.refer(2);
        cache.refer(1);
        cache.display();
    }
}

14. Як повернути масив залежно від позиції K, наприклад, k = 2?

Відповідь: фрагмент коду обертає (return) масив залежно від зазначеної позиції. Хоча це здається простим, він перевіряє ваше розуміння циклів та масивів і, отже, є поширеним питанням на співбесідах з Java.
public static int[] rotateBruteForce(int[] nums, int k) {
 for (int i = 0; i < k; i++) {
 for (int j = nums.length - 1; j > 0; j--) {
 // move each number by 1 place
 int temp = nums[j];
 nums[j] = nums[j - 1];
 nums[j - 1] = temp;
 }
 System.out.println("Array rotation after "+(i+1)+" step");
 printArray(nums);
 System.out.println();
 }
 return nums;
 }

15. Що таке черги (Queues) у Java? Реалізуйте їх за допомогою масивів.

Відповідь: Черги – це лінійні структури, які демонструють порядок операцій у порядку черги. Java дійсно забезпечує простіші реалізації для абстрактних типів даних, таких як черги, стеки і так далі. Однак їхня реалізація з використанням масиву — це питання, яке перевіряє ваше розуміння концепції. Пам'ятайте, що реалізація черги у вигляді масиву не є динамічною.
package org.arpit.java2blog;

public class QueueUsingArrayMain {

    private int capacity;
    int queueArr[];
    int front;
    int rear;
    int currentSize = 0;

    public QueueUsingArrayMain(int sizeOfQueue) {
        this.capacity = sizeOfQueue;
        front = 0;
        rear = -1;
        queueArr = new int[this.capacity];
    }

16. Що таке HeapSort? Напишіть код для його реалізації

Відповідь: HeapSort – це метод сортування, що ґрунтується на структурі даних двійкової (бінарної) купи. Двійкова купа - це двійкове дерево, в якому елементи зберігаються таким чином, що значення батьківського вузла або більше (max-heap), або менше (min-heap), ніж значення в дочірньому вузлі. Код для реалізації HeapSort виглядає так:
public class HeapSort {
    public void sort(int arr[])
    {
        int n = arr.length;

        // Build heap (rearrange array)
        for (int i = n / 2 - 1; i >= 0; i--)
            heapify(arr, n, i);

        // One by one extract an element from heap
        for (int i = n - 1; i > 0; i--) {
            // Move current root to end
            int temp = arr[0];
            arr[0] = arr[i];
            arr[i] = temp;

            // call max heapify on the reduced heap
            heapify(arr, i, 0);
        }
    }

    // To heapify a subtree rooted with node i which is
    // an index in arr[]. n is size of heap
    void heapify(int arr[], int n, int i)
    {
        int largest = i; // Initialize largest as root
        int l = 2 * i + 1; // left = 2*i + 1
        int r = 2 * i + 2; // right = 2*i + 2

        // If left child is larger than root
        if (l < n && arr[l] > arr[largest])
            largest = l;

        // If right child is larger than largest so far
        if (r < n && arr[r] > arr[largest])
            largest = r;

        // If largest is not root
        if (largest != i) {
            int swap = arr[i];
            arr[i] = arr[largest];
            arr[largest] = swap;

            // Recursively heapify the affected sub-tree
            heapify(arr, n, largest);
        }
    }

    /* A utility function to print array of size n */
    static void printArray(int arr[])
    {
        int n = arr.length;
        for (int i = 0; i < n; ++i)
            System.out.print(arr[i] + " ");
        System.out.println();
    }

    // Driver code
    public static void main(String args[])
    {
        int arr[] = { 12, 11, 13, 5, 6, 7 };
        int n = arr.length;

        HeapSort ob = new HeapSort();
        ob.sort(arr);

        System.out.println("Sorted array is");
        printArray(arr);
    }
}

17. Що таке Мемоізація (Memoization)?

Відповідь: Мемоізація – це підхід, який допомагає вирішувати проблеми, спричинені динамічним програмуванням. Цей процес гарантує, що цей метод не буде виконуватися більше одного разу для тих самих вхідних даних. Значення, що повертаються, зберігаються в хеш-таблицях або хеш-картах і використовуються повторно при необхідності. Наведений нижче код є прикладом мемоізації у послідовності Фібоначчі.
import java.io.*;

class GFG
{

// Fibonacci Series
// using Recursion
static int fib(int n)
{

    // Base case
    if (n <= 1)
        return n;

    // recursive calls
    return fib(n - 1) +
        fib(n - 2);
}

// Driver Code
public static void main (String[] args)
{
    int n = 6;
    System.out.println(fib(n));
}
}

18. Напишіть фрагмент коду для реалізації бульбашкового (bubble) сортування

Відповідь: Наведений нижче код є рішенням для сортування міхура, що також є поширеним питанням на співбесідах з Java.
public class BubbleSortExample {
    static void bubbleSort(int[] arr) {
        int n = arr.length;
        int temp = 0;
         for(int i=0; i < n; i++){
                 for(int j=1; j < (n-i); j++){
                          if(arr[j-1] > arr[j]){
                                 //swap elements
                                 temp = arr[j-1];
                                 arr[j-1] = arr[j];
                                 arr[j] = temp;
                         }
                 }
         }
    }
    public static void main(String[] args) {
                int arr[] ={3,60,35,2,45,320,5};
                System.out.println("Array Before Bubble Sort");
                for(int i=0; i < arr.length; i++){
                        System.out.print(arr[i] + " ");
                }
                System.out.println();
                bubbleSort(arr);//sorting array elements using bubble sort
                System.out.println("Array After Bubble Sort");
                for(int i=0; i < arr.length; i++){
                        System.out.print(arr[i] + " ");
                }

        }
}

19. Що таке trie-структури даних у Java?

Відповідь: Trie – це структура даних, яка зберігає дані у впорядкованій деревоподібній структурі, використовуючи ключі зберігання. Положення вузла у дереві визначає ключ, пов'язаний із вузлом, а спадкоємці вузла мають загальний префікс. Завдяки такій структурі trie-файли пропонують кращу продуктивність, а також значно швидше одержують дані. Однак єдиним недоліком використання дерева є те, що йому потрібно більше місця для зберігання.

20. Напишіть фрагмент коду для перетворення HashMap на ArrayList

Відповідь: Наведений нижче код використовується для перетворення HashMap на ArrayList .
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.Set;
public class Java8MapToListExamples
{
    public static void main(String[] args)
    {
        //Creating a HashMap object

        HashMap studentPerformanceMap = new HashMap();

        //Adding elements to HashMap

        studentPerformanceMap.put("John Kevin", "Average");

        studentPerformanceMap.put("Rakesh Sharma", "Good");

        studentPerformanceMap.put("Prachi D", "Very Good");

        studentPerformanceMap.put("Ivan Jose", "Very Bad");

        studentPerformanceMap.put("Smith Jacob", "Very Good");

        studentPerformanceMap.put("Anjali N", "Bad");

        //Getting Set of keys

        Set keySet = studentPerformanceMap.keySet();

        //Creating an ArrayList of keys

        ArrayList listOfKeys = new ArrayList(keySet);

        System.out.println("ArrayList Of Keys :");

        for (String key : listOfKeys)
        {
            System.out.println(key);
        }

        System.out.println("--------------------------");

        //Getting Collection of values

        Collection values = studentPerformanceMap.values();

        //Creating an ArrayList of values

        ArrayList listOfValues = new ArrayList(values);

        System.out.println("ArrayList Of Values :");

        for (String value : listOfValues)
        {
            System.out.println(value);
        }

        System.out.println("--------------------------");

        //Getting the Set of entries

        Set> entrySet = studentPerformanceMap.entrySet();

        //Creating an ArrayList Of Entry objects

        ArrayList> listOfEntry = new ArrayList>(entrySet);

        System.out.println("ArrayList of Key-Values :");

        for (Entry entry : listOfEntry)
        {
            System.out.println(entry.getKey()+" : "+entry.getValue());
        }
    }
}
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ