มี 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
Andreas Dolk

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
Tomáš Zato - Reinstate Monica

66
@ TomášZatoฉันไม่รู้จักคนส่วนใหญ่ แต่จากประสบการณ์ของฉันมันมีประโยชน์สำหรับการเพิ่มซีแมนทิกส์เช่น: typedef int PlayerIDซึ่งทำให้คอมไพเลอร์ตรวจสอบให้แน่ใจว่า PlayerID ไม่ได้ถูกใช้แทนกันกับ ints อื่น ๆ และทำให้โค้ดอ่านได้ง่ายขึ้นสำหรับมนุษย์ . โดยทั่วไปมันเป็นเหมือน enum แต่ไม่มีค่าที่ จำกัด
weberc2

76
@ typedef MegaLongTemplateClass<With, Many, Params> IsShorten;TomášZatoนอกจากนี้ยังมีประโยชน์ในการลดระยะยาวประเภทเช่น
Alex Medveshchek

32
@ weberc2 "ซึ่งทำให้คอมไพเลอร์ตรวจสอบให้แน่ใจว่า PlayerID ไม่ถูกใช้แทนกันกับ ints อื่น" - typedefไม่เปิดใช้งานสิ่งใด ๆ มันให้ชื่ออื่นสำหรับประเภท
emlai

7
นอกจากนี้ยังมีประโยชน์ถ้าเช่นคุณมี ID บางประเภทintและคุณต้องเปลี่ยนเป็นlongคุณต้องเปลี่ยนมันในทุกที่ในรหัสที่คุณทำงานกับ ID หากคุณมีtypedefคุณจะต้องเปลี่ยนมันในที่เดียว
Jardo

101

ถ้านี่คือสิ่งที่คุณหมายถึงคุณสามารถขยายชั้นเรียนที่คุณต้องการที่จะพิมพ์เช่น:

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

5
ฉันเถียงว่านี่คือการต่อต้านใด ๆ เพิ่มเติมรูปแบบกว่าการใช้ typedef ใน C.
Zed

22
แน่นอน - typedefไม่มีปัญหาใด ๆ ที่บทความอธิบายสำหรับชั้นเรียนปลอมเหล่านั้น (และพวกเขาเป็นเรื่องจริงมาก)
Pavel Minaev

30
@Andreas_D: ลิงก์ของคุณคงที่: ibm.com/developerworks/java/library/j-jtp02216/index.html
Janus Troelsen

7
ฉันชอบสิ่งนี้ด้วยเหตุผลเดียวกันกับที่ฉันชอบ typedefs หากคุณมีคอนเทนเนอร์ของวัตถุมันเป็นเรื่องง่ายที่จะสลับประเภทคอนเทนเนอร์โดยการเปลี่ยน typedef นอกจากนี้ยังสามารถแยกคอนเทนเนอร์ให้กับผู้ใช้ (ซึ่งบางครั้งเป็นที่ต้องการ) ฉันมักจะทำเช่นนี้ในชั้นเรียนอื่นดังนั้นประเภทจะชัดเจนมากขึ้น (เช่น MyTree.Branches ที่สาขาของชั้นเรียนขยาย HashSet <MyTree> {})
Josh Petitt

8
แม้ว่าปัญหาหลักของวิธีนี้คือคุณไม่สามารถใช้กับfinalคลาสได้
AJMansfield

14

ไม่มี typedef ใน java เป็น 1.6 สิ่งที่คุณสามารถทำได้คือสร้างคลาส wrapper สำหรับสิ่งที่คุณต้องการเนื่องจากคุณไม่สามารถคลาสย่อยสุดท้ายของคลาส (Integer, Double, etc)


3
บทความต่อต้านรูปแบบอ้างอิงอ้างอิงจากสมมติฐานที่ว่าคุณต้องการย่อการพิมพ์ของคุณ (ซึ่งจริงๆแล้วจะซ่อนข้อมูลประเภทที่เป็นประโยชน์) การใช้งานจริงที่คนส่วนใหญ่ต้องการคือการแยกประเภทและให้คอมไพเลอร์ทำงานให้คุณ ดู IndexT ด้านบน ใบแจ้งหนี้สาธารณะ fetchInvoiceItem (String, String, String); เมื่อเทียบกับใบแจ้งหนี้สาธารณะ fetchInvoiceItem (CustomerId, InvoiceId, InvoiceLineItemId); ประเภทที่ชัดเจนรวมถึงตัวแปลง / เครื่องมือตรวจสอบความถูกต้องทำให้การเขียนโปรแกรมเว็บ API ที่ทุกอย่างเริ่มต้นขึ้นในฐานะ String ที่ปลอดภัยกว่ามาก
englebart

ไม่มีตัวดำเนินการ oveloading ใน java ดังนั้นมันจึงน่าเกลียด
mils

9

ดังที่คนอื่น ๆ พูดถึงมาก่อนแล้ว
ไม่มีกลไกการพิมพ์ดีดใน Java
ฉันยังไม่สนับสนุน "คลาสปลอม" โดยทั่วไป แต่ไม่ควรมีกฎที่เข้มงวดโดยทั่วไปที่นี่:
หากรหัสของคุณใช้ตัวอย่างซ้ำแล้วซ้ำอีก "ประเภทตามทั่วไป" เช่น:

Map<String, List<Integer>> 

แน่นอนคุณควรพิจารณามีคลาสย่อยสำหรับวัตถุประสงค์นั้น
อีกวิธีหนึ่งที่สามารถพิจารณาได้ตัวอย่างเช่นการมีการลดลงของโค้ดใน:

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

จากนั้นใช้ในรหัสของคุณชื่อ ToToNumber และมีงานรวบรวมล่วงหน้า (ANT / Gradle / Maven) เพื่อประมวลผลและสร้างรหัสจาวาที่เกี่ยวข้อง
ฉันรู้ว่าสำหรับผู้อ่านบางคนของคำตอบนี้อาจฟังดูแปลก แต่นี่คือจำนวนเฟรมเวิร์กที่ใช้ "คำอธิบายประกอบ" ก่อนหน้า JDK 5 นี่คือสิ่งที่lombokโครงการทำและกรอบอื่น ๆ


5

จริง ๆ แล้วการใช้ typedef เพียงอย่างเดียวที่ดำเนินการกับ Javaland คือ aliasing นั่นคือให้ชื่อเดียวกันหลายคลาส นั่นคือคุณมีคลาส "A" และคุณต้องการให้ "B" อ้างอิงถึงสิ่งเดียวกัน ใน C ++ คุณต้องทำ "typedef BA;"

น่าเสียดายที่พวกเขาไม่สนับสนุน อย่างไรก็ตามหากคุณควบคุมทุกประเภทที่เกี่ยวข้องคุณสามารถดึงแฮ็คที่น่ารังเกียจในระดับห้องสมุดคุณขยาย B จาก A หรือใช้ B


14
การมีtypedefจะเป็นประโยชน์ในการสร้างนามแฝงสำหรับการเรียกใช้ประเภททั่วไป ตัวอย่างเช่น: typedef A<Long,String> B;(นี่อาจเป็นกรณีพิเศษของสิ่งที่คุณอธิบาย แต่มันแสดงให้เห็นถึงการอุทธรณ์ของแนวคิดที่ชัดเจนยิ่งขึ้น)
igorrs

ในกรณีที่ใช้ของฉันฉันต้องการให้นามแฝงกับประเภทดั้งเดิม real_tสำหรับdoubleและสำหรับbool boolean
Aaron Franke

3

บางทีนี่อาจเป็นอีกสิ่งที่แทนที่ได้:

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

2
คุณไม่คิดว่าเรื่องนี้ตอนนี้มีปัญหาเพราะเมื่อใดก็ตามที่คุณกำหนดmyMapตัวอย่างของประเภทMyMapคุณสามารถทำงานบน HashMap ที่เกิดขึ้นจริงโดยเฉพาะการพิมพ์แทนmyMapInstance.value.SomeOperation() myMapInstance.SomeOperation()มันน่ารำคาญใช่มั้ย
mercury0114

2
คุณยังสามารถทำ myMapInstance.SomeOperation () - นี่คือสิ่งที่ @Delegate มีไว้สำหรับ
shrewquest

