【问题标题】:Automatic type conversion in Java?Java中的自动类型转换?
【发布时间】:2011-01-25 06:09:58
【问题描述】:

有没有办法在 Java 中进行自动隐式类型转换?例如,假设我有两种类型,“FooSet”和“BarSet”,它们都是 Set 的表示形式。类型之间的转换很容易,所以我写了两个实用方法:

/** Given a BarSet, returns a FooSet */
public FooSet barTOfoo(BarSet input) { /* ... */ }

/** Given a FooSet, returns a BarSet */
public BarSet fooTObar(FooSet input) { /* ... */ }

现在说我想调用这样的方法:

public void doSomething(FooSet data) {
    /* .. */
}

但我只有BarSet myBarSet...这意味着额外的输入,例如:

doSomething(barTOfoo(myBarSet));

有没有办法告诉编译器某些类型可以自动转换为其他类型?我知道这在重载的 C++ 中是可能的,但我在 Java 中找不到方法。我只想能够输入:

doSomething(myBarSet);

并且编译器知道自动调用barTOfoo()

【问题讨论】:

  • 更多详细信息...我有两个无法更改的独立库,它们都使用相似但不兼容的数据结构。我经常需要从一个库中获取数据,对其进行操作,然后将其传递给另一个库。我的代码最终到处都是 fooTObar 和 barTOfoo 调用。
  • 这种类似但不完全直接兼容的 API 之间的粘合绝对不是 Java 的优势之一。有很多样板可以完成。
  • 如果有人好奇的话,这两个库是基于 JSON 的对象(用于与 Web 服务通信)和基于 AMF 的对象(用于通过持久 RMTP 连接与 Flash 客户端通信)。 AMF 和 JSON 都有数组、列表、关联数组、对象等的概念。所以在 Java 中,我不断在 AMFDataArray 和 JSONArray、AMFDataObj 和 JSONObject 等之间进行转换。

标签: java type-conversion overloading


【解决方案1】:

答案很简短:在 C++ 中重载是可能的,但在 Java 中没有办法做到这一点。

【讨论】:

  • 在 C# 和许多其他健全的语言中也可以,因为它是一个非常有用的功能。
【解决方案2】:

你可以重载你的方法,像这样:

public void doSomething(FooSet data) {
    /* .. */
}

public void doSomething(BarSet data) {
    doSomething(barTOfoo(data));
}

【讨论】:

  • doSomething 是我无法修改的方法,它在外部库中。但我想编写自己的调用外部方法的重载方法是一种选择。
  • @davr 是的,我在写完答案后看到了那个编辑。我想您的代码和库之间的另一层可能有点麻烦,但这取决于 barTOfoo 和 fooTObar 的麻烦程度......它还允许您更改库代码的实现方式,如果它的功能发生了变化。
【解决方案3】:

你可以同时做这两件事:

(1) 编写在后台进行转换的包装器方法。

(2) 如果您的对象有正确的hashCode 覆盖方法,包装器方法可以管理一个非常简单和快速的缓存,您可以通过简单的Map 实现和可能的同步来构建自己的缓存(如果您同时使用对象完全)。

这将使您摆脱一直在两种类型之间转换的问题,并可能摆脱性能问题。即使您反对缓存,我仍然建议(正如其他海报所说)使用包装方法。这至少可以为您节省大量不必要的输入。

祝你好运。

【讨论】:

    【解决方案4】:

    重载以相反的方式工作,您在接收器对象上声明两个方法:

    public void doSomething(FooSet data)
    {
        /* .. */
    }
    
    public void doSomething(BarSet data)
    {
        doSomething(barToFoo(data));
    }
    

    那么感谢 Dynamic Binding (wikipedia) 在运行时选择了正确的方法。

    当然,Java 中的重载是对象级别的(因为调用仅限于实例或类声明),但它的工作方式相同。

    在你的情况下,如果它在外部库中,你也可以尝试扩展类,因为它是 java 你应该能够做到,并添加方法或使用 reflection (@987654322 @) 动态添加方法。

    【讨论】:

    • doSomething 是我无法修改的方法,它在外部库中。但我想编写自己的调用外部方法的重载方法是一种选择。
    • 无论如何它都不是动态绑定的例子。它只是重载,它发生在编译时基于声明的变量类型。
    【解决方案5】:
    不支持

    自动类型转换(您需要 Scala 的implicit type conversions)。

    但是您可以尝试使用 Variant 类型作为在类型之间切换的接线盒:

    /** Given a BarSet, returns a FooSet */
    public Function<BarSet, FooSet> barTofoo = new Function<BarSet, FooSet>() {
        @Override public FooSet apply(BarSet input) { /* ... */ }
    }
    
    /** Given a FooSet, returns a BarSet */
    public Function<FooSet, BarSet> fooToBar = new Function<FooSet, BarSet>() {
        @Override public BarSet apply(FooSet input) { /* ... */ }
    }
    
    /** Create a type conversion context in which both of these conversions are registered */
    TypeConversionContext fooBarConversionContext = MatchingTypeConversionContext.builder()
        .register(FooSet.class, BarSet.class, fooToBar)
        .register(BarSet.class, FooSet.class, barToFoo)
        .build();
    
    /** Put a FooSet into a Variant, bound to our type conversion context */
    FooSet fooSet = new FooSet();
    Variant data = Variant.of(fooSet).in(fooBarConversionContext);
    
    /** Pull a BarSet out of the Variant */
    public void doSomething(Variant data) {
        Preconditions.checkArgument(data.isConvertibleTo(BarSet.class);
        BarSet barSet = data.as(BarSet.class);
        // ...
    }
    

    【讨论】:

    • 这很有趣,但对我来说这是典型的 Java 过于冗长。我最终会把事情复杂化,而不是像我想要的那样简化它们。
    【解决方案6】:

    Java 的创建考虑到了可见性。每个程序员都应该能够只阅读一行并理解那里发生的事情。这就是它没有运算符重载的原因,这就是它没有任何类型的自动自定义类型转换的原因。因此,除非您围绕将接受来自其他库的类型并显式转换它们的库编写自己的包装器,否则您将不走运。

    【讨论】:

    • 我想这解释了为什么你必须一直使用 String.equals 而不是 == ......太愚蠢了。
    • @davr,确切地说,他们希望您立即发现它是参考还是实际内容正在被比较。
    猜你喜欢
    • 2011-12-28
    • 2011-06-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-23
    • 1970-01-01
    • 2014-04-04
    相关资源
    最近更新 更多