Gibt es ein Java-Äquivalent oder eine Java-Methode für das Schlüsselwort typedef in C ++?


244

Ich stamme aus C und C ++ und fand die vernünftige Verwendung von typedefunglaublich hilfreich. Kennen Sie eine Möglichkeit, ähnliche Funktionen in Java zu erreichen, sei es ein Java-Mechanismus, ein Java-Muster oder eine andere effektive Methode, die Sie verwendet haben?


6
typedef kann verwendet werden oder viele Dinge, gut und schlecht, obwohl nicht jeder sich einig ist, welches was ist. Würde es Ihnen etwas ausmachen zu sagen, welche Aspekte von typedef Ihrer Meinung nach wertvoll sind? Auf diese Weise können wir Ihnen entweder sagen, wie Sie ähnliche Effekte in Java erzielen oder warum Sie dies in Java nicht tun möchten. In der unten stehenden Sammlung von Antworten wird davon ausgegangen, dass Sie über die bevorzugte (oder am meisten gehasste) Verwendung des Autors sprechen.
PanCrit

3
Ich schreibe gerne native Typen, wenn ich sie später in eine Klasse verwandeln möchte. typedef IndexT int; beispielsweise. Wenn ich später möchte, dass IndexT eine Klasse ist, implementiere ich es einfach und entferne das typedef. Es hilft beim Verstecken von Informationen.
JR Lawhorne


1
Ich bin nicht sicher, was die Nachteile davon sind, aber:public interface ScopeFactory { <Scope extends Map<String, Object>> Scope create(...) throws Exception; }
ScootyPuff

Antworten:


112

Java hat primitive Typen, Objekte und Arrays und das war's. Keine typedefs.


37
Ich denke , die meisten Menschen wollen typedefneu zu definieren , booleanzu bool.
Tomáš Zato - Wiedereinsetzung Monica

66
@ TomášZato Ich kenne die meisten Leute nicht, aber meiner Erfahrung nach ist es nützlich, um Semantik wie typedef int PlayerIDdie folgende hinzuzufügen: Dadurch kann der Compiler sicherstellen, dass PlayerIDs nicht austauschbar mit anderen Ints verwendet werden, und Code ist für Menschen viel lesbarer . Im Grunde ist es wie eine Aufzählung, aber ohne einen begrenzten Satz von Werten.
weberc2

76
@ TomášZato Es ist auch nützlich, lange Typen wie z typedef MegaLongTemplateClass<With, Many, Params> IsShorten;.
Alex Medveshchek

32
@ weberc2 "mit dem der Compiler sicherstellen kann, dass PlayerIDs nicht austauschbar mit anderen Ints verwendet werden" - typedefaktiviert so etwas nicht. Es gibt nur einen anderen Namen für einen Typ.
Emlai

7
Auch nützlich, wenn Sie beispielsweise eine ID vom Typ haben intund diese ändern müssen long, müssen Sie sie an jeder Stelle im Code ändern, an der Sie mit der ID arbeiten. Wenn Sie dies typedefgetan hätten , müssten Sie es nur an einer Stelle ändern.
Jardo

101

Wenn Sie dies meinen, können Sie einfach die Klasse erweitern, die Sie eingeben möchten, z. B.:

public class MyMap extends HashMap<String, String> {}

5
Ich würde argumentieren, ob dies mehr Anti-Muster ist als die Verwendung von typedef in C.
Zed

22
Es ist definitiv - typedefhat keines der Probleme, die der Artikel für diese gefälschten Klassen beschreibt (und sie sind sehr real).
Pavel


7
Ich mag das aus dem gleichen Grund, aus dem ich typedefs mag. Wenn Sie einen Container mit Objekten haben, können Sie Containertypen einfach austauschen, indem Sie das typedef ändern. Außerdem kann der Container für den Endbenutzer abstrahiert werden (was manchmal wünschenswert ist). Normalerweise mache ich das in einer anderen Klasse, damit der Typ offensichtlicher wird (dh MyTree.Branches, wo die Klasse Branches HashSet <MyTree> {} erweitert)
Josh Petitt

8
Obwohl das Hauptproblem bei diesem Ansatz darin besteht, dass Sie ihn nicht mit finalKlassen verwenden können.
AJMansfield

14

In Java gibt es ab 1.6 kein typedef. Sie können lediglich eine Wrapper-Klasse für das erstellen, was Sie möchten, da Sie keine endgültigen Klassen (Integer, Double usw.) unterordnen können.


