откуда он знает, что это Runnable?
Прежде всего, давайте удостоверимся, что мы знаем, что означает "Runnable". Опытные Java программисты говорят, что не задумываясь об этом слишком глубоко, но Runnable
- это не класс. Это интерфейс : это спецификация одного или нескольких методов, которые, как ожидается, должен иметь какой-то фактический класс. Когда мы говорим «Runnable», мы на самом деле имеем в виду «экземпляр некоторого класса, который implements Runnable
».
Так как же компилятор узнает, что лямбда-выражение должно создавать «Runnable?» Это легко. Компилятор видел объявление класса Thread
, а объявление класса Thread
явно говорит, что аргумент конструктора должен быть Runnable.
Оба Thread
и Runnable
есть метод run()
.
ОК. Thread implements Runnable
, но не имеет смысла использовать там экземпляр Thread
, потому что метод Thread
class run()
не выполняет то, что вы хотите, чтобы ваш поток выполнял. Компилятор должен определить совершенно новый класс с помощью метода run()
, который выполняет все то, что вы помещаете в тело вашей лямбды. В системе нет другого класса, который бы все это делал.
ОК, так почему новый класс не extends Thread
? (или extends
любой другой существующий класс, который implements Runnable
?)
Просто потому, что для этого нет причин. Конструктор Thread
не говорит, что ему нужен аргумент Thread
. Он говорит, что хочет аргумент Runnable
. Он будет доволен любым классом, implements Runnable
, и никогда не будет ничего делать с объектом, кроме как вызвать его метод run()
.
ОК, но как узнает компилятор превратить лямбда-тело в метод с именем run()
?
, поскольку Runnable
- это интерфейс @functional
, который объявляет ровно один метод. Runnable
объект должен иметь метод run()
, и интерфейс не указывает никакой другой метод, поэтому другого выбора нет.