JavaRush /Java blogi /Random-UZ /Java dasturchisi uchun intervyudan olingan savollar va ja...

Java dasturchisi uchun intervyudan olingan savollar va javoblarni tahlil qilish. 13-qism

Guruhda nashr etilgan
Salom!
Maqsad sari harakat, eng avvalo, harakatdir.
Shuning uchun, biror narsaga erishmoqchi deb o'ylashning o'zi etarli emas. Siz biror narsa qilishingiz kerak - hatto eng kichik qadamlar ham - lekin ularni har kuni bajaring va faqat shu tarzda yakuniy maqsadga erishasiz. Va siz Java dasturchisi bo'lish uchun kelganingiz uchun har kuni Java bo'yicha bilimingizni chuqurlashtirish yo'lida hech bo'lmaganda minimal qadam tashlashingiz kerak. Bugungi Java bosqichi uchun men ishlab chiquvchilar uchun eng mashhur intervyu savollari tahlilining yangi qismi bilan tanishishingizni tavsiya qilaman. Java dasturchisi uchun intervyudan olingan savollar va javoblarni tahlil qilish.  13-1-qismBugun biz kichik mutaxassislar uchun savollarning amaliy qismini ko'rib chiqamiz. Intervyuda amaliy topshiriq kamdan-kam uchraydi. Bunday vaziyatda yo'qolmaslik, sovuqqonlikni saqlashga harakat qilish va optimal echimni taklif qilish yoki hatto bir nechtasini taklif qilish muhimdir. Shuningdek, men muammoni hal qilishda jim turmaslikni, balki fikrlash pog'onasini sharhlab, yechimni yozishni yoki yozgandan so'ng nima qilganingizni va nima uchun so'z bilan tushuntirishni tavsiya qilaman. Bu sizni suhbatdoshga jim qarordan ko'ra ko'proq yoqadi. Shunday ekan, boshlaylik!

111. Tarmoqlar o'rtasida ma'lumotlar almashinuvi qanday amalga oshiriladi?

Java dasturchisi uchun intervyudan olingan savollar va javoblarni tahlil qilish.  13-2-qismTarmoqlar o'rtasida ma'lumot almashish uchun siz turli xil yondashuvlar va vositalardan foydalanishingiz mumkin: masalan, atom o'zgaruvchilari, sinxronlashtirilgan to'plamlar va semafordan foydalaning. Ammo bu muammoni hal qilish uchun men Exchanger bilan misol keltiraman . Exchanger - bu umumiy sinxronizatsiya nuqtasini yaratish orqali bir juft ip o'rtasida elementlar almashinuvini osonlashtiradigan bir vaqtning o'zida to'plamdagi sinxronizatsiya sinfidir . Uning ishlatilishi ikki ip o'rtasida ma'lumotlar almashinuvini soddalashtiradi. Uning ishlash usuli juda oddiy: u exchange() usulini chaqirish uchun ikkita alohida ish zarrachasini kutadi . Ular orasida almashinuv nuqtasiga o'xshash narsa yaratiladi: birinchi ip o'z ob'ektini qo'yadi va buning evaziga ikkinchisining ob'ektini oladi, ikkinchisi esa, o'z navbatida, birinchisining ob'ektini oladi va o'zinikini qo'yadi. Ya'ni, birinchi ish zarrachasi exchange() usulidan foydalanadi va bir xil ob'ektdagi exchange() usulini boshqa ip chaqirmaguncha va ular o'rtasida ma'lumotlar almashguncha bo'sh qoladi . Misol sifatida, Thread sinfining quyidagi amalga oshirilishini ko'rib chiqing :
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();
     }
   }
 }
}
Tarmoq konstruktorida biz String tipidagi ob'ektlarni qabul qiladigan Exchanger ob'ektini aniqlaymiz va ishga tushirilganda (ishlash usulida ) biz o'sha Exchangerda ushbu usuldan foydalanadigan boshqa oqim bilan xabar almashish uchun uning exchange() dan foydalanamiz . Keling, uni asosiyda ishga tushiramiz :
Exchanger<String> exchanger = new Exchanger<>();
CustomThread first = new CustomThread("Первый ", exchanger);
first.setMessage("Сообщение первого потока");
CustomThread second = new CustomThread("Второй", exchanger);
second.setMessage("Сообщение второго потока");
first.start();
second.start();
Konsolda ko'rsatiladi:
Birinchi mavzu xabarni oldi: Ikkinchi ipdan xabar Ikkinchi mavzu xabarni oldi: Birinchi ipdan xabar Ikkinchi ip xabarni oldi: Ikkinchi ipdan xabar Birinchi mavzu xabarni oldi: Birinchi ipdan xabar Ikkinchi mavzu xabarni oldi: Birinchi ipdan xabar Birinchi mavzu xabarni oldi: Ikkinchi ipdan xabar... .
Bu iplar o'rtasida ma'lumotlar almashinuvi muvaffaqiyatli ekanligini anglatadi.

