public class Dog {
// Поля (состояние)
String name;
int age;
// Метод (поведение)
void bark() {
System.out.println(name + " says: Woof!");
}
}
// Создание объекта
Dog d = new Dog();
d.name = "Rex";
d.age = 3;
d.bark(); // Rex says: Woof!
public class Dog {
String name;
int age;
// Конструктор — вызывается при new
public Dog(String name, int age) {
this.name = name; // this — ссылка на текущий объект
this.age = age;
}
// Перегрузка конструктора
public Dog(String name) {
this(name, 0); // вызов другого конструктора
}
}
Dog d1 = new Dog("Rex", 3);
Dog d2 = new Dog("Buddy"); // age = 0
Конструктор по умолчанию — если не написать ни одного, Java сделает пустой Dog() {} сам. Если написал хоть один — дефолтный исчезает.
public class BankAccount {
private double balance; // снаружи не видно
public double getBalance() {
return balance;
}
public void deposit(double sum) {
if (sum > 0) balance += sum;
}
}
BankAccount acc = new BankAccount();
// acc.balance = 100; // ОШИБКА компиляции
acc.deposit(100); // OK
acc.getBalance(); // OK
public class Counter {
static int count = 0; // одно на всех, не на объект
public Counter() {
count++;
}
static void reset() { // вызывается через класс, не объект
count = 0;
}
}
Counter.count; // 0
new Counter();
new Counter();
Counter.count; // 2
Counter.reset();
Counter.count; // 0
Правило: static метод не может обращаться к нестатическим полям.
final int MAX = 100;
MAX = 200; // ОШИБКА — нельзя изменить
final class Locked {} // нельзя наследовать
class Base {
final void show() {} // нельзя переопределить в наследнике
}
public class Animal {
String name;
public Animal(String name) {
this.name = name;
}
public void speak() {
System.out.println(name + " makes a sound");
}
}
public class Cat extends Animal {
public Cat(String name) {
super(name); // конструктор родителя — обязателен первым
}
@Override
public void speak() {
System.out.println(name + " says: Meow!");
}
}
Animal a = new Cat("Whiskers");
a.speak(); // Whiskers says: Meow!
super — ссылка на родителя@Override — маркер переопределения, ловит опечатки// Нельзя создать объект — только наследовать
public abstract class Shape {
String color;
public void setColor(String c) { this.color = c; }
// Без реализации — наследник ОБЯЗАН написать
public abstract double area();
}
public class Circle extends Shape {
double radius;
public Circle(double radius) { this.radius = radius; }
@Override
public double area() {
return Math.PI * radius * radius;
}
}
Shape s = new Circle(5);
s.area(); // 78.53...
// new Shape(); // ОШИБКА
public interface Printable {
void print(); // абстрактный по умолчанию
default void printTwice() { // default — есть реализация
print();
print();
}
}
public interface Saveable {
void save();
}
// Можно реализовывать несколько!
public class Document implements Printable, Saveable {
@Override
public void print() { System.out.println("Printing..."); }
@Override
public void save() { System.out.println("Saving..."); }
}
Интерфейс vs Абстрактный класс:
- Интерфейс: контракты, нет полей состояния, несколько сразу
- Абстракт: поля + реализация, только один родитель
Animal[] animals = {new Cat("Kitty"), new Dog("Rex")};
for (Animal a : animals) {
a.speak(); // каждый говорит по-своему
}
// Проверка типа
Animal a = new Cat("Kitty");
// Старый способ
if (a instanceof Cat) {
Cat c = (Cat) a;
c.purr();
}
// Java 16+ — сразу с переменной
if (a instanceof Cat c) {
c.purr();
}
public class Point {
int x, y;
public Point(int x, int y) { this.x = x; this.y = y; }
@Override
public String toString() {
return "Point(" + x + ", " + y + ")";
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Point)) return false;
Point p = (Point) o;
return x == p.x && y == p.y;
}
}
System.out.println(new Point(1, 2)); // Point(1, 2)
new Point(1, 2).equals(new Point(1, 2)); // true