Обложка: 7 практических заданий с собеседования на позицию Junior Java Developer

7 практических заданий с собеседования на позицию Junior Java Developer

Юрий Авраменко
Юрий Авраменко

Senior Software Developer

Для начинающего разработчика очень важно не только знать теоретическую базу, но и понимать как все работает под «капотом», поэтому зачастую вопросы, задаваемые на собеседовании, не только проверяют теоретические знания, но и способность их применить.

1. Каким будет значение переменной x, выведенной в консоль, при вызове метода bar()?

bar() {
   int[] nums = {1, 2, 3};
   for ( int x = 0; x < nums.length; x++ ) {
       x += nums[x];
   }
   System.out.println(x);
}

Код не с компилируется. Этот вопрос в большей степени проверяет внимательность и сосредоточенность кандидата, в данном примере, переменная x существует только внутри цикла и попытка вывести ее вне цикла приведет к ошибке. Теперь, когда все внимание собрано, можно перейти к следующему вопросу.

2. Какой результат выведет вызов метода foo()?

void foo() {
   String m = "Hello";
   System.out.print(m);
   bar(m);
   System.out.print(m);
}

void bar(String m) {
   m += " World!";
}

“HelloHello”.

Разберем решение детально: С первым выводом Hello вопросов быть не должно, далее в метод bar передаем копию ссылки на строку, теперь на данную строку ссылаются две переменные: m из метода foo и m из метода bar. Так как строки в Java являются immutable, при попытке присоединить к уже существующей строке дополнительное значение  World!, в методе bar произойдет создание новой строки и локальная переменная m этого метода будет ссылаться на новую строку со значением Hello World!, при этом в методе foo в результат будет выведено значение переменной m которая по прежнему ссылается на строку Hello.

3. Каким будет результат сравнения в следующем коде?

String s1 = "abc";
String s2 = "abc";
String s3= new String("abc");
System.out.println("s1 == s2 ? "+(s1==s2));
System.out.println("s1 == s3 ? "+(s1==s3));
System.out.println("s1 equals s3 ? "+(s1.equals(s3)));

s1 == s2 ? true

s1 == s3 ? false

s1 equals s3 ? true

Вопрос на понимание работы пула строк в Java и на понимание сравнения строк. Разберем детально: Переменная s1 ссылается на строку в пуле уникальных строк в памяти, переменная s2 ссылается на ту же саму строку в пуле уникальных строк, что и переменная s1, первое сравнение будет true, так как s1 и s2 ссылаются на один и тот же объект. Переменная s3 ссылается на новый объект, который не находится в пуле уникальных строк, так как он создан через new, следовательно второе сравнение будет false, так как сравниваем переменные которые ссылаются на на два разных объекта. Третье сравнение будет true, так как мы сравниваем строки посимвольно на эквивалентность через equals, а содержимое данных строк одинаково.

4. Напишите реализацию синглтона

Примечание Хотя синглтоны уже давно никто не пишет, вопрос все равно остается актуальным

public class Singleton {

   private static final Singleton instance = new Singleton();

   private Singleton() {
   }

   public static Singleton getInstance() {
       return instance;
   }

   public void print(){
       System.out.println("This is singleton print method");
   }
}

class TestSingleton {

   public static void main(String[] args) {
       Singleton instance = Singleton.getInstance();
       instance.print();
   }
}

Основные моменты при реализации синглтона: Конструктор класса должен быть с модификатором доступа private, что не позволит создать экземпляр этого класса за его пределами; должна быть private static final переменная, хранящая единственный экземпляр этого класса и public static метод возвращающий экземпляр этого класса.

Дополнительный вопрос: Реализовать Lazy initialization (Ленивая инициализация) синглтона.

public class Singleton {

   private static Singleton instance;

   private Singleton() {
   }

   public static Singleton getInstance() {
       if (instance == null) {
           instance = new Singleton();
       }
       return instance;
   }

   public void print() {
       System.out.println("This is singleton print method");
   }
}

Вся особенность Lazy initialization в том, что экземпляр класса создается только в момент первого обращения к нему.

5. Какой результат будет выведен в консоль?

public abstract class OurAbstractClass {

   public OurAbstractClass() {
       System.out.println("This is abstract class constructor");
   }
}

class OurDemoClass extends OurAbstractClass {

   public OurDemoClass() {
       System.out.println("This is demo class constructor");
   }

   public static void main(String[] args) {
       OurDemoClass ourDemoClass = new OurDemoClass();
   }
}
This is abstract class constructor
This is demo class constructor

Вопрос на понимание абстрактных классов. Создать экземпляр абстрактного класса нельзя, но он все же имеет конструктор. Более того любой класс имеет конструктор, даже если он не задан явно (он будет добавлен при компиляции). Здесь важно понимать, что при создании экземпляра наследника, самой первой строкой в конструкторе класса наследника будет вызван конструктор класса родителя.

6. Какая проблема возникнет с этим кодом?

public static void main(String[] args) {
   try {
       foo();
   } catch (IOException e) {
       e.printStackTrace();
   } catch (FileNotFoundException e) {
       e.printStackTrace();
   }

public static void foo()throws IOException,FileNotFoundException {

}

Данный код не с компилируется. Этот вопрос на знание иерархии исключений, в данном случае FileNotFoundException унаследован от IOException, первый catch будет перехватывать все исключения и в следующий блок catch управление не будет передано.

7. Каким будет результат выполнения данного кода?

public static void main(String[] args) {

   List<String> stringList = new ArrayList<>();
   stringList.add("one");
   stringList.add("one and a half");
   stringList.add("two");
   stringList.add("two and a half");
   stringList.add("three and a half");

   System.out.println("Before " + stringList);
   Iterator<String> stringIterator = stringList.iterator();
   while (stringIterator.hasNext()) {
       String next = stringIterator.next();
       if (next.equals("two and a half")) {
           stringList.add("three");
       }
   }

   System.out.println("After " + stringList);
}
Before [one, one and a half, two, two and a half, three and a half]
Exception in thread "main" java.util.ConcurrentModificationException

При попытке добавить элемент в список возникнет исключение связанное с попыткой изменить список , по которому итерируемся, так как итератор для ArrayList изначально это fail-fast итератор. В таком случае необходимо использовать fail-safe итераторы, они работают с клоном коллекции которую потребовалось изменить. В данном случае можно использовать CopyOnWriteArrayList.