Есть ли эквивалент Java или методология для ключевого слова typedef в C ++?

244

Исходя из опыта C и C ++, я обнаружил, что разумное использование typedefочень полезно. Знаете ли вы о способе достижения аналогичной функциональности в Java, будь то механизм Java, шаблон или какой-то другой эффективный способ, который вы использовали?

млрд.
источник
6
Можно использовать typedef или много других вещей, хороших и плохих, хотя не все согласны с тем, что есть что. Не могли бы вы сказать, какие аспекты typedef вы считаете ценными? Таким образом, мы можем либо рассказать вам, как получить аналогичные эффекты в Java, либо почему вы не хотите делать это в Java. Под подборкой ответов ниже каждого предполагается, что вы говорите о любимом (или наиболее ненавистном) использовании автора.
PanCrit
3
Я люблю печатать собственные типы, если позже смогу превратить их в класс. typedef IndexT int; например. Позже, если я хочу, чтобы IndexT был классом, я просто реализую его и удаляю typedef. Это помогает с сокрытием информации.
JR Lawhorne
13
@Alexander - обновленная ссылка: ibm.com/developerworks/java/library/j-jtp02216/index.html
Андреас Долк,
1
Я не уверен, каковы недостатки этого, но:public interface ScopeFactory { <Scope extends Map<String, Object>> Scope create(...) throws Exception; }
ScootyPuff
2
Вам может понравиться Scala stackoverflow.com/a/21223102/203968
oluies

Ответы:

112

У Java есть примитивные типы, объекты и массивы и все. Нет typedefs.

Клетус
источник
38
Я предполагаю , что большинство людей , которые хотят typedefпересмотреть booleanв bool.
Томаш Зато - Восстановить Монику
66
@ TomášZato Я не знаю большинства людей, но по моему опыту, это полезно для добавления семантики, такой как: typedef int PlayerIDкоторая позволяет компилятору гарантировать, что идентификаторы PlayerID не используются взаимозаменяемо с другими int, а также делает код намного более читабельным для людей. , По сути, это как перечисление, но без ограниченного набора значений.
weberc2
76
@ TomášZato Это также полезно для сокращения длинных типов, таких как typedef MegaLongTemplateClass<With, Many, Params> IsShorten;.
Алекс Медещек
32
@ weberc2 ", который позволяет компилятору удостовериться, что идентификаторы игроков не используются взаимозаменяемо с другими объектами" - typedefне включает ничего подобного. Это просто дает другое имя для типа.
Emlai
7
Также полезно, если, например, у вас есть некоторый идентификатор типа, intи вам нужно изменить его на long, вы должны изменить его в каждом месте кода, где вы работаете с этим идентификатором. Если бы вы имели typedef, вам нужно было бы только изменить его в 1 месте.
Jardo
101

Если это то, что вы имеете в виду, вы можете просто расширить класс, который вы хотели бы ввести typedef, например:

public class MyMap extends HashMap<String, String> {}
Zed
источник
5
Я бы поспорил, является ли это более анти-паттерном, чем использование typedef в C.
Zed
22
Это определенно есть - не typedefимеет проблем, описанных в статье для этих поддельных классов (и они очень реальны).
Павел Минаев
30
@Andreas_D: ваша ссылка исправлена: ibm.com/developerworks/java/library/j-jtp02216/index.html
Янус Троелсен,
7
Мне это нравится по той же причине, по которой я люблю typedefs. Если у вас есть контейнер объектов, можно легко поменять типы контейнеров, изменив typedef. Кроме того, он может абстрагировать контейнер до конечного пользователя (что иногда желательно). Обычно я делаю это внутри другого класса, поэтому тип становится более очевидным (например, MyTree.Branches, где класс Branches расширяет HashSet <MyTree> {})
Джош Петитт
8
Хотя главная проблема этого подхода в том, что вы не можете использовать его с finalклассами.
AJMansfield
14

Начиная с версии 1.6, в java нет typedef; вы можете создать класс-оболочку для того, что вам нужно, поскольку вы не можете создавать подклассы конечных классов (Integer, Double и т. Д.).