3
Der Artikel, auf den verwiesen wird, basiert auf der Annahme, dass Sie nur Ihre Eingabe verkürzen möchten (wodurch die hilfreichen Typinformationen tatsächlich ausgeblendet würden). Die wirkliche Verwendung, die die meisten Leute wollen, besteht darin, Typen zu unterscheiden und den Compiler seine Arbeit für Sie erledigen zu lassen. Siehe IndexT oben. öffentliche Rechnung fetchInvoiceItem (String, String, String); versus öffentliche Rechnung fetchInvoiceItem (CustomerId, InvoiceId, InvoiceLineItemId); Explizite Typen plus Konverter / Validatoren machen das Programmieren von Web-APIs, bei denen ALLES als Zeichenfolge beginnt, viel sicherer.
Englebart

Kein Operator, der in Java lädt, so dass es hässlich wird
mils

9

Wie andere bereits erwähnt haben,
gibt es in Java keinen typedef-Mechanismus.
Ich unterstütze auch keine "gefälschten Klassen" im Allgemeinen, aber es sollte hier keine allgemeine strenge Faustregel geben:
Wenn Ihr Code zum Beispiel immer und immer wieder einen "generischen Typ" verwendet, zum Beispiel:

Map<String, List<Integer>> 

Sie sollten auf jeden Fall in Betracht ziehen, eine Unterklasse für diesen Zweck zu haben.
Ein anderer Ansatz, den man in Betracht ziehen kann, besteht beispielsweise darin, eine Verzögerung in Ihrem Code zu haben, wie:

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

Verwenden Sie dann in Ihrem Code NameToNumbers und haben Sie eine Pre-Compiler-Aufgabe (ANT / Gradle / Maven), um relevanten Java-Code zu verarbeiten und zu generieren.
Ich weiß, dass dies für einige Leser dieser Antwort seltsam klingen mag, aber so viele Frameworks haben "Anmerkungen" vor JDK 5 implementiert, genau das macht das Projekt lombok und andere Frameworks.


5

Wirklich, die einzige Verwendung von typedef, die auf Javaland übertragen wird, ist Aliasing - das heißt, der gleichen Klasse werden mehrere Namen gegeben. Das heißt, Sie haben eine Klasse "A" und möchten, dass sich "B" auf dasselbe bezieht. In C ++ würden Sie "typedef BA" ausführen.

Leider unterstützen sie es einfach nicht. Wenn Sie jedoch alle beteiligten Typen steuern, KÖNNEN Sie auf Bibliotheksebene einen bösen Hack ausführen - Sie erweitern entweder B von A oder lassen B A implementieren.


14
Es typedefwäre auch nützlich, Aliase für Aufrufe generischer Typen zu erstellen. Zum Beispiel: typedef A<Long,String> B;(Dies mag ein Sonderfall dessen sein, was Sie beschrieben haben, aber es zeigt den Reiz der Idee etwas deutlicher).
Igorrs

In meinem Anwendungsfall möchte ich primitiven Typen Aliase geben. real_tfür doubleund boolfür boolean.
Aaron Franke

3

Vielleicht könnte dies ein weiterer möglicher Ersatz sein:

@Data
public class MyMap {
    @Delegate //lombok
    private HashMap<String, String> value;
}

2
Denken Sie nicht, dass dies jetzt ein Problem hat, denn wann immer Sie eine myMapInstanz des Typs definieren MyMap, können Sie die tatsächliche HashMap nur durch Eingabe myMapInstance.value.SomeOperation()anstelle von bearbeiten myMapInstance.SomeOperation(). Das ist ärgerlich, nicht wahr?
mercury0114

2
Sie können immer noch myMapInstance.SomeOperation () - das ist, was das @Delegate ist
Shrewquest

3

Wie in anderen Antworten erwähnt, sollten Sie das Pseudo-Typedef-Antimuster vermeiden . Typedefs sind jedoch immer noch nützlich, auch wenn dies nicht der Weg ist, um sie zu erreichen. Sie möchten zwischen verschiedenen abstrakten Typen mit derselben Java-Darstellung unterscheiden. Sie möchten Zeichenfolgen, bei denen es sich um Kennwörter handelt, nicht mit Zeichenfolgen verwechseln, die Straßenadressen sind, oder Ganzzahlen, die einen Versatz darstellen, mit Zeichenfolgen, die einen absoluten Wert darstellen.

Mit dem Checker Framework können Sie ein typedef abwärtskompatibel definieren. Ich arbeite sogar für primitive Klassen wie intund Abschlussklassen wie String. Es hat keinen Laufzeitaufwand und unterbricht keine Gleichheitstests.

Abschnitt Typaliasnamen und Typedefs im Checker Framework-Handbuch beschreiben verschiedene Möglichkeiten zum Erstellen von Typedefs, abhängig von Ihren Anforderungen.




-6

Sie können eine Aufzählung verwenden, obwohl dies semantisch etwas anders ist als eine typedef, da nur eine eingeschränkte Menge von Werten zulässig ist. Eine andere mögliche Lösung ist eine benannte Wrapper-Klasse, z

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

