Automatic type conversion in Java?

2019-02-23 13:51发布

问题:

Is there a way to do automatic implicit type conversion in Java? For example, say I have two types, 'FooSet' and 'BarSet' which both are representations of a Set. It is easy to convert between the types, such that I have written two utility methods:

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

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

Now say there's a method like this that I want to call:

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

But all I have is a BarSet myBarSet...it means extra typing, like:

doSomething(barTOfoo(myBarSet));

Is there a way to tell the compiler that certain types can automatically be cast to other types? I know this is possible in C++ with overloading, but I can't find a way in Java. I want to just be able to type:

doSomething(myBarSet);

And the compiler knows to automatically call barTOfoo()

回答1:

The answer is short: It's possible with overloading in C++ but there is no way to do that in Java.



回答2:

You could overload your methods, something like this:

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

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


回答3:

You could do both together:

(1) Write wrapper methods which do conversion on the back-scenes.

(2) If your objects have proper hashCode overriden method, the wrapper methods may manage a very simple and fast cache, which you can build yourself with simple Map implementation and probably synchronization (if you use the objects concurrently at all).

That will get you rid of both converting between the two types all the time and probably of performance concerns. Even if you go against caching, I would still recommend (as other posters said) to use wrapping methods. That at least saves you lots of unnecessary typing.

Good luck.



回答4:

Overloading works in the opposite way, you declare two methods on the receiver object:

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

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

then thanks to Dynamic Binding (wikipedia) the right method is choosen at run-time.

Of course overloading in Java is scoped at object-level (since calls are restricted to instances or class declarations), but it works in the same way.

In your case you can try by extending the class also if it's in an external library, since it's java you should be able to do it, and add the method or by using reflection (java tutorial) to add the method dynamically.



回答5:

Automatic type conversion isn't supported (you want Scala's implicit type conversions for that).

But you could try using a Variant type as a junction-box for switching between types:

/** 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);
    // ...
}


回答6:

Java was created with visibility in mind. Every programmer should be able read just one line and understand what is happening there. This is why it doesn't have operator overloading, this is why it doesn't have any kind of automatic custom type conversion. So, unless you write your own wrappers around one of the library that will accept types from other library and explicitly convert them, you are out of luck there.