z -
источник
3
Ссылочная статья о шаблонах основана на предположении, что вы просто хотите сократить ввод текста (что на самом деле скрыло бы полезную информацию о типе). Реальное использование, которого хочет большинство людей, - устранение неоднозначности типов и предоставление компилятору своей работы за вас. Смотрите IndexT выше. public Invoice fetchInvoiceItem (String, String, String); в сравнении с общедоступным счетом fetchInvoiceItem (CustomerId, InvoiceId, InvoiceLineItemId); Явные типы плюс конвертеры / валидаторы делают программирование веб-API, где ВСЁ начинается с String, намного безопаснее.
englebart
Нет оператора oveloading в Java, так что это уродливо
мил
9

Как уже упоминалось ранее,
в Java нет механизма определения типа.
Я также не поддерживаю «поддельные классы» в целом, но здесь не должно быть общего строгого практического правила:
если ваш код, например, снова и снова использует «родовой тип», например:

Map<String, List<Integer>> 

Вы должны определенно рассмотреть вопрос о наличии подкласса для этой цели.
Другой подход, который можно рассмотреть, например, иметь в своем коде замедление, подобное:

//@Alias Map<String, List<Integer>>  NameToNumbers;

А затем используйте в своем коде NameToNumbers и задайте задачу перед компилятором (ANT / Gradle / Maven) для обработки и генерации соответствующего кода Java.
Я знаю, что для некоторых читателей этого ответа это может звучать странно, но это то, сколько фреймворков реализовали «аннотации» до JDK 5, это то, чем занимается проект lombok и другие фреймворки.

Яир Заславский
источник
5

Действительно, единственное использование typedef, которое переносится на Javaland, - это псевдонимы, то есть присвоение одному и тому же классу нескольких имен. То есть у вас есть класс «А», и вы хотите, чтобы «Б» относилось к тому же самому. В C ++ вы будете делать "typedef BA;"

К сожалению, они просто не поддерживают это. Однако, если вы контролируете все задействованные типы, вы МОЖЕТЕ осуществить неприятный хак на уровне библиотеки - вы либо расширяете B из A, либо B реализует A.

Зак Йезек
источник
14
Имея typedefтакже было бы полезно создавать псевдонимы для вызовов универсальных типов. Например: typedef A<Long,String> B;(это может быть особый случай того, что вы описали, но он показывает привлекательность идеи немного более четко).
igorrs
В моем случае я хочу дать псевдонимы примитивным типам. real_tдля doubleи boolдля boolean.
Аарон Франке
3

Возможно, это может быть другой возможной заменой:

@Data
public class MyMap {
    @Delegate //lombok
    private HashMap<String, String> value;
}
shrewquest
источник
2
Не думаете ли вы, что в этом сейчас есть проблема, потому что всякий раз, когда вы определяете myMapэкземпляр типа MyMap, вы можете работать с реальным HashMap, только набрав myMapInstance.value.SomeOperation()вместо myMapInstance.SomeOperation(). Это раздражает, не так ли?
mercury0114
2
вы все еще можете сделать myMapInstance.SomeOperation () - это то, для чего предназначен @Delegate
shrewquest
3

Как отмечалось в других ответах, вам следует избегать псевдотипного антипаттерна . Тем не менее, typedefs по-прежнему полезны, даже если это не способ их достижения. Вы хотите различать разные абстрактные типы, имеющие одинаковое представление Java. Вы не хотите смешивать строки, которые являются паролями, с теми, которые являются адресами улиц, или целыми числами, которые представляют смещение, с теми, которые представляют собой абсолютные значения.

Среда проверки позволяет вам определять typedef обратно совместимым способом. Я работаю даже для примитивных классов, таких как intи окончательных классов, таких как String. Он не имеет времени выполнения и не нарушает тесты на равенство.

В разделе « Псевдонимы типов и определения типов» в руководстве по Checker Framework описано несколько способов создания определений типов в зависимости от ваших потребностей.

mernst
источник
-1

В некоторых случаях обязательная аннотация может быть именно тем, что вы ищете:

https://github.com/google/guice/wiki/BindingAnnotations

Или, если вы не хотите зависеть от Guice, может подойти обычная аннотация.

dzs0000
источник
-6

