Статьи

Наследование комментариев метода Javadoc

Хотя страницы JDK Tools и Utilities для инструмента javadoc описывают правила повторного использования комментариев метода Javadoc путем реализации и наследования методов, легко излишне явно описать наследование комментариев с помощью {@inheritDoc} когда это на самом деле не нужно, поскольку одни и те же комментарии будут неявно наследуется. На странице инструмента Java 8 javadoc описаны правила унаследованных комментариев Javadoc метода в разделе « Общее наследование метода », а на странице инструмента Java 7 javadoc аналогичным образом описаны эти правила в разделе « Автоматическое копирование комментариев метода ». Этот пост использует простые примеры кода, чтобы проиллюстрировать некоторые из ключевых правил наследования комментариев метода Javadoc.

Следующие интерфейсы и классы являются надуманными примерами, которые будут использоваться в этом посте для иллюстрации наследования комментариев Javadoc к методам. Некоторые унаследованные / реализующие методы включают свои собственные комментарии Javadoc, которые полностью или частично переопределяют комментарии методов родителя / интерфейса, а другие просто повторно используют документацию методов родителя / интерфейса.

Травоядный Интерфейс

01
02
03
04
05
06
07
08
09
10
11
12
13
14
package dustin.examples.inheritance;
 
/**
 * Marks animals that eat plants.
 */
public interface Herbivorous
{
   /**
    * Eat the provided plant.
    *
    * @param plantToBeEaten Plant that will be eaten.
    */
   void eat(Plant plantToBeEaten);
}

Хищный интерфейс

01
02
03
04
05
06
07
08
09
10
11
12
13
14
package dustin.examples.inheritance;
 
/**
 * Marks an Animal that eats other animals.
 */
public interface Carnivorous
{
   /**
    * Eat the provided animal.
    *
    * @param animalBeingEaten Animal that will be eaten.
    */
   void eat(Animal animalBeingEaten);
}

Всеядный интерфейс

1
2
3
4
5
6
7
8
package dustin.examples.inheritance;
 
/**
 * Eats plants and animals.
 */
public interface Omnivorous extends Carnivorous, Herbivorous
{
}

Viviparous интерфейс

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
package dustin.examples.inheritance;
 
/**
 * Mammals that give birth to young that develop within
 * the mother's body.
 */
public interface Viviparous
{
   /**
    * Give birth to indicated number of offspring.
    *
    * @param numberOfOffspring Number of offspring being born.
    */
   void giveBirth(int numberOfOffspring);
}

Животный класс

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
package dustin.examples.inheritance;
 
/**
 * Animal.
 */
public abstract class Animal
{
   /**
    * Breathe.
    */
   public void breathe()
   {
   }
 
   /**
    * Communicate verbally.
    */
   public abstract void verballyCommunicate();
}

Класс млекопитающих

1
2
3
4
5
6
7
8
package dustin.examples.inheritance;
 
/**
 * Mammal.
 */
public abstract class Mammal extends Animal
{
}

Млекопитающее с классом волос

01
02
03
04
05
06
07
08
09
10
11
12
package dustin.examples.inheritance;
 
import java.awt.*;
 
/**
 * Mammal with hair (most mammals other than dolphins and whales).
 */
public abstract class MammalWithHair extends Mammal
{
   /** Provide mammal's hair color. */
   public abstract Color getHairColor();
}

Класс собаки

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
package dustin.examples.inheritance;
 
import java.awt.Color;
 
import static java.lang.System.out;
 
/**
 * Canine and man's best friend.
 */
public class Dog extends MammalWithHair implements Omnivorous, Viviparous
{
   private final Color hairColor = null;
 
   /**
    * {@inheritDoc}
    * @param otherAnimal Tasty treat.
    */
   @Override
   public void eat(final Animal otherAnimal)
   {
   }
 
   /**
    * {@inheritDoc}
    * @param plantToBeEaten Plant that this dog will eat.
    */
   @Override
   public void eat(final Plant plantToBeEaten)
   {
   }
 
   /**
    * {@inheritDoc}
    * Bark.
    */
   public void verballyCommunicate()
   {
      out.println("Woof!");
   }
 
   /**
    * {@inheritDoc}
    * @param numberPuppies Number of puppies being born.
    */
   @Override
   public void giveBirth(final int numberPuppies)
   {
   }
 
   /**
    * Provide the color of the dog's hair.
    *
    * @return Color of the dog's fur.
    */
   @Override
   public Color getHairColor()
   {
      return hairColor;
   }
}

Кошачий класс

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package dustin.examples.inheritance;
 
import java.awt.Color;
 
import static java.lang.System.out;
 
/**
 * Feline.
 */
public class Cat extends MammalWithHair implements Carnivorous, Viviparous
{
   private final Color hairColor = null;
 
   /**
    * {@inheritDoc}
    */
   @Override
   public void eat(final Animal otherAnimal)
   {
   }
 
   @Override
   public void verballyCommunicate()
   {
      out.println("Meow");
   }
 
   @Override
   public void giveBirth(int numberKittens)
   {
   }
 
   @Override
   public Color getHairColor()
   {
      return hairColor;
   }
}

Лошадь Класс

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package dustin.examples.inheritance;
 
import java.awt.Color;
 
import static java.lang.System.out;
 
/**
 * Equine.
 */
public class Horse extends MammalWithHair implements Herbivorous, Viviparous
{
   private final Color hairColor = null;
 
   /**
    * @param plant Plant to be eaten by this horse.
    */
   @Override
   public void eat(final Plant plant)
   {
   }
 
   /**
    *
    */
   @Override
   public void verballyCommunicate()
   {
      out.println("Neigh");
   }
 
   /**
    * @param numberColts Number of colts to be born to horse.
    */
   @Override
   public void giveBirth(int numberColts)
   {
   }
 
   @Override
   public Color getHairColor()
   {
      return hairColor;
   }
}

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

20161116-inheritancepackagejavadoc

Три класса, представляющих наибольший интерес здесь с точки зрения Javadoc методов, — это классы Dog , Cat и Horse поскольку они реализуют несколько интерфейсов и расширяют MamalWithHair , который расширяет Mammal , который расширяет Animal .

На следующем снимке экрана показан Javadoc для класса Animal отображаемый в веб-браузере.

20161119-animaljavadoc-1

Класс Animal не наследует никаких методов от суперкласса и не реализует никаких методов из интерфейса и не очень интересен для темы этого блога. Однако другие классы, показанные здесь, расширяют этот класс, и поэтому интересно посмотреть, как комментарии его методов влияют на описания методов наследующих классов.

Следующие два снимка экрана представляют собой Javadoc для классов Mammal и MammalWithHair отображаемых в веб-браузере. Там нет комментариев Javadoc о значении Mammal , но есть один комментарий к методу для нового метода, представленного MammalWithHair .

20161119-mammaljavadoc

20161119-mammalwithhairmethodsummary

Следующие три снимка экрана представляют собой подмножества документации Javadoc в веб-браузере для интерфейсов Herbivorous , Carnivorous и Omnivorous . Эти интерфейсы предоставляют документацию для методов, которые будут наследоваться классами, которые реализуют эти методы.

20161119-herbivorousjavadoc

20161119-carnivorousjavadoc

20161119-omnivorousjavadoc

С созданной документацией методов Javadoc для родительских классов и показанных интерфейсов, теперь пришло время посмотреть на сгенерированную документацию для методов классов, расширяющих эти классы и реализующих эти интерфейсы.

Методы в классе Dog показанные ранее, обычно используют {@inheritDoc} в сочетании с дополнительным текстом. Результаты наследования комментариев Javadoc метода от расширенных классов и реализованных интерфейсов в сочетании с дополнительным тестом, предоставленным в комментариях Dog , показаны на следующих снимках экрана.

