C ++中的typedef关键字是否具有Java等效项或方法论?


244

来自C和C ++背景,我发现明智地使用typedef会带来极大的帮助。您是否知道在Java中实现类似功能的方法,无论是Java机制,模式还是您使用的其他有效方法?


6
可以使用typedef或使用许多东西,好与坏,尽管不是每个人都同意哪一个。您介意说您认为typedef的哪些方面有价值吗?这样,我们要么告诉您如何在Java中获得类似的效果,要么为什么不希望在Java中做到这一点。每个答案下面的答案假设您正在谈论作者的最喜欢(或最讨厌)的用法。
PanCrit

3
如果以后可以将其转换为类,则我喜欢typedef本机类型。typedef IndexT int; 例如。以后,如果我希望IndexT是一个类,则只需实现它并删除typedef。它有助于隐藏信息。
JR Lawhorne 2010年


1
我不确定这有什么缺点,但是:public interface ScopeFactory { <Scope extends Map<String, Object>> Scope create(...) throws Exception; }
ScootyPuff

Answers:


112

Java具有原始类型,对象和数组,仅此而已。没有typedef。


37
我想大多数人都希望typedef重新定义booleanbool
托马什Zato -恢复莫妮卡

66
@TomášZato我不认识大多数人,但是根据我的经验,它对添加以下语义非常有用::typedef int PlayerID可使编译器确保PlayerID不与其他int互换使用,并且还使代码对人类更具可读性。基本上,它像一个枚举,但没有一组有限的值。
weberc2

76
@TomášZato缩短诸如的长类型也很有用typedef MegaLongTemplateClass<With, Many, Params> IsShorten;
Alex Medveshchek 2015年

32
@ weberc2“这使编译器可以确保PlayerID不会与其他int互换使用” – typedef没有启用任何此类功能。它只是为类型提供了另一个名称。
emlai

7
例如,如果您有某种类型的ID,int并且需要将其更改为long,则必须在使用该ID的代码中的每个位置进行更改,这也很有用。如果您有typedef,则只需在1个地方进行更改。
杰多

101

如果这是您的意思,则可以简单地扩展您要键入的类,例如:

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

5
我会争论这是否比在C语言中使用typedef更具反模式?
Zed 2009年

22
肯定是- typedef没有文章为那些假类描述的问题(它们是非常真实的)。
帕维尔米纳夫


7
我喜欢它的原因与我喜欢typedef的原因相同。如果您有一个对象容器,则可以通过更改typedef轻松交换容器类型。而且,它可以将容器抽象给最终用户(有时是理想的)。我通常会在另一个类中执行此操作,因此类型会变得更明显(即MyTree.Branches,其中Branches类扩展了HashSet <MyTree> {})
Josh Petitt

8
尽管此方法的主要问题是您不能将其与final类一起使用。
AJMansfield 2014年

14

从1.6开始,java中没有typedef,您可以根据需要创建包装类,因为您不能将最终类(Integer,Double等)作为子类。


3
引用的反模式文章是基于您只想缩短键入(实际上会隐藏有用的类型信息)的假设。大多数人想要的真正用途是消除类型歧义,让编译器为您完成工作。请参阅上面的IndexT。公共发票fetchInvoiceItem(String,String,String); 与公共发票fetchInvoiceItem(CustomerId,InvoiceId,InvoiceLineItemId)相比;显式类型加上转换器/验证器使对Web API进行编程变得更加安全,在此Web API中,一切都以字符串开头。
englebart

没有运营商的java oveloading,因此它的丑陋
密耳

9

正如其他人之前提到的那样,
Java中没有typedef机制。
我也一般不支持“伪类”,但是这里不应有一般的严格经验法则:
例如,如果您的代码反复使用“基于泛型的类型”,例如:

Map<String, List<Integer>> 

您绝对应该考虑为此目的创建一个子类。
可以考虑的另一种方法是,例如,在您的代码中进行如下减速:

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

然后在您的代码NameToNumbers中使用,并执行一个预编译任务(ANT / Gradle / Maven)以处理和生成相关的Java代码。
我知道,对于这个答案的某些读者来说,这听起来可能有些奇怪,但这就是在JDK 5之前有多少个框架实现了“注释”,这就是lombok在做什么以及其他框架。


5

确实,继承到Javaland的typedef唯一用途是别名-即为同一个类提供多个名称。也就是说,您有一个“ A”类,并且您希望“ B”引用同一件事。在C ++中,您将执行“ typedef BA;”。

不幸的是,他们只是不支持它。但是,如果您控制所有涉及的类型,则可以在库级别进行讨厌的破解-您可以从A扩展B或让B实现A。


14
具有typedef对于为泛型类型的调用创建别名也很有用。例如:(typedef A<Long,String> B;这可能是您所描述的特例,但更清楚地显示了该想法的吸引力)。
igorrs

在我的用例中,我想为基本类型赋予别名。real_tdoubleboolboolean
亚伦·弗兰克

3

也许这可能是另一种可能的替代方法:

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

2
难道您不认为这会带来问题吗,因为只要您定义myMap类型的实例MyMap,就只能通过键入myMapInstance.value.SomeOperation()而不是来对实际的HashMap进行操作myMapInstance.SomeOperation()。这很烦人,不是吗?
ink0114 '16

2
您仍然可以执行myMapInstance.SomeOperation()-这就是@Delegate的目的
shrewquest

3

如其他答案所述,您应避免使用伪typedef反模式。但是,即使这不是实现它们的方法,typedef仍然有用。您要区分具有相同Java表示形式的不同抽象类型。您不希望将密码字符串与街道地址字符串或代表偏移量的整数与代表绝对值的字符串混淆。

检查框架使您在向后兼容的方式来定义一个typedef。我甚至为诸如的原始类int和诸如的最终类工作String。它没有运行时开销,并且不会破坏相等性测试。

Checker Framework手册中的“ 部分类型别名”和“ typedef ”描述了根据需要创建Typedef的几种方法。




-6

您可以使用Enum,尽管它在语义上与typedef有所不同,因为它只允许一组受限制的值。另一种可能的解决方案是命名包装类,例如

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

但这似乎更笨拙,尤其是考虑到代码中不清楚该类除作为别名之外没有其他功能。


-7

Typedef允许将项目隐式分配给不是它们的类型。有些人试图通过扩展解决这个问题。在IBM的此处阅读以了解为什么这是一个坏主意的解释。

编辑:虽然强类型推断是有用的事情,但我认为(并希望我们不会)看到typedef托管语言中的丑陋头颅(曾经?)。

编辑2:在C#中,您可以在源文件顶部使用这样的using语句。它已被使用,因此您不必执行显示的第二项。您唯一看到的名称更改是当作用域在两种类型之间引入名称冲突时。重命名仅限于一个文件,使用该文件的每个变量/参数类型都以其全名为人所知。

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

23
“ Typedef允许将项隐式分配给它们不是的类型”这是什么?Typedef只是允许您创建另一个名称作为该类型的别名。类型仍然是完全相同的,您只是得到了一个较短的名称。它与类型推断无关。-1
杰夫

@jalf:实际上,类型推断被用作您所讨论内容的解决方案,但是我举了另一个示例,您可以在其中使用“ typedef”来解决名称冲突。
山姆·哈威尔2009年


@AlexanderMalakhov非常感谢,我继续使用您的链接更新了答案
Dave McClelland

-14

Java中不需要typedef。除了基本元素外,其他所有东西都是对象。没有指针,只有引用。通常使用typedef的方案是在其中创建对象的实例。


19
不,如果您想为某个类型使用更短的名称,仍然需要typedef。或者只是想通过更改源代码中的一个位置来将一种类型的使用替换为另一种类型。
jalf

28
@Bill K:嗯,说,你必须输入类似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>因无聊而错过。
Aleksandar Dimitrov'3

10
@AleksandarDimitrov我知道您在输入此内容时已发表了将近3年的注释,但我觉得指出该示例有多么虚假和不切实际是非常重要的:这些类名中都不包含单词Enterprise
Casey 2014年

4
坏名字会影响可读性。好名字会有所帮助。如果全名太长而难以阅读或搞乱代码格式,Typedefs可以提供帮助。与其他人选择不佳或模棱两可的类名进行交互时,这也将有所帮助。如果您真的认为typedef本质上会使代码不可读,那么您也应该相信永远不要使用import语句,而应该始终引用完全限定的类名。
Christopher Barber 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.