Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Статический полиморфизм
Статический полиморфизм (Compile-Time Polymorphism) — это механизм, при котором решение о том, какой метод или конструктор вызвать, принимается компилятором во время компиляции, а не во время выполнения. В Java это реализуется через перегрузку методов (Method Overloading) и перегрузку операторов (в некоторых языках).
Основная идея
В отличие от динамического полиморфизма, который определяет метод во время выполнения на основе типа объекта, статический полиморфизм использует сигнатуру метода (имя, количество, типы и порядок параметров) для выбора нужной реализации.
1. Перегрузка методов (Method Overloading)
Основной вид статического полиморфизма в Java. Методы с одинаковым именем, но разными параметрами:
Примеры перегрузки
public class Calculator {
// Перегрузка по количеству параметров
public int add(int a, int b) {
return a + b;
}
public int add(int a, int b, int c) {
return a + b + c;
}
// Перегрузка по типам параметров
public double add(double a, double b) {
return a + b;
}
public String add(String a, String b) {
return a + b;
}
// Перегрузка по порядку параметров
public void process(String name, int age) {
System.out.println(name + " is " + age);
}
public void process(int age, String name) {
System.out.println(age + " years old " + name);
}
}
// Использование
Calculator calc = new Calculator();
calc.add(5, 3); // Вызовет первый add: 8
calc.add(5, 3, 2); // Вызовет второй add: 10
calc.add(5.5, 3.2); // Вызовет третий add: 8.7
calc.add("Hello", "World"); // Вызовет четвёртый add: HelloWorld
Правила перегрузки
Методы считаются перегруженными ТОЛЬКО если отличаются:
- Количество параметров
- Типы параметров
- Порядок параметров
НЕ может быть перегрузкой:
// ❌ Только разные возвращаемые типы — ошибка компиляции!
public int getValue() { return 1; }
public double getValue() { return 1.0; }
// ❌ Только разные имена параметров — ошибка компиляции!
public void print(int x) {}
public void print(int y) {}
// ❌ Только разные модификаторы доступа — ошибка компиляции!
public void method() {}
private void method() {}
2. Автоматическое приведение типов при перегрузке
Когда нет точного совпадения типов, Java пытается привести аргументы:
public class TypePromotion {
public void display(int x) {
System.out.println("int: " + x);
}
public void display(double x) {
System.out.println("double: " + x);
}
public static void main(String[] args) {
TypePromotion tp = new TypePromotion();
tp.display(5); // Точное совпадение: вызовет display(int)
tp.display(5.5); // Точное совпадение: вызовет display(double)
tp.display(5L); // long → int или double? Выберет int (ближайший)
tp.display(5.5f); // float → double
}
}
Порядок приведения типов:
- Точное совпадение типов
- Приведение к ширящемуся типу (widening): byte → short → int → long → float → double
- Приведение с помощью boxing/unboxing
- Приведение к суперклассу
3. Перегрузка с varargs
public class VarargOverload {
public void print(String... args) {
System.out.println("varargs: " + args.length);
}
public void print(String s) {
System.out.println("single: " + s);
}
public static void main(String[] args) {
VarargOverload vo = new VarargOverload();
vo.print("one"); // Вызовет print(String s) — точное совпадение
vo.print("one", "two"); // Вызовет print(String... args)
vo.print(); // Вызовет print(String... args) с пустым массивом
}
}
4. Перегрузка конструкторов
Конструкторы тоже могут быть перегружены:
public class Person {
private String name;
private int age;
private String email;
// Конструктор 1
public Person(String name) {
this.name = name;
this.age = 0;
}
// Конструктор 2
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// Конструктор 3
public Person(String name, int age, String email) {
this.name = name;
this.age = age;
this.email = email;
}
}
// Использование
Person p1 = new Person("John");
Person p2 = new Person("Jane", 25);
Person p3 = new Person("Bob", 30, "bob@example.com");
Статический vs Динамический полиморфизм
// ========== СТАТИЧЕСКИЙ ПОЛИМОРФИЗМ (Method Overloading) ==========
public class StaticPolymorphism {
public void show(int x) {
System.out.println("int: " + x);
}
public void show(double x) {
System.out.println("double: " + x);
}
public static void main(String[] args) {
StaticPolymorphism sp = new StaticPolymorphism();
sp.show(5); // Компилятор знает, какой show() вызвать
sp.show(5.5); // Во время компиляции!
}
}
// ========== ДИНАМИЧЕСКИЙ ПОЛИМОРФИЗМ (Method Overriding) ==========
public class Animal {
public void sound() {
System.out.println("Animal sound");
}
}
public class Dog extends Animal {
@Override
public void sound() {
System.out.println("Woof!");
}
}
public class DynamicPolymorphism {
public static void main(String[] args) {
Animal animal = new Dog();
animal.sound(); // Во время выполнения определяется,
// что это Dog, и вызывается Dog.sound()
}
}
Сравнительная таблица
| Аспект | Статический | Динамический |
|---|---|---|
| Когда решается | Во время компиляции | Во время выполнения |
| Механизм | Перегрузка методов | Переопределение методов |
| Условие | Разные сигнатуры | Наследование + @Override |
| Производительность | Быстрее (нет runtime checks) | Медленнее |
| Гибкость | Меньше | Больше |
Практические примеры
1. Логирование с разными типами данных
public class Logger {
public void log(String message) {
System.out.println("[INFO] " + message);
}
public void log(Exception e) {
System.err.println("[ERROR] " + e.getMessage());
e.printStackTrace();
}
public void log(String message, int level) {
System.out.println("[LEVEL " + level + "] " + message);
}
}
// Использование
Logger logger = new Logger();
logger.log("Application started");
logger.log(new NullPointerException("Data is null"));
logger.log("User action", 2);
2. Builder pattern (альтернатива перегрузке)
public class HttpRequest {
private String method;
private String url;
private Map<String, String> headers;
private String body;
// Вместо многочисленных конструкторов используем Builder
public static class Builder {
private String method = "GET";
private String url;
private Map<String, String> headers = new HashMap<>();
private String body;
public Builder(String url) {
this.url = url;
}
public Builder method(String method) {
this.method = method;
return this;
}
public Builder header(String key, String value) {
headers.put(key, value);
return this;
}
public Builder body(String body) {
this.body = body;
return this;
}
public HttpRequest build() {
HttpRequest request = new HttpRequest();
request.method = this.method;
request.url = this.url;
request.headers = this.headers;
request.body = this.body;
return request;
}
}
}
// Использование
HttpRequest request = new HttpRequest.Builder("http://api.example.com")
.method("POST")
.header("Content-Type", "application/json")
.body("{\"key\": \"value\"}")
.build();
Когда избежать чрезмерной перегрузки
// ❌ Слишком много перегрузок — сложно понять и поддерживать
public class Utils {
public String convert(int x) { return String.valueOf(x); }
public String convert(double x) { return String.valueOf(x); }
public String convert(boolean x) { return String.valueOf(x); }
public String convert(Object x) { return x.toString(); }
// ... ещё 10 вариантов
}
// ✅ Лучше использовать более специфичные имена или generics
public class Converter {
public static <T> String toString(T value) {
return value == null ? "null" : value.toString();
}
}
Статический полиморфизм — это мощный инструмент для создания гибкого, типобезопасного кода, хотя его не следует использовать без необходимости.