Связанный тип возврата приложения кажется определенным во время компиляции

Может ли кто-нибудь объяснить мне следующие строки кода:

import org.apache.beam.sdk.Pipeline;
[..]
Pipeline p = Pipeline.create(options);
p.apply(TextIO.read().from("gs://apache-beam-samples/shakespeare/*"))
.apply("ExtractWords", ParDo.of(new DoFn<String, String>() {/* etc */}

Я не понимаю, почему это компилируется. Метод Apply в конвейере возвращает T extends POutput. Интерфейс POutput не имеет метода применения.

В этом случае так получилось, что TextIO.read (). From (...) возвращает PCollection как POutput, а THAT имеет метод apply.

Но что касается контракта на трубопровод, мы знаем, что будет возвращен только POutput. Итак, как компилятор может проверить тип аргумента, переданного первому приложению? Из того, что я помню, когда я кодировал Java, это можно было увидеть только во время выполнения.


person Andrei    schedule 10.12.2017    source источник
comment
Тип T известен во время компиляции.   -  person Oliver Charlesworth    schedule 10.12.2017
comment
это противоречило бы тому, что, как мне кажется, я знал - что во время компиляции T заменяется его ограниченным типом - POutput в нашем случае   -  person Andrei    schedule 10.12.2017


Ответы (1)


Подпись:

public <OutputT extends POutput> OutputT apply(
    String name, PTransform<? super PBegin, OutputT> root) {
  ...
}

Это означает, что для любого возможного типа OutputT, расширяющего POutput, этот метод применим к (String, PTransform<? super PBegin, OutputT>) и возвращает OutputT.

TextIO.read() возвращает TextIO.Read, который расширяет PTransform<PBegin, PCollection<String>>; соответствует PTransform<? super PBegin, OutputT>:

  • Тип PBegin тривиально является супертипом PBegin.
  • Тип PCollection<String> расширяет POutput

Итак, метод .apply() применим с заменой OutputT = PCollection<String>. После подстановки фактического значения OutputT в подпись .apply() возвращается значение PCollection<String>.

То, что вы говорите (OutputT заменяется на POutput), происходит во время стирания типа - подпись стираемого типа Pipeline.apply() равна POutput apply(String, PTransform); и это его подпись в скомпилированном байт-коде Pipeline, если JVM действительно выполняет ее. Однако стирание типа происходит после проверки типа, а не до него - в противном случае почти все программы Java, использующие дженерики, не смогли бы компилироваться.

Это точно то же самое, что происходит, когда вы вызываете Arrays.asList(1, 2, 3) - он возвращает List<Integer>, а не List<Object> или List, даже если подпись со стиранием типа List asList(Object[]).

person jkff    schedule 12.12.2017
comment
Итак, вы говорите, что сначала выполняется явное приведение, а затем применяется стирание типа. Итак, проверив файл .class, я вижу: 18 invokevirtual org.apache.beam.sdk.Pipeline.apply (org.apache.beam.sdk.transforms.PTransform): org.apache.beam.sdk.values.POutput [7 ] 21 checkcast org.apache.beam.sdk.values.PCollection [8] [....] 36 invokevirtual org.apache.beam.sdk.values.PCollection.apply (java.lang.String, org.apache.beam .sdk.transforms.PTransform): org.apache.beam.sdk.values.POutput [13] так что ... вы правы! Спасибо! - person Andrei; 12.12.2017