8

Что такое «сырые типы» и почему их не следует использовать?

1

Вопросы:

  • Что такое "сырой тип" (raw types) в Java, и почему я часто слышу, что их не следует использовать в новом коде?
  • Какова альтернатива, если мы не можем использовать сырые типы, и в чем преимущество этих альтернатив?

5 ответ(ов)

0

"Сырой" тип в Java — это класс, который не является дженерик-типом и работает с "сырыми" объектами, а не с безопасными типизированными параметрами.

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

LinkedList list = new LinkedList();
list.add(new MyObject());
MyObject myObject = (MyObject) list.get(0);

Когда вы добавляете объект в список, ему неважно, какой это тип, и когда вы извлекаете его из списка, вам необходимо явно привести его к ожидаемому типу.

Используя дженерики, вы убираете фактор "неизвестного", так как обязаны явно указать, какие типы объектов могут находиться в списке:

LinkedList<MyObject> list = new LinkedList<MyObject>();
list.add(new MyObject());
MyObject myObject = list.get(0);

Обратите внимание, что с дженериками вам не нужно приводить объект, который вы получаете с помощью метода get, коллекция заранее определена для работы только с MyObject. Этот факт является основным преимуществом дженериков. Он превращает источник ошибок времени выполнения в то, что может быть проверено на этапе компиляции.

0

Что такое "сырая" типизация и почему я часто слышу, что ее не стоит использовать в новом коде?

"Сырая" типизация — это использование обобщенного класса без указания аргумента типа для его параметризованных типов, например, использование List вместо List<String>. Когда в Java были введены обобщения, несколько классов были обновлены для поддержки этой функции. Использование этих классов как "сырых типов" (без указания аргумента типа) позволяло поддерживать совместимость с устаревшим кодом.

"Сырые типы" используются для обеспечения обратной совместимости. Их использование в новом коде не рекомендуется, поскольку применение обобщенного класса с аргументом типа позволяет достичь более строгой типизации, что, в свою очередь, может улучшить понимание кода и привести к более раннему выявлению потенциальных проблем.

Какова альтернатива, если мы не можем использовать "сырые" типы, и чем она лучше?

Предпочтительной альтернативой является использование обобщенных классов по назначению — с подходящими аргументами типа (например, List<String>). Это позволяет программисту более конкретно указывать типы, передает больше информации будущим разработчикам о предполагаемом использовании переменной или структуры данных и позволяет компилятору обеспечивать лучшую строгую типизацию. Эти преимущества могут вместе улучшить качество кода и помочь предотвратить появление некоторых ошибок в коде.

Например, для метода, в котором программист хочет убедиться, что переменная типа List с именем 'names' содержит только строки:

List<String> names = new ArrayList<String>();
names.add("John");          // ОК
names.add(new Integer(1));  // ошибка компиляции
0

Конечно! Вот перевод на русский язык в стиле ответа на StackOverflow.com:


Здесь я рассматриваю несколько случаев, которые могут прояснить концепцию.

1. ArrayList<String> arr = new ArrayList<String>();
2. ArrayList<String> arr = new ArrayList();
3. ArrayList arr = new ArrayList<String>();

Случай 1

ArrayList<String> arr — это переменная-ссылка на ArrayList с типом String, которая ссылается на объект ArrayList типа String. Это означает, что она может хранить только объекты типа String.

Это строгий тип для String, а не "сырой" тип, поэтому предупреждений не будет.

arr.add("hello"); // эта строка компилируется успешно, и предупреждений нет.
arr.add(23);  // приведет к ошибке на этапе компиляции.
// ошибка: no suitable method found for add(int)

Случай 2

В этом случае ArrayList<String> arr имеет строгий тип, но ваш объект new ArrayList(); является "сырым" типом.

arr.add("hello"); // эта строка компилируется, но вызывает предупреждение.
arr.add(23);  // снова приведет к ошибке на этапе компиляции.
// ошибка: no suitable method found for add(int)

Здесь arr является строгим типом. Поэтому при попытке добавить int будет ошибка компиляции.

Предупреждение: Объект "сырого" типа ссылается на переменную с строгим типом ArrayList.

Случай 3

В этом случае ArrayList arr является "сырым" типом, а ваш объект new ArrayList<String>(); имеет строгий тип.

arr.add("hello");  
arr.add(23);  // компилируется без ошибок, но вызывает предупреждение.

В это можно добавить любой тип объекта, поскольку arr — это "сырой" тип.

Предупреждение: Объект строгого типа ссылается на переменную с "сырым" типом.


Надеюсь, это поможет вам понять различия между строгими и "сырыми" типами в Java!

0

Компилятор требует, чтобы вы написали так:

private static List<String> list = new ArrayList<String>();

Потому что иначе вы могли бы добавлять в list любые типы, что делает создание объекта с new ArrayList<String>() бессмысленным. Джавовские обобщения являются особенностью времени компиляции, поэтому объект, созданный с помощью new ArrayList<String>(), будет без проблем принимать элементы типа Integer или JFrame, если его присвоить ссылке на "сырой тип" List — сам объект ничего не знает о том, какие типы он должен содержать, только компилятор это знает.

0

Вот еще один случай, когда "сырые" типы могут вас подвести:

public class StrangeClass<T> {
  @SuppressWarnings("unchecked")
  public <X> X getSomethingElse() {
    return (X)"Testing something else!";
  }

  public static void main(String[] args) {
    final StrangeClass<String> withGeneric    = new StrangeClass<>();
    final StrangeClass         withoutGeneric = new StrangeClass();
    final String               value1,
                               value2;

    // Компилируется
    value1 = withGeneric.getSomethingElse();

    // Вызывает ошибку компиляции:
    // incompatible types: java.lang.Object cannot be converted to java.lang.String
    value2 = withoutGeneric.getSomethingElse();
  }
}

Это может показаться неожиданным, поскольку вы можете подумать, что "сырой" тип влияет только на методы, связанные с параметром типа класса, однако на самом деле это также влияет на обобщенные методы с их собственными параметрами типов.

Как было упомянуто в принятом ответе, вы теряете всю поддержку обобщений в коде сырого типа. Каждый параметр типа преобразуется в его "стирание" (в приведенном примере это просто Object).

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь