Статические методы
Статические методы можно вызывать не используя ссылку на объект. В этом их ключевое отличие от обычных методов класса. Для объявления таких методов используется ключевое слово static . На методы, объявленные как static , накладывается следующие ограничения:
- Они могут непосредственно вызывать только другие статические методы.
- Им непосредственно доступны только статические переменные.
- Они не могут делать ссылки типа this или super .
Пример использования статических методов:
public class StaticMethodClass < static int staticVar = 3; int nonStaticVar; public void nonStaticMethod() < System.out.println("Нестатический метод"); >static void staticMethod(int localVar) < System.out.println("localVar = " + localVar); System.out.println("staticVar = " + staticVar); //Нельзя обратиться к нестатической переменной из статического метода //System.out.println("nonStaticVar language-java">public class StaticMethodDemo < public static void main(String[] args) < StaticMethodClass.staticMethod(42); >>
- Статические переменные
- Статический блок
- Java static import
- Задания
Trustpilot
Комментарии
Зарегистрируйтесь или войдите, чтобы иметь возможность оставить комментарий.
Что такое статический метод java
Статические методы. Плюсы и минусы.
Определение
Статическими методами в Java называют такие методы, которые могут быть вызваны без создания экземпляра класса. Например, метод pow () из класса Math является статическим:
//Math.pow returns double, need cast, display 256 int result = (int) Math.pow(2, 8);
При вызове метода Math.pow (х , а) вычисляется степень x числа а. При выполнении этого метода не используется ни один из экземпляров класса Math. Иными словами, у него нет неявного параметра this. Это означает, что в статических методах не используется текущий объект по ссылке this. (А в нестатических методах неявный параметр this ссылается на текущий объект)
Когда следует использовать
- Когда методу не требуется доступ к данным о состоянии объекта, поскольку все необходимые параметры задаются явно (например, в методе Math.pow ()).
- Когда методу требуется доступ лишь к статическим полям класса
NumberFormat currencyFormatter = NumberFormat.getCurrencylnstance(); NumberFormat percentFormatter = NumberFormat.getPercentlnstance(); double x = 0.1; System.out.println(currencyFormatter.format(x)); // выводит $0.10 System.out.println(percentFormatter.format(x)); // выводит 10%
- Конструктору нельзя присвоить произвольное имя. Его имя всегда должно совпадать с именем класса. Так, в классе NumberFormat имеет смысл применять разные имена для разных типов форматирования.
- При использовании конструктора тип объекта фиксирован. Если же применяются фабричные методы, они возвращают объект типа Decimal Format, наследующий свойства из класса NumberFormat.
Особенности применения
Важным моментом является то, что статические методы переопределять (Override) нельзя. Если объявить такой же метод в классе-наследнике (subclass), т.е. метод с таким же именем и сигнатурой, то лишь «спрячется» метод суперкласса (superclass) вместо переопределения. Это явление известно как сокрытие методов (hiding methods). Это означает, что при обращении к статическому методу, который объявлен как в родительском, так и в дочернем классе, во время компиляции всегда будет вызван метод исходя из типа переменной. В отличие от переопределения, такие методы не будут выполнены во время работы программы. Рассмотрим пример:
class Vehicle < public static void kmToMiles(int km) < System.out.println("Внутри родительского класса/статического метода"); >> class Car extends Vehicle < public static void kmToMiles(int km) < System.out.println("Внутри дочернего класса/статического метода "); >> public class Demo < public static void main(String args[]) < Vehicle v = new Car(); v.kmToMiles(10); >>
Вывод в консоль:
Внутри родительского класса/статического метода
Код наглядно демонстрирует: несмотря на то, что объект имеет тип Car, вызван статический метод из класса Vehicle, т.к. произошло обращение к методу во время компиляции. И при этом ошибки во время компиляции не возникло!
Статические методы в JVM
Статические методы и переменные хранились в области Permgen до 8-й версии java. Начиная с 8-й версии, они хранятся в новой область памяти, которая называется Metaspace
Примеры применения статических методов
- Статическим является метод main - точка входа в Java-программе.Если метод main не объявлен как static, то у JVM при создании экземпляра класса возникает неопределённость, поскольку конструкторов у класса может быть несколько и непонятно, какой из них вызвать. Кроме того, в случае нестатического метода, jvm создаёт объект прежде чем вызвать метод main, что может привести к проблемам с дополнительным выделением памяти.
- Начиная с версии Java 8, в интерфейсах можно писать статические методы, которые аналогичны default методам, за исключением того, что нельзя их переопределить в реализуемых классах:
- Статические методы в интерфейсах хороши для методов - утилит, например, проверки на null, сортировки коллекций;
- Нельзя определять статические методы в интерфейсах для метода класса Object, это приводит к сообщению об ошибке: "This static method cannot hide the instance method from Object".
Достоинства и недостатки
Достоинства
- отсутствует необходимость каждый раз создавать новый объект для доступа к таким методам
- удобны для создания методов-утилит
- загружаются единственный раз при запуске JVM
Недостатки
- В отличие от локальных переменных, статические методы НЕ потокобезопасны (Thread-safe) в Java. На практике это одна из наиболее частых причин возникновения проблем связанных с безопасностью мультипоточного программирования. Учитывая что каждый экземпляр класса имеет одну и ту же копию статической переменной, то такая переменная нуждается в защите — «залочивании» классом. Поэтому при использовании статических переменных необходимо убедиться, что они должным образом синхронизированы (synchronized), во избежание проблем, например таких как «состояние гонки» (race condition).
- В отличие от локальных переменных, статические методы НЕ потокобезопасны (Thread-safe) в Java. На практике это одна из наиболее частых причин возникновения проблем связанных с безопасностью мультипоточного программирования. Когда метод синхронизирован, он блокирует объект, если метод статичен, он блокирует класс, поэтому всегда рекомендуется использовать синхронизированный блок для блокировки только тех разделов метода, которые требуют синхронизации.
- Если статические методы ссылаются на статические переменные, они остаются в памяти всё время жизни загрузчика классов, что может привести к утечкам памяти.
- Неудобно тестировать юнит-тестами. Нельзя создавать mock-объекты, потому что при вызове статического метода задаётся имя класса.
- Поскольку статический метод нельзя переопределить, это приводит к нарушению полиморфизма. Это приводит к низкой гибкости в ситуациях, когда в результате изменений поведение статического метода становится полиморфным: Пример: HourlyPayCalculator.calculatePay(employee, overtimeRate) Данная статическая функция тоже выглядит вполне разумно. Она не работает ни с каким конкретным объектом и получает все данные из своих аргументов. Однако нельзя исключать, что эту функцию потребуется сделать полиморфной. Возможно, в будущем потребуется реализовать несколько разных алгоритмов для вычисления почасовой оплаты — скажем, OvertimeHourlyPayCalculator и StraightTimeHourlyPayCalculator. В этом случае данная функция не может быть статической. Ее следует оформить как нестатическую функцию Employee. Как следствие, что в случае реализации полиморфного поведения сложно управлять поведением по условию. Это возможно сделать при помощи двух подходов: передать флаг через параметр метода или установить статический флаг извне. Проблема с первым подходом в том, что приходится изменять сигнатуру для каждого вызывающего объекта, что приводит к усложнению кода по причине добавления новых и новых флагов. Применение второго подхода может привести к загромождению кода установкой и сбросом флагов:
boolean oldFlag = MyUtils.getFlag(); MyUtils.someMethod(); MyUtils.setFlag( oldFlag );
- поведение статических методов не может стать полиморфным;
- статический метод не ссылается на статические поля;
- обеспечена потокозащищённость.
Статические методы — Java: Введение в ООП
Одна из базовых конструкций в программировании - функция. С помощью функций мы выделяем повторяющиеся блоки кода и вводим новые операции, которые не заложены в язык. В большинстве языков функции создаются просто, для этого достаточно знать синтаксис определения. Ниже пример на JavaScript, который будет понятен даже без знания языка:
// Функция возвращает строку // Типы определять не надо, js динамический язык function greeting() return 'just a string'; > // Вызов можно делать в любом месте // Даже просто в файле, вне других функций greeting(); // 'Just a string'
С Java все немного сложнее. Она не позволяет создавать обычные функции. Java требует наличия класса для определения функций, которые, в этом случае, называются методами. Для сравнения перепишем пример с JavaScript на Java:
// Имя класса можно выбирать произвольно class App // public - дает возможность вызывать метод снаружи класса // static - пока просто нужно, позже разберемся // String - возвращаемый тип public static String greeting() return "just a string"; > > // Любой код в Java выполняется только внутри классов // Поэтому вызов метода greeting() тоже будет где-то внутри // Где-то в другом месте программы class SomeName public static void someMethod() // Для вызова статического метода нужно // указывать имя класса App.greeting(); > >
Если вызов метода идет из того же класса, где он определен, то указывать имя класса перед ним не нужно:
class App public static String greeting() return "just a string"; > public static void main(String[] args) // Тот же класс, поэтому имя не обязательно greeting(); // Хотя, чисто технически, его можно поставить // App.greeting(); > >
Основная разница между функцией greeting() на JavaScript и методом greeting() на Java заключается в наличии класса в определении метода и его же указание при вызове из других классов. Возникает вопрос, зачем нужен класс когда можно просто создавать функции? Вообще так делать было не обязательно, но создатели Java решили по-другому. Например, в Kotlin, который тоже работает на виртуальной машине Java, нет такого ограничения, там можно создавать обычные функции.
Несмотря на наличие класса и смены названия на "метод", по сути, мы получили обычную функцию, которая определена в классе и вызывается через класс. Достигается это за счет ключевого слова static . Без него методы работают совсем по-другому, о чем мы поговорим в следующих уроках. Методы, определенные как static , называют статическими.
Еще немного примеров статических методов из реальной жизни:
// Встроенные в Java // возвращает модуль числа int y = Math.abs(-30); // находит минимальное число int m = Math.min(10, 11); // Из библиотеки org.apache.commons.lang3 // возвращает случайное число int x = RandomUtils.nextInt(1, 1000);
Открыть доступ
Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно
- 130 курсов, 2000+ часов теории
- 1000 практических заданий в браузере
- 360 000 студентов
Наши выпускники работают в компаниях:
Модификатор static в Java: методы
В данной статье мы рассмотрим использование модификатора static для методов. Если же Вас интересует использование модификатора static для переменных, такую статью Вы можете найти по этой ссылочке.
Модификатора static - с англ. "статичный", "постоянный" - делает переменную или метод "независимыми" от объекта. Давайте рассмотрим, как модификатор применяется к методам.
Модификатор static для методов
1. Метод вызывается без создания объекта класса.
Как и в случае с полями, статические методы можно вызывать без создания объекта. Например, представим, что у нас есть класс MyClass - а внутри его два метода, статический и "обычный":
class MyClass < public static void firstMethod ( ) < System . out . println ( "Это статический метод!" ) ; public void secondMethod ( ) < System . out . println ( "Это НЕ статический метод!" ) ;
Мы можем вызвать оба метода, создав объект класса MyClass:
class Test < public static void main ( String args [ ] ) < MyClass c1 = new MyClass ( ) ; c1 . firstMethod ( ) ; c1 . secondMethod ( ) ;
Тем не менее, попробуем записать то же самое без создания объекта - вот так:
class Test < public static void main ( String args [ ] ) < MyClass . firstMethod ( ) ; MyClass . secondMethod ( ) ;
Тут мы заменили название объекта - c1 - на название класса (ведь ни одного объекта теперь у нас нет! :)).
Как Вы думаете, что произойдет?
Естественно, такой код работать не будет. Дело в том, что так обращаться можно только к одному из этих методов - статическому:
class Test < public static void main ( String args [ ] ) < MyClass . firstMethod ( ) ;
Если нам понадобится второй, не статический метод, понадобится создавать объект класса MyClass. Как видите, если обращаться к статическим методам и через название объекта, и название класса, код будет работать. К нестатическим методам нужно обращаться исключительно через название объектов класса.
2. Статические методы нельзя переопределять.
Как Вы помните, один из фундаментальных принципов ООП - это "наследование". Дело в том, что в случаях, когда нам нужно создать новый класс, который имеет много общих свойств с каким-то уже существующим, вместо того, чтобы писать все заново, можно сделать "наследника" существующего класса. Этот "наследник" будет иметь те же самые метод и переменные, что и "родитель".
Тем не менее, в классе-наследнике обычно можно переопределять существующие методы. Это значит, что можно создать метод с таким же названием, только заменить его "внутренности". Так вот, статический метод нельзя переопределить. По аналогии с переменными, можно сказать, что этот метод "один для класса и его наследников" - так же, как статическая переменная "одна для класса и всех его объектов".
3. Статическим методам нужен "статический контекст".
Есть такое правило: статический метод не может ссылаться на нестатическую переменную. Что это значит?
Представьте, что у нас в каком-то классе есть статический метод. То есть это метод, к которому, как Вы знаете, можно обращаться без создания объекта класса. Это значит, что если статический метод будет обращаться к нестатическим переменным (которые попросту "не будут существовать", потому что объект не объявлен), то возникнет ошибка. Поэтому, статические методы могут ссылаться только на статические переменные . Это гарантирует, что во время выполнения нашего метода все элементы будут инициализированы и будут работать. Именно это и называется "статическим контекстом".
Итог двух частей - зачем применяется модификатор static
Итак, Вы в общих чертах поняли, в чем заключается принцип работы модификатора static. Давайте подытожим - как он применяется?
1. Если нужно объявить любую константу - например, = 3,14 - обязательно нужно использовать static. Они объявляются с использованием сочетание "static final":
public class Test < public static final double pi = 3.14159265359 ;
2. Если Вам нужно иметь доступ к переменной или методу без создания экземпляра класса. Например, представим, что у нас есть класс Cat. Логически, нет смысла делать статической переменную "имя кошки" - ведь оно будет индивидуальным для каждого экземпляра класс - т.е. для каждого кота. И метод "мяукать" делать статическим нет смысла - ведь без кошки (без создания объекта класса) вроде как некому будет мяукать
Но если представить, что у нас есть класс Math, в котором будет метод "найти корень квадратный". Это метод мы можем сделать статическим - ведь он нам явно очень пригодится, и будет часто использоваться. А зачем писать две строчки кода (создание экземпляра класса + вызов метода), если можно обойтись одной (вызов метода)? При этом, класс Math не несет никакой логическом нагрузки, в отличии от классов Cat, Dog или Car, и нам совершенно не нужен объект Math чтобы находить квадратные корни
3. У статических переменных и методов есть еще одно полезное свойство - они общие для всех экземпляров класса.
С одной стороны, это перекликается с установкой констант - пункт 1. Например, представьте, что у нас есть класс Cat, в котором есть два поля - "количество_лап" и "количество_хвостов". Понятно, что для всех экземпляров этого класса переменная "количество_лап" будет равна 4, а "количество_хвостов" равна 1. Мы можем сделать эти поля static, потому что они будут общими. Кроме того, это нам поможет сэкономить память, потому что эти переменные не будут "создаваться заново" для каждого экземпляра. Наоборот, все эти экземпляры будут ссылаться на одну и ту же - статическую - переменную.
Тот факт, что статическая переменная общая для всех классов, можно использовать и по-другому. Например, представьте, что у нас есть класс Dog. В этом классе, у нас будет статическая переменная "количество_собак", и мы сделаем так, чтобы каждый раз при создании объекта класса Dog она увеличивалась на 1. Таким образом, мы сможем посчитать, сколько мы создавали объектов! Или, как вариант, эту цифру можно использовать для присвоения уникального идентификационного номера каждой собаке.
Теперь Вы знаете основные способы применения модификатора static. Бывают и другие, но их мы рассмотрим позже.
Статья написана Vertex Academy. Будем рады видеть Вас на наших курсах Java с нуля.
- ← Массив объектов в Java
- Модификатор static в Java: переменные →