user8126985

На Пикабу
105 рейтинг 0 подписчиков 4 подписки 3 поста 0 в горячем

Интерфейсы и абстрактные классы

Случилась со мной такая история ...

Недавно проходил собеседование на Java разработчика, как и на всех собеседованиях, задали вопрос про интерфейсы и абстрактные классы. Конечно, ответил, но все же решил перепроверить информацию на эту тему, так что здесь будет вся моя выдержка за это время

Давайте начнем с базовых ответов по теме интерфейс и абстрактный класс.

На вопрос: "Причем тут абстрактный класс?", отвечу так: "На собеседованиях эти вопросы идут рядом и в целом чем-то они похожи".

Итак, жил был абстрактный класс Василий. Объект этого класса создавать было нельзя, но Василий не унывал по этому поводу, ведь он содержит конструктор, может выполнять определенную логику в своих методах и иметь абстрактные методы (методы, не имеющие реализации, их нужно реализовать в классе наследнике), кроме этого Василий имел собственные поля с модификаторами доступа.

В те времена можно было наследовать много абстрактных классов и Василий не был исключением, наследовали его и всех его родственников. Но так получилось, что множественное наследование приводило к ошибкам наследования (одинаковые методы классов постоянно сорились) тогдв многие абстрактные классы иммигрировали в другие страны, а вместо них к Василию иммигрировали интерфейсы из public abstract Ифрики (нельзя наследовать много классов, но можно реализовывать много интерфейсов)

Таким образом Василий познакомился с интерфесом Амбалой. Амбала рассказал Василию, что он не содержит конструктора и реализовать его нельзя соответственно Методы интерфейса public и abstract по умолчанию

interface SomeInterface {

int SOME_THING = 11;

int foo();

}

Еще Амбала рассказал Василию, что содержит поле, но его поля только публичные, константные и статические, тогда как у Василия поля могут быть какими угодно. Но так было у предков Амбалы, тогда сам Амбала может содержать методы по умолчанию - медоты имеющие реализацию

interface SomeInterface {

default int foo() {

System.out.println("foo");

}

}

Также Амбала может иметь и статические методы, а обращаться к ним можно также как и к статическим методам класс

interface SomeInterface {

static int foo() {

System.out.println("foo");

}

}

public static void main(String[] args) {

SomeInterface.foo();

}

Шли годы и у Амбалы появились дети (jdk 9), они уже умели делать свои методы приватными и эти приватные методы могут быть как статическими так и нет.

Также к Амбале приехали родственники из Ифрики, оказалось, что они не содержат ни методов ни полей. "Как так получилось" - спросил Василий: "Что они умеют делать???".

Родственники рассказали Василию про таинственный полиморфизм: когда пустые интерфейсы используются, для пометки класса, реализующий этот интерфейс, чтобы использовать после этот класс в качестве реализации методов

interface Printable { }

class SomeClass implements Printable {

private int magicNumber = 3;

public int getMagicNumber() {

return magicNumber;

}

@override

public String toString() {

return String.valueOf(magicNumber);

}

}

public class Main {

public static void main(String[] args) {

var someClass = new SomeClass();

print(someClass);

}

public static void print(Printable printable) {

System.out.println(printable);

}

}

Суть в том, что тема интерфейсов оказалось гораздо интереснее чем я думал.

P.S помимо прочего веду телеграмм-канал и буду рад если поддержите IT-литературу.

Показать полностью

Будь как все говорили они ...

Всем привет. Немного душераздирающая и, вероятно, печальная тема.

Недавно слушал стрим на канале Anton Glad о качестве текста, рекомендую всем. На этом стриме он выдал интересную идею, которую я везде слышал и не понимал.

Вот Антон на стриме сказал: "Если звучишь как все, то и попадешь в банерную слепоту как все. Если выглядишь как предложения, от которых отказываются, то и от твоего тоже откажутся". И вот тут у меня произошло некое озарение.

Я уже давно учусь на программиста самостоятельно (без университета, курсов). И вот сейчас меня уже готовы взять на работу. Все это время родилели говорили мне: "У тебя нет вышки, да и образование не математическое, ты дурак, ни кто тебя не возьмет, просто так тратишь время". А недавно прошел собеседование и мне говорят: "берем, давай паспорт".

Когда родители в очередной раз начали говорить: "где тебе это пригодится", я сказал, что меня уже берут на работу ... Их реакция это что-то с чем-то: "Всмысле, без вышки???!!! А так можно?"

Я сразу проанализировал множество прошлых моментов, где мои родители говорили мне что-то похожее и вот, что я понял - они гадают, что будет и не пробуют что-то сделать. То есть они ничего не попробовали сделать, у них нет никаких извесных случаев, а они уже говорят вот так не работает и не пробуй, а оно работает.

Я не говорю за всех, вероятно, только у меня такая ситуация, но у меня в жизни было столько случаев когда я спрашивал, а может вот так попробуем, а мне отвечали: "Нет, так не работает". А почему не работает? - "Ты еще маленький, юношеский максимализм, да и молоко на губах не обсохло", а еще лучше: "А что подумают люди". Как будто какой-то закостеневший слой, толщенная бетонная стена прямо на дороге. Им самим же эти убеждения мешают жить, им предлагали хорошие должности, но они отказывались, потому что придумали себе свою историю, свой мир и живут в нем.

Это я не к осуждению их или кого-либо говорю, а просто поразмышлять над красотой жизни. Сколько из нас живет в подобных убеждениях, боятся чего-то, хотя ничего такого не собираются делать (смелость взять должность, взобраться по карьере, познакомиться с кем-то)

В общем, не знаю я еще к какому выводу можно прийти, что из этого можно вывести, но суть в том, что уже есть сподвижки к этому.

Кстати, вот мой телеграмм-канал, в нем я обсуждаю похожие темы, программирование, IT и жизнь.

Показать полностью
9

Гав, мяу, JVM, JDK, JRE и все такое (немного Java в ленту)

Проще всего понять о чем говорим посмотреть на эту картинку. Более подробно в этом телеграмм-канале

Гав, мяу, JVM, JDK, JRE и все такое (немного Java в ленту)

В чем суть и различие?

JDK (Java Development Kit) - включает в себя Java Development Tools и среду выполнения Java - JRE (Java Runtime Environment).

JDT (Java development tools) - включают в себя около 40 различных инструментов: javac (компилятор), java (лаунчер для приложений), javap (java class file disassembler), jdb (java debugger) и др.

JRE - это пакет всего необходимого для запуска скомпилированной Java-программы. Включает в себя виртуальную машину JVM и библиотеку классов Java Class Library.

Резюмируем. Есть JDK для ведения разработки, которое содержит JRE и интсрументы разработки (тот же компилятор и дебаггер). Дальше сам JRE содержит какую-то JVM и библиотеку непонятных классов

Непосредственно JVM

JVM (Java Virtual Machine) - программа предназначенная для выполнения байт-кода. Благодрая которой, Java может работать на всех платформах. Раньше программы писали под определенную платформу, а теперь можно написать на Java и работать программа будет везде. Собственно JVM существует масса как комерческих, так и с открытым исходным кодом. А для чего пишется столько различных JVM? Нуу... Чтобы на какой-нибудь операционке работало быстрее, так же можно написать свою JVM для каких-либо своих целей

Что делает? Отвечает за загрузку классов, выполнение байт-кода, управление памятью и очисткой мусора (знаменитый сборщик мусора)

А что за байт-код? Когда мы компилирует программу мы получаем на выходе файлы с расширением .class. Это и есть файлы с байт-кодом

Есть вопрос гораздо интереснее, а как это файлы JVM находит? Что за сущность, которая говорит JVM: "О смотри что нашел, тебе нужно?". Сие носит название как Class loader

Class Loader

Загрузчики классов - это классы, часть JVM, они отдают классы в JVM, а дальше она делает с классами что захочет, но перед этим классы должны быть загружены. Загружаются классы не все разом, а по мере необходимости

Загрузчики:

1) Bootstrap classloader загружает основные библиотеки Java, расположенные в папке <JAVA_HOME>/jre/lib. Этот загрузчик является частью ядра JVM, написан на нативном коде (C, C++). Когда JVM загружает классы из rt.jar, она не выполняет все этапы проверки, которые выполняются при загрузке любого другого класс-файла т.к. JVM изначально известно, что все эти классы уже проверены. Поэтому, включать в этот архив какие-либо свои файлы не стоит, в отличие от наших классов, их JVM проверяет

