2016-03-25 6 views
5

Следующий код из библиотеки Android под названием ButterKnife. Я выясняю, как это работает.Генерирование Java-генераторов на основе типа возврата?

@SuppressWarnings("unchecked") // That's the point. 
    public <T> T castParam(Object value, String from, int fromPosition, String to, int toPosition) { 
    try { 
     return (T) value; 
    } catch (ClassCastException e) { 
     throw new IllegalStateException("Parameter #" 
      + (fromPosition + 1) 
      + " of method '" 
      + from 
      + "' was of the wrong type for parameter #" 
      + (toPosition + 1) 
      + " of method '" 
      + to 
      + "'. See cause for more info.", e); 
    } 
    } 

Я попытался воссоздать поведение этой функции:

@SuppressWarnings("unchecked") 
    public static <T> T cast(Object o){ 
     try { 
      return (T) o; 
     } catch (ClassCastException e){ 
      throw new AssertionError("Error"); 
     } 
    } 

и использование:

Object o = new String("test"); 
Double d = cast(o); 

Но исключение не никогда не поймают, то выкинут на линии, когда метод. Почему это?

Также, как это работает? Как метод знает, что делать?

ответ

2

Как пояснил SJuan67, вы не можете использовать разрезы с родовыми типами как Java компилятор

Заменить все параметры типа в родовых типах с их границами или объектом, если параметры типа не ограничены. Таким образом, полученный байт-код содержит только обычные классы, интерфейсы и методы.

Дополнительная информация обо всех ограничениях на генерацию here.

Так нож для масла код будет выглядеть следующим образом:

public Object castParam(Object paramObject, String paramString1, int paramInt1, String paramString2, int paramInt2) 
    { 
    return paramObject; 
    } 

так вопросы:

Q: Но исключение не никогда не поймают, то выкинут на линии, когда вызывается метод. Почему это?

A: Ну его даже не в байтекоде.

В: Также, как это работает? Как метод знает, что делать?

A: Это не так. По крайней мере, не так, как вы думаете. На практике он будет бросать ClassCastException не IllegalStateException или AssertionError, как вы заметили. Вы можете даже попробовать его с приложением образца нож для масла и привязывание известный TextView к CheckBox:

@Bind(R.id.title) CheckBox title; 

Q: Как работает библиотека тогда?

A: Ну IllegalStateException просто не вызывается, и у вас есть ClassCastException. Почему это так, я не совсем уверен. Однако, поскольку ButterKnife генерирует код, это может быть предназначено для предотвращения ошибок компиляции.

, например:

public interface Some { 
} 

public static void weWantSome(Some d) { 
} 

public static void test() { 
    String o = "test"; 
    weWantSome((Some)o); //<-- compile error 
    weWantSome(Main.<Some>cast(o)); //<-- runtime error 
} 

Именно поэтому в предыдущем примере кода компилируется, но не работает.

7

Типы обобщений проверяются только во время компиляции, из-за стирания типа. Это сделано потому, что не было возможности вводить генерики во время выполнения на Java 5 без нарушения обратной совместимости и принудительного перекомпиляции всех уже существующих библиотек.

Краткая история длинной истории, когда вы определяете «общий» класс или метод, фактический код скомпилирован как Object вместо того типа, который вы связываете с этим методом. Все проверки типов выполняются во время компиляции.

Итак, ваш код метода фактически не выполняет листинг в операторе return, так как он присваивает что-то (String) возвращаемому значению Object. Фактическое ClassCastException возвращается вызывающей линией, потому что это место, когда фактически задана эталонная переменная.

+0

Здесь кто-то попытался сделать то же самое: http://stackoverflow.com/questions/14524751/cast-object-to-generic-type-for-returning – SJuan76

+0

Как работает библиотека? – Greyshack

Смежные вопросы