2015-07-11 2 views
-2

Ниже приведен код,Как синтаксис дженериков java помогает избежать литья типов?

import java.util.List; 
import java.util.ArrayList; 


public class Dummy { 
    public static void main(String[] args) { 
     List<String> lst = new ArrayList<String>(); 
     lst.add("a string"); 
     lst.add("another string"); 
     String s = lst.get(0); 
    } //end main 
} 

, когда конструктор new ArrayList<String>(); вызывается, массив типа Object создается.

enter image description here ..

lst держит Object[0] массив.

enter image description here

Итак, если массив типа Object получает созданный конструктором, Как javac не видит проблемы литья типа в этом заявлении String s = lst.get(0);, несмотря на общий синтаксис используется при вызове конструктора?

+4

Это тоталитарная характеристика: компилятор добавляет приведение к байт-коду для вас и гарантирует, что этот прилив не сможет потерпеть неудачу благодаря родовому типу списка. –

+0

http://www.oracle.com/technetwork/articles/java/juneau-generics-2255374.html –

+0

@JBNizet За исключением 'LocalVariableTypeTable' attrbute в байтовом коде, который имеет запись:' 8 30 1 lst Ljava/util/List ; 'для общего синтаксиса, оба сценария выглядят одинаково с точки зрения байтового кода, функционально. – overexchange

ответ

2

Вот некоторые необщего код:

public class MyList { 

    List myData = new ArrayList(); 

    public void add(Object ob) { 
     myData.add(ob); 
    } 

    public Object getAtIndex(int ix) { 
     return myData.get(ix); 
    } 
} 

Этот код позволит вам хранить объект любого типа в ваших MyList случаях даже если договор MyList указывает, что объекты должны быть все одного типа. Более того, если вы используете экземпляр MyList для хранения экземпляров String, вы должны вручную передать их в String при их восстановлении.

String myString = (String) myList.get(1); 

Вышеуказанный класс MyList не является безопасным для типа. Вполне возможно, что вышеприведенный оператор присваивания завершится с классом ClassCastException, если объект, отличный от экземпляра String, был сохранен в вашем экземпляре MyList (что может произойти во время выполнения без какой-либо жалобы).

Вот обобщен класс MyList:

public class MyList<T> { 

    List<T> myData = new ArrayList<>(); 

    public void add(T ob) { 
     myData.add(ob); 
    } 

    public T getAtIndex(int ix) { 
     return myData.get(ix); 
    } 
} 

Теперь компилятор гарантирует, что могут быть добавлены только T экземпляры и извлекаться из экземпляров MyList. Поскольку компилятор гарантирует, что T экземпляров всегда будут возвращены, вы можете использовать синтаксис, как это без какого-либо ручного литья:

String myString = myList.get(1); 

обобщен класс MyList теперь типобезопасный. Компилятор не позволит вам хранить что-либо, кроме T экземпляров в экземплярах MyList, что гарантирует отсутствие во время выполнения ClassCastExceptions. Если вы изучите байт-код, вы обнаружите, что компилятор автоматически разместил бросок.

Generics in Java Только компилирование явление. В байтовом коде все ссылки на T в классе MyList выше заменены на Object. Этот процесс называется «стирание типа».Важно помнить, что безопасность типов в Java обеспечивается только компилятором. Если ваша программа компилируется без ошибок И без каких-либо предупреждений, то ваша программа, дженерики и все, является безопасным по типу. Однако скомпилированная программа практически не сохранила информацию об общих параметрах.

+0

Хотя это правильный обзор, на самом деле это не отвечает на вопрос, почему нет необходимости в типе, требуемом при извлечении элементов из списка, несмотря на то, что внутренний массив в 'ArrayList' имеет тип' Object [] '. – Seelenvirtuose

+0

В успешно скомпилированном общем коде компилятор автоматически добавит листинг из типа Object (или из ограниченного типа). Нужно будет изучить байт-код, чтобы увидеть этот актерский состав. Он не должен присутствовать в исходном коде, потому что компилятор уже заверил, что присвоение является безопасным по типу. – scottb

+0

Нет, в исходном коде 'ArrayList' просто открыто выражение. См. Ответ @ chrylis для этого. Вопрос ОП не требовал использования родового типа (я полагаю, он это знает); он спросил о внутренней детали 'ArrayList'. – Seelenvirtuose

0

От дальше вниз в классе:

@SuppressWarnings("unchecked") 
E elementData(int index) { 
    return (E) elementData[index]; 
} 

public E get(int index) { 
    rangeCheck(index); 

    return elementData(index); 
} 

Это @SuppressWarnings говорит компилятору, что вы уверены в бесконтрольной гипсе, что вы выполняете там. Поскольку все остальные операции, такие как get(int), используют параметр типа E, это ограничивает обработку небезопасного типа конкретными местами, где разработчик может удостовериться в правильности обработки броска.

+2

Downvoter ухаживает за комментарием, тем более, что downvote пришел слишком быстро, чтобы избиратель мог прочитать ответ? – chrylis

+1

Противовес, может быть? – Seelenvirtuose

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