2) Extension classloader загружает код в каталоги расширений (<JAVA_HOME>/jre/lib/ext, или любой другой каталог, указанный системным свойством java.ext.dirs). Если нужно, чтобы какой-то класс загружался каждый раз при старте Java машины, можешь скопировать исходный файл класса в эту папку, и он будет автоматически загружаться

3) System classloader загружает код, найденный в java.class.path, который сопоставляется с переменной среды CLASSPATH. Это реализуется классом sun.misc.Launcher$AppClassLoader.

Загрузчик классов выполняет в строгом порядке:

1) загрузка - находит и импортирует двоичные данные для типа.

2) связывание - выполняет проверку, подготовку и (необязательно) разрешение.

3) проверка - обеспечивает правильность импортируемого типа.

4) подготовка - выделяет память для переменных класса и инициализация памяти значениями по умолчанию.

5) разрешение - преобразует символические ссылки из типа в прямые ссылки.

6) инициализация - вызывает код Java, который инициализирует переменные класса их правильными начальными значениями.

Немного о проверке корректности .class

Файл скомпилированного класса (.class) содержит дополнительную информацию о классе: имя, модификаторы, супер-класс, супер-интерфейсы, поля, методы и атрибуты

Так при загрузке класса:

1) происходит чтение класс-файла, т.е проверка корректности формата

2) создается представление класса в Constant pool (Meta space, область памяти для такого рода делов)

3) грузятся супер-классы и супер-интерфейсы. Если они не будут загружены, то и сам класс не будет загружен

Загрузчик классов написан на Java. Поэтому возможно создать свой собственный загрузчик классов, не понимая тонких деталей JVM. У каждого загрузчика классов Java есть родительский загрузчик классов, определенный при создании экземпляра нового загрузчика классов или в качестве системного загрузчика классов по умолчанию для виртуальной машины

И это не все

Java нужно как-то интерпретировать байт-код, для этого есть угадайте что, интерпретатор, работает он быстро, но его недостатком является медленное выполнение. Если функция выполняется много раз он каждый раз заново компилирует байт-код в машинный код. Такую проблему решает JIT

JIT (just in time) - компилятор, который использует интерпретатор когда увидит функцию, использующую несколько раз. Т.е. интерпретатор видит повторяющийся код => отдает его на съедение JIT, а после использует сразу скомпилированный код от JIT (нативный код) и ему не нужно заново компилировать байт-код

Области тьмы (памяти)

JVM использует множество областей памяти для работы, одни области сооздаются при запуске программы и работают пока она не закончится, другие существуют поменьше

1) Heap (куча) - создается при запуске и работает пока программа не завершится. В ней хранятся объекты доступные для всех потоков из всех участков программы (не нужные объекты чистит сборщик мусора). Может быть фиксированного размера и определяться по мере выполнения программы

2) Run-Time Constant Pool - область хранения класса или интерфейса в рантайме. Хранит информацию о классе, константы (числовые литералы, ссылки на методы и поля)

3) Native Method Stacks - стеки для поддержки нативных методов, написанных не на Java

4) Java Virtual Machine Stacks - стек для потоков, т.е. каждый поток имеет свой стек. Стеки могут быть как фиксированного размера, так и динамически изменяться

5) Program Counter Register (PCR) - каждый поток имеет такую область памяти, в ней хранится адрес инструкции на которой поток завершился, чтобы потом начать с этой инструкции

Frame - новый frame создается каждый раз, когда вызывается метод. Frame уничтожается, когда завершается вызов метода. Соответсвенно раз фрэйм создается для создания метода, каждый фрейм имеет свои константы, локальные переменные. А фрейм, который выполняетсяв данный момент называется текущим, т.к. работать может только один фрейм во всей программе.
Каждый frame содержит ссылку на run-time constant pool для поддержки динамического связывания метода. Динамическое связывание загружает классы по мере необходимости. Позднее связывание методов и переменных вносит изменения в другие классы, которые метод использует с меньшей вероятностью нарушить этот код.

Почитать о том как я проходил собеседования, об IT и жизни можешь в этом телеграмм-канале

Показать полностью 1
Отличная работа, все прочитано!