Ответ
1. String Pool и Immutability строк
Строковые литералы кэшируются в пуле строк (String Pool) для экономии памяти. Оператор new создает новый объект в куче.
String a = "hello"; // Может быть взята из пула
String b = "hello"; // Ссылается на тот же объект из пула, что и 'a'
String c = new String("hello"); // Создается новый объект String
System.out.println(a == b); // true (одинаковые ссылки)
System.out.println(a == c); // false (разные объекты)
System.out.println(a.equals(c)); // true (одинаковое содержимое)
2. Кэширование значений в классах-обертках (Integer Cache)
JVM кэширует объекты Integer для значений от -128 до 127.
Integer i1 = 127;
Integer i2 = 127;
System.out.println(i1 == i2); // true (объект из кэша)
Integer i3 = 128;
Integer i4 = 128;
System.out.println(i3 == i4); // false (созданы новые объекты)
// Сравнивайте значения через .equals()
3. Переопределение (Override) vs Перегрузка (Overload)
@Override: Аннотация для метода, который переопределяет метод суперкласса/интерфейса. Проверяет совместимость сигнатур во время компиляции.- Перегрузка: Создание метода с тем же именем, но другими параметрами в том же классе.
4. Try-with-Resources (AutoCloseable)
Конструкция автоматически закрывает ресурсы, реализующие AutoCloseable, даже при возникновении исключения.
try (FileInputStream fis = new FileInputStream("file.txt");
BufferedReader br = new BufferedReader(new InputStreamReader(fis))) {
System.out.println(br.readLine());
} // fis.close() и br.close() вызываются автоматически здесь
5. Ленивая инициализация статических полей (Initialization-on-demand holder idiom) Класс-холдер загружается только при первом обращении к его статическому полю.
public class Singleton {
private Singleton() {}
private static class Holder {
static final Singleton INSTANCE = new Singleton(); // Инициализация здесь
}
public static Singleton getInstance() {
return Holder.INSTANCE; // Загрузка класса Holder и создание INSTANCE
}
} Ответ 18+ 🔞
А, ну вот, опять эти ваши Java-заморочки, блядь. Сидишь, бывает, на собеседовании, а тебе такой: "Расскажи про String Pool". И ты такой, блядь, вспоминаешь, что это не бассейн для строк, а какая-то ёбнутая экономия памяти, пиздец.
Смотри, тут всё просто, как три копейки, но мозг выносит. Возьмём строки.
String a = "hello";
String b = "hello";
String c = new String("hello");
Вот a и b — это, типа, два алкаша у одного ларька. Оба кричат "hello" одному и тому же продавцу, то есть ссылаются на один и тот же объект в этом самом пуле, String Pool'е, блядь. Поэтому a == b даст true. А этот выёбок c, который через new создался — это уже новый, отдельный алкаш, который пришёл со своим "hello", но из другого подъезда. Он в памяти новый объект, поэтому a == c — это false, хоть он и кричит то же самое. А вот a.equals(c) — true, потому что equals смотрит не на рожу, а на то, что кричат, на содержимое, блядь.
Дальше, про эти ваши обёртки, Integer. Тут JVM, такая хитрая жопа, решила сэкономить и закэшировала маленькие циферки от -128 до 127.
Integer i1 = 127;
Integer i2 = 127;
System.out.println(i1 == i2); // true
Всё ок, оба ссылаются на один закэшированный объект, как близнецы-братья. Но как только вылезаешь за границу — пиши пропало!
Integer i3 = 128;
Integer i4 = 128;
System.out.println(i3 == i4); // false
Всё, кэш кончился, создаются два новых, отдельных объекта. И тут уже == не работает, надо equals использовать, а то на ровном месте багу наловишь, в рот меня чих-пых!
Теперь про @Override и перегрузку. Это две большие разницы, ёпта!
@Override— это когда ты в наследнике говоришь: "Батя, твой метод — говно, я сейчас перепишу по-своему". И аннотация@Overrideстоит как охранник, который проверяет, а точно ли у отца был такой метод, а то вдруг ты опечатался и пишешь какую-то хуйню. Компилятор сразу в морду даст.- Перегрузка (Overload) — это когда в одном классе у тебя несколько методов с одним именем, но разными параметрами. Типа, "позвать Петю", "позвать Петю с бутылкой", "позвать Петю с бутылкой и закуской". Имя одно —
callPetya, а сигнатуры разные. Вот и вся магия, блядь.
А вот try-with-resources — это вообще песня, ебать мои старые костыли! Раньше надо было в finally блоке эти ваши FileInputStream и BufferedReader закрывать, руки отпадали. А теперь?
try (FileInputStream fis = new FileInputStream("file.txt");
BufferedReader br = new BufferedReader(new InputStreamReader(fis))) {
System.out.println(br.readLine());
}
Засунул ресурсы в скобки после try — и спи спокойно. Они сами закроются, даже если посередине чтения исключение выскочит. Реализуют они интерфейс AutoCloseable, и всё, красота. Не жизнь, а малина.
Ну и на десерт — моя любимая ленивая инициализация синглтона, она же Initialization-on-demand holder idiom. Выглядит страшно, но гениально просто.
public class Singleton {
private Singleton() {} // Конструктор спрятали, чтоб не выёбывались
private static class Holder {
static final Singleton INSTANCE = new Singleton(); // Вот где создаётся!
}
public static Singleton getInstance() {
return Holder.INSTANCE; // А вот когда запросили — тогда и загрузился класс Holder
}
}
Суть в чём, блядь? Класс Holder загрузится в память только тогда, когда кто-то впервые вызовет getInstance(). И только тогда создастся этот самый INSTANCE. До этого — ни хуя не происходит. И потокобезопасно, и лениво, и красиво. Ёперный театр, вот это я понимаю — паттерн!
Вот так вот, коротко и без воды, а то некоторые лекции раздувают, что заслушаешься, блядь.