Почему Thread не является абстрактным классом и start() не является окончательным?

Почему класс Thread реализован как обычный класс, а не абстрактный класс с run() - абстрактным.

Может ли это возникнуть какие-либо проблемы? Или это имеет какое-то значение в этом отношении?

Кроме того, метод Thread.start() должен быть очень специфическим методом , функциональность которого не может быть реализована каким-либо другим классом (если я не ошибаюсь). И, следовательно, я думаю, что ключевое слово final было бы уместным для этого больше, чем любой другой метод.

Но я могу переопределить этот метод и использовать его как мне нравится,

public class Test extends Thread {
    public static void main (String... args) {
        Thread test = new Test();
        test.start();
    }

    @Override
    public void run() {
        System.out.println("New thread started...");
    }

    @Override
    public void start() {
        System.out.println("Did anyone tell you I will spawn a new thread??");
    }
}

Он явно напечатан,

Кто-нибудь скажет вам, что я создам новый поток?

Есть ли какое-либо использование в переопределении, кроме путаницы с заменой инженера?

Если нет, почему этот метод не был объявлен final в классе Thread?

Ответ 1

Почему класс Thread был реализован как обычный класс, а не абстрактный класс, при котором метод run() является абстрактным.

Этот вопрос на самом деле сводится к тому, что вы всегда должны предпочитать композицию над наследованием.

Если класс Thread был объявлен как abstract, язык должен был предоставить другой класс, который был бы расширен от него, который программисты могли бы использовать для создания Thread. Тогда возникнет вопрос о том, почему этот класс extends из Thread не является abstract. Если язык не предоставил другой класс, который extends из Thread, программистам пришлось бы создать свой собственный класс extend из Thread и переопределить метод run().

Если нет, почему метод не был объявлен final в классе Thread?

Единственное возможное объяснение, которое я могу дать, заключается в том, что разработчики языка видели некоторые прецеденты для переопределения start, когда класс был введен в JDK. Первая версия Java, которую я использовал, была 1,5, и я лично не встречал прецедента, где я нашел необходимость переопределить start. Как заявил в своем ответе JB Nizet

если бы Java была переработана с нуля сегодня, есть хороший шанс, что дизайн будет другим.

Ответ 2

Конечно, вы можете стрелять в ногу, но это не значит, что вы должны.

Почему класс Thread реализован как обычный класс, а не абстрактный класс, когда метод run() является абстрактным.

Потому что рекомендуемый способ создания старта - это не подклассы Thread. Рекомендуемый способ - определить Runnable и передать его в качестве аргумента конструктору Thread:

Runnable r = new Runnable() {
    @Override
    public void run() {
        ...
    }
};
Thread t = new Thread(r);
t.start();

И, следовательно, я думаю, что последнее ключевое слово было бы уместным для этого больше, чем любой другой метод.

Да и нет. Вы не можете заменить реализацию start() своей собственной реализацией, но вы можете делать дополнительные вещи в start(), если хотите:

@Override
public void start() {
    System.out.println("Did anyone tell you I will spawn a new thread??");
    super.start();
}

Тем не менее, если бы Java была переработана с нуля сегодня, есть хороший шанс, что дизайн будет другим. Помните, что этот класс датируется Java 1.0 и по-прежнему поддерживает обратную совместимость.

Ответ 3

Почему Thread.start() не final?

Вы уверены, что никогда не захотите его переопределить?

Class MyThreadFactory implements ThreadFactory {
    @Override
    public Thread newThread(Runnable r) {
        return new Thread(r) {
            @Override
            public void start() {
                LOGGER.info("Starting thread " + this);
                super.start();
            }
        };
    }
}