Czy w C ++ istnieje odpowiednik lub metodologia Java dla słowa kluczowego typedef?

244

Pochodząc z języków C i C ++ uważam, że rozsądne użycie typedefjest niezwykle pomocne. Czy znasz sposób na osiągnięcie podobnej funkcjonalności w Javie, niezależnie od tego, czy jest to mechanizm Java, wzorzec, czy inny skuteczny sposób, którego używałeś?

bn.
źródło
6
Typedef może być używany lub wiele rzeczy, dobrych i złych, choć nie wszyscy zgadzają się co do tego, która jest która. Czy mógłbyś powiedzieć, które aspekty pisania są według Ciebie cenne? W ten sposób możemy Ci powiedzieć, jak uzyskać podobne efekty w Javie lub dlaczego nie chcesz tego robić w Javie. Poniższy zbiór odpowiedzi zakłada, że ​​mówisz o ulubionym (lub najbardziej znienawidzonym) zastosowaniu autora.
PanCrit,
3
Lubię pisać na maszynie rodzime typy, jeśli mogę później przekształcić je w klasę. typedef IndexT int; na przykład. Później, jeśli chcę, aby IndexT był klasą, po prostu go implementuję i usuwam typedef. Pomaga w ukryciu informacji.
JR Lawhorne,
13
@Alexander - zaktualizowano link: ibm.com/developerworks/java/library/j-jtp02216/index.html
Andreas Dolk
1
Nie jestem pewien, jakie są tego wady, ale:public interface ScopeFactory { <Scope extends Map<String, Object>> Scope create(...) throws Exception; }
ScootyPuff

Odpowiedzi:

112

Java ma prymitywne typy, obiekty i tablice i to wszystko. Brak typedefs.

Cletus
źródło
38
Chyba większość ludzi chce typedefna nowo zdefiniować booleando bool.
Tomáš Zato - Przywróć Monikę
66
@ TomášZato Nie znam większości ludzi, ale z mojego doświadczenia wynika, że ​​przydatne jest dodawanie semantyki, takiej jak: typedef int PlayerIDktóra pozwala kompilatorowi upewnić się, że PlayerID nie są używane zamiennie z innymi intami, a także sprawia, że ​​kod jest znacznie bardziej czytelny dla ludzi . Zasadniczo jest to jak wyliczenie, ale bez ograniczonego zestawu wartości.
weberc2
76
@ TomášZato Przydatne jest także skracanie długich typów, takich jak typedef MegaLongTemplateClass<With, Many, Params> IsShorten;.
Alex Medveshchek
32
@ weberc2 „co pozwala kompilatorowi upewnić się, że identyfikatory PlayerID nie są używane zamiennie z innymi intami” - typedefnie włącza żadnej takiej rzeczy. To po prostu daje inną nazwę dla typu.
emlai
7
Przydatny również, jeśli na przykład masz jakiś identyfikator typu inti musisz go zmienić na long, musisz zmienić go w każdym miejscu kodu, w którym pracujesz z tym identyfikatorem. Gdybyś miał typedef, musiałbyś to zmienić tylko w 1 miejscu.
Jardo
101

Jeśli to masz na myśli, możesz po prostu rozszerzyć klasę, którą chcesz wpisać, np .:

public class MyMap extends HashMap<String, String> {}
Zed
źródło
5
Kłócę się, czy jest to bardziej anty-wzór niż użycie typedef w C.
Zed
22
Zdecydowanie jest - typedefnie ma żadnego problemu opisanego w artykule dla tych fałszywych klas (i są one bardzo realne).
Pavel Minaev
30
@Andreas_D: twój link, naprawiono: ibm.com/developerworks/java/library/j-jtp02216/index.html
Janus Troelsen
7
Lubię to z tego samego powodu, dla którego lubię typedefs. Jeśli masz kontener obiektów, łatwo zmieniaj typy kontenerów, zmieniając typedef. Może także abstrakcyjnie udostępnić kontener użytkownikowi końcowemu (co czasem jest pożądane). Zwykle robiłbym to w innej klasie, więc wtedy typ staje się bardziej oczywisty (tj. MyTree.Branches, gdzie klasy Oddziały rozszerzają HashSet <MyTree> {})
Josh Petitt
8
Chociaż głównym problemem tego podejścia jest to, że nie można go używać z finalklasami.
AJMansfield
14

W wersji Java nie ma typedef od 1.6, możesz zrobić klasę otoki dla tego, co chcesz, ponieważ nie można podklasować klas końcowych (liczba całkowita, podwójna itp.)

