🔥 🚀 Важно для всех, кто работает с Java! 🔥
На JavaRocks ты найдешь уникальные туториалы, практические задачи и редкие книги, которых не найти в свободном доступе. Присоединяйся к нашему Telegram-каналу JavaRocks — стань частью профессионального сообщества!
Всем привет! Сегодня мы подробно изучим, что такое классы и объекты в Java.

Классы и объекты: определение.
В основе объектно-ориентированного программирования (ООП) лежат такие понятия, как классы и объекты.
Класс Java напоминает чертеж дома, в котором дана инструкция к его постройке. Тем не менее, это не сам дом. Классы определяют:
- Свойства (атрибуты или поля) – характеристики объекта
- Методы (функции) – то, что может делать объект
- Конструкторы – специальные методы, создающие новые объекты
Вот простой пример объявления класса в Java:
public class Dog {
// Свойства (переменные экземпляра)
String breed;
String color;
int age;
// Метод
public void bark() {
System.out.println("Woof! Woof!");
}
// Метод с возвращаемым значением
public int getAgeInHumanYears() {
return age * 7;
}
}
Run CodeЕсли класс – это чертеж, то объект – это дом, который вы строите. Объекты – это экземпляры классов, хранящиеся в памяти. Можно провести такую аналогию: класс – это формочка для печенья, а объекты – это сами печеньки: формы у них одинаковые, а состав может быть разным 🙂
Вот пример создания объекта в Java:
// Создаём объекты Dog
Dog myDog = new Dog(); // первый объект
Dog neighborDog = new Dog(); // второй объект
// Определяем свойства для myDog
myDog.breed = "Golden Retriever";
myDog.color = "Golden";
myDog.age = 3;
// Определяем свойства для neighborDog
neighborDog.breed = "Dalmatian";
neighborDog.color = "White with black spots";
neighborDog.age = 5;
// Используем метод
myDog.bark(); // Вывод: Woof! Woof!
System.out.println(myDog.breed + " is " + myDog.getAgeInHumanYears() + " years old in human years.");
// Вывод: Golden Retriever is 21 years old in human years.
Run CodeОсновные составляющие класса
Поля (переменные экземпляра)
Это переменные, объявленные внутри класса, которые отражают характеристики объектов:
public class Person {
// Переменные экземпляра (поля)
String name;
int age;
double height;
boolean isEmployed;
}
Run CodeУ каждого объекта класса Person будет своя копия этих переменных, в которых будут храниться индивидуальные значения.
Методы
Методы определяют поведение объектов:
public class Calculator {
// Метод без параметров и возврата значения
public void clear() {
// Код для сброса настроек калькулятора
}
// Метод с параметрами и возвратом значения
public int add(int a, int b) {
return a + b;
}
}
Run CodeКонструкторы
Конструкторы – это специальные методы, которые инициализируют новые объекты. Они имеют то же имя, что и класс, и не имеют возвращаемого типа:
public class Car {
String make;
String model;
int year;
// Конструктор по умолчанию
public Car() {
make = "Unknown";
model = "Unknown";
year = 2023;
}
// Параметризованный конструктор
public Car(String make, String model, int year) {
this.make = make;
this.model = model;
this.year = year;
}
}
Run Codethis
относится к текущему объекту и помогает отличить переменные экземпляра от параметров конструктора, если они имеют одинаковое имя.
Модификаторы доступа
Они определяют уровень доступа для классов, методов и полей. Существует 4 разновидности:
- Публичный (public): предоставляет неограниченный доступ из любого другого класса
- Частный (private): доступ возможен только в пределах одного класса
- Защищенный (protected): доступ для классов из того же пакета и всех подклассов
- По умолчанию (default): доступ возможен только в пределах одного пакета
public class BankAccount {
private double balance; // Доступ толкьо в пределах класса BankAccount
public void deposit(double amount) { // Неограниченный доступ
if (amount > 0) {
balance += amount;
}
}
protected void applyInterest() { // Доступ для класса из того же пакета и всех подклассов
balance *= 1.03;
}
}
Run CodeСоздание и инициализация объектов в Java
С помощью слова new
мы можем создавать объекты:
Car myCar = new Car("Honda");
Распределение памяти в Java
Когда вы создаете объект:
- Ссылка (например, myCar) находится в стеке.
- Данные объекта располагаются в куче.
- Ссылка указывает на адрес объекта в куче.
Это важно, потому что несколько ссылок могут ссылаться на один и тот же объект:
Car car1 = new Car("Ford");
Car car2 = car1; // Тот же объект
car2.model = "Chevy";
System.out.println(car1.model); // Вывод: Chevy
Run CodeРазница между классами и объектами
Проясним различия между классами и объектами с помощью сопоставительной таблички:
Аспект | Класс | Объект |
Определение | “шаблон” | Экземпляр класса |
Создание | Создается единожды | Из одного класса можно создать несколько объектов |
Распределение памяти | Загружается в память один раз | Под каждый объект выделена своя память |
Формат существования | Логическая конструкция (существует в коде), своего рода “идея” | “Физическая” сущность (существует в памяти во время выполнения программы), то есть материальное воплощение “идеи” |
Как объявить | public class ClassName { } | ClassName objectName = new ClassName(); |
Когда создается | Во время компиляции | Во время выполнения программы |
Содержимое | Поля, методы, конструкторы | Реальные данные |
Вот как в одном классе Car
можно создать несколько объектов с разными состояниями:
// Класс ("чертеж")
public class Car {
String make;
String model;
int year;
public Car(String make, String model, int year) {
this.make = make;
this.model = model;
this.year = year;
}
public void displayInfo() {
System.out.println(year + " " + make + " " + model);
}
}
// Создание различных объектов одного класса
Car sedan = new Car("Honda", "Accord", 2020);
Car suv = new Car("Toyota", "RAV4", 2021);
Car truck = new Car("Ford", "F-150", 2019);
// У каждого объетка своё состояние
sedan.displayInfo(); // Вывод: 2020 Honda Accord
suv.displayInfo(); // Вывод: 2021 Toyota RAV4
truck.displayInfo(); // Вывод: 2019 Ford F-150
Run CodeДоступ к элементам класса
После создания объектов необходимо знать, как работать с их полями и методами. В Java для этого используется оператор точка (.
):
Доступ к полям
Person person = new Person();
person.name = "John"; // Устанавливаем значение поля
System.out.println(person.name); // Получаем значение поля
Run CodeВызов методов
Calculator calc = new Calculator();
int result = calc.add(5, 3); // Вызов метода
System.out.println(result); // Вывод: 8
Run CodeПри работе с приватными полями (как и должно быть при инкапсуляции, то есть при объединении объектов с их свойствами и методами с возможностью ограничения доступа к ним) вам понадобятся методы доступа getter и setter:
public class Student {
private String name;
private double gpa;
// Getter method
public String getName() {
return name;
}
// Setter method
public void setName(String name) {
this.name = name;
}
public double getGpa() {
return gpa;
}
public void setGpa(double gpa) {
if (gpa >= 0 && gpa <= 4.0) { // Валидация
this.gpa = gpa;
} else {
System.out.println("Invalid GPA value");
}
}
}
Student student = new Student();
student.setName("Emma");
student.setGpa(3.8);
System.out.println(student.getName() + ": " + student.getGpa()); // Вывод: Emma: 3.8
Run CodeКонструкторы в классах Java
Конструкторы инициализируют объекты при их создании. Рассмотрим более подробно.
Конструктор по умолчанию
Если вы не определили ни одного конструктора, Java предоставит конструктор по умолчанию без параметров:
public class Book {
String title;
String author;
// Java неявно предоставит:
// public Book() { }
}
Book book = new Book(); // Использование дефолтного конструктора
Run CodeОднако, как только вы определите какой-либо конструктор, Java больше не будет предоставлять его по умолчанию:
public class Book {
String title;
String author;
public Book(String title) {
this.title = title;
this.author = "Unknown";
}
}
// Book book = new Book(); // Ошибка! Конструктор по умолчанию больше не доступен
Book book = new Book("Java Programming"); // Необходимо использовать определенный пользователем конструктор
Run CodeConstructor overloading
Constructor overloading – это наличие в одном классе нескольких конструкторов с разными параметрами:
public class Book {
String title;
String author;
int pages;
// Конструктор без параметров
public Book() {
title = "Untitled";
author = "Unknown";
pages = 0;
}
// Конструктор только с названием
public Book(String title) {
this.title = title;
author = "Unknown";
pages = 0;
}
// Конструктор со всеми полями
public Book(String title, String author, int pages) {
this.title = title;
this.author = author;
this.pages = pages;
}
}
Run CodeConstructor Chaining
Constructor Chaining – это процесс вызова одного конструктора из другого внутри того же класса или между родительским и дочерним классом. В первом случае можно использовать this()
, во втором – super()
:
public class Book {
String title;
String author;
int pages;
public Book() {
this("Untitled", "Unknown", 0);
}
public Book(String title) {
this(title, "Unknown", 0);
}
public Book(String title, String author) {
this(title, author, 0);
}
public Book(String title, String author, int pages) {
this.title = title;
this.author = author;
this.pages = pages;
}
}
Run CodeЭтот метод позволяет снизить степень дублирования кода и централизует логику инициализации.
Переменные и методы экземпляра
При работе с классами и объектами в Java важно понимать разницу между членами экземпляра (его переменными/методами, привязанными к объектам) и статическими членами (привязанными к классу):
Переменные экземпляра
У каждого объекта есть своя копия переменных экземпляра:
public class Dog {
String name; // Переменная экземпляра уникальна для каждого объекта Dog
public Dog(String name) {
this.name = name;
}
}
Dog dog1 = new Dog("Rex");
Dog dog2 = new Dog("Buddy");
System.out.println(dog1.name); // Вывод: Rex
System.out.println(dog2.name); // Вывод: Buddy
Run CodeИзменение переменной экземпляра в одном объекте не влияет на другие объекты:
dog1.name = "Max";
System.out.println(dog1.name); // Вывод: Max
System.out.println(dog2.name); // Вывод прежний: Buddy
Run CodeМетоды экземпляра
Методы экземпляра работают с конкретными объектами и имеют доступ к их переменным:
public class Counter {
private int count = 0;
public void increment() { // Метод экземпляра
count++;
}
public int getCount() { // Метод экземпляра
return count;
}
}
Counter c1 = new Counter();
Counter c2 = new Counter();
c1.increment();
c1.increment();
c2.increment();
System.out.println(c1.getCount()); // Вывод: 2
System.out.println(c2.getCount()); // Вывод: 1
Run CodeСтатические члены vs члены экземпляра
Статические члены принадлежат самому классу, а не объектам:
public class MathUtils {
// Статическая переменная - переменная, общая для всех объектов
public static final double PI = 3.14159;
// Переменная экземпляра уникальна для каждого объекта
private double result;
// Статический метод вызывается через класс
public static double square(double num) {
return num * num;
}
// Метод экземпляра требует объект
public void storeResult(double value) {
this.result = value;
}
}
// Статические члены вызываются через имя класса
double area = MathUtils.square(5) * MathUtils.PI;
// Членам экземпляра требуется объект
MathUtils utils = new MathUtils();
utils.storeResult(area);
Run CodeКлассы Java и концепции ООП
Классы и объекты Java составляют основу объектно-ориентированного программирования (ООП). Давайте посмотрим, как классы реализуют ключевые принципы ООП:
Инкапсуляция
Объединение и защита данных:
public class Wallet {
private double money;
public void addMoney(double amount) {
if (amount > 0) money += amount;
}
}
Run CodeНаследование
Классы могут наследовать свойства других классов:
public class Animal {
String species;
Animal(String species) { this.species = species; }
void eat() { System.out.println("Eating..."); }
}
public class Dog extends Animal {
Dog() { super("Canine"); }
@Override
void eat() { System.out.println("Dog eats kibble"); }
}
Run CodeПолиморфизм
Возможность работать с объектами как с экземплярами родительского класса:
Animal myDog = new Dog();
myDog.eat(); // Вывод: Dog eats kibble
Run CodeПродвинутые методы создания объектов
Хотя new
– это самый распространенный способ создания объектов, Java предлагает и другие методы:
Использование рефлексии
API рефлексии в Java позволяет создавать объекты динамически:
try {
// Получаем объект Class для нужного класса
Class carClass = Class.forName("com.example.Car");
// Создаем новый экземпляр с помощью конструктора без параметров
Object carObject = carClass.newInstance();
// Для новых версий Java:
// Object carObject = carClass.getDeclaredConstructor().newInstance();
// Приводим к нужному типу
Car car = (Car) carObject;
car.displayInfo();
} catch (Exception e) {
e.printStackTrace();
}
Run CodeЭто особенно полезно, когда во время компиляции неизвестно, какой именно класс нужно создать.
Клонирование объектов
Вы можете создать копию существующего объекта с помощью метода clone()
:
public class User implements Cloneable {
private String name;
private int age;
// Конструктор и другие методы...
@Override
public User clone() throws CloneNotSupportedException {
return (User) super.clone();
}
}
User originalUser = new User("John", 30);
try {
User clonedUser = originalUser.clone();
System.out.println(clonedUser.getName()); // John
} catch (CloneNotSupportedException e) {
e.printStackTrace();
Run CodeВажно: стандартный метод clone()
создает поверхностную копию (shallow copy). Для сложных объектов может потребоваться реализация глубокого копирования (deep cloning).
Распространенные ошибки
- Забыть инициализировать объекты:
Person person; // Объект объявлен, но не инициализирован
person.speak(); // NullPointerException!
Run Code- Путать статические члены и члены экземпляра:
public class Counter {
private int count;
public static void incrementCount() {
count++; // Ошибка! Не удается получить доступ к переменной экземпляра из статического метода
}
}
Run Code- Не понимать, что в Java используется только pass-by-value (передача по значению), но не pass-by-reference (передача по ссылке)
public void changeCar(Car car) {
car = new Car("New Car"); // Не влияет на оригинальную ссылку
}
Run Code- Прямой доступ к изменяемому полю:
public class Team {
public ArrayList players; // Прямой доступ к изменяемому полю - плохая практика
}
Run CodeПримеры хороших практик
- Инкапсуляция данных с помощью приватных полей и публичных геттеров/сеттеров:
private List players;
public List getPlayers() {
return new ArrayList<>(players); // Возвращает копию для сохранения инкапсуляции
}
Run Code- Инициализация всех переменных экземпляра:
private String name = ""; // Пустая строка вместо null
private List items = new ArrayList<>(); // Пустой список вместо null
Run Code- Использование осмысленных имен классов и переменных:
// Плохо
public class X {
private int y;
public void z() { }
}
// Хорошо
public class Customer {
private int accountNumber;
public void processPayment() { }
}
Run Code- Следование принципу единственной ответственности (Single Responsibility Principle): каждый класс должен иметь только одну причину для изменения. Разбивайте сложные классы на более мелкие и специализированные.
- По возможности отдавайте предпочтение композиции, а не наследованию:
// Вместо наследования:
class ElectricCar extends Car { }
// Лучше использовать композицию:
class Car {
private Engine engine; // Автомобиль содержит двигатель
}
Run CodeЧасто задаваемые вопросы о классах и объектах Java
- Класс vs объект: класс – это чертеж; объект – это построенная по нему вещь.
- Возможен ли класс без объектов? Да, например, служебные классы по типу Math.
- А если нет конструктора? Java добавляет его по умолчанию.
- Возможно реализовать несколько конструкторов? Да, с помощью constructor overloading.
- Что по модификаторам доступа? Используйте
private
для полей,public
для API. - Как запретить создание экземпляров? Используйте приватный конструктор.
Заключение
Классы и объекты – это фундамент программирования на Java, помогающий создавать организованный, удобный для многократного использования код. Классы и объекты обеспечивают структуру, необходимую для моделирования реальных объектов и эффективного решения сложных задач.
Главное – практика, практика и ещё раз практика!
Перевод статьи «Java Classes and Objects».
Еще полезные материалы по данной теме: «Создание объектов: детальное изучение»