Created
November 22, 2018 12:23
-
-
Save isRuslan/1f310297cc4eb847e3ffaf90bc9018e2 to your computer and use it in GitHub Desktop.
Опросник на java джуниора
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Думаю, очень круто было бы в начале предупредить, что знание тонкостей языка не так важно, | |
как умение размышлять и делать разумные предположения | |
1. Immutable strings | |
String a = "hello "; | |
String b = a; | |
a = a + "world!"; | |
System.out.println(b); | |
Я не помню, как хранятся строки и являются ли они примитивным типом. | |
Но думаю, что выведется "hello " | |
Для переменной a будет создана новая ссылка | |
"Верно. Строки - не примитивы. Все примитивы с маленькой буквы." | |
"Присвоение [String b = a] - копирование ссылки" | |
2. List vs Arraylist vs Linkedlist | |
В чем разница? | |
Когда стоит использовать какой? | |
Частое чтение по индексу? | |
Частое добавление в конец? | |
Частое добавление в начало? | |
Частое добавление в середину? | |
Как итерироваться по LinkedList? | |
Что такое List непонятно. Думаю что базовый интерфейс, который даже инстанцировать нельзя "Да" | |
Пара других – это отсылка внутренней реализации – массив или список. "Да" | |
Частое чтение по индексу? – Array "Да" | |
Частое добавление в конец? – Может быть пофиг. | |
Но надо учитывать, что добавление в массив будет приводить к повторному выделению памяти. | |
"Да, но в великом большинстве случаев ArrayList будет эфективнее по всем параметрам" | |
Частое добавление в начало? – Тут точно список "Да" | |
Частое добавление в середину? – Список "Да" | |
Как итерироваться по LinkedList? Указатель на next должен быть. Наверное ещё можно Set из него получить | |
"Нет. Указатель на next скрыт от тебя в реализации." | |
"Плюс, не понятно как можно было бы итерировать абстарктный List, " | |
"если бы способ итерации зависел от имплементации" | |
"Самый распространенный способ итерации - foreach loop" | |
" for (Integer elem : list) { " | |
" System.out.println(elem); " | |
" } " | |
"Он крутой, но им нельзя удалять элементы" | |
"Он реально - синтаксический сахор над Iterator" | |
" List<Integer> list = new LinkedList<>(); " | |
" Iterator<Integer> iterator = list.iterator(); " | |
" while (iterator.hasNext()) { " | |
" Integer next = iterator.next(); " | |
" System.out.println(next); " | |
" } " | |
"Iterator умеет iterator.remove() почти всегда :)" | |
"foreach работает, если коллекция (List в данном случае) implements Iterable<T>" | |
"Ну и третий способ через Stream API (c java 8) - это правильная стандартная реализация наших болтсов" | |
" List<Integer> list = new LinkedList<>(); " | |
" list.forEach(System.out::println); " | |
"Set получить можно, если туда перекопировать все елементы из листа с помощью set.addAll(list)" | |
"Но итерировать по сету нужно точно так же :)" | |
"Еще на всякий случай добавлю, что LinkedList - пролинкован в обе стороны" | |
"Т.е. эффективно итерировать его можно в обе стороны" | |
3. Equals | |
public class Fruit { | |
private String name; | |
private int price; | |
public Fruit(String name, int price) { | |
this.name = name; | |
this.price = price; | |
} | |
} | |
Fruit a = new Fruit("banana", 37); | |
Fruit b = a; | |
Fruit c = new Fruit("banana", 37); | |
System.out.println(a == b); | |
System.out.println(a == c); | |
System.out.println(a.equals(c)); | |
Что выведет код? | |
Как сделать так, чтобы логически одинаковые фрукты были равны? | |
true, "Да" | |
false, "Да" | |
true, "Нет, попался :)" | |
"Если в классе не определить метод equals, то берется equals первого родителя, у которого он есть" | |
"В данном случае это Object" | |
"Для Object equals() - это тоже просто проверка ссылки" | |
В первых друх случаях мы сравниваем ссылки, а не объекты | |
Хм. Можно какое-то внутреннее хранилище для уникальных объектов создать, например хешмапу с ключём из имени и цены. | |
Если элемента в мапе нет, то кладём его туда | |
Если есть, то возвращаем ссылку на то, что нашли | |
"Можно, но слишком сложно" | |
"Правильный ответ - определить метод equals()" | |
"который будет возвращать true, если цена и имя равны" | |
"PS В нашем коде мы так не делаем, потому что у нас есть ru.yandex.misc.lang.DefaultObject" | |
"который магически через рефлексию (и скорее всего не очень эффективно по производительности) определяет этот метод" | |
"PSS Вместе с equals() обычно определяют еще и hashCode() потому что у них тесно связаные контракты" | |
"Но это уже совсем другая история с умными словами типа рефлексивность, " | |
"симметричночть, транзитивность и принцип подстановки Лискова" | |
4. Sort (Comarable/Comparator) | |
public class Person { | |
public String name; | |
public int age; | |
} | |
Отсортировать List<Person> by age desc | |
Желательно 2 способа | |
Тут мне надо в книжку смотреть... | |
Догадка | |
List<Person> sortedList = originalList.sortBy((p1, p2) -> p1.age - p2.age) | |
"Догадка почти правильная :)" | |
"Первый способ такой:" | |
" originalList.sort((a, b) -> a.age - b.age); | |
"или без лямбды | |
" originalList.sort(new Comparator<Person>() { | |
" @Override | |
" public int compare(Fruit a, Fruit b) { | |
" return a.age - b.age; | |
" } | |
" }); | |
"или с вспомогательным компаратором | |
" originalList.sort(Comparator.comparingInt(a -> a.age)); | |
"Это все - одно и то же" | |
"Важно, что он in-place" | |
"Но можно и иначе" | |
После доки | |
Collections.sort(mArrayList, new Comparator<Person>() { | |
@Override | |
public int compare(Person p1, Person p2) { | |
return p2.age == p1.age ? 0 : p2.age - p1.age / Math.abs(p2.age - p1.age); | |
} | |
}); | |
" это как без лямбды, но с какими-то очень странными извращениями | |
" я их пока не понял | |
" скинь плз доку, где ты это вычитал | |
"Второй важный способ - заимлементить Comparable<Person> | |
" class Person implements Comparable<Person> { | |
" public String name; | |
" public int age; | |
" | |
" @Override | |
" public int compareTo(Person o) { | |
" return this.age - o.age; | |
" } | |
" } | |
"Тогда можно делать просто так: | |
" Collections.sort(list); | |
5. Default constructor & initialization | |
public class Person { | |
public String name; | |
public int age; | |
} | |
Person p = new Person(); | |
"Если ни одного конструктора не определено, то дефолтный создастся сам" | |
System.out.println(p.name); | |
"Если не определять фвно значения полей, они задаются дефолтами типа 0, false, null" | |
System.out.println(p.age); | |
Person p1 = new Person("John", 12); | |
"Такой конструктор сам не создается - будет ошибка компеляции" | |
Что выведет код? | |
Какой-то он странный. Информации о конструкторе нет, поэтому может вывести всё, что угодно | |
Если конструктор не определён, то вообще с ошибкой упадёт | |
Может вывести дефолтные значения, пустую строку и 0 | |
6. Remove from collection by predicate | |
Удалить из List<Person> тех, у кого name на G | |
(Желательно in-place) | |
Тоже надо книжку смотреть. | |
"Писал про Iterator в задачке #2 - он может удалять | |
"фильтер тоже ок, но он не in-place" | |
" List<Person> filteredList = originalList.stream()" | |
" .filter(p -> p.name.startsWith("G")).collect(Collectors.toList()); | |
" ну и другой вариант не in-place - пробежаться и положить в новый список только правильных людей | |
7. Unboxing | |
for (Integer i = 0; i <= Integer.MAX_VALUE; i++) { | |
System.out.println(i); | |
} | |
Какие проблемы есть в этом коде? | |
Что-нибудь про unboxing | |
"Да - unboxing и boxing будут происходить на каждой итерации" | |
"Если просто поменять Integer на int, то будет работать в 700 раз быстрее (1400мс -> 2мс)" | |
"Но намного важнее проблема в том, что цикл бесконечный :) | |
"любой Integer <= Integer.MAX_VALUE | |
8. Exceptions | |
Какие бывают исключения? | |
Какие нужно ловить, а какие нет? | |
Зачем нужен блок finally? | |
Когда блок finally не выполняется? | |
Например так? | |
try { | |
System.exit(1); | |
// или выдернуть провод из розетки | |
} finally { | |
System.out.println("finally"); | |
} | |
Какие бывают исключения? – тут у меня пробел в знаниях. Буду исправлять | |
"Ожидаемый ответ: checked и unchecked (runtime)" | |
"Более полный ответ: " | |
# Throwable | |
# / \ | |
# Error Exception | |
# / / \ | |
# ... RuntimeException \ | |
# / ... | |
# ... | |
" Наследников RuntimeException не нужно ловить или декларировать в сигнатуре (unchecked) | |
" Наследнико Exception (но не RuntimeException), нужно ловить или декларировать в сигнатуре (checked) | |
" Error - совсем системные ошибки, которые почти всегда не восстанавливаемые (типа краша JVM) | |
Какие нужно ловить, а какие нет? – ?? | |
Зачем нужен блок finally? – должен выполняться в любом случае | |
и при успешном выполнении блок внутри try и при catch "Да" | |
Когда блок finally не выполняется? – ?? | |
" Например так | |
" try { | |
" System.exit(1); | |
" // или выдернуть провод из розетки | |
" } finally { | |
" System.out.println("finally"); | |
" } | |
Так в исключениях у меня сплошные проблемы | |
9. Casts & compilation time | |
class Vehicle {}; | |
class Car extends Vehicle {}; | |
class Lexus extends Car {}; | |
class Vegetable {}; | |
Vehicle a = new Vehicle(); | |
Vehicle b = new Car(); | |
Car c = new Vegetable(); | |
Lexus d = new Lexus(); | |
c = b; | |
c = (Car) b; | |
b = d; | |
d = a | |
d = (Lexus) a; | |
Где ошибки? | |
Какие на этапе компиляции, какие в рантайме? | |
Car c = new Vegetable(); – упадёт при компиляции Эти типы нельзя приводить друг к другу "Да" | |
Дальше примеры с c кажутся странными и я их игнорирую "Задачу я поставил плохо :( подумаю еще" | |
d = a; – упадёт на компиляции. Vehicle нельзя привести к родительскому типу. "Да" | |
d = (Lexus) a; – вот это наверное в рантайме грохнется "Да" | |
10. Abstract class | |
Что такое абстрактный класс? | |
Что будет, если создать инстанс абстрактного класса (new) | |
Почему? | |
Когда лучше использовать интерфейсы? | |
Класс который описывает некоторый интерфейс и предоставляет реализацию части методов "Да" | |
Нельзя его инстанцировать, потому-то он и абстрактный. "Да" | |
Только наследника получится сделать, определив недостающие методы "Да" | |
Декомпозиция и вот это всё, когда хотим один и тот же класс использовать в разных полезных методах. | |
Для меня это способ замены множественного наследования | |
"Такой ответ я бы тоже принял. " | |
"Но можно просто сказать: например, когда хотим сразу 2 интерфейса имплементить - " | |
"с абстрактными классами так нельзя" | |
11. Not lazy method args | |
static int foo() { | |
System.out.println("foo"); | |
return 1; | |
} | |
static int bar(boolean a, int b) { | |
if (a) { | |
return b; | |
} | |
return 0; | |
} | |
public static void main(String[] args) { | |
int res = bar(false, foo()); | |
System.out.println(res); | |
} | |
Что выведет данный код? | |
foo | |
1 | |
"Нет | |
#foo | |
#0 | |
"Это не так важно, но ты попал мимо смысла задачи" | |
"Это проверка на наш недавний баг с Option.when(), про который рассказывал Руслан" | |
"Кто-то может подумать, что если false, и результат foo() не будет использован, " | |
"то и выполнятся он не будет" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment