Лекция 03. Основы классов¶
Классы и объекты¶
Основы¶
Классы и объекты¶
Пример описания класса:
class Point {
int x, y; // экземплярные переменные
Point() { // конструктор
x=0; y=0;
}
Point (int x1,int y1) { // конструктор
x=x1; y=y1;
}
int getX() {return x;}
int getY() {return y;}
}
Пример создания экземпляра класса и ссылки на него:
Point p1 = new Point();
Point p2 = p1;
Класс Коробка:
class Box {
int width; // ширина коробки
int height; // высота коробки
int depth; // глубина коробки
// Конструктор
Box(int w,int h,int d) {
width = w;
height = h;
depth = d;
}
// вычисляем объём коробки
int getVolume() {
return width * height * depth;
}
}
Hello world¶
Еще одна версия Hello, world!. Создаем экземпляр класса, внутри которого объявлен main.
public class GreetHW
{
String text="Hello, world!";
void print() {
System.out.println(text);
}
public static void main(String[] args) {
GreetHW greet=new GreetHW();
greet.print();
}
}
Статические переменные¶
Объявление: static <type> <name>
Обращение: <classname>.<varname>
- создаются в единственном экземпляре;
- существуют вне зависимости от объектов класса;
- создаются JVM в момент первого обращения к классу;
- допускают обращение до создания объектов класса;
Статические методы¶
Статические методы:
- могут вызывать только другие статические методы
- должны обращаться только к статическим переменным
- внутри статических методов нельзя использовать ссылки this и super
Статический блок¶
Объявление:
static
{
// ....
}
Статический блок кода выполняется один раз при первоначальной загрузке класса
public class Fruits {
static String[] list = new String[3];
static {
list[0]="Apple";
list[1]="Orange";
list[2]="Banana";
}
public static void main(String[] args) {
for(int i=0;i<list.length;i++)
System.out.println(list[i]);
}
}
Использование this¶
Указатель на экземпляр this может использоваться для вызова одного конструктора из другого
public class Rectangle
{
private int x, y, width, height;
public Rectangle() {
this(0, 0, 0, 0);
}
public Rectangle(int width, int height) {
this(0, 0, width, height);
}
public Rectangle(int x, int y, int width, int height) {
this.x = x; this.y = y;
this.width = width; this.height = height;
}
}
Управление доступом¶
В Java используется похожая на С++ модель разграничения доступа к элементам классов.
Тем не менее, у нее есть ряд отличий:
- Спецификатор доступа пишется перед каждым элементом класса;
- Отсутствие спецификатора перед элементом тоже задает уровень доступа.
Правила доступа сведены в следующую таблицу:
Пользователь | Private | Отсутствие | Protected | Public |
Один и тот же класс | Yes | Yes | Yes | Yes |
Подкласс класса того же пакета | No | Yes | Yes | Yes |
Класс пакета | No | Yes | Yes | Yes |
Подкласс класса из другого пакета | No | No | Yes | Yes |
Класс другого пакета | No | No | No | Yes |
Пакеты¶
- В первой строке файла может быть 1 необязательный оператор package.
- В следующих строках может быть 1 или несколько необязательных операторов import- Далее идут описания классов и интерфейсов.
- Среди классов, описанных в одном файле, только один может быть объявлен с модификатором public.
Свойства пакетов:
- Каждый пакет предоставляет уникальное пространство имен для своего содержимого.
- Допустимы вложенные пакеты.
Рассмотрим процесс разработки пакета для работы с простыми числами Prime.
package Prime;
public class Prime {
public static boolean testPrime(int value) {
boolean isprime=true;
for(int i=2;i*i<=value;i++)
if(value%i==0) {
isprime=false;
break;
}
return isprime;
}
public static int nextPrime(int begin) {
while(!testPrime(++begin));
return begin;
}
public static int nPrime(int begin,int num) {
while(num>0) {
while(!testPrime(++begin));
num--;
}
return begin;
}
}
Добавим в пакет еще один файл с классом Factorization:
package Prime;
public class Factorization
{
public static void factorIt(int n) {
for(int i=2;i*i<=n;i++) {
if(n % i==0) {
System.out.print(" "+i);
n/=i;
}
}
System.out.println();
}
}
Оба файла Prime.java и Factorization.java помещаем в каталог Prime.
Демо-файл (класс), использующий пакет Prime:
import Prime.*;
public class Demo
{
public static void main(String[] args) {
for(int i=1;i<15;i++)
System.out.println(Prime.nPrime(1,i));
Factorization.factorIt(123456);
}
}
Структура проекта:
.
├── Demo.class
├── Demo.java
└── Prime
├── Factorization.class
├── Factorization.java
├── Prime.class
└── Prime.java
При вложенности пакетов имена разделяют точкой, а структура каталогов на диске соответствует вложениям.
anton.alg.Prime -> anton/alg/Prime
Перечисления¶
enum Season
{
WINTER, SPRING, SUMMER, AUTUMN
}
..
Season season = Season.SPRING;
if (season == Season.SPRING) {
season = Season.SUMMER;
}
System.out.println(season);
Объявляя enum, мы неявно создаем класс, производный от java.lang.Enum
Конструкция
enum Season { }
эквивалентна
class Season extends java.lang.Enum { }
Явным образом наследоваться от java.lang.Enum не позволяет компилятор, но:
System.out.println(Season.class.getSuperclass());
дает вывод:
class java.lang.Enum
Класс, созданный компилятором для реализации перечисления – enum-класс, а возможные значения перечисляемого типа – элементы enum.
Элементы перечисления - экземпляры enum-класса, доступные статически.
Их статическая доступность позволяет нам выполнять сравнение с помощью оператора сравнения ссылок.
Season season = Season.SUMMER;
if (season == Season.AUTUMN)
season = Season.WINTER;
Любой enum-класс наследует java.lang.Enum, который содержит ряд методов полезных для всех перечислений.
Пример:
Season season = Season.WINTER;
System.out.println("season.name()=" + season.name() +
" season.toString()=" + season.toString() +
" season.ordinal()=" + season.ordinal());
Вывод:
season.name()=WINTER
season.toString()=WINTER
season.ordinal()=0
Задача: получить элемент enum по его строковому представлению.
Решение: В каждом enum-классе компилятор автоматически создает специальный статический метод:
public static EnumClass valueOf(String name)},
который возвращает элемент перечисления EnumClass с названием, равным name.
Пример использования:
String name = "WINTER"; Season season = Season.valueOf(name);
Результат: переменная season будет равна Season.WINTER
Если элемент не будет найден, то будет выброшен IllegalArgumentException, а если name равен null -
NullPointerException.
Иногда необходимо получить список всех элементов enum-класса во время выполнения. Для этих целей в каждом enum-классе компилятор
создает метод:
public static EnumClass[ ] values()
Пример использования:
System.out.println(Arrays.toString(Season.values()));
Вывод:
[WINTER, SPRING, SUMMER, AUTUMN]
Обратите внимание, что ни метод valueOf(), ни метод
values() не определен в классе java.lang.Enum.
Вместо этого они автоматически добавляются компилятором на этапе
компиляции enum-класса.
Методы с переменным числом аргументов¶
Для указания аргумента переменной длины используют три точки (...).
Например:
static void vaTest(int ... v) { … }
Эта синтаксическая конструкция указывает компилятору, что метод vaTest () может вызываться с нулем или более аргументов.
В результате v неявно объявляется как массив типа int [ ]. Таким образом, внутри метода vaTest () доступ к v
осуществляется с использованием синтаксиса обычного массива.
class VarArgs
{
static void vaTest(int ... v) {
System.out.println("Кол-во аргументов: " + v.length);
for (int i=0;i<v.length;i++) {
System.out.print (v[i] + " ");
}
public static void main(String args[]) {
vaTest (10); //1 аргумент
vaTest (1, 2, 3); //3 аргумента
vaTest (); // без аргументов
}
}
Вместе с параметром переменной длины массив может содержать обычные параметры. Однако параметр переменной длины должен быть последним
параметром, объявленным методом.