枪火工厂游戏
17.89MB · 2025-10-15
Mermaid
类图我在 [Java] 一些类图 这篇文章里画了一些类图,但是那些类图是我手动生成的,虽说画图的过程有利于加深自己的理解,但是查看各个类/接口的信息毕竟比较麻烦,如果可以把生成类图的过程自动化,就可以大大提升画类图的效率了。
本文展示了我自己写的可以生成简单类图的 java
代码。文中展示了用它生成的以下类的类图
ArrayList
LinkedList
java.util.Arrays$ArrayList
(Arrays.asList(...)
方法返回的是它的实例)List
/Set
/Deque
HashMap
/LinkedHashMap
/ConcurrentHashMap
Set12
/SetN
(Set.of(...)
方法返回的是它们的实例)java.util.JumboEnumSet
和 java.util.RegularEnumSet
(它们是 EnumSet
仅有的子类)java.util.concurrent.ThreadPoolExecutor
我写了如下的 java
代码,它可以自动生成简单的 Mermaid
类图。
请将以下代码保存为 ClassDiagramGenerator.java
⬇️
import java.lang.reflect.AccessFlag;
import java.util.*;
public class ClassDiagramGenerator {
private final Map<Class<?>, RealizationRelation> realizationRelations = new HashMap<>();
private final Map<Class<?>, InheritanceRelation> inheritanceRelations = new HashMap<>();
private final Set<Class<?>> analyzedClasses = new HashSet<>();
public static void main(String[] args) {
ClassDiagramGenerator generator = new ClassDiagramGenerator();
generator.convert(args).forEach(generator::analyzeHierarchy);
generator.generateClassDiagram();
generator.generateNameMappingTable();
}
/**
* Convert class name to the corresponding class object
*
* @param classNames give class names
* @return a list that contains corresponding class objects
*/
private List<Class<?>> convert(String[] classNames) {
if (classNames.length == 0) {
String hint = "Please refer to below usage and specify at least ONE class name!";
String usage = "Usage: java ClassDiagramGenerator 'java.util.ArrayList' 'java.util.LinkedList'";
throw new IllegalArgumentException(String.join(System.lineSeparator(), hint, usage));
}
List<Class<?>> classList = new ArrayList<>(classNames.length);
for (String className : classNames) {
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;
}
/**
* 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() {
System.out.println();
System.out.println("| 在上图中的类名/接口名 | `Fully Qualified Name` |");
System.out.println("| --- | --- |");
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);
}
classNames.put(simpleName, c.getName());
});
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).superNode().getSimpleName(), c.getSimpleName());
}
if (realizationRelations.containsKey(c)) {
String type = c.isInterface() ? "<|--" : "<|..";
realizationRelations.get(c).interfaceList().forEach(item -> {
System.out.printf("%s %s %s%n", item.getSimpleName(), type, c.getSimpleName());
});
}
});
generateSpecialClassAnnotation();
}
/**
* This method generated 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)) {
analyzeSuperClass(currClass);
analyzeInterfaces(currClass);
analyzedClasses.add(currClass);
}
}
private void analyzeSuperClass(Class<?> currClass) {
Class<?> superclass = currClass.getSuperclass();
if (superclass == null || superclass == Object.class) {
return;
}
analyzeHierarchy(superclass);
inheritanceRelations.put(currClass, new InheritanceRelation(currClass, superclass));
}
private void analyzeInterfaces(Class<?> currClass) {
Class<?>[] interfaces = currClass.getInterfaces();
for (Class<?> item : interfaces) {
analyzeHierarchy(item);
}
var interfaceList = Arrays.stream(interfaces).toList();
realizationRelations.put(currClass, new RealizationRelation(currClass, interfaceList));
}
}
/**
* A record class to hold inheritance relation
*/
record InheritanceRelation(Class<?> currNode, Class<?> superNode) {
}
/**
* A record class to hold realization relation
*/
record RealizationRelation(Class<?> currNode, List<Class<?>> interfaceList) {
}
用以下命令可以编译 ClassDiagramGenerator.java
javac ClassDiagramGenerator.java
请注意,ClassDiagramGenerator
生成的类图中,不包含任何泛型信息,而且也不展示任何字段/方法。
下面举一些例子,说明 ClassDiagramGenerator.java
的用法。
1
: 生成 ArrayList
的类图请运行以下命令以生成对应的内容 ⬇️
java ClassDiagramGenerator 'java.util.ArrayList'
运行结果是 Markdown
格式的,而掘金文档的编辑区支持相关格式。您可以通过下图所示的方式来体验在掘金的文档中如何画类图 ⬇️
classDiagram
AbstractCollection <|-- AbstractList
List <|.. AbstractList
AbstractList <|-- ArrayList
List <|.. ArrayList
RandomAccess <|.. ArrayList
Cloneable <|.. ArrayList
Serializable <|.. ArrayList
Iterable <|-- Collection
Collection <|-- SequencedCollection
Collection <|.. AbstractCollection
SequencedCollection <|-- List
<<Abstract>> AbstractList
<<Abstract>> AbstractCollection
<<interface>> RandomAccess
<<interface>> Iterable
<<interface>> Collection
<<interface>> SequencedCollection
<<interface>> List
<<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/ 看到的效果如下 ⬇️ (需要自行将结果复制到那个网页去)
2
: 生成 LinkedList
的类图请运行以下命令以生成对应的内容 ⬇️
java ClassDiagramGenerator 'java.util.LinkedList'
运行结果是 Markdown
格式的,展示如下
classDiagram
Queue <|-- Deque
SequencedCollection <|-- Deque
AbstractCollection <|-- AbstractList
List <|.. AbstractList
Iterable <|-- Collection
Collection <|-- SequencedCollection
AbstractList <|-- AbstractSequentialList
Collection <|-- Queue
AbstractSequentialList <|-- LinkedList
List <|.. LinkedList
Deque <|.. LinkedList
Cloneable <|.. LinkedList
Serializable <|.. LinkedList
Collection <|.. AbstractCollection
SequencedCollection <|-- List
<<Abstract>> AbstractList
<<Abstract>> AbstractSequentialList
<<Abstract>> AbstractCollection
<<interface>> Deque
<<interface>> Iterable
<<interface>> Collection
<<interface>> SequencedCollection
<<interface>> Queue
<<interface>> List
<<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 |
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
AbstractList <|-- ArrayList
RandomAccess <|.. ArrayList
Serializable <|.. ArrayList
AbstractCollection <|-- AbstractList
List <|.. AbstractList
Iterable <|-- Collection
Collection <|-- SequencedCollection
Collection <|.. AbstractCollection
SequencedCollection <|-- List
<<Abstract>> AbstractList
<<Abstract>> AbstractCollection
<<interface>> RandomAccess
<<interface>> Iterable
<<interface>> Collection
<<interface>> SequencedCollection
<<interface>> List
<<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
Collection <|-- Set
Queue <|-- Deque
SequencedCollection <|-- Deque
Iterable <|-- Collection
Collection <|-- SequencedCollection
Collection <|-- Queue
SequencedCollection <|-- List
<<interface>> Set
<<interface>> Deque
<<interface>> Iterable
<<interface>> Collection
<<interface>> SequencedCollection
<<interface>> Queue
<<interface>> List
在上图中的类名/接口名 | 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
AbstractMap <|-- HashMap
Map <|.. HashMap
Cloneable <|.. HashMap
Serializable <|.. HashMap
HashMap <|-- LinkedHashMap
SequencedMap <|.. LinkedHashMap
Map <|.. AbstractMap
AbstractMap <|-- ConcurrentHashMap
ConcurrentMap <|.. ConcurrentHashMap
Serializable <|.. ConcurrentHashMap
Map <|-- SequencedMap
Map <|-- ConcurrentMap
<<Abstract>> AbstractMap
<<interface>> Map
<<interface>> SequencedMap
<<interface>> ConcurrentMap
<<interface>> Cloneable
<<interface>> Serializable
在上图中的类名/接口名 | 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 |
6
: 生成 java.util.ImmutableCollections$Set12
和 java.util.ImmutableCollections$SetN
的类图当我们调用 Set.of(...)
方法时,会得到 java.util.ImmutableCollections$Set12
或 java.util.ImmutableCollections$SetN
的实例。
请运行以下命令以生成对应的内容 ⬇️
java ClassDiagramGenerator 'java.util.ImmutableCollections$Set12' 'java.util.ImmutableCollections$SetN'
运行结果是 Markdown
格式的,展示如下
classDiagram
AbstractCollection <|-- AbstractImmutableCollection
Collection <|-- Set
AbstractImmutableSet <|-- Set12
Serializable <|.. Set12
Iterable <|-- Collection
AbstractImmutableSet <|-- SetN
Serializable <|.. SetN
Collection <|.. AbstractCollection
AbstractImmutableCollection <|-- AbstractImmutableSet
Set <|.. AbstractImmutableSet
<<Abstract>> AbstractImmutableCollection
<<Abstract>> AbstractCollection
<<Abstract>> AbstractImmutableSet
<<interface>> Set
<<interface>> Iterable
<<interface>> Collection
<<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
的类图请运行以下命令以生成对应的内容 ⬇️
java ClassDiagramGenerator 'java.util.JumboEnumSet' 'java.util.RegularEnumSet'
运行结果是 Markdown
格式的,展示如下
classDiagram
Collection <|-- Set
AbstractSet <|-- EnumSet
Cloneable <|.. EnumSet
Serializable <|.. EnumSet
Iterable <|-- Collection
EnumSet <|-- JumboEnumSet
AbstractCollection <|-- AbstractSet
Set <|.. AbstractSet
Collection <|.. AbstractCollection
EnumSet <|-- RegularEnumSet
<<Abstract>> EnumSet
<<Abstract>> AbstractSet
<<Abstract>> AbstractCollection
<<interface>> Set
<<interface>> Iterable
<<interface>> Collection
<<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
AbstractExecutorService <|-- ThreadPoolExecutor
ExecutorService <|.. AbstractExecutorService
<<Abstract>> AbstractExecutorService
<<interface>> AutoCloseable
<<interface>> ExecutorService
<<interface>> Executor
在上图中的类名/接口名 | 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 |