Java
28.07.2020 | https://habr.com/ru/articles/512730/ |
Keywords
if
else
switch
case
while
do
for
break
continue
return
try
catch
finally
throw
throws
assert
class
interface
enum
extends
implements
abstract
final
static
void
synchronized
volatile
transient
native
strictfp
boolean
byte
short
int
long
float
double
char
public
private
protected
default
import
package
this
super
new
null
true
false
instanceof
goto
const
record
package
Механизм организации классов и интерфейсов в группы для упрощения управления кодом и предотвращения конфликтов имён.
package com.example.myapp;
public class MyClass {
public void sayHello() {
System.out.println("Hello!");
}
}
Basic Types
byte
Хранит целые числа небольшого диапазона от -128 до 127.
byte a = 10;
short
Хранит целые числа среднего диапазона от -32,768 до 32,767.
short a = 1000;
int
Хранит целые числа от -2³¹ до 2³¹-1. Обеспечивает хороший баланс между диапазоном значений и объемом занимаемой памяти.
int number = 100;
long
Хранит целые числа большого диапазона от -2⁶³ до 2⁶³-1. Можно указать литерал L
.
long bigNumber = 10000000000L;
float
Хранит числа с плавающей точкой одинарной точности. Требует суффикс f
или F
. Точность - примерно 6-7 цифр.
float pi = 3.14f;
double
Хранит числа с плавающей точкой двойной точности. По умолчанию все дробные значения считаются double
. Точность - примерно 15-16 цифр. Можно указать литерал D
.
double pi = 3.1415926535d;
boolean
Храненит логические значения true
или false
.
boolean isJavaFun = true;
char
Храненит символы Unicode. Символы указываются в одиночных кавычках.
char letter = 'A';
char unicodeChar = '\u0041'; // 'A' в Unicode
Basic Type Casting
int
→ long
Не требует явного приведения, так как long
(64-бита) шире, чем int
(32-бита). Преобразование происходит автоматически (implicit casting).
int intVal = 42;
long longVal = intVal;
int
→ float
Не требует явного приведения типов. Преобразование происходит автоматически (implicit cast), так как float
может точно представлять все значения int
.
int intVal = 100;
float floatVal = intVal;
int
→ double
Не требует явного приведения типов. Это автоматическое (неявное) преобразование, так как double
может точно представлять все значения int
.
int intVal = 42;
double doubleVal = intVal;
long
→ int
Требует явное приведение типов (explicit cast), так как int
(32 бита) уже, чем long
(64 бита). Возможна потеря данных, если значение не помещается в диапазон int
.
long longVal = 123456789L;
int intVal = (int) longVal;
long
→ float
Требует явное приведение типов (explicit cast), так как long
(64-битное целое) шире, чем float
(32-битное число с плавающей точкой). Возможна потеря точности, особенно для больших значений.
long longVal = 123456789012345L;
float floatVal = (float) longVal;
long
→ double
Не требует явного приведения, так как double
(64-бита) может точно представлять все значения long
(также 64-бита), но с плавающей точкой.
long longVal = 123456789L;
double doubleVal = longVal;
float
→ int
Требует явное приведение (explicit cast), так как int
— целочисленный тип, а float
— дробный. Дробная часть будет отброшена без округления.
float floatVal = 5.99f;
int intVal = (int) floatVal;
float
→ long
Требует явное приведение типов, так как float
— это число с плавающей точкой, а long
— целочисленный тип. Дробная часть отбрасывается.
float floatVal = 12345.67f;
long longVal = (long) floatVal;
float
→ double
Не требует явного кастинга, так как double
(64-бита) шире, чем float
(32-бита). Преобразование происходит автоматически.
float floatVal = 3.14f;
double doubleVal = floatVal;
double
→ int
Требует явное приведение типов, так как дробная часть (double
) будет отброшена, а значение округляется в сторону нуля.
double doubleVal = 3.99;
int intVal = (int) doubleVal;
double
→ long
Требует явное приведение, так как double
(64-битное число с плавающей точкой) содержит дробную часть, которая отбрасывается, и может выходить за пределы диапазона long
.
double doubleVal = 123456789.99;
long longVal = (long) doubleVal;
double
→ float
Требуется явное приведение типов (explicit cast), так как float
(32 бита) менее точный, чем double
(64 бита). Возможна потеря точности.
double doubleVal = 3.141592653589793;
float floatVal = (float) doubleVal;
Reference Types
Byte
Целое число от -128 до 127.
Byte b = 127;
Short
Целое число от -32,768 до 32,767.
Short s = 32000;
Integer
Целое число от -2³¹ до 2³¹-1.
Integer i = 100000;
Long
Целое число от -2⁶³ до 2⁶³-1.
Long l = 10000000000L;
Float
Дробное число с одинарной точностью.
Float f = 3.14f;
Double
Дробное число с двойной точностью.
Double d = 3.14159265359;
Boolean
Значение true
или false
.
Boolean bool = true;
Character
Символ в Unicode.
Character c = 'A';
Boxing
Процесс преобразования примитивного типа данных в объект его соответствующего типа-обертки.
int primitiveInt = 42; // Примитивный тип
Integer wrappedInt = primitiveInt; // Боксинг, превращает примитив в объект
Unboxing
Процесс преобразования объекта типа-обертки в соответствующий примитивный тип.
Integer wrappedInt = 42; // Объект типа Integer
int primitiveInt = wrappedInt; // Анбоксинг, превращает объект в примитив
сlass
В Java класс — это основная конструкция для определения объектов и инкапсуляции данных и поведения. Классы могут содержать поля (переменные экземпляра), методы и конструкторы.
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public void introduce() {
System.out.println("Hi, I'm " + name + " and I'm " + age + " years old.");
}
}
Person person = new Person("Alice", 30);
person.introduce(); // Вывод: Hi, I'm Alice and I'm 30 years old.
new
Используется для создания нового экземпляра класса. Выделяет память под объект и вызывает конструктор класса.
Person person = new Person("Alice", 30); // Создание нового объекта Person
extends
Используется для наследования классов. Позволяет одному классу (подклассу) наследовать свойства и методы другого класса (суперкласса).
class Animal {
void sound() {
System.out.println("Animal sound");
}
}
class Dog extends Animal { // Dog наследует Animal
void sound() {
System.out.println("Bark");
}
}
implements
Используется для реализации интерфейсов. Позволяет классу реализовывать методы, объявленные в интерфейсе.
interface Drawable {
void draw(); // Метод без тела
}
class Circle implements Drawable { // Circle реализует интерфейс Drawable
public void draw() {
System.out.println("Drawing a circle");
}
}
instanceof
Проверяет, является ли объект экземпляром определенного класса или его подкласса.
• Можно использовать для проверки интерфейсов.
String text = "Hello, world!";
if (text instanceof String) {
System.out.println("Это строка!");
}
record
Класс для неизменяемых объектов. Он автоматически создаёт конструктор, геттеры, equals
, hashCode
и toString
.
public record Point(int x, int y) {}
Статическая загрузка классов
Происходит во время компиляции. Компилятор знает о классах и их зависимостях заранее. Статическая загрузка используется, когда класс загружается до его первого использования. Например, при инициализации статических переменных или вызове статических методов.
// В этом примере статический блок будет выполнен до вызова метода main.
public class StaticLoading {
static {
System.out.println("Static block executed");
}
public static void main(String[] args) {
System.out.println("Main method executed");
}
}
Динамическая загрузка классов
Происходит во время выполнения программы. Классы загружаются по мере необходимости, что позволяет уменьшить время начальной загрузки и память. Динамическая загрузка используется с помощью механизма рефлексии или в контексте загрузки классов в ответ на определенные действия.
// В этом примере класс SomeClass загружается динамически во время выполнения программы.
public class DynamicLoading {
public static void main(String[] args) {
try {
Class<?> clazz = Class.forName("SomeClass"); // Динамическая загрузка класса
Object obj = clazz.getDeclaredConstructor().newInstance(); // Создание экземпляра
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
e.printStackTrace();
}
}
}
interface
Задаёт контракт с методами, которые класс должен реализовать.
interface Animal {
void sound(); // абстрактный метод
default void eat() { // метод с реализацией
System.out.println("This animal eats food.");
}
}
class Dog implements Animal {
@Override
public void sound() {
System.out.println("Woof");
}
}
public class Main {
public static void main(String[] args) {
Dog dog = new Dog();
dog.sound(); // Woof
dog.eat(); // This animal eats food.
}
}
default
Добавляет метод с реализацией в интерфейс. Классы, которые его реализуют, могут не переопределять этот метод.
interface Example {
default void show() {
System.out.println("Default method in interface");
}
}
Functions
void
Когда метод объявлен с использованием void, это означает, что он не возвращает никаких значений. Внутри метода можно выполнять действия, такие как вывод на экран, изменение значений полей объекта и так далее, но не может быть оператора return
с каким-либо значением.
void increment() {
count++;
}
• Функция, возвращающая значение.
int add(int a, int b) {
return a + b; // Возвращает сумму a и b
}
• Передача переменного количества аргументов.
void printNumbers(int... numbers) {
for (int number: numbers) {
System.out.print(number + " ");
}
System.out.println();
}
// Вызов метода с переменным количеством аргументов
printNumbers(1, 2, 3, 4, 5);
Modifiers
public
Позволяет получить доступ к методу, переменной или классу из любого места в программе.
• Может использоваться с классами, методами, конструкторами, интерфейсами и переменными.
public class Example {
public int number;
public void display() {
System.out.println("This is a public method.");
}
}
protected
Открывает доступ к методу или переменной внутри класса, его подклассов и классов в том же пакете.
class Animal {
protected void makeSound() {
System.out.println("Some sound");
}
}
class Dog extends Animal {
public void bark() {
makeSound(); // доступ через наследование
System.out.println("Woof");
}
}
private
Закрывает доступ к методу или переменной для всех, кроме самого класса. Такие данные недоступны для подклассов и других классов даже в одном пакете.
class Account {
private double balance;
private void updateBalance(double amount) {
balance += amount;
}
public void deposit(double amount) {
if (amount > 0) {
updateBalance(amount); // доступ только внутри класса
}
}
}
final
Запрещает изменение. Переменная становится неизменяемой после инициализации, метод нельзя переопределить в подклассе, а класс — наследовать.
final class Constants {
final int MAX_USERS = 100;
final void displayMax() {
System.out.println("Max users: " + MAX_USERS);
}
}
// Наследование и изменение метода запрещены
// class ExtendedConstants extends Constants {} // Ошибка
static
Делает метод, переменную или вложенный класс привязанными к классу, а не к его экземпляру. Доступ возможен без создания объекта.
class Outer {
static class Inner {
static void sayHello() {
System.out.println("Hello from static class!");
}
}
}
Outer.Inner.sayHello(); // вызов без создания объектов
IO
InputStream
Используется для чтения данных из источника.
InputStream inputStream = new FileInputStream("file.txt");
int data;
while ((data = inputStream.read()) != -1) {
System.out.print((char) data);
}
inputStream.close();
BufferedInputStream
Ускоряет чтение данных из потока, используя внутренний буфер. Вместо обращения к ресурсу каждый раз, он загружает данные большими порциями, что экономит время.
public class BufferedInputStreamExample {
public static void main(String[] args) {
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream("file.txt"))) {
int byteData;
while ((byteData = bis.read()) != -1) {
System.out.print((char) byteData);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
OutputStream
Используется для записи данных в целевой объект.
OutputStream outputStream = new FileOutputStream("file.txt");
outputStream.write(65); // Запишет символ 'A'
outputStream.close();
BufferedOutputStream
Ускоряет запись данных, копя их в буфере и отправляя сразу крупными порциями. Это снижает количество операций и делает запись эффективнее.
public class Example {
public static void main(String[] args) {
try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("output.txt"))) {
bos.write("Пример использования BufferedOutputStream.".getBytes());
bos.flush(); // Сбрасываем буфер
} catch (IOException e) {
e.printStackTrace();
}
}
}
Reader
Абстрактный класс для чтения символов. Предназначен для обработки текстовых данных и поддерживает работу с различными кодировками.
Reader reader = new FileReader("file.txt");
int data;
while ((data = reader.read()) != -1) {
System.out.print((char) data);
}
reader.close();
BufferedReader
Ускоряет чтение текстовых данных, загружая их в буфер большими порциями. Он умеет читать строки целиком, что удобно для работы с текстовыми файлами.
public class BufferedReaderExample {
public static void main(String[] args) {
try (BufferedReader br = new BufferedReader(new FileReader("input.txt"))) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Writer
Абстрактный класс для записи символов. Он позволяет записывать текстовые данные в различные выходные источники.
Writer writer = new FileWriter("file.txt");
writer.write('A');
writer.close();
BufferedWriter
Ускоряет запись текста, используя буфер. Вы записываете данные частями, а он отправляет их в файл, когда буфер заполняется или вручную вызывается flush()
.
public class BufferedWriterExample {
public static void main(String[] args) {
try (BufferedWriter bw = new BufferedWriter(new FileWriter("output.txt"))) {
bw.write("Пример использования BufferedWriter.");
bw.newLine(); // Добавляем перенос строки
bw.write("Записываем текст быстрее.");
bw.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Exceptions
Checked Exceptions (проверяемые исключения)
Исключения, которые обязательно нужно обработать либо с помощью try-catch
, либо указав в сигнатуре метода throws
. Если вы этого не сделаете, код не скомпилируется.
Примеры
• IOException
— ошибки ввода-вывода.
• SQLException
— ошибки при работе с базой данных.
• ClassNotFoundException
— класс не найден.
• InterruptedException
— поток был прерван.
Unchecked Exceptions (непроверяемые исключения)
Исключения, которые не требуют обязательной обработки, обычно связаны с логическими ошибками в коде или некорректными входными данными.
Примеры
• NullPointerException
— обращение к null
.
• ArithmeticException
— деление на ноль.
• IndexOutOfBoundsException
— выход за границы массива или списка.
• IllegalArgumentException
— недопустимый аргумент в методе.
Throwable
Базовый класс для всех исключений, которые могут возникнуть в программе. От него наследуются Error
и Exception
.
Throwable
├── Error
│ ├── StackOverflowError
│ └── OutOfMemoryError
│
└── Exception
├── RuntimeException
│ ├── NullPointerException
│ ├── IllegalArgumentException
│ └── IndexOutOfBoundsException
├── IOException
└── SQLException
Error
Критические ошибки (например, переполнение памяти), которые обычно нельзя обработать.
Exception
Проблемы, которые можно и нужно обрабатывать (например, деление на ноль или отсутствие файла).
try
Cодержит код, который может вызвать исключение. Это обязательная часть конструкции.
try {
int result = 10 / 0;
System.out.println("Результат: " + result);
} catch (Exception e) {}
catch
Перехватывает исключение, если оно возникло в try
.
try {
int result = 10 / 0; // ArithmeticException
} catch (ArithmeticException e) {
System.out.println("Деление на ноль недопустимо: " + e.getMessage());
}
finally
Выполняется всегда, независимо от того, было исключение или нет.
try {
int result = 10 / 0;
} catch (ArithmeticException e) {
System.out.println("Ошибка: " + e.getMessage());
} finally {
System.out.println("Этот блок выполнится в любом случае.");
}
throw
Используется для выброса исключения.
if (age < 18) {
throw new IllegalArgumentException("Age must be 18 or older");
}
throws
Указывает, какие исключения метод может выбросить.
public void readFile(String path) throws IOException {
// Чтение файла
}
enum
Перечисление, специальный тип для фиксированного набора значений (констант).
enum Day {
MONDAY, TUESDAY, WEDNESDAY;
}
Day today = Day.MONDAY;
name
Возвращает имя константы enum
как строку.
enum Day {
MONDAY, TUESDAY, WEDNESDAY
}
public static void main(String[] args) {
System.out.println(Day.MONDAY.name()); // "MONDAY"
}
ordinal
Возвращает порядковый номер (индекс) константы.
enum Day {
MONDAY, TUESDAY, WEDNESDAY
}
public static void main(String[] args) {
System.out.println(Day.MONDAY.ordinal()); // 0
}
Generics
Механизм, позволяющий создавать классы, интерфейсы и методы с параметризованными типами.
• Примитивные типы (например, int
, char
) не могут использоваться в качестве параметров типа. Вместо этого используются их обертки (Integer
, Character
).
• Статические поля с параметризованными типами не допускаются.
• Невозможно создать массив дженериков.
• Общие классы. Дженерики позволяют создавать классы с параметрами типа, которые определяются при создании объекта.
public class Box<T> {
private T item;
public void setItem(T item) {
this.item = item;
}
public T getItem() {
return item;
}
}
// Использование
Box<String> stringBox = new Box<>();
stringBox.setItem("Hello");
String item = stringBox.getItem(); // Возвращает строку
• Общие методы. Методы также могут быть параметризованы типами.
public class Utils {
public static <T> void printArray(T[] array) {
for (T element: array) {
System.out.println(element);
}
}
}
// Использование
Integer[] numbers = {1, 2, 3};
Utils.printArray(numbers); // Печатает числа
• Существующие классы. Дженерики широко используются в стандартной библиотеке Java, например, в коллекциях:
List<String> list = new ArrayList<>();
list.add("One");
String first = list.get(0); // Безопасно, возвращает строку
• Ограничения дженериков. Дженерики могут иметь ограничения, позволяющие использовать только определенные типы:
public class ComparableBox<T extends Comparable<T>> {
private T item;
public void setItem(T item) {
this.item = item;
}
public T getItem() {
return item;
}
public boolean isGreater(T other) {
return item.compareTo(other) > 0;
}
}
• Стирание типов. В Java дженерики реализованы с помощью стирания типов (type erasure). Это означает, что информация о типах дженериков не сохраняется во время выполнения.
List<String> stringList = new ArrayList<>();
List<Integer> integerList = new ArrayList<>();
// На этапе выполнения они обе являются List
Lambdas
Лямбда-выражения в Java — способ писать компактный код для реализации функциональных интерфейсов. Они позволяют передавать поведение в виде параметра и упрощают работу с анонимными классами.
• Лямбда-выражения работают с функциональными интерфейсами — интерфейсами с одним методом.
• Лямбды появились в Java 8.
// Обычный способ через анонимный класс
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("Hello, world!");
}
};
// Лямбда-выражение
Runnable lambdaRunnable = () -> System.out.println("Hello, world!");
lambdaRunnable.run();
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
names.stream()
.filter(name -> name.startsWith("A"))
.forEach(name -> System.out.println(name));
::
Оператор Method Reference используется для ссылки на методы или конструкторы, упрощая синтаксис лямбда-выражений.
• Ссылка на статический метод.
class Utils {
public static void print(String s) {
System.out.println(s);
}
}
public static void main(String[] args) {
List<String> list = List.of("Hello", "World");
list.forEach(Utils::print); // Ссылка на метод
}
• Ссылка на метод экземпляра объекта.
public static void main(String[] args) {
List<String> list = List.of("apple", "banana");
list.forEach(System.out::println); // Ссылка на метод println объекта System.out
}
• Ссылка на метод экземпляра конкретного объекта.
class StringUtils {
public void printUpperCase(String s) {
System.out.println(s.toUpperCase());
}
}
public static void main(String[] args) {
StringUtils utils = new StringUtils();
List<String> list = List.of("java", "kotlin");
list.forEach(utils::printUpperCase);
}
• Ссылка на конструктор.
class User {
String name;
User(String name) {
this.name = name;
}
}
public static void main(String[] args) {
Function<String, User> userFactory = User::new; // Ссылка на конструктор
User user = userFactory.apply("Alice");
System.out.println(user.name);
}
@FunctionalInterface
Используется для обозначения интерфейсов с единственным абстрактным методом. Указывает, что интерфейс предназначен для использования с лямбда-выражениями или ссылками на методы.
• Интерфейс с @FunctionalInterface
должен содержать только один абстрактный метод.
• Могут быть дополнительные методы по умолчанию (default
) или статические методы.
• Если в интерфейсе больше одного абстрактного метода, компилятор выдаст ошибку.
@FunctionalInterface
interface MyFunction {
void sayHello(String name);
}
public class Example {
public static void main(String[] args) {
MyFunction greet = (name) -> System.out.println("Hello, " + name);
greet.sayHello("World");
}
}
native
Используется для объявления методов, реализованных на нативных языках, таких как C или C++. Это позволяет вызывать функции операционной системы или использовать библиотеки, написанные не на Java.
• Нативные методы требуют подключения JNI (Java Native Interface).
public class NativeExample {
// Объявление нативного метода
public native void printMessage();
static {
// Загрузка нативной библиотеки
System.loadLibrary("NativeLib");
}
public static void main(String[] args) {
new NativeExample().printMessage();
}
}
Serializable
Указывает, что объект может быть сериализован, то есть преобразован в поток байтов.
class User implements Serializable {
String name;
int age;
User(String name, int age) {
this.name = name;
this.age = age;
}
}
transient
Модификатор, который указывает, что поле не должно быть сериализовано. При сериализации значения таких полей будут пропущены и заменены на значение по умолчанию (например, null
для объектов, 0
для чисел).
class User implements Serializable {
String name;
transient String password; // Поле не будет сериализовано
User(String name, String password) {
this.name = name;
this.password = password;
}
}
Ручная сериализация
В режиме ручного управления в Serializable
можно самостоятельно контролировать процесс сериализации и десериализации с помощью методов writeObject()
и readObject()
. Это полезно, когда требуется особая логика или нужно исключить чувствительные данные.
class User implements Serializable {
String name;
transient String password; // Поле не будет сериализовано автоматически
User(String name, String password) {
this.name = name;
this.password = password;
}
// Метод для кастомной сериализации
private void writeObject(ObjectOutputStream oos) throws IOException {
oos.defaultWriteObject(); // Сериализуем обычные поля
oos.writeObject(encrypt(password)); // Сериализуем пароль в зашифрованном виде
}
// Метод для кастомной десериализации
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
ois.defaultReadObject(); // Десериализуем обычные поля
password = decrypt((String) ois.readObject()); // Расшифровываем пароль
}
private String encrypt(String data) {
return new StringBuilder(data).reverse().toString(); // Пример шифрования (реверс строки)
}
private String decrypt(String data) {
return new StringBuilder(data).reverse().toString(); // Расшифровка
}
}
Dynamic Proxy
Механизм, позволяющий создавать объекты-прокси во время выполнения, которые могут перехватывать вызовы методов и выполнять кастомную логику. Используется для создания гибких и динамических реализаций интерфейсов без написания дополнительных классов.
• Работает только с интерфейсами.
• Логику обработки вызова метода определяет интерфейс InvocationHandler
, реализующий метод invoke()
.
interface HelloService {
void sayHello(String name);
}
public class DynamicProxyExample {
public static void main(String[] args) {
HelloService proxy = (HelloService) Proxy.newProxyInstance(
HelloService.class.getClassLoader(),
new Class[]{HelloService.class},
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Method " + method.getName() + " is called with args: " + args[0]);
return null;
}
}
);
proxy.sayHello("World"); // Вызов метода прокси
}
}
Java Version Match
Java Runtime | Java |
---|---|
49 | Java 5 |
50 | Java 6 |
51 | Java 7 |
52 | Java 8 |
53 | Java 9 |
54 | Java 10 |
55 | Java 11 |
56 | Java 12 |
57 | Java 13 |
58 | Java 14 |
59 | Java 15 |
60 | Java 16 |
61 | Java 17 |
62 | Java 18 |
63 | Java 19 |
64 | Java 20 |
65 | Java 21 |
Вопросы на собесе (11)
Generics (2)
- Какие есть проблемы у дженериков в Java?
• Стирание типов: информация о типах удаляется на этапе компиляции, что не позволяет проверять их в рантайме.
• Нет поддержки примитивов: дженерики работают только с объектами, приходится использовать классы-обёртки, что увеличивает потребление памяти.
• Ограниченный полиморфизм: несовместимость типов (например,
List<Object>
иList<String>
) требует wildcard (? extends T/? super T
) для гибкости.
- Что такое стирание типов у дженериков?
Это процесс, при котором информация о типах стирается во время компиляции, чтобы сохранить совместимость с ранними версиями Java. В результате, в байт-коде дженерики представлены в виде базовых типов
Object
или других ограничений, заданных черезextends
.
- Какие есть проблемы у дженериков в Java?
Exceptions (2)
- Различие проверенных и непроверенных исключений в Java?
• Проверенные исключения (checked) должны быть либо обработаны в коде, либо объявлены с помощью
throws
, и проверяются на этапе компиляции.• Непроверенные исключения (unchecked) включают наследников
RuntimeException
и не требуют обязательной обработки или объявления.
- Как в Java работает ключевое слово throws?
Указывает, что метод может выбросить одно или несколько исключений, которые должны быть обработаны вызывающим кодом либо с помощью
try
-catch
, либо с добавлениемthrows
в сигнатуру метода.
- Различие проверенных и непроверенных исключений в Java?
Другие (7)
- Разница между примитивными и ссылочными типами в Java?
Примитивные типы в Java хранят сами значения, занимают меньше памяти и расположены в стеке, тогда как ссылочные типы хранят ссылку на объект в куче, что позволяет работать с более сложными структурами и поддерживать значение
null
.
- Различие final finally и finalize?
•
final
используется для объявления неизменяемых переменных, классов или методов.•
finally
— блок кода, который выполняется послеtry-catch
, независимо от того, было ли исключение.•
finalize
— метод, вызываемый сборщиком мусора перед удалением объекта из памяти.
- В чем разница между обычным и статическим классом в Java?
Обычный класс связан с экземпляром, а статический класс (вложенный) может существовать без создания экземпляра внешнего класса.
- Разница между статической и динамической загрузкой классов?
Статическая загрузка классов происходит при компиляции, а динамическая — во время выполнения программы с использованием рефлексии.
- Какое максимальное значение у 32-битного Int?
2^{31} - 1
- Для чего в Java используется ключевое слово static?
static
обозначает члены класса, которые принадлежат самому классу, а не его экземплярам. Это позволяет обращаться к статическим переменным и методам без создания объекта, что полезно для хранения констант и вспомогательных методов.
- Есть две переменные: Integer a = 100, Integer b = 100. Результатом сравнения a == b будет?
• true
• false
- Разница между примитивными и ссылочными типами в Java?