W3docs

Классы и объекты Java

Определите класс Java и создайте объекты из него — основа объектно-ориентированной модели Java.

Класс — это определение; объект — это экземпляр этого определения, существующий во время выполнения. Класс описывает как выглядит собака и что она умеет делать; объект — это Рекс, конкретная собака, живущая в памяти, пока работает ваша программа. Всё изложенное ниже строится на этом различии.

Определение класса

Определение класса находится в отдельном файле .java, названном по имени класса. Тело содержит поля (данные, которые несёт каждый экземпляр) и методы (поведение, которое может выполнять каждый экземпляр).

public class Dog {
  String name;
  int    age;

  void describe() {
    System.out.println(name + ", age " + age);
  }
}

Это объявляет тип. Оно ещё не создаёт никаких собак — точно так же, как написание int не создаёт целое число.

Создание объекта с помощью new

Ключевое слово new просит JVM выделить место для одного экземпляра и вернуть ссылку на него:

Dog d = new Dog();

На этой строке происходят три вещи:

  1. Выделение памяти. JVM находит место в куче, достаточное для Dog.
  2. Инициализация по умолчанию. Каждое поле получает значение по умолчанию — null для объектов, 0 для int, false для boolean.
  3. Вызов конструктора. () вызывает конструктор. Мы не написали ни одного, поэтому Java предоставила конструктор без аргументов по умолчанию, который ничего дополнительного не делает. Следующая глава о конструкторах охватывает написание собственных.

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

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

Доступ к полю осуществляется с помощью записи <ссылка>.<поле>:

d.name = "Rex";
d.age  = 3;
System.out.println(d.name);   // Rex

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

d.describe();    // Rex, age 3

Точка одинакова в обоих случаях; является ли правая часть полем или методом, зависит только от того, что следует далее.

Ссылки — это не объекты

Это самое важное предложение в данной главе: переменная классового типа хранит ссылку, а не сам объект.

Dog a = new Dog();
a.name = "Rex";

Dog b = a;           // copies the REFERENCE, not the dog
b.name = "Buddy";

System.out.println(a.name);   // Buddy

a и b указывают на один и тот же объект в куче, поэтому изменение через одну из них видно через другую. Сравните с примитивами:

int x = 5;
int y = x;       // copies the value
y = 9;
System.out.println(x);    // still 5

x и y независимы — примитивы копируются по значению. Глава о передаче по значению подробнее рассматривает, что это означает для аргументов методов.

null и NullPointerException

Ссылочная переменная может быть null, то есть «не указывает ни на какой объект»:

Dog d = null;
d.describe();    // NullPointerException

null — это то, что вы получаете, если никогда не присвоили объект, или если поле объектного типа не было явно инициализировано. Разыменование null (запись d.something при d == null) генерирует NullPointerException во время выполнения. Написание кода, который не падает на null, — это половина практики Java.

Внимание
NullPointerException — это ошибка времени выполнения, а не ошибка компиляции — код компилируется нормально и падает только тогда, когда эта строка действительно выполняется. Исправление состоит в том, чтобы убедиться, что переменная указывает на реальный объект (d = new Dog();), или защититься проверкой (if (d != null) d.describe();) перед разыменованием.

Сравнение объектов: == и equals

Для ссылок == спрашивает «указывают ли эти две переменные на один и тот же объект?»:

Dog a = new Dog();
Dog b = new Dog();
Dog c = a;

System.out.println(a == b);   // false — different objects
System.out.println(a == c);   // true  — same object

Если вы хотите сравнить содержимое двух объектов, вы вместо этого вызываете метод equals — каждый класс наследует метод по умолчанию от Object, но по умолчанию он просто проверяет равенство ссылок. Вы переопределяете equals, чтобы задать нужный смысл; см. главу equals & hashCode далее в этой части.

Один файл, много объектов

Одно определение класса поддерживает неограниченное количество экземпляров. Все они разделяют одну структуру, но каждый имеет собственное состояние:

Dog rex   = new Dog();   rex.name   = "Rex";   rex.age   = 3;
Dog molly = new Dog();   molly.name = "Molly"; molly.age = 7;

rex.describe();     // Rex, age 3
molly.describe();   // Molly, age 7

Метод вроде describe читает из this — объекта, на котором он вызван, — поэтому один и тот же код выводит разный результат в зависимости от того, на каком экземпляре он вызван.

Где живут классы

Файл .java, объявляющий public class Dog, должен называться Dog.java. В одном файле можно иметь непубличные классы, но только один public класс на файл, и его имя должно совпадать с именем файла. В небольших программах этой главы мы часто будем помещать вспомогательные классы в тот же файл, что и main, используя вложенные классы static, просто чтобы пример умещался в одном файле.

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

java— editable, runs on the server

Что дальше

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

Практика

Практика
Дано Dog a = new Dog(); Dog b = a; b.name = 'Rex'; — что выведет System.out.println(a.name)?
Дано Dog a = new Dog(); Dog b = a; b.name = 'Rex'; — что выведет System.out.println(a.name)?
Was this page helpful?