W3docs

Модификаторы без доступа в Java

Модификаторы без доступа в Java — static, final, abstract, synchronized, transient, volatile — и что каждый из них контролирует.

Модификаторы доступа Java — public, protected, private — управляют тем, кто может видеть член класса. Модификаторы без доступа управляют тем, как он ведёт себя. Это небольшой набор ключевых слов, изменяющих принадлежность, изменяемость, работу с потоками, сериализацию и кое-что ещё. Эта глава является картой; каждый модификатор подробнее рассмотрен в отдельной главе или разделе.

Полный список

МодификаторПрименяется кЧто делает
staticполя, методы, вложенные классы, блокиПринадлежит классу, а не экземплярам
finalклассы, методы, поля, параметры, локальные переменныеНельзя переприсвоить/переопределить/расширить
abstractклассы, методыНет тела / нельзя инстанциировать; должен быть реализован подклассом
synchronizedметоды, блокиТолько один поток одновременно может выполнять его на заданной блокировке
volatileполяЧтения/записи не кешируются в локальной памяти потока
transientполяПропускается при сериализации по умолчанию
nativeметодыРеализация находится в коде не на Java (обычно C/C++)
strictfpклассы, методыПринудительное строгое поведение IEEE-754 для чисел с плавающей точкой (в основном историческое)
defaultметоды интерфейсаПредоставляет тело по умолчанию в интерфейсе
sealed / non-sealedклассы, интерфейсыОграничивает, какие классы могут расширять (Java 17+)

Вы будете постоянно встречать static, final, abstract и default. Остальные встречаются только тогда, когда возникает соответствующая задача.

static — принадлежит классу

Член static ассоциирован с самим классом, а не с каким-либо конкретным экземпляром:

public class Counter {
  int instanceCount;          // one per Counter object
  static int classCount;      // one shared by everyone
}

static настолько распространён, что для него есть отдельная глава — см. java-static.

final — нельзя изменить

final означает «эта привязка зафиксирована после установки». Он применяется к нескольким разным вещам:

final int MAX = 100;          // local variable cannot be reassigned
public final class Money {}   // class cannot be extended
public final void close() {}  // method cannot be overridden
private final int balance;    // field assigned once, then immutable

final является основой констант (static final), неизменяемых объектов и безопасного проектирования наследования. Подробно рассмотрен в java-final.

abstract — нет тела, необходимо заполнить

abstract, применённый к классу, означает «нельзя инстанциировать этот класс напрямую — только подклассы». Применённый к методу, означает «тела нет — каждый конкретный подкласс должен предоставить своё»:

public abstract class Shape {
  public abstract double area();      // no body
}

public class Circle extends Shape {
  double r;
  public double area() { return Math.PI * r * r; }
}

new Shape() — ошибка компиляции; new Circle() работает. Рассмотрено в абстрактных классах.

synchronized — один поток за раз

Когда два потока могут вызвать один и тот же метод на одном и том же объекте, пометка метода как synchronized гарантирует, что в один момент времени выполняется только один:

public synchronized void deposit(int amount) {
  balance += amount;
}

Это простейшая форма блокировки. В книге есть целый раздел про конкурентность; пока достаточно знать, что такое ключевое слово существует и что оно в целом делает. Полная информация в synchronization.

volatile — видимость между потоками

Без volatile потоки могут кешировать значение поля. Операции чтения в одном потоке могут никогда не увидеть записи из другого:

private volatile boolean stopped = false;

volatile заставляет каждое чтение обращаться к основной памяти, а каждую запись — идти в основную память. Это лёгкий аналог synchronized для простых полей-флагов — подробности о модели памяти в volatile.

transient — пропустить при сериализации

Встроенная сериализация объектов Java (Serializable) по умолчанию записывает каждое поле. transient говорит «не включать это» — обычно используется для кешей, вычисленных значений или вещей, которые не имеют смысла за пределами запущенной программы:

public class Session {
  String userId;
  transient String passwordHash;     // not serialized
}

Современный код использует JSON-сериализаторы чаще, чем Serializable, но ключевое слово по-прежнему полезно в библиотеках, которые его поддерживают. Подробнее в serialization.

native — реализован в другом месте

native предназначен для методов, тело которых написано на другом языке (C/C++ через JNI). Вы редко пишете их сами; они встречаются в низкоуровневых библиотеках:

public native int currentTimeMillis();

strictfp — строгая арифметика с плавающей точкой

Изначально strictfp обеспечивал предсказуемую арифметику IEEE-754 для чисел с плавающей точкой на разных платформах. Начиная с Java 17, вся арифметика с плавающей точкой является неявно строгой, что делает ключевое слово бездействующим. Его можно в основном игнорировать; оно встречается в старых кодовых базах.

default — в методах интерфейса

Внутри интерфейса default позволяет предоставить тело метода вместо того, чтобы оставлять его абстрактным:

public interface Greeter {
  default String greet(String name) {
    return "Hello, " + name;
  }
}

Без default метод интерфейса не имеет тела, и каждый реализующий класс должен написать своё. Подробно рассмотрено в default methods.

sealed и non-sealed

Класс sealed задаёт точный список классов, которым разрешено его расширять. Подклассы должны затем выбрать: быть final, sealed или non-sealed:

public sealed class Shape permits Circle, Square { }
public final class Circle extends Shape { }
public non-sealed class Square extends Shape { }

Полезно для закрытых иерархий типов — см. sealed classes.

Комбинирование модификаторов

Обычно модификаторы можно свободно объединять в следующем принятом порядке:

public  static  final   int MAX = 100;
private static  volatile int counter;
protected abstract       void onInit();

Некоторые комбинации недопустимы: метод не может быть одновременно abstract и final, одновременно abstract и private, или одновременно abstract и static. Компилятор сообщит, когда вы нарушите правило.

Рабочий пример

java— editable, runs on the server

Что дальше

Следующие две главы подробно рассматривают два наиболее часто используемых модификатора: static для членов уровня класса и final для неизменяемости. Читайте их по порядку.

Практика

Практика
Какой модификатор без доступа означает, что член класса принадлежит самому классу, а не каждому его экземпляру?
Какой модификатор без доступа означает, что член класса принадлежит самому классу, а не каждому его экземпляру?
Was this page helpful?