Type Erasure (Стирание типов)

Последнее обновление: 10.10.2025

Хотя язык Java позволяет создавать обобщенные типы и методы, которые используют параметры типа, однако на уровне виртуальной машины Java в реальности не существует никаких обобщенных типов и методов — все объекты принадлежат обычным классам. При компиляции параметры типа удаляются и заменяются либо типом Object для параметров типа без ограничений, либо их типами-ограничениями. Данный процесс называется type erasure (стирание типов).

Например, возьмем следующий обобщенный класс:

class Person<T>{

    private T id;
    private String name;

    T getId(){ return id; }
    String getName() { return name; }

    Person(T id, String name){

        this.id = id;
        this.name = name;
    }
}

Здесь поскольку для параметра T не установлено ограничений, то он просто заменяется на Object. То есть в итоге мы получим следующий класс:

class Person{

    private Object id;
    private String name;

    Object getId(){ return id; }
    String getName() { return name; }

    Person(Object id, String name){

        this.id = id;
        this.name = name;
    }
}

Причем без разницы, какими типами типизируется объект Person в программе:

Person tom = new Person<Integer>(456, "Tom");
Person bob = new Person<String>("qwert", "Bob");

В обоих этих случаях для среды выполнения Java параметр T будет представлять тип Object.

Если результат метода или поле класса представляет параметр типа и этот результат метода или поле присваиваются внешней переменной, то среда выполняет необходимые преобразования. Например, если мы имеет следующий код:

var tom = new Person<Integer>(456, "Tom");
int tomId = tom.getId();
System.out.println(tomId);

То среда выполнения трактует этот код наподобие следующего:

var tom = new Person(456, "Tom");
int tomId = (int) tom.getId();
System.out.println(tomId);

Параметры типа с ограничениями

Теперь рассмотрим другой пример - применение ограничений типа:

class Message{
 
    private String text; // текст сообщения
    String getText(){ return text; }
 
    Message(String text)
    {
        this.text = text;
    }
}

class Messenger<T extends Message> {
 
    private T message;
    T getMessage() { return this.message; }
 
    Messenger(T message) { this.message = message;  }
 
    void send() {
        System.out.println("Отправляется сообщение: " + message.getText());
    }
}

В данном случае класс Messenger типизируется параметром T, для которого установлено ограничение в виде типа Message, поэтому внутри класса Messenger тип T заменяется на Message:

class Messenger {
 
    private Message message;
    Message getMessage() { return this.message; }
 
    Messenger(Message message) { this.message = message;  }
 
    void send() {
        System.out.println("Отправляется сообщение: " + message.getText());
    }
}

Если для одного параметра типа установлено несколько ограничений, то параметр тпиа заменяется на тип из первого ограничения. Например:

class Messenger<T extends Message & Printable> {
 
    void sendMessage(T message){
 
        message.print();
    }
}
interface Printable{
 
    void print();
}
 
class Message{
 
    private String text; // текст сообщения
    String getText(){ return text; }
 
    Message(String text){

        this.text = text;
    }
}

Здесь в классе Messenger параметр типа T должен представлять одновременно класс Message и интерфейс Printable (класс, который наследуется от Message и реализует интерфейс Printable). В итоге для виртуальной срежы Java этот класс будет выглядеть наподобие следующего:

class Messenger {
 
    void sendMessage(Message message){
 
        ((Printable)message).print();
    }
}

То есть параметр типа T заменяется на первое ограничение - тип Message, а если используется функционал из второго ограничения, то выполняется преобразование.

Помощь сайту
Юмани:
410011174743222
Номер карты:
4048415020898850
Morty Proxy This is a proxified and sanitized view of the page, visit original site.