z -
źródło
3
Przywołany artykuł anty-wzorcowy opiera się na założeniu, że chcesz po prostu skrócić pisanie (co w rzeczywistości ukryłoby przydatne informacje o typie). Rzeczywistym zastosowaniem większości ludzi jest ujednoznacznienie typów i pozwolenie kompilatorowi wykonać swoją pracę za Ciebie. Zobacz Indeks T powyżej. faktura publiczna fetchInvoiceItem (String, String, String); kontra faktura publiczna fetchInvoiceItem (CustomerId, InvoiceId, InvoiceLineItemId); Jawne typy plus Konwertery / Walidatory sprawiają, że programowanie interfejsów API sieci Web, w których WSZYSTKO zaczyna się jako ciąg znaków jest znacznie bezpieczniejsze.
englebart
Żaden operator oveloading w Javie, więc robi się brzydkie
Mils
9

Jak wspomniano wcześniej,
w Javie nie ma mechanizmu typedef.
Nie popieram też ogólnie „fałszywych klas”, ale nie powinna tu obowiązywać ogólna ścisła zasada:
jeśli na przykład Twój kod używa w kółko „ogólnego typu”, na przykład:

Map<String, List<Integer>> 

Zdecydowanie powinieneś rozważyć podklasę do tego celu.
Innym podejściem, które można rozważyć, jest na przykład spowolnienie w kodzie:

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

A następnie użyj w kodzie NameToNumbers i wykonaj zadanie przed kompilatorem (ANT / Gradle / Maven) w celu przetworzenia i wygenerowania odpowiedniego kodu Java.
Wiem, że dla niektórych czytelników tej odpowiedzi może to zabrzmieć dziwnie, ale tyle frameworków zaimplementowało „adnotacje” przed JDK 5, to właśnie robi projekt lombok i inne frameworki.

Jair Zasławski
źródło
5

Naprawdę, jedynym zastosowaniem typedef, które przenosi się do Javaland, jest aliasing - czyli nadawanie tej samej klasie wielu nazw. Oznacza to, że masz klasę „A” i chcesz, aby „B” odnosiło się do tej samej rzeczy. W C ++ będziesz robił „typedef BA;”

Niestety po prostu tego nie obsługują. Jeśli jednak kontrolujesz wszystkie zaangażowane typy, MOŻESZ pociągnąć nieprzyjemnego hacka na poziomie biblioteki - albo rozszerzasz B z A, albo masz B implementujące A.

Zack Yezek
źródło
14
Posiadanie typedefrównież byłoby przydatne do tworzenia aliasów dla wywołań typów ogólnych. Na przykład: typedef A<Long,String> B;(może to być szczególny przypadek tego, co opisałeś, ale bardziej wyraźnie pokazuje atrakcyjność tego pomysłu).
Igorrs
W moim przypadku chcę nadać aliasy typom pierwotnym. real_tza doublei boolza boolean.
Aaron Franke
3

Być może może to być kolejna możliwa zamiana:

@Data
public class MyMap {
    @Delegate //lombok
    private HashMap<String, String> value;
}
przebiegłość
źródło
2
Czy nie uważasz, że ma to teraz problem, ponieważ za każdym razem, gdy definiujesz myMapinstancję typu MyMap, możesz operować na rzeczywistym HashMap tylko pisząc myMapInstance.value.SomeOperation()zamiast myMapInstance.SomeOperation(). To denerwujące, prawda?
mercury0114
2
nadal możesz zrobić myMapInstance.SomeOperation () - po to jest @Delegate
przebiegła
3

Jak zauważono w innych odpowiedziach, należy unikać antypateru pseudo-typedef . Jednak typedefs są nadal przydatne, nawet jeśli nie jest to sposób na ich osiągnięcie. Chcesz rozróżnić różne typy abstrakcyjne, które mają tę samą reprezentację Java. Nie chcesz mieszać ciągów znaków, które są hasłami z tymi, które są adresami ulic lub liczb całkowitych reprezentujących przesunięcie z tymi z tymi, które reprezentują wartość bezwzględną.

Ramowa Checker pozwala na zdefiniowanie typedef w wstecznie zgodny sposób. Pracuję nawet dla prymitywnych klas takich jak inti klas końcowych takich jak String. Nie ma narzutu w czasie wykonywania i nie przełamuje testów równości.

Sekcja Aliasy typów i typedefs w podręczniku Checker Framework opisuje kilka sposobów tworzenia typedefs, w zależności od potrzeb.

mernst
źródło
-6

Możesz użyć Enum, chociaż jest to semantycznie nieco inne niż typedef, ponieważ pozwala tylko na ograniczony zestaw wartości. Innym możliwym rozwiązaniem jest nazwana klasa opakowania, np

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

