Почему 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?
источник
Thread
урок был заключительным. Конструктор уже принимает исполняемый объект, поэтому для создания потока наследование не требуется.Ответы:
На самом деле этот вопрос сводится к тому, что вы всегда должны предпочесть композицию наследованию.
Если бы
Thread
класс был объявлен какabstract
, язык должен был бы предоставить другой класс, расширяющий его, который программисты могли бы использовать для созданияThread
. Ваш вопрос будет затем о том, почему этот классextends
отThread
неabstract
. Если бы в языке не было другого класса,extends
из которого происходило быThread
, программистам пришлось бы создать свой собственный класс,extend
из которого был бы,Thread
и переопределитьrun()
метод.Единственное возможное объяснение, которое я могу дать, заключается в том, что разработчики языка видели некоторые варианты использования для переопределения,
start
когда класс был представлен в JDK. Первой версией Java, которую я использовал, была 1.5, и я лично не встречал варианта использования, в котором я обнаружил бы необходимость переопределенияstart
. Как заявил Дж. Б. Низет в своем ответеисточник
Вы, конечно, можете выстрелить себе в ногу, но это не значит, что вы должны это делать.
Поскольку рекомендуемый способ создания запуска потока - это не создание подкласса Thread. Рекомендуемый способ - определить a
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 и по-прежнему имеет обратную совместимость.
источник
Вы уверены , что никогда не захотите его отменять?
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(); } }; } }
источник
Я чувствую, что для ответов нужно опубликовать несколько калибровок:
Нет! Я не стал бы. Это все равно что сказать: «Вы уверены, что хотите объявить эту переменную частной?» Потому что, если бы я мог объявить любую переменную, которую я использую, как общедоступную, не опасаясь, что другие разработчики могут испортить мою логику проектирования, кодирование было бы легким делом. Одна из наиболее важных целей концепций OOPS, таких как Область видимости, абстракция, полиморфизм, обработка ошибок и т. Д., Состоит в том, чтобы сообщить другим разработчикам дизайн и намерения, стоящие за вашим кодом. Как указано в вопросе, когда вы переопределяете метод запуска, никто вас не заставляет использовать super.start (). @Codebender написал метод запуска потока без использования super.start (), и компилятор никогда не жаловался. Значит, он может сломать весь механизм Threading, а компилятор может просто позволить ему пройти? Метод запуска потока гарантирует, что метод запуска вызывается и выполняется в нужное время! Это очень важно для самой концепции Threading. Я был бы более чем счастлив, если бы я что-то здесь пропустил. 2.
Хорошо, если кодовый бендер разрешен дизайном, чтобы подклассифицировать Thread и испортить метод запуска. По этой логике, дизайн стреляет себе в ногу. Согласно другому заявлению (с которым я полностью согласен), Runnable является рекомендуемым способом. Тогда почему мы вообще позволяем классу Thread создавать экземпляр потока без ограничений? Далее следуют:
Это на самом деле подтверждает утверждение codebender, что метод start должен быть окончательным, когда вы говорите это ... ^
Единственный действительный момент уже упоминается как побочное примечание, но это фактический ответ. на этот вопрос.
"Обратная совместимость".
Фактически, улучшения даже были внесены в JDK 5.0, когда они включали множество важных дополнений и уточнений в модель параллелизма Java. Мы хотим, чтобы обратная совместимость поддерживалась полностью, и именно поэтому класс Thread остается таким же, как и раньше, хотя в настоящее время рекомендуется использовать интерфейс Runnable.
Опять же, я был бы более чем счастлив, если бы меня поправили, если я что-то упустил.
источник