W3docs

Атрибуты класса Java (Поля)

Объявление полей экземпляра в классе Java, установка начальных значений и доступ к ним через объекты.

Атрибуты класса — это переменные, объявленные внутри него: данные, которые несёт каждый объект. Большинство авторов называют их полями (именно так принято в Спецификации языка Java), а «атрибут» — более общий термин ООП; они обозначают одно и то же. Эта глава посвящена их объявлению, начальным значениям и способам чтения и записи извне класса.

Объявление поля

Поле выглядит как локальная переменная, но располагается в теле класса, а не внутри метода:

public class Book {
  String title;
  String author;
  int    pages;
  boolean inPrint;
}

Каждый экземпляр Book получает собственную копию этих четырёх полей. У двух книг — две отдельные строки title, два отдельных числа pages и так далее. Поля существуют столько же, сколько сам объект: до тех пор, пока на него нет ни одной ссылки.

Значения по умолчанию

Если поле не инициализировано, Java сделает это за вас. Значения по умолчанию зависят от типа:

ТипЗначение по умолчанию
byte, short, int, long0
float, double0.0
char'�' (нулевой символ, code point 0 — не пробел)
booleanfalse
любой объектный типnull
Book b = new Book();
System.out.println(b.title);    // null
System.out.println(b.pages);    // 0
System.out.println(b.inPrint);  // false

Это одно из ключевых отличий полей от локальных переменных внутри методов: локальные переменные не получают значений по умолчанию, и компилятор не позволит прочитать такую переменную до того, как ей присвоено значение. Поля всегда начинают с чего-то определённого.

Встроенные инициализаторы

Полю можно задать значение прямо при объявлении:

public class Book {
  String title   = "Untitled";
  int    pages   = 0;
  boolean inPrint = true;
}

Инициализатор выполняется один раз при создании объекта, в порядке объявления, до тела конструктора. Если для поля требуется более сложная настройка — это задача конструктора.

Чтение и запись полей

Снаружи класса используется синтаксис <ссылка>.<поле>, а внутри — просто <имяПоля> (или this.<имяПоля>):

Book b = new Book();
b.title = "Effective Java";    // write
String t = b.title;            // read

Внутри класса:

public class Book {
  String title;
  void rename(String t) {
    title = t;             // same as this.title = t;
  }
}

Глава ключевое слово this рассказывает, когда требуется явный квалификатор this., а когда он не нужен.

Соглашения об именовании

Имена полей Java записываются в стиле lowerCamelCase:

String firstName;       // good
String first_name;      // not Java style
String FirstName;       // looks like a class

Для boolean-полей часто используются префиксы is или has (isPublished, hasIndex), что делает код более читаемым: if (book.isPublished). Константы — поля, значение которых не меняется — записываются в UPPER_SNAKE_CASE и помечаются static final; это рассматривается в главах static и final.

Поля экземпляра и поля класса

По умолчанию поля принадлежат каждому экземпляру — у каждого объекта своя копия. Если добавить static, поле будет принадлежать самому классу: существует ровно одна копия, общая для всех экземпляров:

public class Counter {
  int count;            // instance — each Counter has its own
  static int total;     // class    — one shared by all Counters
}

Counter a = new Counter();
Counter b = new Counter();
a.count++;   b.count++;   b.count++;
Counter.total++;

System.out.println(a.count);          // 1
System.out.println(b.count);          // 2
System.out.println(Counter.total);    // 1, accessed through the class

Подробности — в главе static; пока считайте, что каждое поле является полем экземпляра, если явно не помечено static.

Публичные поля — почти всегда ошибка

Java позволяет написать public String title; и дать внешнему коду прямой доступ к изменению поля. На практике так почти никогда не делают. Как только поле становится публичным, вы теряете возможность проверять записываемые значения, менять тип поля в будущем или добавлять логику при чтении — любой, кто обращается к полю, жёстко привязан к его текущему представлению.

Стандартный подход — пометить поля как private и открыть доступ через геттеры и сеттеры:

public class Book {
  private String title;

  public String getTitle()          { return title; }
  public void   setTitle(String t)  { this.title = t; }
}

Это называется инкапсуляцией. Главы encapsulation и getters & setters подробно описывают этот паттерн. В ранних примерах мы показываем поля напрямую для простоты, но в реальном Java-коде они всегда private.

Поля хранят ссылки, а не объекты

Когда тип поля — класс (а не примитив), поле является ссылкой. Два объекта могут ссылаться на один и тот же объект через свои поля:

public class Author { String name; }
public class Book   { Author author; }

Author a = new Author();
a.name = "Joshua Bloch";

Book b1 = new Book();   b1.author = a;
Book b2 = new Book();   b2.author = a;     // same Author object

a.name = "J. Bloch";
System.out.println(b1.author.name);   // J. Bloch
System.out.println(b2.author.name);   // J. Bloch

Все предупреждения из предыдущей главы остаются в силе: иногда это именно то, что нужно, а иногда — источник ошибок. Если у каждой книги должен быть свой Author, нужно присваивать каждой new Author().

Практический пример

java— editable, runs on the server

Что дальше

Поля — это состояние объекта. Вторая составляющая — его поведение — описывается методами, объявленными в классе. Следующая глава о методах класса показывает, как прикреплять методы к экземплярам и как они получают доступ к определённым вами полям.

Практика

Практика
Поле экземпляра типа int объявлено, но ему никогда не присваивалось значение. Что в нём будет при обращении через только что созданный объект?
Поле экземпляра типа int объявлено, но ему никогда не присваивалось значение. Что в нём будет при обращении через только что созданный объект?
Was this page helpful?