Возможен ли список Java нескольких типов - PullRequest
0 голосов
/ 11 октября 2018

вчера я наткнулся на странное поведение Java / Spring / IntelliJ, которое мне не удалось объяснить.

Это приложение Spring Boot, созданное с помощью jdk1.8.0_152.

Я запустилэтот простой SQL для заполнения моей БД:

CREATE TABLE TEST_ORGANIZATION
(
    ID NUMBER(19) NOT NULL,
    NAME VARCHAR(255) NOT NULL
);

INSERT INTO TEST_ORGANIZATION (ID, NAME) VALUES ('1', 'test1');
INSERT INTO TEST_ORGANIZATION (ID, NAME) VALUES ('2', 'test2');

Вот мой класс Entity:

@Data
@NoArgsConstructor
@Entity
public class TestOrganization {

    @Id
    private Long id;

    @NotNull
    private String name;
}

И мой репозиторий JPA:

public interface TestOrganizationRepository extends JpaRepository<TestOrganization, Long> {

    @Query("SELECT new map(id as key, name as value) FROM TestOrganization")
    List<Map<String, String>> findAllAndMapById();
}

И это где вещизапутатьсяЯ написал простой модульный тест для проверки значений, но оказывается, что он не работает на втором утверждении:

@Test
public void shouldGetDocumentByName() {
    List<String> values = testOrganizationRepository.findAllAndMapById()
            .stream()
            .flatMap( m -> m.values().stream() )
            .collect( Collectors.toList() );

    assertThat( values ).isNotEmpty();
    assertThat( values ).allMatch( n -> n instanceof String );
}

При отладке с IntelliJ он показывает значения следующим образом:

enter image description here

Как это возможно?Почему я могу иметь длинные значения в списке строк?

Также:

 values.add(1L) // fails to compile
 values.get(0).getClass().name // returns java.lang.String
 values.get(1).getClass().name // returns java.lang.Long

Ответы [ 3 ]

0 голосов
/ 11 октября 2018

Это возможно из-за стирания типа в Java.Короче говоря, это означает, что во время выполнения Java не знает о вашем универсальном типе, поэтому любой объект List работает с типом Object.Обобщения сделаны так, чтобы иметь безопасность типа компиляции.Но вы можете прочитать о стирании типов более подробно, например здесь .

То же поведение, которое вы можете эмулировать самостоятельно:

public static void main(String[] args) {
    List<String> list = new ArrayList<>();
    addToList(list);
    System.out.println(list);
}

private static void addToList(List list) {
    list.add(1L);
    list.add(42);
    list.add("String");
    list.add(new Runnable() {
        @Override
        public void run() {}
    });
}

Этот код отлично работает какдо тех пор, пока вы не попытаетесь оперировать записями списка в виде строк.Но когда вы добавляете что-то вроде:

for (String s : list) {
    System.out.println(s);
}

Вы получите java.lang.ClassCastException.

Итак, во время компиляции вы работаете с List<String>, но во время выполнения Java знает только оList.

0 голосов
/ 11 октября 2018

Рассмотрим следующий пример:

public static void main(String[] args) {
    List a = new ArrayList();
    a.add("a");
    a.add(1L);

    List<String> b = new ArrayList(a);

    System.out.println(b);
}

Это выводит

[a, 1]

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

public interface List<E> extends Collection<E>

преобразуется в

public interface List extends Collection

во время компиляции.

Если E связан, то есть E расширяет MyClass, он будет преобразован в MyClass.

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

0 голосов
/ 11 октября 2018

да, вы можете, вот небольшой пример

public static void main(String args) {
        List objects = new ArrayList();
        objects.add("string");
        objects.add(1L);

        List<String> onlyStrings = objects;

    }

вы можете преобразовать свой неуниверсальный список в List, если хотите, (вы получите кучу предупреждений компилятора).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...