Dies scheint jedoch viel klobiger zu sein, insbesondere angesichts der Tatsache, dass aus dem Code nicht hervorgeht, dass die Klasse keine andere Funktion als einen Alias ​​hat.


-7

Mit Typedef können Elemente implizit Typen zugewiesen werden, die sie nicht sind. Einige Leute versuchen, dies mit Erweiterungen zu umgehen. Lesen Sie hier bei IBM, um zu erklären, warum dies eine schlechte Idee ist.

Bearbeiten: Während starke Typinferenz eine nützliche Sache ist, denke ich nicht (und hoffe wir werden nicht), dass typedefes hässlichen Kopf in verwalteten Sprachen aufzieht (jemals?).

Bearbeiten 2: In C # können Sie eine using-Anweisung wie diese oben in einer Quelldatei verwenden. Es wird verwendet, damit Sie den zweiten angezeigten Punkt nicht ausführen müssen. Die Namensänderung wird nur angezeigt, wenn ein Bereich eine Namenskollision zwischen zwei Typen einführt. Das Umbenennen ist auf eine Datei beschränkt, außerhalb derer jeder verwendete Variable- / Parametertyp unter seinem vollständigen Namen bekannt ist.

using Path = System.IO.Path;
using System.IO;

23
"Mit Typedef können Elemente implizit Typen zugewiesen werden, die sie nicht sind." Was? Mit Typedef können Sie einfach einen anderen Namen als Alias ​​für den Typ erstellen. Der Typ ist immer noch genau der gleiche, Sie erhalten nur einen kürzeren Namen dafür. Es hat nichts mit Typinferenz zu tun. -1
Jalf

@jalf: Eigentlich wird Typinferenz als Lösung für genau das verwendet, worüber Sie sprechen, aber ich habe ein anderes Beispiel gegeben, in dem Sie ein "typedef" verwenden können, um eine Namenskollision zu umgehen.
Sam Harwell


@ AlexanderMalakhov Danke, ich habe die Antwort mit Ihrem Link aktualisiert
Dave McClelland

-14

In Java ist typedef nicht erforderlich. Alles ist ein Objekt außer den Grundelementen. Es gibt keine Zeiger, nur Referenzen. Die Szenarien, in denen Sie normalerweise typedefs verwenden würden, sind Instanzen, in denen Sie stattdessen Objekte erstellen.


19
Nein, typedef wird weiterhin benötigt, wenn Sie einen kürzeren Namen für einen Typ wünschen. Oder nur, wenn Sie die Verwendung eines Typs durch einen anderen ersetzen möchten, indem Sie eine Stelle im Quellcode ändern.
Jalf

28
@ Bill K: meh, sagen Sie, nachdem Sie etwas wie std :: map <int, std :: map <std :: string, boost :: shared_ptr <std :: string >>> :: const_iterator a eingeben mussten einige Male. In diesem Fall verbessert ein typedef mit Namensverkürzung die Lesbarkeit und behindert sie nicht.
Joel

22
Das Umbenennen eines Typs kann die Lesbarkeit drastisch verbessern. Was ist leichter zu lesen und zu verstehen (und damit besser lesbar :) UnmodifiableDirectedGraph<IncrediblyFancyEdgeType, IncrediblyFancyAbstractNode.EvenFancierConcreteNode>oder IncrediblyFancyGraph? Ich kann mich immer auf die Definition beziehen, um herauszufinden, worum es eigentlich geht. Auf diese Weise kann ich auch sicher sein, dass ich UnmodifiableDirectedGraph<IncrediblyFancyEdge,IncredilyFancyAbstractNode.SlightlyLessFancyConcreteNode>aus purer Langeweile nichts verpassen werde .
Aleksandar Dimitrov

10
@AleksandarDimitrov Ich weiß, dass Ihr Kommentar während der Eingabe fast 3 Jahre alt ist, aber ich halte es für sehr wichtig, darauf hinzuweisen, wie erfunden und unrealistisch dieses Beispiel ist: Keiner dieser Klassennamen enthält das Wort Enterprise.
Casey

4
Schlechte Namen beeinträchtigen die Lesbarkeit. Gute Namen helfen. Typedefs können helfen, wenn der vollständige Name so lang ist, dass er schwer zu lesen ist oder die Code-Formatierung durcheinander bringt. Dies ist auch hilfreich, wenn Sie mit schlecht ausgewählten oder mehrdeutigen Klassennamen anderer Personen interagieren. Wenn Sie wirklich glauben, dass ein typedef Ihren Code von Natur aus unlesbar macht, sollten Sie auch glauben, dass Sie niemals Importanweisungen verwenden und sich immer auf vollständig qualifizierte Klassennamen beziehen sollten.
Christopher Barber
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.