Рубрики
Без рубрики

Понимание объектов Java, абстрактных и конкретных

Пытаюсь понять разрастание Java, по одному конструктору за раз.. Помечено как начинающие, java, ооп.

В последнее время я много работал на 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 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 ArrayList extends 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 ArrayList extends 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”