Глубоко извиняюсь, не могли бы прояснить . Метод method4 вызывается из method3 без создания объекта . Так почему мы не объявляем method4 static? Даже после всех комментариев и ответов пока не догоняю.
Методы method3() и method4() объявлены без использования ключевого слова static, то есть являются так называемыми методами экземпляра. Такие методы могут быть вызваны только в контексте объекта класса, которому они принадлежат. Другими словами, поскольку вызов метода method3() "вложен" в контекст объекта Solution, то и всё "содержимое" метода method3() также выполняется в контексте объекта.
Если совсем просто:
- из статического метода непосредственно можно вызвать только другой статический метод. Для вызова метода экземпляра из статического метода необходим объект;
- из метода экземпляра можно непосредственно вызвать как другой метод экземпляра, так и статический метод.
publicclassSolution{// 3. Поле step должно быть статическим, чтобы его значение сохранялось// вне зависимости от создания объектов типа Solution:publicstaticint step;publicstaticvoidmain(String[] args){method1();}// 1. Поскольку method1() вызывается из статического метода main() без создания объекта,// method1() также должен быть статическим:publicstaticvoidmethod1(){method2();}// 2. Из-за того, что method1() теперь статический, method2() также должен быть статическим,// чтобы его можно было вызвать в теле метода method1() (по аналогии с п.1):publicstaticvoidmethod2(){newSolution().method3();}publicvoidmethod3(){method4();}publicvoidmethod4(){
step++;for(StackTraceElement element :Thread.currentThread().getStackTrace())System.out.println(element);if(step >1)return;main(null);}}
Выполнение программы начинается с метода main( ), поэтому начнём с него.
1. В методе main( ) производится вызов метода method1( ). Поскольку method1( ) вызывается из статического контекста без создания объекта (как известно, метод main( ) всегда статический), то и method1( ) также должен быть статическим.
2. Из-за того, что method1( ) теперь статический, method2( ) тоже должен быть статическим, чтобы его можно было вызвать в теле метода method1( ) (по аналогии с п.1).
3. Теперь метод method3( ) также вызывается из статического контекста (из метода method2( ) ), но он вызывается не напрямую, а посредством создаваемого объекта new Solution( ). Поэтому делать method3( ) статическим нет необходимости
4. В методе method4( ) в консоль выводится стек-трейс – перечень методов, которые были вызваны к текущему моменту. После этого проверяется значение переменной step, и если оно не превышает 1, опять вызывается метод main( ) и цепочка вызовов main( ) – method1( ) – method2( ) – method3( ) – method4( ) повторяется. В итоге получается замкнутая петля: в теле method4( ) снова проверяется значение переменной step, но оно снова равно 1, потому что переменная step существует только в пределах объекта Solution, а этот объект каждый раз создаётся заново в методе method2( ). Иными словами, оператор инкремента step++ увеличивает на 1 значение новой переменной step во вновь созданном объекте (напомню, изначально при создании объекта step = 0); предыдущий объект Solution пропадает после выхода из method4( ), ведь ссылка на него нигде не сохраняется.
Чтобы разорвать бесконечный «замкнутый круг» необходимо сделать статической переменную step. Тогда эта переменная будет существовать в пределах класса Solution, а это значит, что она будет доступна без создания объекта типа Solution. Теперь её значение будет сохраняться после инкрементирования step++, увеличиваясь на 1 при каждом вызове method4( ). В конце «второго круга» значение step станет равным 2, и метод method4( ) завершится командой return, завершая в итоге всю программу.
Скажите пожалуйста а как может создаваться новый обьект new Solutions без указании имени обьекта всегда же создавали раньше так Имя обьекта = new Solutions?
И в каких случаях это используется?
Для создания объекта необходимо вызвать конструктор класса, предварив его ключевым словом new:
newSolution();
При выполнении этой строки будет создан экземпляр класса Solution, но в следующий же момент этот объект будет утерян, поскольку ссылка на него нигде не сохраняется. Для того, чтобы иметь возможность использовать объект в дальнейшем после его создания, следует привязать его к переменной соответствующего типа:
Solution s =newSolution();
s.method3();
Благодаря ссылочной переменной s имеется возможность получения доступа к объекту, например, для вызова содержащегося в нём метода method3( ).
В некоторых случаях объект нужен для выполнения только одной операции, после выполнения которой надобность в этом объекте пропадает. В этом случае можно использовать сокращённую запись:
newSolution().method3();
Здесь на созданном объекте Solution сразу же вызывается метод method3( ) (то есть нас интересует не сам объект, а только одноразовый вызов метода, содержащегося в объекте).
А можно узнать у вас?
Откуда взялось вот это "for (StackTraceElement element : Thread.currentThread().getStackTrace())
System.out.println(element);"
А именно StackTraceElement element и это Thread.currentThread().getStackTrace
Ведь нигде они не инициализировались или инкрементировались, или это методы, такие как System out print(ln) ?
Thread.currentThread() - это статический метод класса Thread, возвращающий ссылку на текущий поток исполнения. Затем на объекте потока вызывается метод getStackTrace(), который возвращает массив элементов StackTraceElement, или так называемый стек-трейс. Таким образом, цикл перебора можно расписать подробнее:
// Получаем стек-трейс для текущего потока:StackTraceElement[] stackTrace =Thread.currentThread().getStackTrace();// Перебираем элементы стек-трейса при помощи цикла foreach:for(StackTraceElement element : stackTrace){System.out.println(element);}
Запись цикла в стиле foreach означает следующее: из массива stackTrace последовательно извлекаются элементы, каждый из которых в свою очередь помещается в переменную element. На каждой итерации цикла текущий элемент массива stackTrace выводится в консоль.
Thread - это стандартный класс, находящийся в пакете java.lang. Пусть Вас не пугает обилие методов, определённых в этом классе - в рамках данной задачи нам нужен только метод Thread.currentThread(), чтобы получить доступ к стек-трейсу. Потоки исполнения - отдельная сложная тема, они будут изучаться гораздо позже. Цикл foreach подробно описан в этой статье, он часто облегчает написание кода.
В задачах курса авторы иногда забегают наперёд: используются понятия и темы, не рассматриваемые в предыдущих лекциях. Если задача кажется непонятной, просто отложите её на время. Постепенно Ваши знания (в том числе полученные из последующих лекций) сложатся в общую картину, и Вы с лёгкостью решите отложенную задачу. И конечно же, активно пользуйтесь поиском в интернете. Изучение различных точек зрения касательно какого-либо вопроса позволит Вам сложить наиболее ясную картину о предмете изучения.
Охренеть!, т.е. круто!