3

ตามที่ระบุไว้ในคำตอบอื่น ๆ คุณควรหลีกเลี่ยงการหลอก typedef antipattern อย่างไรก็ตาม typedefs ยังคงมีประโยชน์แม้ว่าจะไม่ใช่วิธีที่จะทำให้สำเร็จ คุณต้องการแยกแยะความแตกต่างระหว่างชนิดนามธรรมที่แตกต่างกันซึ่งมีการแสดง Java เดียวกัน คุณไม่ต้องการที่จะรวมสตริงที่เป็นรหัสผ่านกับที่อยู่ถนนหรือจำนวนเต็มที่แสดงถึงการชดเชยกับผู้ที่มีค่าที่แน่นอน

ตรวจสอบกรอบช่วยให้คุณสามารถกำหนด typedef ในทางย้อนกลับกันได้ ผมทำงานได้แม้กระทั่งสำหรับการเรียนแบบดั้งเดิมเช่นและชั้นเรียนสุดท้ายเช่นint Stringไม่มีค่าใช้จ่ายในการดำเนินการและไม่ทำลายการทดสอบความเท่าเทียมกัน

ส่วนประเภทนามแฝงและ typedefsในคู่มือ Framework ตัวตรวจสอบอธิบายหลายวิธีในการสร้าง typedefs ขึ้นอยู่กับความต้องการของคุณ


0

Kotlin สนับสนุนชนิดนามแฝงhttps://kotlinlang.org/docs/reference/type-aliases.html คุณสามารถเปลี่ยนชื่อประเภทและประเภทฟังก์ชั่น



-6

คุณสามารถใช้ Enum ได้แม้ว่าจะมีความหมายแตกต่างจาก typedef เพียงเล็กน้อยซึ่งอนุญาตให้ใช้ชุดค่าที่ จำกัด เท่านั้น อีกวิธีที่เป็นไปได้คือคลาส wrapper ที่มีชื่อเช่น

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

แต่ดูเหมือนว่าจะเป็นวิธีที่ clunky โดยเฉพาะอย่างยิ่งเนื่องจากมันไม่ชัดเจนจากรหัสที่ชั้นไม่มีฟังก์ชั่นอื่น ๆ กว่าเป็นนามแฝง


-7

Typedef อนุญาตให้ไอเท็มถูกกำหนดโดยนัยกับชนิดที่ไม่ใช่ บางคนพยายามหลีกเลี่ยงสิ่งนี้ด้วยส่วนขยาย อ่านที่ IBM ที่นี่สำหรับคำอธิบายว่าทำไมนี่เป็นความคิดที่ไม่ดี

แก้ไข: ในขณะที่การอนุมานประเภทที่แข็งแกร่งเป็นสิ่งที่มีประโยชน์ฉันไม่คิดว่า (และหวังว่าเราจะไม่) เห็นtypedefการอบรมเลี้ยงดูมันน่าเกลียดในภาษาที่มีการจัดการ (เคย?)

แก้ไข 2: ใน C # คุณสามารถใช้คำสั่ง use เช่นนี้ที่ด้านบนของไฟล์ต้นฉบับ มันถูกใช้ดังนั้นคุณไม่จำเป็นต้องทำรายการที่สองที่แสดง ครั้งเดียวที่คุณเห็นการเปลี่ยนชื่อคือเมื่อขอบเขตแนะนำการชนกันของชื่อระหว่างสองประเภท การเปลี่ยนชื่อนั้น จำกัด อยู่ที่หนึ่งไฟล์ซึ่งนอกเหนือจากตัวแปร / พารามิเตอร์ทุกประเภทที่ใช้มันเป็นที่รู้จักกันในชื่อเต็ม

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

23
"Typedef อนุญาตให้ไอเท็มถูกกำหนดโดยนัยให้กับประเภทที่ไม่ใช่" คืออะไร Typedef ช่วยให้คุณสามารถสร้างชื่ออื่นเป็นนามแฝงสำหรับประเภท ประเภทนี้ยังคงเหมือนเดิมคุณเพิ่งได้ชื่อสั้นลง มันไม่มีส่วนเกี่ยวข้องกับการอนุมานประเภท -1
jalf

