Java является объектно-ориентированным языком, поэтому такие понятия как "класс" и "объект" играют в нем ключевую роль. Любую программу на Java можно представить как набор взаимодействующих между собой объектов.
Шаблоном или описанием объекта является класс, а объект представляет экземпляр этого класса. Можно еще провести следующую аналогию. У нас у всех есть некоторое представление о человеке - наличие двух рук, двух ног, головы, туловища и т.д. Есть некоторый шаблон - этот шаблон можно назвать классом. Реально же существующий человек (фактически экземпляр данного класса) является объектом этого класса.
В принципе ранее уже использовались классы. Например, в предыдущих темах мы определяли класс Program, в котором определялся весь остальной код приложения. Например:
class Program{
public static void main(String[] args) {
System.out.println("Hello METANIT.COM");
}
}
Здесь у нас класс Program, в котором определен метод main, и этот метод выводит на консоль некоторое сообщение. Для вывода на консоль мы используем еще один класс - System.
Теперь же посмотрим, как мы можем определять и использовать другие классы.
Класс определяется с помощью ключевого слова сlass, после которого идет название класса:
class имя_класса{
}
Название класса подчиняется тем же правилам, что и названия переменных. Но в целом в Java есть условность, что обычно названия классов начинаются с большой буквы.
После названия класса идут фигурные скобки, между которыми помещается тело класса - то есть его компоненты (поля и методы).
Например, определим класс, который назовем Person:
// класс Program
class Program{
public static void main(String[] args) {
}
}
// класс Person
class Person{ }
После имени класса Person идут пустые фигурные скобки, то есть класс Person не имеет никаких компонентов. Стоит отметить, что, как правило, классы определяются в разных файлах, но в данном случае для простоты мы определяем два класса в одном файле.
Классы в Java представляют отдельные типы данных. И когда мы определяем новый класс, который даже ничего не делает и не имеет никакого содержимого, то фактически мы определяем новый тип данных. И как в случае со стандартными и уже имеющимися в Java типами данных мы можем определить переменные этого типа. Например:
class Program{
public static void main(String[] args) {
Person tom; // определяем переменную класса Person
}
}
// класс Person
class Person{ }
В данном случае в методе main класса Program определена переменная типа Person, которая называется "tom". Пока такая переменная не имеет никакого значения, то есть она не инициализирована. По большому счету мы ее пока не можем использовать, поэтому вначале необходимо создать объект класса Person.
Для создания объекта применяются конструкторы. По сути конструкторы представляют специальные методы, которые называются так же как и класс, и которые вызываются при создании нового объекта класса и выполняют инициализацию объекта. Общий синтаксис вызова конструктора:
new конструктор_класса(параметры_конструктора);
Сначала идет оператор new, который выделяет память для объекта, а после него идет вызов конструктора.
Если в классе не определено ни одного конструктора (как в случае с нашим пустым классом Person), то для этого класса автоматически создается пустой конструктор по умолчанию, который не принимает никаких параметров. Поэтому применим конструктор по умолчанию для создания объекта класса Person:
class Program{
public static void main(String[] args) {
Person tom = new Person(); // создание объекта класса Person
}
}
// класс Person
class Person{ }
Для создания объекта Person используется выражение new Person(). В итоге после выполнения данного выражения в памяти будет выделен участок, где будут храниться все данные объекта Person. А переменная tom получит ссылку на созданный объект, и через эту переменную мы можем использовать данный объект и обращаться к его функциональности.
Но пока в классе Person мы не определили никакой функциональности, тем не менее Java позволяет нам вывести объект на консоль:
class Program{
public static void main(String[] args) {
Person tom = new Person(); // создание объекта класса Person
System.out.println(tom); // выводим объект tom на консоль
}
}
// класс Person
class Person{ }
В данном случае Java выводит на консоль некоторое текстовое представление объекта типа "Person@1dbd16a6".
Любой объект может обладать двумя основными характеристиками: состояние - некоторые данные, которые хранит объект, и поведение - действия, которые может совершать объект.
Для хранения состояния объекта в классе применяются поля или переменные класса.
Например, выше мы определили пустой класс Person. Добавим в него поля. Что за поля мы будем в него добавлять? Класс Person у нас будет представлять некоторого человека. У человека же мы можем выделить такие признаки как имя и возраст (при желании можно выделить и больше признаков). Поэтому добавим для этих признаков в класс поля:
class Person{
String name; // имя
int age; // возраст
}
Поле name представляет имя человека и представляет строку, а age - его возраст и представляет число.
Для обращения к функциональности класса - полям, методам (а также другим элементам класса) применяется точечная нотация точки - после объекта класса ставится точка, а затем элемент класса::
объект.поле_класса объект.метод_класса(параметры_метода)
Например, обратимся к полям объекта Person::
class Program{
public static void main(String[] args) {
Person tom = new Person(); // создание объекта класса Person
// получаем значения полей
System.out.println(tom.name); // null
System.out.println(tom.age); // 0
// устанавливаем новые значения полей
tom.name = "Tom";
tom.age = 41;
// повторно получаем значения полей
System.out.println(tom.name); // Tom
System.out.println(tom.age); // 41
}
}
// класс Person
class Person{
String name;
int age;
}
Для обращения к полю name объекта tom применяется выражение tom.name, а для обращения к полю age - выражение tom.age. В программе мы сначала получаем значение полей и выводим их на консоль:
System.out.println(tom.name); System.out.println(tom.age);
А затем устанавливаем их значения. Так, полю name передаем строку, поскольку это поле представляет тип String, а полю age передаем число, так как оно представляет целочисленный тип int. В итоге мы получим следующий консольный вывод программы:
null 0 Tom 41
Если мы посмотрим на вывод предыдущей программы, то увидим, что до присвоения значения полям они принимают некоторые значения по умолчанию.
Если полю класса явным образом не присваивается значение, то ему автоматически будет присвоено значение по умолчанию: числам — 0, логическим значениям — false, а ссылкам на объекты (например, строкам) —
null. В этом состоит важное различие между полями и локальными переменными: локальные переменные в методе необходимо явно инициализировать, тогда как в классе,
если вы не инициализируете поле, оно автоматически инициализируется значением по умолчанию (0, false или null).
ОДнако поля можно явным образом инициализировать некоторыми значениями. Например:
class Program{
public static void main(String[] args) {
Person tom = new Person();
System.out.println(tom.name); // Undefined
System.out.println(tom.age); // 1
}
}
// класс Person
class Person{
String name = "Undefined";
int age = 1;
}
Подобным образом мы можем создавать большее количество объектов. Например:
class Program{
public static void main(String[] args) {
Person tom = new Person();
Person bob = new Person();
// устанавливаем новые значения полей объекта tom
tom.name = "Tom";
tom.age = 41;
// устанавливаем новые значения полей объекта bob
bob.name = "Bob";
bob.age = 46;
// получаем значения полей объекта tom
System.out.println(tom.name); // Tom
System.out.println(tom.age); // 41
// получаем значения полей объекта bob
System.out.println(bob.name); // Bob
System.out.println(bob.age); // 46
}
}
// класс Person
class Person{
String name;
int age;
}
Здесь создается два объекта класса Person - tom и bob. Для каждого из этих объектов будет выделяться своя область в памяти, и каждый из этих объектов будет иметь свой набор полей name и age.