- Абстракция
- Инкапсуляция
- Наследование
- Полиморфизм
package org.stepic.java; // Принадлежность класса пакету
public class HelloWorld {
// ...
}
Полное имя класса из примера выше: org.stepic.java.HelloWorld
.
В отсутствие директивы принадлежность пакету класс принадлежит пакету по умолчанию.
Классы того же пакета могут ссылаться друг на друга по короткому имени. Классы разных пакетов должны ссылаться друг на друга по полному имени или использовать импорт:
import org.stepic.java.HelloWorld;
import java.util.*;
Используется для импорта статических полей и методов:
import static java.lang.Math.sqrt;
import static java.lang.System.out;
java.lang
java.io
java.nio
java.math
java.time
java.util
java.util.regex
javax.xml
...
org.stepik.java
com.google.common
org.apache.maven
com.intellij.idea
net.sf.json
io.netty
...
public class ModifiedDemo {
public static void visibleEverywhere() {}
protected static void inSubclasses() {}
static void inPackage() {}
private void inClass() {}
}
public
- разрешен доступ отовсюду без ограниченийprotecterd
- доступ разрешен только для классов наследников и для классов текущего пакета- отсутствие модификатора - доступ только в пределах пакета
private
- доступ только в пределах класса
protected
и pivate
не пременимы к классам верхнего уровня.
package java.lang;
public final class Integer {}
В файле может быть только один public класс. Ключевое слово final в объявлении класса означает что от данного класса нельзя наследоваться.
package java.lang;
public final class Integer {
private final int value;
}
Модификатор final у поля означает что полю можно присвоить значение только один раз, после чего изменения будут запрещены.
package java.lang;
public final class Integer {
private final int value;
public Integer(int value) {
this.value = value;
}
}
Без объявления конструктора в классе будет создан конструктор по умолчанию. Запрет на создание экземпляров класса:
package java.lang;
public final class Math {
private Math() {}
}
В классе может быть несколько конструкторов с разными параметрами:
package java.math;
public class BigInteger {
public BigInteger(String val) {
this(val, 10); // Вызов другого конструктора
}
public BigInteger(String val, int radix) {}
}
Для реализации деструктора стоит завести отдельный метод close и вызвать его самостоятельно:
package java.io;
public class FileInputStream {
protected void finalize() {
// Auto cleanup
}
public void close() {}
}
package java.lang;
public final class Integer {
private final int value;
public int intValue() {
return value;
}
}
Модификатор final у метода означает что данный метод не может быть переопределен в классах-наследниках.
В классе может быть несколько методов с одинаковыми именами, но разным набором параметров:
package java.lang;
public final class String {
public int indexOf(int ch) {
return indexOf(ch, 0);
}
public int indexOf(int ch, int fromIndex) {}
}
package java.lang;
public final class Integer {
public static final int MIN_VALUE = 0x80000000; // Константа
public static int rotateRight(int i, int distance) {
return (i >>> distance) | (i << -distance);
}
}
package java.util;
public class ArrayList<E> {
Object[] elementData;
public Iterator<E> iterator() {
return new Itr();
}
private class Itr implements Iterator<E> {
int cursor;
}
}
Вложенный класс, объявленный с модификатором static
теряет возможность обращаться к нестатическим членам внешнего класса.
public class BadExample {
public static final int MONDAY = 1;
public static final int TUESDAY = 1;
public static final int WEDNESDAY = 1;
public static final int THURSDAY = 1;
public static final int FRIDAY = 1;
public static final int SATURDAY = 1;
public static final int SUNDAY = 1;
}
Пример с перечислением:
package java.time;
public enum DayOfWeek {
MONDAY, // public static final
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY,
SATURDAY,
SUNDAY
// Дальше можно объявлять поля и методы как в обычном классе
// Можно создать конструктор и передавать аргументы в элементы выше
}
Методы:
for (DayOfWeek day : DayOfWeek.values()) {
System.out.println(day.ordinal() + " " + day.name());
}
name()
- возвращает строку - имя элемента как в исходном кодеordinal()
- возвращает число - порядковый метод элемента перечисления, начиная с нуляvalues()
- озвращает массив возможных элементов перечисления
package java.lang;
public final class Character {
@Deprecated
public static boolean isJavaLetter(char c) {}
@SuppressWarnings("unchecked")
public static final Class<Character> TYPE = (Class<Character>) Class.getPrivitiveClass("char");
}
Пример с геометрическими фигурами: gitgist.
Унаследоваться можно только от одного класса.
package java.lang;
public final class BigDecimal extends Number {
public int intValue() {}
// No shortValue() method,
// it's inherited from Number
}
Возвращаемое значени подкласса должно быть того же класса что и оригинал или быть его подкласса.
package java.lang;
public final class StringBuilder extends AbstractStringBuilder {
@Override
public StringBuilder append(String str) {}
// Base method in AbstractStringBuilder:
// AbstractStringBuilder append(String str)
}
Создание экземпляра класса наследника всегда включает вызов конструктора родителя. Если у конструктора нет параметров, то компилятор сам подставит вызов родительского конструктора первой строчкой в конструктор наследника, в противном случае нужно сделать все это руками:
package java.lang;
public final class StringBuilder extends AbstractStringBuilder {
public StringBuilder() {
super(16);
}
@Override
public StringBuilder append(String str) {
super.append(str); // Вызов оригинального метода
return this;
}
}
Использование ключевого слова super
разрешено только к теле класса наследника.
package java.lang;
public final class String /* extends object */ {}
Если S является подтипом T, то все объекты базового класса T в программе могут быть заменены на объекты класса S, без изменения каких-либо желательных свойств программы. Другими словами поведение подтипов не должно противоречить поведению базового класса.
Класс может соответствовать и абстрактному понятию. Для выражения этой концепции используется ключевое слово
abstract
:
public abstract class Shape {
private final Color color;
public Shape(Color color) {
this.color = color;
}
public Color getColor() {
return color;
}
public double getArea() {
return Double.NaN;
}
}
Для абстрактного класса нельзя создавать экземпляры. У абстрактного класса могут быть абстрактные методы (без реализации):
public abstract class Shape {
...
public abstract double getArea();
Альтернатива абстрактному классу, в котором все методы публичные и абстрактные.
public interface OrderService {
Order[] getOrdersByClient(long clientId);
}
Для обратной совместимости в интерфейсы добавлена возможность реализации default-методов:
package org.stepic.java.orders;
import java.time.LocalDate;
public interface OrderService {
Order[] getOrdersByClient(long clientId);
// Добавление этого метода сломает компиляцию в унаследованных классах, где не будет его реализации
// Order[] getOrdersByClient(long clientId, LocalDate date);
// Будет использоваться для классов наследников, где не переопределен
default Order[] getOrdersByClient(long clientId, LocalDate date) {
Order[] allOrders = getOrdersByClient(clientId);
return Orders.filterByDate(allOrders, date);
}
}
Реалиация интерфейса:
public class OrderServiceImpl
extends ServiceBase
implements OrderService {
public Order[] getOrdersByClient(long clientId) {
...
}
}
В стандартной библиотеки присутствует большое число интерфейсов.
Интерфейс с единственным абстрактным методом:
package java.lang;
@FunctionalInterface
public interface Comparator<T> {
int compare(T o1, T o2);
}
Пример использования:
package org.stepic.java.timer;
public class Timer {
public long measureTime(Runnable runnable) {
long startTime = Sytem.currentTimeMillis();
runnable.run();
return System.currentTimeMillis() - startTime();
}
Главная программа:
package org.stepic.java.timer;
import java.math.BigDecimal;
public class Main {
public static void main(String[] args) {
Timer timer = new Timer();
long time = timer.measureTime(new BigDecimalPower());
System.out.println(time);
}
private static class BigDecimalPower implements Runnable {
@Override
public void run() { new BigDecimal("1234567").pow(10000); }
}
}
Упрощенно с ссылкой на метод:
public class Main {
public static void main(String[] args) {
Timer timer = new Timer();
long time = timer.measureTime(Main::bigDecimalPower);
System.out.println(time);
}
private static void bigDecimalPower {
new BigDecimal("1234567").pow(10000);
}
}
Упрощенно с lambda:
public class Main {
public static void main(String[] args) {
Timer timer = new Timer;
long time = timer.measureTime(() -> new BigDecimal("1234567").pow(10000));
System.out.println(time);