В последнее время я много работал на Java, но только когда мой проект потребовал, чтобы я принял некоторые из известных шаблонов объектно-ориентированного проектирования, я понял, насколько я был совершенно не уверен в том, что происходит на фундаментальном уровне, поэтому я обнаружил, что это настоящая проблема – не отставать от всей терминологии. Я почувствовал себя так, словно врезался в кирпичную стену.
Я решил потратить некоторое время на распаковку некоторых из этих строительных блоков – так что давайте откроем двери для некоторых из этого жаргона Java. Я надеюсь, что если вы когда-либо чувствовали себя в подобном положении, эти заметки могут помочь вам лучше понять разрастание Java.
Жаргон Java #1: Создание Объектов
В Java почти все является объектом – например, String
, ArrayList
Список массивов//и Хэш-карта
. Объекты создаются из классов. Думайте о коде вашего класса как о руководстве по эксплуатации Java для создания объекта.
Создание объекта требует создания экземпляра класса – поэтому фраза создание экземпляра класса часто используется людьми, которые хотят казаться особенно умными. Но вы можете использовать оба термина взаимозаменяемо, в зависимости от того, с кем вы разговариваете или пытаетесь выиграть в Скрэббл.
Чтобы формально создать объект/создать экземпляр класса, то есть сказать, что мы должны сделать, чтобы остановить компилятор от полного использования Mr. Resetti на нас, мы выполняем трехэтапный процесс: объявление, создание экземпляра и инициализация.
Объявление достигается путем указания type
и name
переменной, поэтому мы могли бы сообщить Java Dragon viserion;
, что подготовило бы все и настроило на принятие типа Dragon
. Но на данный момент наш объект в настоящее время ближе к моему текущему счету, чем грозный дракон: он пуст. В нем ничего нет. Zip, nada, nil или, в частности, null
.
Всегда следите за null
. Если бы у меня были дети, я бы не хотел, чтобы они болтались с null
.
Для справки: Java также имеет оба примитива и ссылочные переменные, на которые мы можем сейчас махать руками, но которые потенциально могут время от времени создавать некоторые дополнительные проблемы, как правило, когда дело доходит до назначения и сравнения. Но, эй, мы программируем на Java, так что, вероятно, можно с уверенностью предположить, что мы все время от времени попадаем в неприятные ситуации.
В любом случае, мы готовы к шагам 2 и 3 – созданию экземпляра и инициализации, которые любят работать в паре:
viserion = new Dragon();
Оператор new
| создает экземпляр класса, выделяя требуемую память за кулисами, а затем возвращает ссылку (адрес) этой памяти, чтобы наша переменная viserion знала, куда отправлять любого, кто постучится. Вызов
new также требует вызова конструктора, в котором скобки входят в сцену. Часть
() обрабатывает
инициализацию , которая вынюхивает конструктор класса, соответствующий сигнатуре, и, наконец, полностью настраивает наш объект и подготавливает его к выходу.
Конструкторы в классе Java имеют то же имя, что и класс, и не имеют возвращаемого типа. Если мы взглянем на наш класс Dragon
, мы увидим, что у него есть две сигнатуры конструктора: одна, которая может реагировать на конструктор с нулевым аргументом, который, в свою очередь, вызовет наш конструктор с двумя аргументами, для которого требуется //| и
Mouth аргумент со значениями по умолчанию.
public class Dragon { private Stomach stomach; private Mouth mouth; public Dragon() { this(new BigStomach(), new BigMouth()); } public Dragon(Stomach stomach, Mouth mouth) { this.stomach = stomach; this.mouth = mouth; } public eat(Food food) { mouth.consume(food); stomach.digest(food); } public dracarys(Target target) { return mouth.breatheFire(target); } }
Конструкторы являются обязательными для классов, но если один из них явно не определен, то компилятор будет обрабатывать класс с нулевым аргументом конструктор по умолчанию совершенно бесплатно.
Мы также разделили объявление и создание экземпляра/инициализацию viserion
на две строки, что необязательно – мы также можем объявить все наше назначение в одной строке, если захотим. Нам даже не нужно присваивать наши объекты переменным, и вместо этого мы можем использовать их непосредственно в выражении. Давайте соберем все это вместе и создадим еще одного Дракона
:
Dragon drogon = new Dragon(new GiantStomach(), new GiantMouth());
Мы объявляем ссылочную переменную dragon
, создавая экземпляр нашего класса Dragon с помощью new
а затем инициализируем его с помощью нашего конструктора, который реагирует на Желудок
и Рот
подпись. Мы также создаем два новых объекта, Гигантский живот
и Гигантский Рот
, непосредственно в нашем вызове конструктора.
А теперь, как насчет реального примера? Посмотрите, как ArrayList
содержит три сигнатуры конструктора в исходном коде Java:
// Constructs an empty list with the specified initial capacity. public ArrayList(int initialCapacity) { if (initialCapacity > 0) { this.elementData = new Object[initialCapacity]; } else if (initialCapacity == 0) { this.elementData = EMPTY_ELEMENTDATA; } else { throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); } } // Constructs an empty list with an initial capacity of ten. public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; } // Constructs a list containing the elements of the specified collection, in the order they are returned by the collection's iterator. public ArrayList(Collection extends E> c) { elementData = c.toArray(); if ((size = elementData.length) != 0) { if (elementData.getClass() != Object[].class) elementData = Arrays.copyOf(elementData, size, Object[].class); } else { this.elementData = EMPTY_ELEMENTDATA; } }
Черт возьми, это было довольно сложно воспринять. Считайте, что это работа над фундаментом. Если ты хоть в чем-то похож на меня, ты часто знаю этот материал на самом деле, вы знаете, не зная этого, так что приятно освежить знания.
Жаргон Java #2: Конкретные классы
Это слово всплывает повсюду, и я обнаружил, что вы должны знать, что оно означает по умолчанию. Для протокола, я действительно не знал, что это значит в течение месяцев .
Резюмируя это в предложении, конкретный класс – это любой класс, который вы можете создать (создать экземпляр) с помощью ключевого слова new
. В конкретных классах реализованы все их методы, независимо от того, сколько интерфейсов они реализуют
или классов, которые они расширяют
.
Когда дело доходит до создания чего-то конкретного, не требуется никаких конкретных языковых ключевых слов, но вы, вероятно, часто увидите всплывающее слово на диаграммах UML, и люди рассказывают об объектно-ориентированном программировании, поэтому приятно знать, что происходит, чтобы вы могли принять участие в разговоре.
Наш класс Dragon
– это добросовестный, на 100% сертифицированный бетон, что совершенно легко сделать, когда вы не используете ничего абстрактного. Мне легче думать о классах как о конкретных по умолчанию и только в терминах конкретных и абстрактных при использовании либо наследования (через extends
), либо интерфейсов (через implements
).
Жаргон Java #3: Интерфейсы
Если конкретный класс – это руководство по эксплуатации, интерфейс – это схема – это список нереализованных сигнатур методов, которые, заявляя, что мы будем реализовывать
интерфейс, наш класс обязуется поддерживать. Когда класс выбирает реализацию
интерфейса, часто говорят, что это контракт – потому что класс, который реализует, по сути, обещает включить эти методы.
Невыполнение контракта на интерфейс также приведет к тому, что компилятор посетит вас глубокой ночью, при условии, что вы компилируете свой код ночью. Он не будет этому рад.
Класс Java может реализовывать множество интерфейсов, как вы можете видеть с помощью ArrayList
:
public class ArrayListextends AbstractList implements List , RandomAccess, Cloneable, java.io.Serializable {
Вы заметите множество интерфейсов “-able”, когда будете работать на Java – здесь мы можем видеть Поддающийся клонированию
и Сериализуемый
, и вы будете видеть, как они всплывают снова и снова, но сейчас мы сосредоточимся на List
. Обратите внимание, как Список
использует интерфейс ключевое слово вместо
класса
:
public interface List{ int size(); boolean isEmpty(); //... there's plenty more empty methods
Ни size()
, ни is Empty()
не реализованы в этом интерфейсе. Мы не смогли создать объект List
из этого интерфейса с помощью ключевого слова new
, поэтому это не конкретный класс. Но, реализуя List
, ArrayList
обязуется следовать контракту и гарантировать, что он знает, как отвечать при отправке запросов на любую из сигнатур метода интерфейса.
Интерфейсы подобны небольшому галстуку-бабочке для некоторых ваших классов – они добавляют аккуратную степень формальности, которую уважает проверка типов. Вы также можете использовать имена интерфейсов в качестве типа для ваших ссылочных переменных, что означает, что любому классу, реализующему этот интерфейс, будет разрешено назначать его.
Жаргон Java #4: Абстрактные классы
Абстрактные классы могут иметь как реализованные, так и нереализованные методы, но они не являются конкретными, потому что они не могут создать объект с помощью ключевого слова new
. Однако подклассы могут использовать extends
ключевое слово для наследования их функциональности.
Многие коллекции списков Java наследуются от абстрактного класса Список тезисов
:
// AbstractList.java public abstract class AbstractList{ //... public boolean add(E e) { add(size(), e); return true; } public abstract E get(int index);
Обратите внимание на ключевое слово abstract
, используемое для обозначения как абстрактного класса, так и абстрактного метода: использование последнего требует объявления первого. Также обратите внимание, что абстрактный метод get
лишен фигурных скобок и имеет точку с запятой, аналогично тому, как мы объявляли наши методы интерфейса ранее.
ArrayList
является подклассом AbstractList
и поэтому должен реализовывать получить
метод, но унаследует метод add
:
// ArrayList.java public class ArrayListextends AbstractList implements List , RandomAccess, Cloneable, java.io.Serializable { // ... public E get(int index) { Objects.checkIndex(index, size); return elementData(index); }
Если ArrayList
не реализовал свой собственный метод get
при расширении AbstractList
ему пришлось бы объявить свой класс abstract
, чтобы насытить компилятор, что означало бы, что он не сможет создавать объекты, используя new
ключевое слово, а также не смог бы достичь столь желаемого конкретного статуса.
Подведение Итогов
Мы рассмотрели, что делает конкретный и абстрактный класс в Java, что означало ознакомление с тем, как создаются экземпляры классов. Мы перешли от простого примера Dragon
класса к рассмотрению некоторых фрагментов исходного кода из JDK 12, взглянув на то, как ArrayList
расширяет AbstractList
и реализует ArrayList
.
Понимание этих строительных блоков создает чрезвычайно полезную основу для понимания строгой объектно-ориентированной природы некоторых наиболее известных шаблонов проектирования Java.
Был ли этот пост полезен для вас? Я был бы очень признателен за любые комментарии и отзывы о том, есть ли что-нибудь, что можно было бы прояснить или объяснить лучше. Я также был бы очень признателен за любые исправления!
Оригинал: “https://dev.to/martingaston/understanding-java-objects-abstract-and-concrete-488a”