ale wydaje się to bardziej niezręczne, szczególnie biorąc pod uwagę, że z kodu nie wynika jasno, że klasa nie ma innej funkcji niż jako alias.

Steve B.
źródło
-7

Typedef umożliwia niejawne przypisanie elementów do typów, którymi nie są. Niektóre osoby próbują obejść ten problem za pomocą rozszerzeń; przeczytaj tutaj w IBM, aby uzyskać wyjaśnienie, dlaczego jest to zły pomysł.

Edycja: Mimo że wnioskowanie silnym typem jest przydatne, nie sądzę (i mam nadzieję, że tego nie zobaczymy) typedef wychowywanie brzydkiej głowy w zarządzanych językach (kiedykolwiek?).

Edycja 2: W języku C # możesz użyć instrukcji using w górnej części pliku źródłowego. Jest używany, więc nie musisz robić drugiego pokazanego elementu. Zmiana nazwy występuje tylko wtedy, gdy zakres wprowadza kolizję nazwy między dwoma typami. Zmiana nazwy jest ograniczona do jednego pliku, poza którym każdy typ zmiennej / parametru, który go używał, jest znany pod pełną nazwą.

using Path = System.IO.Path;
using System.IO;
Sam Harwell
źródło
23
„Typedef pozwala domyślnie przypisać elementy do typów, które nie są”. Co? Typedef pozwala po prostu utworzyć inną nazwę jako alias dla typu. Typ jest wciąż taki sam, otrzymujesz tylko krótszą nazwę. Nie ma to nic wspólnego z wnioskowaniem typu. -1
jalf
@jalf: W rzeczywistości wnioskowanie o typie jest stosowane jako rozwiązanie dokładnie tego, o czym mówisz, ale podałem inny przykład, w którym możesz użyć „typedef”, aby obejść kolizję nazw.
Sam Harwell
1
zaktualizowany link: ibm.com/developerworks/java/library/j-jtp02216/index.html
Alexander Malakhov
@AlexanderMalakhov Dzięki, poszedłem naprzód i zaktualizowałem odpowiedź z twoim linkiem
Dave McClelland
-14

W Javie nie ma potrzeby pisania na maszynie. Wszystko jest przedmiotem oprócz prymitywów. Nie ma żadnych wskaźników, tylko odniesienia. Scenariusze, w których normalnie użyłbyś typedefs, to instancje, w których zamiast tego tworzysz obiekty.

Markus Koivisto
źródło
19
Nie, potrzeba typedef nadal istnieje, jeśli chcesz mieć krótszą nazwę dla typu. Lub po prostu, jeśli chcesz móc zastąpić użycie jednego typu innym typem, zmieniając jedno miejsce w kodzie źródłowym.
jalf
28
@Bill K: meh, powiedz, że po wpisaniu czegoś takiego jak std :: map <int, std :: map <std :: string, boost :: shared_ptr <std :: string>>> :: const_iterator a kilka razy. W takim przypadku skrót maszynowy skracający nazwę poprawia czytelność, a nie przeszkadza.
Joel
22
Zmiana nazwy typu może znacznie poprawić czytelność. Co jest łatwiejsze do odczytania i zrozumienia (a zatem bardziej czytelne :) UnmodifiableDirectedGraph<IncrediblyFancyEdgeType, IncrediblyFancyAbstractNode.EvenFancierConcreteNode>lub IncrediblyFancyGraph? Zawsze mogę odwołać się do definicji, aby dowiedzieć się, o co tak naprawdę chodzi. W ten sposób mogę mieć pewność, że nie umknę UnmodifiableDirectedGraph<IncrediblyFancyEdge,IncredilyFancyAbstractNode.SlightlyLessFancyConcreteNode>z czystej nudy.
Aleksandar Dimitrov
10
@AleksandarDimitrov Wiem, że twój komentarz ma prawie 3 lata, kiedy to piszę, ale uważam, że bardzo ważne jest wskazanie, jak wymyślony i nierealistyczny jest ten przykład: żadna z tych nazw klas nie zawiera tego słowa Enterprise.
Casey
4
Złe nazwy utrudniają czytelność. Dobre imiona pomagają. Typedefs może pomóc, jeśli pełna nazwa jest tak długa, że ​​trudno ją odczytać lub zepsuć formatowanie kodu. Pomogłoby to również podczas interakcji z kiepsko wybranymi lub niejednoznacznymi nazwami klas innych osób. Jeśli naprawdę uważasz, że typedef z natury sprawi, że Twój kod stanie się nieczytelny, powinieneś również uwierzyć, że nigdy nie powinieneś używać instrukcji importu i zawsze powinieneś odwoływać się do w pełni kwalifikowanych nazw klas.
Christopher Barber