JavaRush /Java Blog /Random-ID /Analisis tanya jawab dari wawancara untuk pengembang Java...

Analisis tanya jawab dari wawancara untuk pengembang Java. Bagian 13

Dipublikasikan di grup Random-ID
Halo!
Gerakan menuju suatu tujuan, pertama-tama, adalah gerakan.
Oleh karena itu, tidak cukup hanya berpikir bahwa Anda ingin mencapai sesuatu. Anda perlu melakukan sesuatu - bahkan langkah terkecil sekalipun - tetapi lakukan setiap hari, dan hanya dengan cara ini Anda akan mencapai tujuan akhir. Dan karena Anda di sini untuk menjadi pengembang Java, Anda perlu mengambil setidaknya satu langkah minimal untuk memperdalam pengetahuan Anda tentang Java setiap hari. Untuk langkah Java hari ini, saya sarankan Anda membiasakan diri dengan bagian baru dari analisis pertanyaan wawancara paling populer untuk pengembang. Analisis tanya jawab dari wawancara untuk pengembang Java.  Bagian 13 - 1Hari ini kita akan membahas bagian praktis dari pertanyaan untuk spesialis Junior. Tugas praktis saat wawancara bukanlah hal yang aneh. Penting untuk tidak tersesat dalam situasi seperti ini, cobalah untuk tetap tenang dan menawarkan solusi optimal, atau bahkan beberapa. Saya juga merekomendasikan untuk tidak berdiam diri saat memecahkan suatu masalah, tetapi mengomentari alur pemikiran Anda dan menulis solusinya, atau setelah menulis, jelaskan dengan kata-kata apa yang Anda lakukan dan mengapa. Ini akan membuat Anda lebih disayangi pewawancara daripada keputusan diam-diam. Jadi mari kita mulai!

111. Bagaimana cara bertukar data antar thread?

Analisis tanya jawab dari wawancara untuk pengembang Java.  Bagian 13 - 2Untuk bertukar data antar thread, Anda dapat menggunakan banyak pendekatan dan cara yang berbeda: misalnya, menggunakan variabel atom, koleksi tersinkronisasi, dan semaphore. Namun untuk mengatasi masalah tersebut, saya akan memberikan contoh dengan Exchanger . Exchanger adalah kelas sinkronisasi dari paket konkuren yang memfasilitasi pertukaran elemen antara sepasang thread dengan membuat titik sinkronisasi umum. Penggunaannya menyederhanakan pertukaran data antara dua thread. Cara kerjanya cukup sederhana: ia menunggu dua thread terpisah memanggil metode exchange() miliknya . Sesuatu seperti titik pertukaran dibuat di antara mereka: utas pertama menempatkan objeknya dan menerima objek dari yang lain sebagai imbalannya, dan yang terakhir, pada gilirannya, menerima objek dari yang pertama dan menempatkan miliknya sendiri. Artinya, thread pertama menggunakan metode exchange() dan menganggur hingga thread lain memanggil metode exchange() pada objek yang sama dan data dipertukarkan di antara keduanya. Sebagai contoh, perhatikan implementasi kelas Thread berikut :
public class CustomThread extends Thread {
 private String threadName;
 private String message;
 private Exchanger<String> exchanger;

 public CustomThread(String threadName, Exchanger<String> exchanger) {
   this.threadName = threadName;
   this.exchanger = exchanger;
 }

 public void setMessage(final String message) {
   this.message = message;
 }

 @Override
 public void run() {
   while (true) {
     try {
       message = exchanger.exchange(message);
       System.out.println(threadName + " поток получил сообщение: " + message);
       Thread.sleep(1000);
     } catch (Exception e) {
       e.printStackTrace();
     }
   }
 }
}
Di konstruktor thread, kita mendefinisikan objek Exchanger yang menerima objek bertipe String , dan saat startup (dalam metode run ) kita menggunakan exchange() untuk bertukar pesan dengan thread lain yang menggunakan metode ini di Exchanger yang sama . Mari kita jalankan di main :
Exchanger<String> exchanger = new Exchanger<>();
CustomThread first = new CustomThread("Первый ", exchanger);
first.setMessage("Сообщение первого потока");
CustomThread second = new CustomThread("Второй", exchanger);
second.setMessage("Сообщение второго потока");
first.start();
second.start();
Konsol akan menampilkan:
Thread pertama menerima pesan: Pesan dari thread kedua Thread kedua menerima pesan: Pesan dari thread pertama Thread kedua menerima pesan: Pesan dari thread kedua Thread pertama menerima pesan: Pesan dari thread pertama Yang kedua thread menerima pesan: Pesan dari thread pertama Thread pertama menerima pesan: Pesan dari thread kedua... .
Artinya pertukaran data antar thread berhasil.

