Patryk Krawczyk:
昨日私が説明することができなかったことをいくつかの奇妙なのJava /春/ IntelliJの行動につまずきました。
これはjdk1.8.0_152で作られた春のブートアプリケーションです。
私は自分のDBを埋めるために、この単純な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');
ここに私のエンティティクラスがあります:
@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のでデバッグする場合、それが示した値、このように:
これはどのように可能ですか?なぜ私は文字列のリストの中に長い値を持つことができるのですか?
また:
values.add(1L) // fails to compile
values.get(0).getClass().name // returns java.lang.String
values.get(1).getClass().name // returns java.lang.Long
セルギBishyr:
これは、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
。