Вы можете использовать Enum, хотя это семантически немного отличается от typedef тем, что он допускает только ограниченный набор значений. Другим возможным решением является именованный класс-оболочка, например

public class Apple {
      public Apple(Integer i){this.i=i; }
}

но это кажется более неуклюжим, особенно учитывая, что из кода не ясно, что у класса нет другой функции, кроме как псевдоним.

Стив Б.
источник
-7

Typedef позволяет неявно назначать элементы тем типам, которыми они не являются. Некоторые люди пытаются обойти это с помощью расширений; Прочитайте здесь, в IBM, чтобы объяснить, почему это плохая идея.

Редактировать: Хотя строгий вывод типов является полезной вещью, я не думаю (и надеюсь, что мы этого не сделаем) не вижу, как typedefподнимать эту уродливую голову на управляемых языках (когда-либо?).

Редактировать 2: В C # вы можете использовать оператор использования, как это в верхней части исходного файла. Он используется, поэтому вам не нужно делать второй элемент, показанный. Единственный раз, когда вы видите изменение имени, это когда в области возникает конфликт имен между двумя типами. Переименование ограничено одним файлом, вне которого каждая используемая переменная / тип параметра известна своим полным именем.

using Path = System.IO.Path;
using System.IO;
Сэм Харвелл
источник
23
«Typedef позволяет неявно присваивать элементам типы, которыми они не являются» Что? Typedef просто позволяет вам создать другое имя в качестве псевдонима для типа. Тип все тот же, вы получите более короткое имя. Это не имеет никакого отношения к выводу типа. -1
jalf
@jalf: На самом деле, вывод типа используется как решение именно того, о чем вы говорите, но я привел еще один пример, где вы можете использовать «typedef», чтобы обойти конфликт имен.
Сэм Харвелл
1
обновленная ссылка: ibm.com/developerworks/java/library/j-jtp02216/index.html
Александр Малахов
@AlexanderMalakhov Спасибо, я пошел дальше и обновил ответ своей ссылкой
Дейв МакКлелланд,
-14

Нет необходимости в typedef в Java. Все является Объектом, кроме примитивов. Там нет указателей, только ссылки. Сценарии, в которых вы обычно используете typedef, - это экземпляры, в которых вы создаете объекты.

Маркус Койвисто
источник
19
Нет, потребность в typedef все еще существует, если вы хотите более короткое имя для типа. Или просто, если вы хотите иметь возможность заменить использование одного типа другим, изменив одно место в исходном коде.
Джалф
28
@ Bill K: meh, скажем, что после того, как вам нужно было напечатать что-то вроде std :: map <int, std :: map <std :: string, boost :: shared_ptr <std :: string>>> :: const_iterator a несколько раз. В этом случае typedef с сокращением имени повышает удобочитаемость, а не затрудняет ее.
Джоэл
22
Переименование типа может значительно улучшить читаемость. Что легче читать и понимать (и, следовательно, более читабельно :) UnmodifiableDirectedGraph<IncrediblyFancyEdgeType, IncrediblyFancyAbstractNode.EvenFancierConcreteNode>или IncrediblyFancyGraph? Я всегда могу обратиться к определению, чтобы узнать, о чем оно на самом деле. Таким образом, я также могу быть уверен, что не скучаю UnmodifiableDirectedGraph<IncrediblyFancyEdge,IncredilyFancyAbstractNode.SlightlyLessFancyConcreteNode>по чистой скуке.
Александар Димитров
10
@AleksandarDimitrov Я знаю, что вашему комментарию уже почти 3 года, когда я набираю это, но я чувствую, что очень важно указать, насколько надуманным и нереальным этот пример: ни одно из названий классов не содержит слова Enterprise.
Кейси
4
Плохие имена мешают читабельности. Добрые имена помогают. Typedefs может помочь, если полное имя настолько длинное, что его становится трудно читать, или испортило форматирование кода. Это также поможет при взаимодействии с чужими плохо выбранными или неоднозначными именами классов. Если вы действительно верите, что typedef по сути сделает ваш код нечитаемым, то вы также должны верить, что вам никогда не следует использовать операторы import и всегда следует ссылаться на полностью определенные имена классов.
Кристофер Барбер