112. Apa perbedaan antara kelas Thread dan antarmuka Runnable?

Hal pertama yang saya perhatikan adalah bahwa Thread adalah sebuah kelas, Runnable adalah sebuah antarmuka, yang merupakan perbedaan yang sangat jelas =D Analisis tanya jawab dari wawancara untuk pengembang Java.  Bagian 13 - 3Saya juga akan mengatakan bahwa Thread menggunakan Runnable (komposisi). Artinya, kita punya dua cara:
  1. Mewarisi dari Thread , ganti metode run, lalu buat objek ini dan mulai thread melalui metode start() .

  2. Implementasikan Runnable di kelas tertentu, implementasikan metode run() -nya , lalu buat objek Thread , dengan menugaskan implementasi objek antarmuka Runnable ini ke konstruktornya . Nah, pada akhirnya, luncurkan objek Thread menggunakan metode start() .

Apa yang lebih disukai? Mari kita berpikir sedikit:
  • Saat Anda mengimplementasikan antarmuka Runnable , Anda tidak mengubah perilaku thread. Pada dasarnya Anda hanya memberikan sesuatu pada thread untuk dijalankan. Dan inilah komposisi kami, yang pada gilirannya dianggap sebagai pendekatan yang baik.

  • mengimplementasikan Runnable memberikan lebih banyak fleksibilitas pada kelas Anda. Jika Anda mewarisi dari Thread , maka tindakan yang Anda lakukan akan selalu ada di thread. Namun jika Anda mengimplementasikan Runnable, itu tidak harus hanya berupa thread. Lagi pula, Anda bisa menjalankannya di thread atau meneruskannya ke beberapa layanan pelaksana. Ya, atau serahkan saja ke suatu tempat sebagai tugas dalam aplikasi single-thread.

  • Menggunakan Runnable memungkinkan Anda memisahkan eksekusi tugas secara logis dari logika kontrol thread.

  • Di Java, hanya pewarisan tunggal yang dimungkinkan, sehingga hanya satu kelas yang dapat diperluas. Pada saat yang sama, jumlah antarmuka yang dapat diperluas tidak terbatas (yah, tidak sepenuhnya tidak terbatas, tetapi 65535 , tetapi kemungkinan besar Anda tidak akan pernah mencapai batas ini).

Nah, terserah Anda untuk memutuskan mana yang lebih baik untuk digunakan ^^

113. Ada benang T1, T2 dan T3. Bagaimana cara menerapkannya secara berurutan?Analisis tanya jawab dari wawancara untuk pengembang Java.  Bagian 13 - 4

Hal pertama dan paling sederhana yang terlintas dalam pikiran adalah menggunakan metode join() . Ini menangguhkan eksekusi thread saat ini (yang memanggil metode) hingga thread yang memanggil metode tersebut selesai dieksekusi. Mari buat implementasi thread kita sendiri:
public class CustomThread extends Thread {
private String threadName;

 public CustomThread(final String  threadName){
   this.threadName = threadName;
 }

 @Override
 public void run() {
   System.out.println(threadName + " - начал свою работу");
   try {
     // происходит некая логика
     Thread.sleep(1000);
   } catch (InterruptedException e) {
     e.printStackTrace();
   }

   System.out.println(threadName + " - закончил свою работу");
 }
}
Mari kita mulai tiga thread tersebut satu per satu menggunakan join() :
CustomThread t1 = new CustomThread("Первый поток");
t1.start();
t1.join();
CustomThread t2 = new CustomThread("Второй поток");
t2.start();
t2.join();
CustomThread t3 = new CustomThread("Третий поток");
t3.start();
t3.join();
Keluaran konsol:
Thread pertama - memulai pekerjaannya Thread pertama - menyelesaikan pekerjaannya Thread kedua - memulai pekerjaannya Thread kedua - menyelesaikan pekerjaannya Thread ketiga - memulai pekerjaannya Thread ketiga - menyelesaikan pekerjaannya
Artinya kita telah menyelesaikan tugas kita. Selanjutnya kita lanjutkan langsung ke tugas praktek di tingkat Junior .

Tugas praktis

114. Jumlah Diagonal Matriks (masalah Leetcode)

Syarat: Hitung jumlah semua elemen pada diagonal utama dan semua elemen pada diagonal tambahan yang bukan merupakan bagian dari diagonal utama. Analisis tanya jawab dari wawancara untuk pengembang Java.  Bagian 13 - 51. Dengan matriks berbentuk: mat = [[1,2,3], [4,5,6], [7,8,9]] Outputnya seharusnya - 25 2. Dengan matriks - mat = [[1,1 ,1,1], [1,1,1,1], [1,1,1,1], [1,1,1,1]] Outputnya seharusnya - 8 3. Dengan a matriks - mat = [[ 5]] Kesimpulannya seharusnya - 5 Jeda membaca dan terapkan keputusan Anda. Solusi saya adalah sebagai berikut:
public static int countDiagonalSum(int[][] matrix) {
 int sum = 0;
 for (int i = 0, j = matrix.length - 1; i < matrix.length; i++, j--) {
   sum += matrix[i][i];
   if (j != i) {
     sum += matrix[i][j];
   }
 }
 return sum;
}
Semuanya terjadi dengan satu lintasan melalui larik, di mana kita memiliki dua indeks untuk laporan: i - untuk melaporkan baris larik dan kolom diagonal utama, j - untuk melaporkan kolom diagonal tambahan. Jika sel diagonal utama dan sel diagonal tambahan bertepatan, maka salah satu nilai diabaikan saat menghitung jumlahnya. Mari kita periksa menggunakan matriks dari kondisi:
int[][] arr1 = {
   {1, 2, 3},
   {4, 5, 6},
   {7, 8, 9}};
System.out.println(countDiagonalSum(arr1));

int[][] arr2 = {
   {1, 1, 1, 1},
   {1, 1, 1, 1},
   {1, 1, 1, 1},
   {1, 1, 1, 1}};
System.out.println(countDiagonalSum(arr2));

int[][] arr3 = {{5}};
System.out.println(countDiagonalSum(arr3));
Keluaran konsol:
25 8 5

115. Pindahkan Nol (tantangan Leetcode)

Kondisi: Dalam array bilangan bulat, pindahkan semua angka 0 ke akhir, pertahankan urutan relatif elemen bukan nol. 1. Dengan array: [0,1,0,3,12] Outputnya harusnya: [1,3,12,0,0] 2. Dengan array: [0] Outputnya harusnya: [0] Jeda dan tulis keputusan saya... Keputusan saya:
public static void moveZeroes(int[] nums) {
 int counterWithoutNulls = 0;
 int counterWithNulls = 0;
 int length = nums.length;
 while (counterWithNulls < length) {
   if (nums[counterWithNulls] == 0) {// находим нулевые элементы и увеличиваем счётчик
     counterWithNulls++;
   } else { // сдвигаем элементы на количество найденных нулевых элементов слева
     nums[counterWithoutNulls++] = nums[counterWithNulls++];
   }
 }
 while (counterWithoutNulls < length) {
   nums[counterWithoutNulls++] = 0;// заполняем последние элементы массива нулями согласно счётчику нулей
 }
}
Penyelidikan:
int[] arr1 = {1, 2, 0, 0, 12, 9};
moveZeroes(arr1);
System.out.println(Arrays.toString(arr1));

int[] arr2 = {0};
moveZeroes(arr2);
System.out.println(Arrays.toString(arr2));
Keluaran konsol:
[1, 2, 12, 9, 0, 0] [0]

116. Diberikan Daftar nama <String>. Hapus huruf pertama dari setiap nama dan putar daftar yang diurutkan

1. Hal pertama yang terlintas dalam pikiran adalah metode kelas Collections , yang berisi banyak metode tambahan untuk koleksi:
public static List<String> processTheList(List<String> nameList) {
 for (int i = 0; i < nameList.size(); i++) {
   nameList.set(i, nameList.get(i).substring(1));
 }
 Collections.sort(nameList);
 return nameList;
}
2. Selain itu, jika kita menggunakan Java versi 8 dan lebih tinggi, kita cukup menunjukkan solusinya melalui stream:
public static List<String> processTheList(List<String> nameList) {
 return nameList.stream()
     .map(x -> x.substring(1))
     .sorted().collect(Collectors.toList());
}
Terlepas dari solusi yang dipilih, pemeriksaannya mungkin sebagai berikut:
List<String> nameList = new ArrayList();
nameList.add("John");
nameList.add("Bob");
nameList.add("Anna");
nameList.add("Dmitriy");
nameList.add("Peter");
nameList.add("David");
nameList.add("Igor");