20161119-dogjavadocmethodsummary

20161119-dogjavadocmethoddetailtop

20161119-dogjavadocmethoddetailbottom

Последний набор снимков экрана демонстрирует, что документация класса Dog смешивает документацию его «родителей» с его собственной конкретной документацией. Это не удивительно. Методы класса Dog обычно явно наследуют документацию Javadoc от родителей (базовые классы и интерфейсы), но класс Cat основном не имеет комментариев Javadoc к своим методам, за исключением метода eat , который просто использует {@inheritDoc} . Сгенерированные выходные данные веб-браузера из этого класса показаны на следующих снимках экрана.

20161119-catjavadocmethodsummary

20161119-catjavadocmethoddetail

Методы в Cat , к которым не применены комментарии Javadoc, отображаются в сгенерированной документации веб-браузера с документацией, унаследованной от их базовых классов или интерфейсов, и документация по этим методам включает фразу «Описание, скопированное из класса:» или «Описание, скопированное из интерфейса: »В зависимости от обстоятельств. Один метод Cat , который явно включает тег документации {@inheritDoc} , копирует документацию метода родителя, но не включает в себя сообщение «Описание скопировано из».

Методы класса Horse обычно вообще не документированы, поэтому их сгенерированная документация содержит сообщение «Описание скопировано из…». Методы eat() и giveBirth() класса Horse переопределяют часть @param поэтому документация по параметрам для этих двух методов в сгенерированной документации веб-браузера (показанной в следующем наборе снимков экрана) специфична для Horse .

20161119-horsemethodsummary

20161119-horsemethoddetailtop

20161119-horsemethoddetailbottom

Из приведенных выше списков кода и снимков экрана сгенерированной документации из этого кода можно сделать некоторые наблюдения относительно наследования комментариев Javadoc методов путем расширения и реализации классов. Эти наблюдения также описаны в документации по инструменту javadoc :

  • Комментарии Javadoc наследуются от методов родительского класса и от реализованных методов интерфейса либо неявно, когда текст не указан (Javadoc вообще отсутствует, либо пустой Javadoc /** */ ).
    • Документация по javadoc : «Команда javadoc позволяет наследовать комментарии метода в классах и интерфейсах, чтобы заполнить пропущенный текст или явно наследовать комментарии метода».
  • Использование {@inheritDoc} явно заявляет, что комментарии должны быть унаследованы.
    • Документация javadoc : «Вставьте встроенный тег {@inheritDoc} в основное описание @param или в комментарий тега @return , @param или @throws . Соответствующее унаследованное основное описание или комментарий тега копируется в это место ».
  • Неявное и явное наследование документации метода может быть достигнуто в комбинации с использованием тегов {@inheritDoc} в разных местах в комментарии метода.

Учитывая вышеприведенные наблюдения и рекламируемый « Алгоритм комментариев к методу », хорошим правилом для написания Javadoc с точки зрения HTML, сгенерированного из Javadoc, является определение общих комментариев на максимально высоком уровне и возможность автоматического наследования Документация Javadoc для расширенных классов и реализованных интерфейсов ‘методов’ должна иметь место, добавляя или переопределяя только части текста Javadoc метода, которые необходимы для пояснения или улучшения описания для метода более низкого уровня. Это лучше, чем копирование и вставка одного и того же комментария ко всем методам в иерархии наследования или реализации и необходимость их последующего совместного обновления.

Этот пост был посвящен презентации в браузере сгенерированной документации по методам Javadoc. К счастью, наиболее часто используемые Java IDE ( NetBeans [ CTRL + hover ], IntelliJ IDEA [ CTRL + Q / Settings ], Eclipse [ F2 / hover / Javadoc View ] и JDeveloper [ CTRL-D ]) поддерживают представление Javadoc, которое обычно следует тем же правилам наследования документации метода. Это означает, что разработчики Java часто могут писать меньше документации и почти полностью избегать повторяющейся документации в иерархиях наследования и реализации.