Как заставить Java принять условный тип для одного из параметров вызова метода? - PullRequest
2 голосов
/ 04 марта 2010

Этот вопрос сложно сформулировать, поэтому мне придется использовать несколько примеров кода. По сути, у меня есть (перегруженный) метод, который принимает 3 параметра, последний из которых я перегрузил. Например, иногда последний параметр - String, иногда - double и т. Д. Я хочу вызвать этот метод, используя троичное условное выражение в качестве последнего параметра, чтобы в зависимости от определенного значения он передавал либо двойной или Строка. Вот пример ...

перегруженные заголовки метода:

writeToCell(int rowIndex, int colIndex, double value)

writeToCell(int rowIndex, int colIndex, String value)

Что я пытаюсь сделать:

writeToCell(2, 4, myValue != null ? someDouble : someString);

Это, однако, вызывает ошибку компиляции:

The method writeToCell(int, int, double) in the type MyType is not applicable 
for the arguments (int, int, Object&Comparable<?>&Serializable)

Кажется, что Java не «достаточно умна» (или просто не имеет встроенной функциональности), чтобы понять, что у любого из вариантов есть метод, который его поддерживает. У меня вопрос - есть ли способ сделать это? Я знаю, что могу имитировать его, передавая значение типа double в виде строки (например, writeToCell(2, 4, myValue != null ? someDouble.toString() : someString);), но метод должен получить его как тип данных double.

Логика говорит мне, что нет никакого способа заставить Java принять это утверждение ... Но стоит попробовать, так как это приведет к гораздо более ясному коду для меня. Кто-нибудь знает способ сделать это ...?

Ответы [ 6 ]

4 голосов
/ 04 марта 2010

Вызовы методов разрешаются статически, во время компиляции, а не динамически, во время выполнения. Поэтому, как вы можете видеть, компилятор ищет тип, который соответствует обоим возможным аргументам в этом выражении.

Вы можете сделать то, что делает SDK, и определить свой метод как

writeToCell(int rowIndex, int colIndex, Object value)

и затем первая строка будет

final String repr = String.valueOf(value);

Существует множество других решений, но лучше не задумываться над этим.

Демонстрация:

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);
}

Если бы поиск метода был динамическим, то вы бы видели «лягушки» оба раза. Это статично.

3 голосов
/ 04 марта 2010

Есть ли какая-то особая причина не просто записать это?

if (myValue == null)
  writeToCell(2, 4, someString);
else
  writeToCell(2, 4, someDouble);
0 голосов
/ 04 марта 2010

Возвращаемый тип из троичной операции передается в java.lang.Object как общий класс суперкласса как String, так и autoboxed double, поэтому вам нужно будет предоставить сигнатуру метода для объекта, а затем использовать его сделать соответствующее приведение и вызвать соответствующий метод:

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;
 }
}
0 голосов
/ 04 марта 2010

Спасибо всем за все ваши предложения и объяснения.

Мой коллега посмотрел на мой код и предложил решение, которое я реализовал. Я вставил следующий код в начало моего двойного метода:

if(value == null){
   writeToCell(rowIndex, colIndex, someString)
}
else{
   ...method body... 
}

Я знаю, что эта реализация не всегда может быть лучшей идеей, но, поскольку мне почти всегда нужно проверять нулевое значение при передаче двойного значения этому методу, это имеет смысл в этой ситуации. Таким образом, мне не нужно каждый раз повторять код проверки (if / ternary), и мои вызовы методов намного чище.

0 голосов
/ 04 марта 2010

Я подозреваю, что он засоряется, потому что тип объекта (и, следовательно, перегруженной версии, которая должна быть вызвана) не может быть определен во время компиляции. Это похоже на:

Object o = myValue != null ? someDouble : someString;
writeToCell(2, 4, o);
0 голосов
/ 04 марта 2010

Тернарный оператор должен возвращать тот же тип из предложения «then» или «else». Если вы можете иметь дело с Double вместо double, тогда вы можете попробовать

Object o = (myValue != null ? someDouble : someString);
writeToCell(2, 4, o);

и измените метод writeToCell, чтобы он принимал аргументы (int, int, Object).

...