@jalf: ที่จริงแล้วการอนุมานประเภทนั้นใช้เป็นวิธีแก้ปัญหาที่คุณพูดถึง แต่ฉันได้ยกตัวอย่างอีกตัวอย่างหนึ่งซึ่งคุณสามารถใช้ "typedef" เพื่อหลีกเลี่ยงการชนกันของชื่อ
Sam Harwell


@AlexanderMalakhov ขอบคุณฉันเดินไปข้างหน้าและมีการปรับปรุงคำตอบที่มีการเชื่อมโยงของคุณ
เดฟแมคคลีแลนด์

-14

ไม่จำเป็นต้องพิมพ์ typedef ใน Java ทุกอย่างเป็นวัตถุยกเว้นสำหรับดั้งเดิม ไม่มีพอยน์เตอร์อ้างอิงเท่านั้น สถานการณ์ที่คุณมักจะใช้ typedefs เป็นกรณีที่คุณสร้างวัตถุแทน


19
ไม่ความจำเป็นในการพิมพ์ยังคงมีอยู่หากคุณต้องการชื่อที่สั้นลงสำหรับประเภท หรือเพียงแค่ถ้าคุณต้องการที่จะสามารถแทนที่การใช้ประเภทหนึ่งด้วยอีกประเภทหนึ่งโดยการเปลี่ยนสถานที่หนึ่งในรหัสที่มา
jalf

28
@ บิล K: meh พูดได้ว่าหลังจากที่คุณพิมพ์ std :: map <int, std :: map <std :: string, boost :: shared_ptr <std :: string>>> :: const_iterator a ไม่กี่ครั้ง ในกรณีนั้น typedef การย่อชื่อจะช่วยเพิ่มความสามารถในการอ่าน แต่ไม่เป็นอุปสรรค
Joel

22
การเปลี่ยนชื่อประเภทสามารถปรับปรุงความสามารถในการอ่านได้อย่างมาก การอ่านและทำความเข้าใจง่ายกว่าคืออะไร (และสามารถอ่านได้ง่ายขึ้น :) UnmodifiableDirectedGraph<IncrediblyFancyEdgeType, IncrediblyFancyAbstractNode.EvenFancierConcreteNode>หรือIncrediblyFancyGraph? ฉันสามารถอ้างถึงคำจำกัดความเพื่อค้นหาว่ามันเกี่ยวกับอะไร ด้วยวิธีนี้ฉันสามารถมั่นใจได้ว่าฉันจะไม่พลาดUnmodifiableDirectedGraph<IncrediblyFancyEdge,IncredilyFancyAbstractNode.SlightlyLessFancyConcreteNode>ความเบื่อที่แท้จริง
Aleksandar Dimitrov

10
@AleksandarDimitrov ฉันรู้ว่าความคิดเห็นของคุณเป็นเกือบ 3 ปีขณะที่ฉันพิมพ์นี้ Enterpriseแต่ผมรู้สึกว่ามันเป็นสิ่งสำคัญมากที่จะชี้ให้เห็นวิธีการประดิษฐ์และไม่สมจริงว่าตัวอย่างคือไม่มีชื่อชั้นเหล่านั้นมีคำว่า
Casey

4
ชื่อไม่ดีขัดขวางการอ่านได้ ชื่อที่ดีช่วยได้ Typedefs สามารถช่วยได้หากมีชื่อเต็มยาวจนยากที่จะอ่านหรือขันการจัดรูปแบบโค้ดของคุณ นอกจากนี้ยังจะช่วยเมื่อมีปฏิสัมพันธ์กับชื่อคลาสที่เลือกหรือไม่ชัดเจนของคนอื่น หากคุณเชื่อจริง ๆ ว่า typedef โดยเนื้อแท้จะทำให้โค้ดของคุณไม่สามารถอ่านได้คุณควรเชื่อว่าคุณไม่ควรใช้คำสั่งนำเข้าและควรอ้างอิงชื่อคลาสที่ผ่านการรับรองโดยสมบูรณ์
Christopher Barber
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.