System.out.println(processTheList(nameList));
Keluaran konsol:
[avid, eter, gor, mitriy, nna, ob, ohn]

117. Balikkan susunannya

Solusi 1 Sekali lagi, hal pertama yang terlintas dalam pikiran adalah menggunakan metode kelas utilitas tambahan Collections . Tapi karena kita memiliki array, pertama-tama kita perlu mengubahnya menjadi koleksi (daftar):
public static Integer[] reverse(Integer[] arr) {
 List<Integer> list = Arrays.asList(arr);
 Collections.reverse(list);
 return list.toArray(arr);
}
Solusi 2 Karena pertanyaannya adalah tentang array, saya pikir perlu untuk menunjukkan solusinya tanpa menggunakan fungsionalitas yang sudah jadi, dan bisa dikatakan, menurut klasik:
public static Integer[] reverse(Integer[] arr) {
 for (int i = 0; i < arr.length / 2; i++) {
   int temp = arr[i];
   arr[i] = arr[arr.length - 1 - i];
   arr[arr.length - 1 - i] = temp;
 }
 return arr;
}
Penyelidikan:
Integer[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9};
System.out.println(Arrays.toString(reverse(arr)));
Keluaran konsol:
[9, 8, 7, 6, 5, 4, 3, 2, 1]

118. Periksa apakah suatu string merupakan palindrom

Analisis tanya jawab dari wawancara untuk pengembang Java.  Bagian 13 - 6Solusi 1 Perlu segera diingat StringBuilder : ini lebih fleksibel dan kaya akan berbagai metode dibandingkan dengan String biasa . Kami terutama tertarik pada metode sebaliknya :
public static boolean isPalindrome(String string) {
 string = string.toLowerCase(); //приводит всю строку к нижнему регистру
 StringBuilder builder = new StringBuilder();
 builder.append(string);
 builder.reverse(); // перевочиваем строку методом Builder-а
 return (builder.toString()).equals(string);
}
Solusi: Pendekatan selanjutnya adalah tanpa menggunakan “celah” yang ada. Kami membandingkan karakter di belakang string dengan karakter terkait di depan:
public static boolean isPalindrome(String string) {
  string = string.toLowerCase();
 int length = string.length();
 int fromBeginning = 0;
 int fromEnd = length - 1;
 while (fromEnd > fromBeginning) {
   char forwardChar = string.charAt(fromBeginning++);
   char backwardChar = string.charAt(fromEnd--);
   if (forwardChar != backwardChar)
     return false;
 }
 return true;
}
Dan kami memeriksa kedua pendekatan tersebut:
boolean isPalindrome = isPalindrome("Tenet");
System.out.println(isPalindrome);
Keluaran konsol:
BENAR

119. Tulis algoritma pengurutan sederhana (Bubble, Selection atau Shuttle). Bagaimana cara memperbaikinya?

Sebagai algoritma implementasi sederhana, saya memilih pengurutan pilihan - Pengurutan Pilihan:
public static void selectionSorting(int[] arr) {
 for (int i = 0; i < arr.length - 1; i++) {
   int min = i;
   for (int j = i + 1; j < arr.length; j++) {
     if (arr[j] < arr[min]) {
       min = j; // выбираем минимальный элемент в текущем числовом отрезке
     }
   }
   int temp = arr[min]; // меняем местами минимальный элемент с элементом под индексом i
   arr[min] = arr[i]; // так How отрезок постоянно уменьшается
   arr[i] = temp; // и выпадающие из него числа будут минимальными в текущем отрезке
 } // и How итог - числа оставшиеся вне текущей итерации отсортированы от самого наименьшего к большему
}
Versi yang ditingkatkan akan terlihat seperti ini:
public static void improvedSelectionSorting(int[] arr) {
 for (int i = 0, j = arr.length - 1; i < j; i++, j--) { // рассматриваемый отрезок с каждой итерацией
   // будет уменьшаться с ДВУХ сторон по одному элементу
   int min = arr[i];
   int max = arr[i];
   int minIndex = i;
   int maxIndex = i;
   for (int n = i; n <= j; n++) { // выбираем min и max на текущем отрезке
     if (arr[n] > max) {
       max = arr[n];
       maxIndex = n;
     } else if (arr[n] < min) {
       min = arr[n];
       minIndex = n;
     }
   }
   // меняем найденный минимальный элемент с позиции с индексом min на позицию с индексом i
   swap(arr, i, minIndex);

   if (arr[minIndex] == max) {// срабатывает, если элемент max оказался смещен предыдущей перестановкой -
     swap(arr, j, minIndex); // на старое место min, поэтому с позиции с индексом min смещаем его на позицию j
   } else {
     swap(arr, j, maxIndex); // простое обмен местами элементов с индексами max и j
   }
 }
}

static int[] swap(int[] arr, int i, int j) {
 int temp = arr[i];
 arr[i] = arr[j];
 arr[j] = temp;
 return arr;
}
Nah, sekarang kita perlu memastikan apakah penyortiran sudah benar-benar membaik. Mari kita bandingkan kinerjanya:
long firstDifference = 0;
long secondDifference = 0;
long primaryTime;
int countOfApplying = 10000;
for (int i = 0; i < countOfApplying; i++) {
 int[] arr1 = {234, 33, 123, 4, 5342, 76, 3, 65,
     3, 5, 35, 75, 255, 4, 46, 48, 4658, 44, 22,
     678, 324, 66, 151, 268, 433, 76, 372, 45, 13,
     9484, 499959, 567, 774, 473, 3, 32, 865, 67, 43,
     63, 332, 24, 1};
 primaryTime = System.nanoTime();
 selectionSorting(arr1);
 firstDifference += System.nanoTime() - primaryTime;

 int[] arr2 = {234, 33, 123, 4, 5342, 76, 3, 65,
     3, 5, 35, 75, 255, 4, 46, 48, 4658, 44, 22,
     678, 324, 66, 151, 268, 433, 76, 372, 45, 13,
     9484, 499959, 567, 774, 473, 3, 32, 865, 67, 43,
     63, 332, 24, 1};
 primaryTime = System.nanoTime();
 improvedSelectionSorting(arr2);
 secondDifference += System.nanoTime() - primaryTime;
}

System.out.println(((double) firstDifference / (double) secondDifference - 1) * 100 + "%");
Kedua jenis tersebut dimulai pada siklus yang sama, karena jika ada loop terpisah, pengurutan dari kode di atas akan menunjukkan hasil yang lebih buruk daripada jika ditempatkan kedua. Hal ini disebabkan oleh fakta bahwa program “memanas” dan kemudian bekerja sedikit lebih cepat. Tapi saya akan sedikit keluar dari topik. Setelah lima kali menjalankan pemeriksaan ini di konsol, saya melihat peningkatan kinerja sebesar: 36.41006735635892% 51.46131097160771% 41.88918834013988% 48.091980705743566% 37.120220461591444% Bagi saya, ini cukup bagus hasil. Analisis tanya jawab dari wawancara untuk pengembang Java.  Bagian 13 - 7

120. Tulislah algoritma (urutan tindakan) untuk menyusun literal bertipe int dengan literal bertipe byte. Jelaskan apa yang terjadi pada ingatan

  1. nilai byte diubah menjadi int. Bukan 1 byte memori yang akan dialokasikan untuk itu, tetapi seperti semua nilai int - 4, jika nilai ini belum ada di tumpukan int. Jika ada, tautan ke sana akan diterima begitu saja.

  2. Dua nilai int akan ditambahkan dan nilai ketiga akan diperoleh. Bagian memori baru akan dialokasikan untuk itu - 4 byte (atau referensi akan diterima dari tumpukan int ke nilai yang ada).

    Dalam hal ini, memori dua int akan tetap terisi, dan nilainya masing-masing akan disimpan di tumpukan int.

Sebenarnya, di sinilah pertanyaan tingkat Junior dari daftar kami berakhir. Mulai artikel selanjutnya kita akan memahami permasalahan tingkat menengah. Saya ingin mencatat bahwa pertanyaan tingkat menengah juga secara aktif ditanyakan kepada pengembang tingkat pemula - Junior. Jadi pantau terus. Baiklah, itu saja untuk hari ini: sampai jumpa!Analisis tanya jawab dari wawancara untuk pengembang Java.  Bagian 13 - 8
Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION