Введение
В предыдущих статьях я уже несколько раз упоминал наследование. Настало время написать подробную статью про эту вещь.
В Java класс может наследоваться от другого класса, получая его методы и поля, который в свою очередь может наследоваться от ещё одного класса и т. д. В Java нет множественного наследования классов. Один класс может наследоваться напрямую только от одного другого класса.
Класс, который наследуется от другого класса, называется подклассом (subclass), дочерним классом (child class), потомком или расширенным классом (extended class).
Класс, от которого наследуется дочерний класс, называется родительским классом (parent class), предком, суперклассом (superclass) или базовым классом (base class).
В самой вершине иерархии наследования находится класс
Object , от которого наследуются все классы, для которых не указан явно суперкласс. Таким образом все классы (кроме самого
Object ) напрямую или через какое-либо количество уровней наследования наследуются от класса
Object.
Идея наследования классов состоит в том, что когда вы хотите создать новый класс, например
Goblin , и уже существует какой-нибудь класс, который уже реализует часть функциональности, необходимой нашему классу, например
Monster , то вы можете указать этот класс в качестве родительского класса, унаследовав таким образом все его члены (поля, вложенные классы и методы экземпляров). Конструкторы не наследуются и не являются членами классов, но можно вызвать конструктор базового класса из конструктора дочернего класса.
Дочерний класс наследует все
public и
protected члены своего родителя независимо от пакета, в котором расположен родительский класс. Если дочерний и родительский класс находятся в одном пакете, то дочерний класс наследует также package-private члены своего родителя.
- Унаследованные поля можно использовать напрямую, как все другие поля.
- Можно объявить в дочернем классе поле с таким же именем, как и поле в родительском классе, тогда это поле скроет (hide) поле родительского класса (НЕ рекомендуется так делать).
- В дочернем классе можно объявлять поля, которых нет в родительском классе.
- Унаследованные методы можно использовать напрямую.
- Можно объявить метод экземпляров в дочернем классе с точно такой же сигнатурой, что и метод экземпляров в родительском классе, тогда этот метод переопределит (override) метод суперкласса.
- Можно объявить в дочернем классе статический метод с точно такой же сигнатурой, что и статический метод в родительском классе, тогда этот метод скроет (hide) метод родительского класса.
- В дочернем классе можно объявлять новые методы, которых нет в родительском классе.
- В дочернем классе можно объявить конструктор, который будет явно (с помощью ключевого слова
super ) или неявно вызывать конструктор базового класса.
Дочерний класс не наследует
private члены родительского класса, однако если в родительском классе есть
protected ,
public или package-private (для случая нахождения дочернего и родительского класса в одном пакете) методы для доступа к
private полям, то они могут использоваться дочерним классом.
Конвертировать с использованием StringBuffer или StringBuilder
StringBuilder и StringBuffer – это классы, используемые для объединения нескольких значений в одну строку. StringBuffer является потокобезопасным, но медленным, тогда как StringBuilder не является поточно-ориентированным, но работает быстрее.
Пример 1
class Method5 { public static void main(String args[]) { int number1 = -1234; StringBuilder sb = new StringBuilder(); sb.append(number1); String str1 = sb.toString(); System.out.println("With StringBuilder method: string = " + str1); StringBuffer SB = new StringBuffer(); SB.append(number1); String str2 = SB.toString(); System.out.println("With StringBuffer method: string = " + str2); } }
Вывод
With StringBuilder method: string = -1234 With StringBuffer method: string = -1234
Объект StringBuilder представляет объект String, который можно изменять и обрабатывать как массив с последовательностью символов. Чтобы добавить новый аргумент в конец строки, экземпляр StringBuilder реализует метод append().
Пример 2
class Method6 { public static void main(String args[]) { String str1 = new StringBuilder().append(1234).toString(); System.out.println("With StringBuilder method: string = " + str1); String str2 = new StringBuffer().append(1234).toString(); System.out.println("With StringBuffer method: string = " + str2); } }
Вывод
With StringBuilder method: string = -1234 With StringBuffer method: string = -1234
Наиболее важным является вызов метода toString(), чтобы получить строковое представление данных.
взаимное преобразование INT и Чара
Во введении, мы можем видеть, чтоТип представляет собой тип данных, 32-битный, потому что его бит имеет число символов, так что диапазон значений: -2 ^ 31 до 2 ^ 31 — 1.
и16-битовые данные не является число символов, его диапазон: от 0 до 2 ^ 32 -1, 0 — 65535, с шестнадцатеричным кодом, это: ‘\ u0000’ — ‘\ uffff’.
Из предыдущего введения, мы можем видеть , что ни какие символы материи, в компьютере, также хранится в виде чисел ( в основном один бинарный), так и в Java, независимо от того , один символа или переменной символьного типа, тот факт , также номер, так что вы можете непосредственно присвоить значение переменной CHAR непосредственно на номер (не более, чем диапазон полукокса), вы можете вывести его результаты:
Выход:
Можно видеть, что символы, соответствующие ASCII код 97 выводится правильно: «A».
Точно так же мы можем присвоить символ переменной Int, потому что символы также ряд.
Выход:
Даже, можно вычислить число с символом в выражении:
Выход:
Поскольку код, соответствующий ASCII-символа «B» 98, 97 больше, чем «а», так что после добавления «A», это символ «B». В то же время, тип INT NUM2 непосредственно применяет его, или может быть получен желаемый «б».
Класс GregorianCalendar
GregorianCalendar является конкретной реализацией класса Calendar, который отображает обычный григорианский календарь, с которым Вы знакомы. Мы не обсуждали класс Calendar в этом учебнике, для этого Вы можете посмотреть стандартную документацию Java.
Метод getInstance() Calendar возвращает GregorianCalendar, который инициализирован по умолчанию текущей датой и временем, локализацией и часовым поясом. GregorianCalendar определяет два поля: н. э и до н. э. Они представляют собой две эпохи, которые определяются по григорианскому календарю.
Существует несколько конструкторов для объектов GregorianCalendar:
№ | Конструктор и его описание |
1 | GregorianCalendar()Создает значение GregorianCalendar, используя по умолчанию текущей датой и временем, локализацией и часовым поясом. |
2 | GregorianCalendar(int year, int month, int date)Создает GregorianCalendar в соответствии с заданной датой в часовом поясе и локализацией по умолчанию. |
3 | GregorianCalendar(int year, int month, int date, int hour, int minute)Создает GregorianCalendar в соответствии с заданной датой и временем в часовом поясе и локализацией по умолчанию. |
4 | GregorianCalendar(int year, int month, int date, int hour, int minute, int second)Создает GregorianCalendar в соответствии с заданной датой и временем в часовом поясе и локализацией по умолчанию. |
5 | GregorianCalendar(Locale aLocale)Создает GregorianCalendar в соответствии с текущим временем в часовом поясе по умолчанию в рамках заданной локализации. |
6 | GregorianCalendar(TimeZone zone)Конструирует GregorianCalendar, основанный на текущем времени в данной зоне времени с локализацией по умолчанию. |
7 | GregorianCalendar(TimeZone zone, Locale aLocale)Конструирует GregorianCalendar, основанный на текущем времени в заданном часовом поясе и локализации. |
Список нескольких полезных методов, предоставляемых классом GregorianCalendar:
№ | Методы с описанием |
1 | void add(int field, int amount)Добавляет указанное количество времени в данное временное поле в соответствии с правилами календаря. |
2 | protected void computeFields()Преобразует время по Гринвичу в миллисекунды до значения полей времени. |
3 | protected void computeTime()Преобразует значения временного поля Календаря в UTC формате в миллисекундах. |
4 | boolean equals(Object obj)Сравнивает этот GregorianCalendar эталонным объектом. |
5 | int get(int field)Получает значение для поля заданного времени. |
6 | int getActualMaximum(int field)Возвращает максимальное значение, которое это поле может иметь, учитывая текущую дату. |
7 | int getActualMinimum(int field)Возвращает минимальное значение, которое это поле может иметь, учитывая текущую дату. |
8 | int getGreatestMinimum(int field)Возвращает наибольшее минимальное значение для данного поля, если изменяется. |
9 | Date getGregorianChange()Получает изменения даты по григорианскому календарю. |
10 | int getLeastMaximum(int field)Возвращает минимально максимальное значение для данного поля, если изменяется. |
11 | int getMaximum(int field)Возвращает максимальное значение для данного поля. |
12 | Date getTime()Определяет текущее время в соответствии с календарем. |
13 | long getTimeInMillis()Получает текущее время по Календарю как длительное. |
14 | TimeZone getTimeZone()Возвращает часовой пояс. |
15 | int getMinimum(int field)Возвращает минимальное значение для данного поля. |
16 | int hashCode()Переопределите хэш-код. |
17 | boolean isLeapYear(int year)Определяет, является ли год високосным. |
18 | void roll(int field, boolean up)Добавление или вычитание (вверх/вниз) одной единицы времени в данном временном поле без изменений в больших полях. |
19 | void set(int field, int value)Устанавливает временное поле с заданным значением. |
20 | void set(int year, int month, int date)Задает значения для поля год, месяц и дата. |
21 | void set(int year, int month, int date, int hour, int minute)Задает значения для поля год, месяц, дату, час и минуту. |
22 | void set(int year, int month, int date, int hour, int minute, int second)Задает значения для поля год, месяц, дату, час, минуту и секунду. |
23 | void setGregorianChange(Date date)Устанавливает дату изменения грегорианского календаря. |
24 | void setTime(Date date)Устанавливает в соответствии с данным календарем текущее время с заданной датой. |
25 | void setTimeInMillis(long millis)Устанавливает в соответствии с данным календарем текущее время от заданного long значения. |
26 | void setTimeZone(TimeZone value)Задает часовой пояс со значением заданного часового пояса. |
27 | String toString()Возвращает строковое представление календаря. |
Символы (тип char)
Для хранения символов Java использует специальный тип char. Он отличается от типа char в языках C/C++, где представляет собой целочисленный тип с размером 8 бит. В Java для char используется кодировка Unicode и для хранения Unicode-символов используется 16 бит или 2 байта. Диапазон допустимых значений — от 0 до 65536 (отрицательных значений не существует).
Из примера выше видно, что переменной можно присвоить код символа или непосредственно сам символ, который следует окружить одинарными кавычками. Попробуйте запустить пример и посмотреть, какое слово получится из трёх указанных символов.
Не следует путать символ ‘a’ со строкой «a», состоящей из одного символа. На экране монитора они выглядят одинаково, но в программах ведут себя по разному.
Стандартные символы ASCII можно выводить сразу. Если нужно вывести специальный символ из Unicode, то можно воспользоваться шестнадцатеричным представлением кода в escape-последовательности — вы указываете обратную наклонную черту и четыре цифры после u. Например:
Хотя тип char используется для хранения Unicode-символов, его можно использовать как целочисленный тип, используя сложение или вычитание.
В результате получим:
Если вы думаете, что увеличив значение переменной ch1 ещё на одну единицу, получите символ «й», то глубоко заблуждаетесь.
Чтобы узнать, какой символ содержится в значении переменной, заданной как int, можно воспользоваться двумя специальными методами из класса EncodingUtils:
Для стандартных символов ASCII:
Для расширенной таблицы символов:
Методы работают со строками, но если мы используем строку из одного символа, то получим то, что нам нужно.
В упрощённом виде, если работаем со стандартными символами ASCII (on 0 до 127), то можно получить символ из int ещё проще.
Класс Character
Класс Character является оболочкой вокруг типа char. Чтобы получить значение типа char, содержащее в объекте класса Character, вызовите метод charValue().
С классом Character редко имеют дело в Android, но помните, что класс содержит огромное количество констант и методов. Например, можно определить, является ли символ цифрой или буквой, или написан ли символ в нижнем или в верхнем регистре.
Использование API ZonedDateTime
Java 8 предоставляет ZonedDateTime , когда нам нужно иметь дело с конкретной датой и временем часового пояса. ZoneId – это идентификатор, используемый для представления различных зон. Существует около 40 различных часовых поясов, и ZoneId используется для их представления следующим образом.
В этом фрагменте кода мы создаем Зону для Парижа:
ZoneId zoneId = ZoneId.of("Europe/Paris");
Набор всех идентификаторов зон можно получить следующим образом:
Set allZoneIds = ZoneId.getAvailableZoneIds();
LocalDateTime может быть преобразован в определенную зону:
ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, zoneId);
Метод ZonedDateTime предоставляет метод parse для получения конкретной даты часового пояса:
ZonedDateTime.parse("2015-05-03T10:15:30+01:00[Europe/Paris]");
Другой способ работы с часовым поясом-использовать OffsetDateTime . OffsetDateTime – это неизменяемое представление даты-времени со смещением. Этот класс хранит все поля даты и времени с точностью до наносекунд, а также смещение от UTC/Гринвича.
Экземпляр OffsetDateTime можно создать, как показано ниже, с помощью Zone Offset . Здесь мы создаем LocalDateTime , представляющий 6:30 утра 20 февраля 2015 года:
LocalDateTime localDateTime = LocalDateTime.of(2015, Month.FEBRUARY, 20, 06, 30);
Затем мы добавим два часа к этому времени, создав смещение зоны и установив для экземпляра LocalDateTime :
ZoneOffset offset = ZoneOffset.of("+02:00"); OffsetDateTime offSetByTwo = OffsetDateTime .of(localDateTime, offset);
Теперь у нас есть LocalDateTime 2015-02-20 06:30 +02:00. Теперь давайте перейдем к тому, как изменить значения даты и времени с помощью классов Period и Duration .
Backport и альтернативные варианты
8.1. Использование проектной информации
Для организаций, которые находятся на пути перехода на Java 8 с Java 7 или Java 6 и хотят использовать API даты и времени, project threeten предоставляет возможность обратного порта. Разработчики могут использовать классы, доступные в этом проекте, для достижения той же функциональности, что и в новом Java 8 Date и Time API, и как только они перейдут на Java 8, пакеты могут быть переключены. Артефакт для проекта можно найти в центральном репозитории maven :
org.threetenthreetenbp1.3.1
8.2. Библиотека Joda-Time
Другой альтернативой для Java 8 Date и Time library является Joda-Time library. На самом деле Java 8 Date Time API был совместно разработан автором библиотеки Joda-Time (Стивен Коулборн) и Oracle. Эта библиотека предоставляет практически все возможности, которые поддерживаются в Java 8 Date Time project. Артефакт можно найти в maven central , включив в свой проект приведенную ниже зависимость pom:
joda-timejoda-time2.9.4
Что такое Stream?
Интерфейс представляет собой последовательность элементов, над которой можно производить различные операции.
Операции над стримами бывают или промежуточными (intermediate) или конечными (terminal). Конечные операции возвращают результат определенного типа, а промежуточные операции возвращают тот же стрим. Таким образом вы можете строить цепочки из несколько операций над одним и тем же стримом.
У стрима может быть сколько угодно вызовов промежуточных операций и последним вызов конечной операции. При этом все промежуточные операции выполняются лениво и пока не будет вызвана конечная операция никаких действий на самом деле не происходит (похоже на создание объекта или , без вызова ).
Стримы создаются на основе источников каких-либо, например классов из .
Ассоциативные массивы (maps), например, , не поддерживаются.
Операции над стримами могут выполняться как последовательно, так и параллельно.
Потоки не могут быть использованы повторно. Как только была вызвана какая-нибудь конечная операция, поток закрывается.
Кроме универсальных объектных существуют особые виды стримов для работы с примитивными типами данных , и : , и . Эти примитивные стримы работают так же, как и обычные объектные, но со следующими отличиями:
- используют специализированные лямбда-выражения, например, или вместо и ;
- поддерживают дополнительные конечные операции , , .
Что такое «ссылка на метод»?
Если существующий в классе метод уже делает все, что необходимо, то можно воспользоваться механизмом method reference (ссылка на метод) для непосредственной передачи этого метода. Такая ссылка передается в виде:
- для статического метода;
- для метода экземпляра;
- для конструктора.
Результат будет в точности таким же, как в случае определения лямбда-выражения, которое вызывает этот метод.
private interface Measurable { public int length(String string); } public static void main(String[] args) { Measurable a = String::length; System.out.println(a.length("abc")); }
Ссылки на методы потенциально более эффективны, чем использование лямбда-выражений. Кроме того, они предоставляют компилятору более качественную информацию о типе и при возможности выбора между использованием ссылки на существующий метод и использованием лямбда-выражения, следует всегда предпочитать использование ссылки на метод.
Что такое инт
Переменная — это область памяти, которая содержит значение. Каждая переменная имеет тип данных. Другими словами, каждая переменная способна хранить данные определенного типа. Тип данных определяет, сколько памяти выделить для хранения значения в этом месте памяти.
Одним из основных типов данных в Java является примитивный тип данных; это основные типы данных, доступные в Java. «Инт» является одним из них. Значение по умолчанию для переменной int равно 0. Кроме того, оно выделяет 4 байта при хранении данных.
Пример таков.
Рисунок 1: Java-программа с int
В приведенной выше программе x и y — две переменные типа int. Они хранят значения 10 и 20. Есть еще одна переменная типа int, которая называется sum. Сумма x и y сохраняется в переменной sum. Наконец, метод println отображает вывод на консоли.
В чем разница между Collection и Stream?
Коллекции позволяют работать с элементами по отдельности, тогда как стримы так делать не позволяют, но вместо этого предоставляют возможность выполнять функции над данными как над одним целым.
Также стоит отметить важность самой концепции сущностей: — это прежде всего воплощение Структуры Данных. Например, не просто хранит в себе элементы, он реализует идею множества с уникальными элементами,
тогда как , это прежде всего абстракция необходимая для реализации конвейера вычислений, собственно поэтому, результатом работы конвейера являются те или иные Структуры Данных или же результаты проверок/поиска и т.п
Для чего нужны функциональные интерфейсы Function, DoubleFunction, IntFunction и LongFunction?
— интерфейс, с помощью которого реализуется функция, получающая на вход экземпляр класса и возвращающая на выходе экземпляр класса .
Методы по умолчанию могут использоваться для построения цепочек вызовов (, ).
Function<String, Integer> toInteger = Integer::valueOf; Function<String, String> backToString = toInteger.andThen(String::valueOf); backToString.apply("123"); // "123"
- — функция, получающая на вход и возвращающая на выходе экземпляр класса ;
- — функция, получающая на вход и возвращающая на выходе экземпляр класса ;
- — функция, получающая на вход и возвращающая на выходе экземпляр класса .
Для чего нужен метод collect() в стримах?
Метод является конечной операцией, которая используется для представление результата в виде коллекции или какой-либо другой структуры данных.
принимает на вход , который содержит четыре этапа: supplier — инициализация аккумулятора, accumulator — обработка каждого элемента, combiner — соединение двух аккумуляторов при параллельном выполнении, — необязательный метод последней обработки аккумулятора. В Java 8 в классе реализовано несколько распространённых коллекторов:
- , , — представляют стрим в виде списка, коллекции или множества;
- , — позволяют преобразовать стрим в ;
- , , — возвращают среднее значение;
- , , — возвращает сумму;
- , , — возвращают с разными агрегатными значениями;
- — разделяет коллекцию на две части по соответствию условию и возвращает их как ;
- — разделяет коллекцию на несколько частей и возвращает ;
- — дополнительные преобразования значений для сложных .
Так же существует возможность создания собственного коллектора через :
Collector<String, List<String>, List<String>> toList = Collector.of( ArrayList::new, List::add, (l1, l2) -> { l1.addAll(l2); return l1; } );
Преобразование с использованием Integer.toString(int)
Класс Integer имеет статический метод, который возвращает объект String, представляющий параметр int, указанный в функции Integer.toString(int). Этот подход, в отличие от других, может возвращать исключение NullPointerException.
Синтаксис
Есть два разных выражения для метода Integer.toString():
public static String toString(int i) public static String toString(int i, int radix)
Параметры
Параметры этого метода:
- i: целое число, которое будет преобразовано.
- radix: используемая система счисления базы для представления строки.
Возвращаемое значение
Возвращаемое значение для обоих выражений – строка Java, представляющая целочисленный аргумент «i». Если используется параметр radix, возвращаемая строка определяется соответствующим основанием.
Пример
package MyPackage; public class Method1 { public static void main(String args[]) { int n = Integer.MAX_VALUE; String str1 = Integer.toString(n); System.out.println("The output string is: " + str1); int m = Integer.MIN_VALUE; String str2 = Integer.toString(m); System.out.println("The output string is: " + str2); } }
Типы с плавающей точкой
Числа с плавающей точкой (иногда их называют действительными числами) применяются при вычислении выражений, в которых требуется точность до десятичного знака. Например, это может быть вычисление квадратного корня, значений синуса, косинуса и т.п. Существует два типа с плавающей точкой: float и double, которые представляют числа одинарной и двойной точности.
Слово «плавающая» означает, что десятичная точка может располагаться в любом месте (она «плавает»). Вот коты плавать не особенно любят, поэтому они не float и не double.
Тип float
Тип float определяет значение одинарной точности, которое занимает 32 бит. Переменные данного типа удобны, когда требуется дробная часть без особой точности, например, для денежных сумм.
Рекомендуется добавлять символ F или f для обозначения этого типа, иначе число будет считаться типом double.
Конвертируем из строки.
Класс Float является оболочкой для данного типа. Без необходимости не используйте в Android класс Float.
Также есть специальный класс BigDecimal для проведения арифметических действий повышенной точности (финансовые расчёты).
Тип double
Тип double обеспечивает двойную точность, что видно из его названия (double — двойная). Занимает 64 бит для хранения значений. Многие математические функции возвращают значения типа double. Кстати, современные процессоры оптимизированы под вычисления значений двойной точности, поэтому они предпочтительнее, чем тип float.
Тип double содержит не только числа, но и слова. Сейчас вам докажу. Разделим число типа double на ноль. Ошибки не произойдёт.
Пример вернёт значение Infinity (Бесконечность). Если разделить отрицательное число на ноль, то вернётся -Infinity.
А что произойдёт, если сложить две бесконечности? Если рассуждать логически, то сломается интернет, наступит конец света или можно вызвать Волдеморта. Я долго не решался, но потом набрался храбрости и попробовал.
Вернулось ещё одно слово — NaN. Что это вообще? Может должно вернуться Nyan — ну вы знаете, это странный котик, который летит бесконечно в космосе, оставляя за собой шлейф из радуги.
Умножать две бесконечности я побоялся. И вам не советую.
Класс Double является оболочкой для данного типа. Без необходимости не используйте в Android класс Double.
Конвертация double в строку
При работе с числами double следует держать ухо востро. Рассмотрим пример конвертации трёх чисел.
Первые два числа нормально преобразовались, а вот третье число преобразовалось в строку в странном виде (на самом деле это научное представление числа). И это может источником проблемы при передаче строки куда-нибудь, например, на сервер. Если сервер не ожидает от вас такой подлости, то будет генерировать ошибки из-за странной записи. Нужно найти другие способы конвертации.
Первый способ — используем String.format().
Последний пример самый подходящий для нас, но вам нужно знать, сколько знаков идёт после десятичной точки. Остальные два пригодятся, если число можно округлить.
Второй способ — метод Double.toString(). У меня метод превратил число в «непонятную» строку. А у некоторых этот пример возвращал строку в нормальном виде. Не заслуживает доверия.
Третий способ — добавить пустую строку. В Android не помогло, хотя тоже утверждается, что у кого-то выводится в нормальном виде. Врут, наверное.
Четвёртый экзотический способ, которым редко пользуются — DecimalFormat.
Что такое default методы интерфейса?
Java 8 позволяет добавлять неабстрактные реализации методов в интерфейс, используя ключевое слово :
interface Example { int process(int a); default void show() { System.out.println("default show()"); } }
- Если класс реализует интерфейс, он может, но не обязан, реализовать методы по умолчанию, уже реализованные в интерфейсе. Класс наследует реализацию по умолчанию.
- Если некий класс реализует несколько интерфейсов, которые имеют одинаковый метод по умолчанию, то класс должен реализовать метод с совпадающей сигнатурой самостоятельно. Ситуация аналогична, если один интерфейс имеет метод по умолчанию, а в другом этот же метод является абстрактным — никакой реализации по умолчанию классом не наследуется.
- Метод по умолчанию не может переопределить метод класса .
- Помогают реализовывать интерфейсы без страха нарушить работу других классов.
- Позволяют избежать создания служебных классов, так как все необходимые методы могут быть представлены в самих интерфейсах.
- Дают свободу классам выбрать метод, который нужно переопределить.
- Одной из основных причин внедрения методов по умолчанию является возможность коллекций в Java 8 использовать лямбда-выражения.