How can I force Java to accept a conditional type for one of the parameters of a method call?
This question is hard to phrase, so I'm going to have to use some code samples. Basically, I have an (overloaded) method that takes 3 parameters, the last of which I overloaded. As in, sometimes the last parameter is a String
, sometimes it's a double
, etc. I want to call this method using a ternary conditional expression as the last parameter, so that depending on a certain value, it will pass either a double or a String开发者_开发问答. Here's an example...
Overloaded method headers:
writeToCell(int rowIndex, int colIndex, double value)
writeToCell(int rowIndex, int colIndex, String value)
What I'm trying to do:
writeToCell(2, 4, myValue != null ? someDouble : someString);
This, however, causes a compilation error:
The method writeToCell(int, int, double) in the type MyType is not applicable
for the arguments (int, int, Object&Comparable<?>&Serializable)
It seems that Java isn't "smart enough" (or just doesn't have the functionality built in on purpose) to realize that either option has a method that supports it. My question is - is there any way to do this? I know I can sort of simulate it by passing in the double as a String (e.g. writeToCell(2, 4, myValue != null ? someDouble.toString() : someString);
), but the method needs to receive it as a double data type.
Logic tells me that there's no way to force Java to accept this statement... But it's worth a try, as it will result in a lot clearer code for me. Anyone know of a way to do this...?
Method calls are resolved statically, at compile time, not dynamically, at runtime. Therefore, the compiler is looking for the type that matches both of the possible arguments in that expression, as you can see.
You could do what the SDK does a lot of, and define your method as
writeToCell(int rowIndex, int colIndex, Object value)
and then have the first line be
final String repr = String.valueOf(value);
There are plenty of other solutions, but it's best not to overthink this.
Demonstration:
static class WrongAgain
{
void frob(final Object o)
{
System.out.println("frobo " + o);
}
void frob(final String s)
{
System.out.println("frobs " + s);
}
}
public static void main(final String[] args)
{
final WrongAgain wa = new WrongAgain();
wa.frob("foo");
Object o = "foo";
wa.frob(o);
}
If method lookup were dynamic, then the you'd see "frobs" both times. It's static.
Is there any particular reason not to just write it out?
if (myValue == null)
writeToCell(2, 4, someString);
else
writeToCell(2, 4, someDouble);
The return type from the ternary operation is being upcast to java.lang.Object, as the common superclass class of both String and the autoboxed double, so you would have to provide the method signature for the object, and then use that to make the appropriate cast and call the relevant method:
public class SoCast {
public static void main(String[] args) {
SoCast sc = new SoCast();
Double someDouble = 3.14;
String someString = "foo";
String myValue = null;
sc.writeToCell(2, 4, myValue != null ? someDouble : someString);
myValue = "hello";
sc.writeToCell(2, 4, myValue != null ? someDouble : someString);
}
private int writeToCell(int rowIndex, int colIndex, Object value) {
int result = -1;
if (value instanceof String) {
result = this.writeToCell(rowIndex, colIndex, (String) value);
} else if (value instanceof Double) {
result = this.writeToCell(rowIndex, colIndex, (Double) value);
}
return result;
}
private int writeToCell(int rowIndex, int colIndex, Double value) {
return 1;
}
private int writeToCell(int rowIndex, int colIndex, String value) {
return 5;
}
}
I suspect that it chokes up because the type of object (and hence overloaded version which should be called) cannot be determined at compile time. It's similar to:
Object o = myValue != null ? someDouble : someString;
writeToCell(2, 4, o);
Thanks everyone for all your suggestions and explanations.
A coworker of mine took a look at my code and suggested a solution that I implemented. I inserted the following code into the beginning of my double method:
if(value == null){
writeToCell(rowIndex, colIndex, someString)
}
else{
...method body...
}
I know that this implementation might not always be the best idea, but since I almost always need to check for null when passing a double value to this method, it makes the most sense in this situation. This way I don't have to repeat the check code (if / ternary statement) each time, and my method calls are much cleaner.
The ternary operator has to return the same type from the "then" or "else" clause. If you can deal with Double
instead of double
, then you could try
Object o = (myValue != null ? someDouble : someString);
writeToCell(2, 4, o);
and change the writeToCell
method to accept arguments (int, int, Object)
.
精彩评论