112. Thread sinfi va Runnable interfeysi o'rtasidagi farq nima?

Men e'tiborga oladigan birinchi narsa - bu Thread - bu sinf, Runnable - bu interfeys, bu juda aniq farq =D Java dasturchisi uchun intervyudan olingan savollar va javoblarni tahlil qilish.  13-3-qismMen shuni ham aytamanki, Thread Runnable (kompozitsiya) dan foydalanadi . Ya'ni, bizda ikkita yo'l bor:
  1. Thread dan meros qilib oling , ishga tushirish usulini bekor qiling, so'ngra ushbu ob'ektni yarating va start() usuli orqali ipni boshlang .

  2. Runnable-ni ma'lum bir sinfda amalga oshiring , uning run() usulini qo'llang va keyin Thread ob'ektini yarating, Runnable interfeysining ushbu ob'ektini konstruktoriga tayinlang . Oxirida start() usuli yordamida Thread obyektini ishga tushiring .

Nima afzal? Keling, bir oz o'ylab ko'raylik:
  • Runnable interfeysini amalga oshirganingizda , siz ipning harakatini o'zgartirmaysiz. Asosan, siz shunchaki ipni ishga tushirish uchun biror narsa berasiz. Va bu bizning kompozitsiyamiz, bu o'z navbatida yaxshi yondashuv hisoblanadi.

  • Runnable dasturini amalga oshirish sizning sinfingizga ko'proq moslashuvchanlikni beradi. Agar siz Thread dan meros bo'lsangiz , bajarayotgan amal har doim ipda bo'ladi. Agar siz Runnable dasturini amalga oshirsangiz , u shunchaki ip bo'lishi shart emas. Axir, siz uni ish zarrachasida ishga tushirishingiz yoki ba'zi bir ijrochi xizmatiga topshirishingiz mumkin. Xo'sh, yoki shunchaki bitta tarmoqli ilovada vazifa sifatida uni biron joyga o'tkazing.

  • Runnable- dan foydalanish sizga vazifani bajarishni ipni boshqarish mantig'idan mantiqiy ajratish imkonini beradi.

  • Java-da faqat bitta meros mumkin, shuning uchun faqat bitta sinfni kengaytirish mumkin. Shu bilan birga, kengaytiriladigan interfeyslar soni cheksizdir (yaxshi, cheksiz emas, lekin 65535 , lekin siz bu chegaraga hech qachon erisha olmaysiz).

Xo'sh, nimadan foydalanish afzalroq bo'lishini o'zingiz hal qilasiz ^^

113. T1, T2 va T3 iplari mavjud. Qanday qilib ularni ketma-ket amalga oshirish kerak?Java dasturchisi uchun intervyudan olingan savollar va javoblarni tahlil qilish.  13-4-qism

Aqlga keladigan birinchi va eng oddiy narsa bu join() usulidan foydalanishdir . U joriy ish zarrachasining (usul deb ataladigan) bajarilishini, usul deb atalgan ip bajarilishini tugatmaguncha to'xtatib turadi. Keling, o'z ish zarrachamizni yarataylik:
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 + " - закончил свою работу");
 }
}
Keling, join() yordamida uchta shunday mavzuni birma-bir boshlaylik :
CustomThread t1 = new CustomThread("Первый поток");
t1.start();
t1.join();
CustomThread t2 = new CustomThread("Второй поток");
t2.start();
t2.join();
CustomThread t3 = new CustomThread("Третий поток");
t3.start();
t3.join();
Konsol chiqishi:
Birinchi ip - ishini boshladi Birinchi ip - ishini tugatdi Ikkinchi ip - ish boshladi Ikkinchi ip - ishini tugatdi Uchinchi ip - ish boshladi Uchinchi ip - ishini tugatdi
Bu bizning vazifamizni bajarganimizni anglatadi. Keyinchalik, biz to'g'ridan-to'g'ri kichik darajadagi amaliy vazifalarga o'tamiz .

