如何自动生成简单的 Mermaid 类图
背景
我在 [Java] 一些类图 这篇文章里画了一些类图,虽说手动生成类图的过程有利于加深自己的理解,但是查看各个类/接口的信息毕竟比较麻烦,如果可以把生成类图的过程自动化,就可以大大提升画类图的效率了。
本文展示了我自己写的可以生成简单类图的 java 代码。文中展示了用它生成的以下类的类图
ArrayListLinkedListjava.util.Arrays$ArrayList(Arrays.asList(...)方法返回的是它的实例)List/Set/DequeHashMap/LinkedHashMap/ConcurrentHashMapSet12/SetN(Set.of(...)方法返回的是它们的实例)java.util.JumboEnumSet/java.util.RegularEnumSet(EnumSet.of(...)方法返回的是它们的实例)java.util.concurrent.ThreadPoolExecutor- 自己手写一些类/接口
代码
我写了如下的 java 代码,它可以自动生成简单的 Mermaid 类图。
请将以下代码保存为 ClassDiagramGenerator.java ⬇️
import java.lang.reflect.AccessFlag;
import java.util.*;
public class ClassDiagramGenerator {
private final Map<Class<?>, Class<?>[]> realizationRelations = new HashMap<>();
private final Map<Class<?>, Class<?>> inheritanceRelations = new HashMap<>();
private final Set<Class<?>> analyzedClasses = new LinkedHashSet<>();
private final Set<Class<?>> ignoredClasses = new HashSet<>();
private static final Class<Object> OBJECT_CLASS = Object.class;
private static final String IGNORE_OPTION = "-i";
private static final String USAGE = "Usage: java ClassDiagramGenerator [-i 'java.io.Serializable'] [-i 'java.lang.Cloneable'] 'java.util.ArrayList' 'java.util.LinkedList'";
public static void main(String[] args) {
ClassDiagramGenerator generator = new ClassDiagramGenerator();
generator.convert(args).forEach(generator::analyzeHierarchy);
generator.showIgnoredClasses();
generator.generateClassDiagram();
generator.generateNameMappingTable();
}
public ClassDiagramGenerator() {
ignoredClasses.add(OBJECT_CLASS);
}
private void ignoreClass(String className) {
try {
Class<?> clazz = Class.forName(className);
ignoredClasses.add(clazz);
} catch (ClassNotFoundException e) {
String message = String.format("Class with name=%s can't be found, please check!", className);
throw new RuntimeException(message);
}
}
/**
* Convert class name to the corresponding class object.
* The "-i" option (it means some class should be ignored) will be handled in this method.
*
* @param classNames give class names
* @return a list that contains corresponding class objects
*/
private List<Class<?>> convert(String[] classNames) {
int index = 0;
while (index < classNames.length && classNames[index].equals(IGNORE_OPTION)) {
if (index + 1 >= classNames.length) {
String hint = "Please refer to below usage and specify correct parameter with the '-i' option!";
throw new IllegalArgumentException(String.join(System.lineSeparator(), hint, USAGE));
}
ignoreClass(classNames[index + 1]);
index += 2;
}
if (index == classNames.length) {
String hint = "Please refer to below usage and specify at least ONE class name!";
throw new IllegalArgumentException(String.join(System.lineSeparator(), hint, USAGE));
}
List<Class<?>> classList = new ArrayList<>(classNames.length);
for (; index < classNames.length; index++) {
String className = classNames[index];
try {
Class<?> clazz = Class.forName(className);
classList.add(clazz);
} catch (ClassNotFoundException e) {
String message = String.format("Class with name=%s can't be found, please check!", className);
throw new RuntimeException(message);
}
}
return classList;
}
private void showIgnoredClasses() {
List<Class<?>> classes = ignoredClasses.stream().
filter(c -> c != OBJECT_CLASS).
toList();
if (!classes.isEmpty()) {
System.out.println("**请注意:以下的类/接口在类图中被忽略了**");
classes.forEach(c -> System.out.println("* `" + c.getName() + "`"));
System.out.println();
}
}
/**
* Generate header for Mermaid class diagram
*/
private void generateHeader() {
System.out.println("```mermaid");
System.out.println("classDiagram");
System.out.println();
}
/**
* Generate footer for Mermaid class diagram
*/
private void generateFooter() {
System.out.println("```");
}
/**
* Generate main content in Mermaid class diagram
*/
private void generateClassDiagram() {
generateHeader();
doGenerateClassDiagram();
generateFooter();
}
/**
* Generate a Markdown table that contains name mapping
*/
private void generateNameMappingTable() {
Map<String, String> classNames = new TreeMap<>();
analyzedClasses.forEach(c -> {
String simpleName = c.getSimpleName();
if (classNames.containsKey(simpleName)) {
String prevName = classNames.get(simpleName);
String currName = c.getName();
String message = String.format("Duplicated simple class name detected! (%s and %s have the same simple name)", prevName, currName);
throw new IllegalArgumentException(message);
}
if (!simpleName.equals(c.getName())) {
classNames.put(simpleName, c.getName());
}
});
if (!classNames.isEmpty()) {
System.out.println();
System.out.println("| 在上图中的类名/接口名 | `Fully Qualified Name` |");
System.out.println("| --- | --- |");
classNames.forEach((simpleName, name) -> {
String row = String.format("| `%s` | `%s` |", simpleName, name);
System.out.println(row);
});
}
}
private void doGenerateClassDiagram() {
analyzedClasses.forEach(c -> {
if (inheritanceRelations.containsKey(c)) {
System.out.printf("%s <|-- %s%n", inheritanceRelations.get(c).getSimpleName(), c.getSimpleName());
}
if (realizationRelations.containsKey(c)) {
String type = c.isInterface() ? "<|--" : "<|..";
Arrays.stream(realizationRelations.get(c)).forEach(item -> {
System.out.printf("%s %s %s%n", item.getSimpleName(), type, c.getSimpleName());
});
}
});
generateSpecialClassAnnotation();
}
/**
* This method generates annotation for
* 1. Abstract classes
* 2. Interfaces
*/
private void generateSpecialClassAnnotation() {
Set<Class<?>> abstractClasses = new LinkedHashSet<>();
Set<Class<?>> interfaces = new LinkedHashSet<>();
analyzedClasses.forEach(c -> {
if (c.isInterface()) {
interfaces.add(c);
} else if (c.accessFlags().contains(AccessFlag.ABSTRACT)) {
abstractClasses.add(c);
}
});
if (!abstractClasses.isEmpty() || !interfaces.isEmpty()) {
System.out.println();
abstractClasses.forEach(c -> System.out.println("<<Abstract>> " + c.getSimpleName()));
interfaces.forEach(c -> System.out.println("<<interface>> " + c.getSimpleName()));
}
}
private void analyzeHierarchy(Class<?> currClass) {
if (!analyzedClasses.contains(currClass) && !ignoredClasses.contains(currClass)) {
analyzeSuperClass(currClass);
analyzeInterfaces(currClass);
analyzedClasses.add(currClass);
}
}
private void analyzeSuperClass(Class<?> currClass) {
Class<?> superclass = currClass.getSuperclass();
if (superclass == null || ignoredClasses.contains(superclass)) {
return;
}
analyzeHierarchy(superclass);
if (!inheritanceRelations.containsKey(currClass)) {
inheritanceRelations.put(currClass, superclass);
}
}
private void analyzeInterfaces(Class<?> currClass) {
Class<?>[] interfaces = currClass.getInterfaces();
for (Class<?> item : interfaces) {
analyzeHierarchy(item);
}
if (!realizationRelations.containsKey(currClass)) {
Class<?>[] filteredInterfaces = Arrays.stream(interfaces).
filter(c -> !ignoredClasses.contains(c)).
toArray(Class<?>[]::new);
realizationRelations.put(currClass, filteredInterfaces);
}
}
}
用以下命令可以编译 ClassDiagramGenerator.java
javac ClassDiagramGenerator.java
注意事项
请注意,ClassDiagramGenerator 生成的类图中,不包含任何泛型信息,而且也不展示任何字段/方法。
例子
ClassDiagramGenerator 的使用有如下两种方式 ⬇️
java ClassDiagramGenerator C1 C2 C3java ClassDiagramGenerator -i EC1 -i EC2 C1 C2 C3
其中
C1/C2/C3表示要分析的类/接口的全限定类名(不必恰好是3个,但是至少要指定一个)EC1/EC2表示要排除的类/接口的全限定类名(可以不排除任何类/接口,也可以排除若干个类/接口)
这样说还是比较抽象,下面举一些例子,来说明 ClassDiagramGenerator 的用法。
例 1: 生成 ArrayList 的类图
请运行以下命令以生成对应的内容 ⬇️
java ClassDiagramGenerator 'java.util.ArrayList'
运行结果是 Markdown 格式的,而掘金文档的编辑区支持相关格式。您可以通过下图所示的方式来体验在掘金的文档中如何画类图 ⬇️
运行结果
classDiagram
Iterable <|-- Collection
Collection <|.. AbstractCollection
Collection <|-- SequencedCollection
SequencedCollection <|-- List
AbstractCollection <|-- AbstractList
List <|.. AbstractList
AbstractList <|-- ArrayList
List <|.. ArrayList
RandomAccess <|.. ArrayList
Cloneable <|.. ArrayList
Serializable <|.. ArrayList
<<Abstract>> AbstractCollection
<<Abstract>> AbstractList
<<interface>> Iterable
<<interface>> Collection
<<interface>> SequencedCollection
<<interface>> List
<<interface>> RandomAccess
<<interface>> Cloneable
<<interface>> Serializable
| 在上图中的类名/接口名 | Fully Qualified Name |
|---|---|
AbstractCollection | java.util.AbstractCollection |
AbstractList | java.util.AbstractList |
ArrayList | java.util.ArrayList |
Cloneable | java.lang.Cloneable |
Collection | java.util.Collection |
Iterable | java.lang.Iterable |
List | java.util.List |
RandomAccess | java.util.RandomAccess |
SequencedCollection | java.util.SequencedCollection |
Serializable | java.io.Serializable |
变通的方式
如果您无法在掘金的文档中使用 Mermaid,那么也可以前往 mermaid.live/ 来查看对应的类图,我在 mermaid.live/ 看到的效果如下 ⬇️ (需要自行将结果复制到那个网页去)
如何忽略某些类/接口
有的用户并不关心 java.lang.Cloneable 和 java.io.Serializable,此时可以通过 -i 选项忽略指定的类/接口,具体的命令如下 ⬇️
java ClassDiagramGenerator -i 'java.lang.Cloneable' -i 'java.io.Serializable' 'java.util.ArrayList'
运行结果
请注意:以下的类/接口在类图中被忽略了
java.lang.Cloneablejava.io.Serializable
classDiagram
Iterable <|-- Collection
Collection <|.. AbstractCollection
Collection <|-- SequencedCollection
SequencedCollection <|-- List
AbstractCollection <|-- AbstractList
List <|.. AbstractList
AbstractList <|-- ArrayList
List <|.. ArrayList
RandomAccess <|.. ArrayList
<<Abstract>> AbstractCollection
<<Abstract>> AbstractList
<<interface>> Iterable
<<interface>> Collection
<<interface>> SequencedCollection
<<interface>> List
<<interface>> RandomAccess
| 在上图中的类名/接口名 | Fully Qualified Name |
|---|---|
AbstractCollection | java.util.AbstractCollection |
AbstractList | java.util.AbstractList |
ArrayList | java.util.ArrayList |
Collection | java.util.Collection |
Iterable | java.lang.Iterable |
List | java.util.List |
RandomAccess | java.util.RandomAccess |
SequencedCollection | java.util.SequencedCollection |
例 2: 生成 LinkedList 的类图
请运行以下命令以生成对应的内容 ⬇️
java ClassDiagramGenerator 'java.util.LinkedList'
运行结果是 Markdown 格式的,展示如下
运行结果
classDiagram
Iterable <|-- Collection
Collection <|.. AbstractCollection
Collection <|-- SequencedCollection
SequencedCollection <|-- List
AbstractCollection <|-- AbstractList
List <|.. AbstractList
AbstractList <|-- AbstractSequentialList
Collection <|-- Queue
Queue <|-- Deque
SequencedCollection <|-- Deque
AbstractSequentialList <|-- LinkedList
List <|.. LinkedList
Deque <|.. LinkedList
Cloneable <|.. LinkedList
Serializable <|.. LinkedList
<<Abstract>> AbstractCollection
<<Abstract>> AbstractList
<<Abstract>> AbstractSequentialList
<<interface>> Iterable
<<interface>> Collection
<<interface>> SequencedCollection
<<interface>> List
<<interface>> Queue
<<interface>> Deque
<<interface>> Cloneable
<<interface>> Serializable
| 在上图中的类名/接口名 | Fully Qualified Name |
|---|---|
AbstractCollection | java.util.AbstractCollection |
AbstractList | java.util.AbstractList |
AbstractSequentialList | java.util.AbstractSequentialList |
Cloneable | java.lang.Cloneable |
Collection | java.util.Collection |
Deque | java.util.Deque |
Iterable | java.lang.Iterable |
LinkedList | java.util.LinkedList |
List | java.util.List |
Queue | java.util.Queue |
SequencedCollection | java.util.SequencedCollection |
Serializable | java.io.Serializable |
如果想忽略 java.lang.Cloneable 和 java.io.Serializable,可以使用 -i 选项,具体的命令如下 ⬇️
java ClassDiagramGenerator -i 'java.lang.Cloneable' -i 'java.io.Serializable' 'java.util.LinkedList'
运行结果如下 ⬇️
请注意:以下的类/接口在类图中被忽略了
java.lang.Cloneablejava.io.Serializable
classDiagram
Iterable <|-- Collection
Collection <|.. AbstractCollection
Collection <|-- SequencedCollection
SequencedCollection <|-- List
AbstractCollection <|-- AbstractList
List <|.. AbstractList
AbstractList <|-- AbstractSequentialList
Collection <|-- Queue
Queue <|-- Deque
SequencedCollection <|-- Deque
AbstractSequentialList <|-- LinkedList
List <|.. LinkedList
Deque <|.. LinkedList
<<Abstract>> AbstractCollection
<<Abstract>> AbstractList
<<Abstract>> AbstractSequentialList
<<interface>> Iterable
<<interface>> Collection
<<interface>> SequencedCollection
<<interface>> List
<<interface>> Queue
<<interface>> Deque
| 在上图中的类名/接口名 | Fully Qualified Name |
|---|---|
AbstractCollection | java.util.AbstractCollection |
AbstractList | java.util.AbstractList |
AbstractSequentialList | java.util.AbstractSequentialList |
Collection | java.util.Collection |
Deque | java.util.Deque |
Iterable | java.lang.Iterable |
LinkedList | java.util.LinkedList |
List | java.util.List |
Queue | java.util.Queue |
SequencedCollection | java.util.SequencedCollection |
例 3: 生成 java.util.Arrays$ArrayList 的类图
调用 Arrays.asList(...) 方法,得到的是 java.util.Arrays$ArrayList 的实例。
请运行以下命令以生成对应的内容 ⬇️
java ClassDiagramGenerator 'java.util.Arrays$ArrayList'
运行结果是 Markdown 格式的,展示如下
运行结果
请注意下图中的 ArrayList 是 java.util.Arrays 中的一个嵌套类,而不是我们平时常用的 java.util.ArrayList
classDiagram
Iterable <|-- Collection
Collection <|.. AbstractCollection
Collection <|-- SequencedCollection
SequencedCollection <|-- List
AbstractCollection <|-- AbstractList
List <|.. AbstractList
AbstractList <|-- ArrayList
RandomAccess <|.. ArrayList
Serializable <|.. ArrayList
<<Abstract>> AbstractCollection
<<Abstract>> AbstractList
<<interface>> Iterable
<<interface>> Collection
<<interface>> SequencedCollection
<<interface>> List
<<interface>> RandomAccess
<<interface>> Serializable
| 在上图中的类名/接口名 | Fully Qualified Name |
|---|---|
AbstractCollection | java.util.AbstractCollection |
AbstractList | java.util.AbstractList |
ArrayList | java.util.Arrays$ArrayList |
Collection | java.util.Collection |
Iterable | java.lang.Iterable |
List | java.util.List |
RandomAccess | java.util.RandomAccess |
SequencedCollection | java.util.SequencedCollection |
Serializable | java.io.Serializable |
例 4: 生成 List/Set/Deque 的类图
请运行以下命令以生成对应的内容 ⬇️
java ClassDiagramGenerator 'java.util.List' 'java.util.Set' 'java.util.Deque'
运行结果是 Markdown 格式的,展示如下
运行结果
classDiagram
Iterable <|-- Collection
Collection <|-- SequencedCollection
SequencedCollection <|-- List
Collection <|-- Set
Collection <|-- Queue
Queue <|-- Deque
SequencedCollection <|-- Deque
<<interface>> Iterable
<<interface>> Collection
<<interface>> SequencedCollection
<<interface>> List
<<interface>> Set
<<interface>> Queue
<<interface>> Deque
| 在上图中的类名/接口名 | Fully Qualified Name |
|---|---|
Collection | java.util.Collection |
Deque | java.util.Deque |
Iterable | java.lang.Iterable |
List | java.util.List |
Queue | java.util.Queue |
SequencedCollection | java.util.SequencedCollection |
Set | java.util.Set |
例 5: 生成 HashMap/LinkedHashMap/ConcurrentHashMap 的类图
请运行以下命令以生成对应的内容 ⬇️
java ClassDiagramGenerator 'java.util.HashMap' 'java.util.LinkedHashMap' 'java.util.concurrent.ConcurrentHashMap'
运行结果是 Markdown 格式的,展示如下
运行结果
classDiagram
Map <|.. AbstractMap
AbstractMap <|-- HashMap
Map <|.. HashMap
Cloneable <|.. HashMap
Serializable <|.. HashMap
Map <|-- SequencedMap
HashMap <|-- LinkedHashMap
SequencedMap <|.. LinkedHashMap
Map <|-- ConcurrentMap
AbstractMap <|-- ConcurrentHashMap
ConcurrentMap <|.. ConcurrentHashMap
Serializable <|.. ConcurrentHashMap
<<Abstract>> AbstractMap
<<interface>> Map
<<interface>> Cloneable
<<interface>> Serializable
<<interface>> SequencedMap
<<interface>> ConcurrentMap
| 在上图中的类名/接口名 | Fully Qualified Name |
|---|---|
AbstractMap | java.util.AbstractMap |
Cloneable | java.lang.Cloneable |
ConcurrentHashMap | java.util.concurrent.ConcurrentHashMap |
ConcurrentMap | java.util.concurrent.ConcurrentMap |
HashMap | java.util.HashMap |
LinkedHashMap | java.util.LinkedHashMap |
Map | java.util.Map |
SequencedMap | java.util.SequencedMap |
Serializable | java.io.Serializable |
如果想忽略 java.lang.Cloneable 和 java.io.Serializable,可以使用 -i 选项,具体的命令如下 ⬇️
java ClassDiagramGenerator -i 'java.lang.Cloneable' -i 'java.io.Serializable' 'java.util.HashMap' 'java.util.LinkedHashMap' 'java.util.concurrent.ConcurrentHashMap'
运行结果如下 ⬇️
请注意:以下的类/接口在类图中被忽略了
java.lang.Cloneablejava.io.Serializable
classDiagram
Map <|.. AbstractMap
AbstractMap <|-- HashMap
Map <|.. HashMap
Map <|-- SequencedMap
HashMap <|-- LinkedHashMap
SequencedMap <|.. LinkedHashMap
Map <|-- ConcurrentMap
AbstractMap <|-- ConcurrentHashMap
ConcurrentMap <|.. ConcurrentHashMap
<<Abstract>> AbstractMap
<<interface>> Map
<<interface>> SequencedMap
<<interface>> ConcurrentMap
| 在上图中的类名/接口名 | Fully Qualified Name |
|---|---|
AbstractMap | java.util.AbstractMap |
ConcurrentHashMap | java.util.concurrent.ConcurrentHashMap |
ConcurrentMap | java.util.concurrent.ConcurrentMap |
HashMap | java.util.HashMap |
LinkedHashMap | java.util.LinkedHashMap |
Map | java.util.Map |
SequencedMap | java.util.SequencedMap |
例 6: 生成 java.util.ImmutableCollections$Set12 和 java.util.ImmutableCollections$SetN 的类图
当我们调用 Set.of(...) 方法时,会得到以下两个类的实例 ⬇️
java.util.ImmutableCollections$Set12java.util.ImmutableCollections$SetN
请运行以下命令以生成对应的内容 ⬇️
java ClassDiagramGenerator 'java.util.ImmutableCollections$Set12' 'java.util.ImmutableCollections$SetN'
运行结果是 Markdown 格式的,展示如下
运行结果
classDiagram
Iterable <|-- Collection
Collection <|.. AbstractCollection
AbstractCollection <|-- AbstractImmutableCollection
Collection <|-- Set
AbstractImmutableCollection <|-- AbstractImmutableSet
Set <|.. AbstractImmutableSet
AbstractImmutableSet <|-- Set12
Serializable <|.. Set12
AbstractImmutableSet <|-- SetN
Serializable <|.. SetN
<<Abstract>> AbstractCollection
<<Abstract>> AbstractImmutableCollection
<<Abstract>> AbstractImmutableSet
<<interface>> Iterable
<<interface>> Collection
<<interface>> Set
<<interface>> Serializable
| 在上图中的类名/接口名 | Fully Qualified Name | |
|---|---|---|
AbstractCollection | java.util.AbstractCollection | |
AbstractImmutableCollection | java.util.ImmutableCollections$AbstractImmutableCollection | |
AbstractImmutableSet | java.util.ImmutableCollections$AbstractImmutableSet | |
Collection | java.util.Collection | |
Iterable | java.lang.Iterable | |
Serializable | java.io.Serializable | |
Set | java.util.Set | |
Set12 | java.util.ImmutableCollections$Set12 | |
SetN | java.util.ImmutableCollections$SetN |
例 7: 生成 java.util.JumboEnumSet 和 java.util.RegularEnumSet 的类图
当我们调用 EnumSet.of(...) 方法时,会得到以下两个类的实例 ⬇️
java.util.JumboEnumSetjava.util.RegularEnumSet
请运行以下命令以生成对应的内容 ⬇️
java ClassDiagramGenerator 'java.util.JumboEnumSet' 'java.util.RegularEnumSet'
运行结果是 Markdown 格式的,展示如下
运行结果
classDiagram
Iterable <|-- Collection
Collection <|.. AbstractCollection
Collection <|-- Set
AbstractCollection <|-- AbstractSet
Set <|.. AbstractSet
AbstractSet <|-- EnumSet
Cloneable <|.. EnumSet
Serializable <|.. EnumSet
EnumSet <|-- JumboEnumSet
EnumSet <|-- RegularEnumSet
<<Abstract>> AbstractCollection
<<Abstract>> AbstractSet
<<Abstract>> EnumSet
<<interface>> Iterable
<<interface>> Collection
<<interface>> Set
<<interface>> Cloneable
<<interface>> Serializable
| 在上图中的类名/接口名 | Fully Qualified Name |
|---|---|
AbstractCollection | java.util.AbstractCollection |
AbstractSet | java.util.AbstractSet |
Cloneable | java.lang.Cloneable |
Collection | java.util.Collection |
EnumSet | java.util.EnumSet |
Iterable | java.lang.Iterable |
JumboEnumSet | java.util.JumboEnumSet |
RegularEnumSet | java.util.RegularEnumSet |
Serializable | java.io.Serializable |
Set | java.util.Set |
例 8: 生成 ThreadPoolExecutor 的类图
请运行以下命令以生成对应的内容 ⬇️
java ClassDiagramGenerator 'java.util.concurrent.ThreadPoolExecutor'
运行结果是 Markdown 格式的,展示如下
运行结果
classDiagram
Executor <|-- ExecutorService
AutoCloseable <|-- ExecutorService
ExecutorService <|.. AbstractExecutorService
AbstractExecutorService <|-- ThreadPoolExecutor
<<Abstract>> AbstractExecutorService
<<interface>> Executor
<<interface>> AutoCloseable
<<interface>> ExecutorService
| 在上图中的类名/接口名 | Fully Qualified Name |
|---|---|
AbstractExecutorService | java.util.concurrent.AbstractExecutorService |
AutoCloseable | java.lang.AutoCloseable |
Executor | java.util.concurrent.Executor |
ExecutorService | java.util.concurrent.ExecutorService |
ThreadPoolExecutor | java.util.concurrent.ThreadPoolExecutor |
例 9: 自己手写一些类/接口,用 ClassDiagramGenerator 生成类图
请将以下代码保存为 E.java
class A {}
class B extends A {}
class C extends B implements I1, I2, I3 {}
class D extends C implements I1, I4 {}
interface I1 {}
interface I2 {}
interface I3 {}
interface I4 {}
public class E extends D implements I1, I4 { }
用如下的命令可以编译 E.java 并为 E 生成类图
javac E.java
java -cp . ClassDiagramGenerator 'E'
运行结果
classDiagram
A <|-- B
B <|-- C
I1 <|.. C
I2 <|.. C
I3 <|.. C
C <|-- D
I1 <|.. D
I4 <|.. D
D <|-- E
I1 <|.. E
I4 <|.. E
<<interface>> I1
<<interface>> I2
<<interface>> I3
<<interface>> I4
如果想忽略掉某些类/接口,例如想忽略 B 和 I4,那么可以使用如下的命令 ⬇️
java -cp . ClassDiagramGenerator -i 'B' -i 'I4' 'E'
运行结果如下 ⬇️ 请注意:以下的类/接口在类图中被忽略了
I4B
classDiagram
I1 <|.. C
I2 <|.. C
I3 <|.. C
C <|-- D
I1 <|.. D
D <|-- E
I1 <|.. E
<<interface>> I1
<<interface>> I2
<<interface>> I3