Amaliy topshiriqlar

114. Matritsaning diagonal yig‘indisi (Leetcode muammosi)

Shart: Asosiy diagonalning barcha elementlari va qo'shimcha diagonalning asosiy diagonalning bir qismi bo'lmagan barcha elementlari yig'indisini hisoblang. Java dasturchisi uchun intervyudan olingan savollar va javoblarni tahlil qilish.  13-5-qism1. Ko'rinishdagi matritsa bilan: mat = [[1,2,3], [4,5,6], [7,8,9]] Chiqish - 25 bo'lishi kerak 2. Matritsa bilan - mat = [[1,1 ,1,1], [1,1,1,1], [1,1,1,1], [1,1,1,1]] Chiqish - 8 3 bo'lishi kerak. a matritsa - mat = [[ 5]] Xulosa bo'lishi kerak - 5 O'qishni to'xtatib turing va qaroringizni amalga oshiring. Mening yechimim quyidagicha bo'ladi:
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;
}
Hamma narsa massivdan bir marta o'tish bilan sodir bo'ladi, bunda bizda hisobot uchun ikkita indeks mavjud: i - massiv qatorlari va asosiy diagonal ustunlari haqida xabar berish uchun, j - qo'shimcha diagonal ustunlari haqida xabar berish uchun. Agar asosiy diagonal va qo'shimcha katakcha mos kelsa, yig'indini hisoblashda qiymatlardan biri e'tiborga olinmaydi. Shartdagi matritsalar yordamida tekshiramiz:
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));
Konsol chiqishi:
25 8 5

115. Nollarni siljitish (Leetcode challenge)

Shart: Butun sonli massivda nolga teng bo'lmagan elementlarning nisbiy tartibini saqlab, barcha 0 larni oxirigacha ko'chiring. 1. Massiv bilan: [0,1,0,3,12] Chiqish quyidagicha bo'lishi kerak: [1,3,12,0,0] 2. Massiv bilan: [0] Chiqish quyidagicha bo'lishi kerak: [0] To'xtab, qarorimni yozing... Mening qarorim:
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;// заполняем последние элементы массива нулями согласно счётчику нулей
 }
}
Imtihon:
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));
Konsol chiqishi:
[1, 2, 12, 9, 0, 0] [0]

116. Berilgan ro'yxat <String> nomlari. Har bir nomdan birinchi harfni olib tashlang va tartiblangan ro'yxatni aylantiring

1. Aqlga keladigan birinchi narsa bu Collections sinfining usullari bo'lib , unda to'plamlar uchun ko'plab yordamchi usullar mavjud:
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. Bundan tashqari, agar biz Java 8 va undan yuqori versiyalaridan foydalansak, yechimni oqimlar orqali ko‘rsatishimiz kifoya:
public static List<String> processTheList(List<String> nameList) {
 return nameList.stream()
     .map(x -> x.substring(1))
     .sorted().collect(Collectors.toList());
}
Tanlangan yechimdan qat'i nazar, tekshirish quyidagicha bo'lishi mumkin:
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));
Konsol chiqishi:
[avid, eter, gor, mitriy, nna, ob, ohn]

117. Massivni aylantiring

Yechim 1 Shunga qaramay, aqlga kelgan birinchi narsa yordamchi yordamchi sinfning usullaridan foydalanishdir Collections . Ammo bizda massiv bor ekan, avval uni to'plamga (ro'yxat) aylantirishimiz kerak:
public static Integer[] reverse(Integer[] arr) {
 List<Integer> list = Arrays.asList(arr);
 Collections.reverse(list);
 return list.toArray(arr);
}
2-echim Savol massiv haqida bo'lganligi sababli, menimcha, tayyor funksionallikni qutidan tashqarida ishlatmasdan va klassikaga ko'ra, yechimni ko'rsatish kerak:
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;
}
Imtihon:
Integer[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9};
System.out.println(Arrays.toString(reverse(arr)));
Konsol chiqishi:
[9, 8, 7, 6, 5, 4, 3, 2, 1]

118. Satrning palindrom ekanligini tekshiring

Java dasturchisi uchun intervyudan olingan savollar va javoblarni tahlil qilish.  13-6-qism1-yechim StringBuilder- ni zudlik bilan esga olish kerak : u oddiy String bilan solishtirganda ancha moslashuvchan va turli usullarga boy . Bizni ayniqsa teskari usul qiziqtiradi :
public static boolean isPalindrome(String string) {
 string = string.toLowerCase(); //приводит всю строку к нижнему регистру
 StringBuilder builder = new StringBuilder();
 builder.append(string);
 builder.reverse(); // перевочиваем строку методом Builder-а
 return (builder.toString()).equals(string);
}
Yechim: Keyingi yondashuv qutidagi "bo'shliqlar" dan foydalanmasdan bo'ladi. Biz satrning orqa qismidagi belgilarni old tomondan tegishli belgilar bilan taqqoslaymiz:
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;
}
Va ikkala yondashuvni ham tekshiramiz:
boolean isPalindrome = isPalindrome("Tenet");
System.out.println(isPalindrome);
Konsol chiqishi:
rost

119. Oddiy tartiblash algoritmini yozing (Bubble, Selection yoki Shuttle). Uni qanday yaxshilash mumkin?

Amalga oshirish uchun oddiy algoritm sifatida men tanlovni saralashni tanladim - Tanlovni saralash:
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 итог - числа оставшиеся вне текущей итерации отсортированы от самого наименьшего к большему
}
Yaxshilangan versiya quyidagicha ko'rinadi:
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;
}
Xo'sh, endi saralash haqiqatan ham yaxshilanganiga ishonch hosil qilishimiz kerak. Keling, samaradorlikni taqqoslaylik:
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 + "%");
Ikkala tur ham bir xil tsiklda boshlangan, chunki agar alohida looplar bo'lsa, yuqoridagi koddan saralash ikkinchi o'ringa qo'yilgandan ko'ra yomonroq natijalarni ko'rsatadi. Buning sababi dasturning "isishi" va keyin biroz tezroq ishlashidir. Lekin men mavzudan biroz chetga chiqyapman. Konsolda ushbu tekshiruvni besh marta o'tkazgandan so'ng, men ishlashning o'sishini ko'rdim: 36,41006735635892% 51,46131097160771% 41,88918834013988% 48,09198070574370162 , men uchun bu 32214%. juda yaxshi natija. Java dasturchisi uchun intervyudan olingan savollar va javoblarni tahlil qilish.  13-7-qism

120. Int tipidagi literalni bayt tipidagi literal bilan tuzish algoritmini (harakatlar ketma-ketligini) yozing. Xotira bilan nima sodir bo'lishini tushuntiring

  1. bayt qiymati int ga aylantiriladi. Buning uchun 1 bayt xotira ajratilmaydi, lekin barcha int qiymatlari kabi - 4, agar bu qiymat hali int stekida bo'lmasa. Agar mavjud bo'lsa, unga havola shunchaki olinadi.

  2. Ikkita int qiymati qo'shiladi va uchinchisi olinadi. Buning uchun yangi xotira bo'limi ajratiladi - 4 bayt (yoki int stekidan mavjud qiymatga havola olinadi).

    Bunday holda, ikkita int xotirasi hali ham band bo'ladi va ularning qiymatlari mos ravishda int stekida saqlanadi.

Aslida, bizning ro'yxatimizdagi Junior darajasidagi savollar shu erda tugaydi. Keyingi maqoladan boshlab biz o'rta darajadagi muammolarni tushunamiz. Shuni ta'kidlashni istardimki, o'rta darajadagi savollar boshlang'ich darajadagi ishlab chiquvchilarga - Juniorga ham faol so'raladi. Shuning uchun bizni kuzatib boring. Xo'sh, bugun hammasi shu: ko'rishguncha!Java dasturchisi uchun intervyudan olingan savollar va javoblarni tahlil qilish.  13-8-qism
Izohlar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION