最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

一文詳解Java如何自動生成簡單的Mermaid類圖

 更新時間:2025年10月10日 08:32:12   作者:金銀銅鐵  
這篇文章主要為大家詳細介紹了Java如何自動生成簡單的Mermaid類圖,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下

背景

雖說手動生成類圖的過程有利于加深自己的理解,但是查看各個類/接口的信息畢竟比較麻煩,如果可以把生成類圖的過程自動化,就可以大大提升畫類圖的效率了。

本文展示了我自己寫的可以生成簡單類圖的 java 代碼。文中展示了用它生成的以下類的類圖

  • ArrayList
  • LinkedList
  • java.util.Arrays$ArrayListArrays.asList(...) 方法返回的是它的實例)
  • List/Set/Deque
  • HashMap/LinkedHashMap/ConcurrentHashMap
  • Set12/SetNSet.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 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).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)) {
            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, superclass);
    }

    private void analyzeInterfaces(Class<?> currClass) {
        Class<?>[] interfaces = currClass.getInterfaces();
        for (Class<?> item : interfaces) {
            analyzeHierarchy(item);
        }

        realizationRelations.put(currClass, interfaces);
    }
}

用以下命令可以編譯 ClassDiagramGenerator.java

javac ClassDiagramGenerator.java

注意事項

請注意,ClassDiagramGenerator 生成的類圖中,不包含任何泛型信息,而且也不展示任何字段/方法。

例子

下面舉一些例子,說明 ClassDiagramGenerator.java 的用法。

例1: 生成ArrayList的類圖

請運行以下命令以生成對應(yīng)的內(nèi)容 

java ClassDiagramGenerator 'java.util.ArrayList'

運行結(jié)果是 Markdown 格式的

運行結(jié)果

在上圖中的類名/接口名Fully Qualified Name
AbstractCollectionjava.util.AbstractCollection
AbstractListjava.util.AbstractList
ArrayListjava.util.ArrayList
Cloneablejava.lang.Cloneable
Collectionjava.util.Collection
Iterablejava.lang.Iterable
Listjava.util.List
RandomAccessjava.util.RandomAccess
SequencedCollectionjava.util.SequencedCollection
Serializablejava.io.Serializable

變通的方式

如果您無法在掘金的文檔中使用 Mermaid,那么也可以前往 mermaid.live/ 來查看對應(yīng)的類圖,我在 mermaid.live/ 看到的效果如下 (需要自行將結(jié)果復(fù)制到那個網(wǎng)頁去)

例2: 生成LinkedList的類圖

請運行以下命令以生成對應(yīng)的內(nèi)容 

java ClassDiagramGenerator 'java.util.LinkedList'

運行結(jié)果是 Markdown 格式的,展示如下

運行結(jié)果

在上圖中的類名/接口名Fully Qualified Name
AbstractCollectionjava.util.AbstractCollection
AbstractListjava.util.AbstractList
AbstractSequentialListjava.util.AbstractSequentialList
Cloneablejava.lang.Cloneable
Collectionjava.util.Collection
Dequejava.util.Deque
Iterablejava.lang.Iterable
LinkedListjava.util.LinkedList
Listjava.util.List
Queuejava.util.Queue
SequencedCollectionjava.util.SequencedCollection
Serializablejava.io.Serializable

例3: 生成java.util.Arrays$ArrayList的類圖

調(diào)用 Arrays.asList(...) 方法,得到的是 java.util.Arrays$ArrayList 的實例。 請運行以下命令以生成對應(yīng)的內(nèi)容 

java ClassDiagramGenerator 'java.util.Arrays$ArrayList'

運行結(jié)果是 Markdown 格式的,展示如下

運行結(jié)果

請注意下圖中的 ArrayListjava.util.Arrays 中的一個嵌套類,而不是我們平時常用的 java.util.ArrayList

在上圖中的類名/接口名Fully Qualified Name
AbstractCollectionjava.util.AbstractCollection
AbstractListjava.util.AbstractList
ArrayListjava.util.Arrays$ArrayList
Collectionjava.util.Collection
Iterablejava.lang.Iterable
Listjava.util.List
RandomAccessjava.util.RandomAccess
SequencedCollectionjava.util.SequencedCollection
Serializablejava.io.Serializable

例4: 生成List/Set/Deque的類圖

請運行以下命令以生成對應(yīng)的內(nèi)容 

java ClassDiagramGenerator 'java.util.List' 'java.util.Set' 'java.util.Deque'

運行結(jié)果是 Markdown 格式的,展示如下

運行結(jié)果

在上圖中的類名/接口名Fully Qualified Name
Collectionjava.util.Collection
Dequejava.util.Deque
Iterablejava.lang.Iterable
Listjava.util.List
Queuejava.util.Queue
SequencedCollectionjava.util.SequencedCollection
Setjava.util.Set

例5: 生成HashMap/LinkedHashMap/ConcurrentHashMap的類圖

請運行以下命令以生成對應(yīng)的內(nèi)容 

java ClassDiagramGenerator 'java.util.HashMap' 'java.util.LinkedHashMap' 'java.util.concurrent.ConcurrentHashMap'

運行結(jié)果是 Markdown 格式的,展示如下

運行結(jié)果

在上圖中的類名/接口名Fully Qualified Name
AbstractMapjava.util.AbstractMap
Cloneablejava.lang.Cloneable
ConcurrentHashMapjava.util.concurrent.ConcurrentHashMap
ConcurrentMapjava.util.concurrent.ConcurrentMap
HashMapjava.util.HashMap
LinkedHashMapjava.util.LinkedHashMap
Mapjava.util.Map
SequencedMapjava.util.SequencedMap
Serializablejava.io.Serializable

例6: 生成java.util.ImmutableCollections$Set12和java.util.ImmutableCollections$SetN的類圖

當我們調(diào)用 Set.of(...) 方法時,會得到以下兩個類的實例 

  • java.util.ImmutableCollections$Set12
  • java.util.ImmutableCollections$SetN

請運行以下命令以生成對應(yīng)的內(nèi)容 

java ClassDiagramGenerator 'java.util.ImmutableCollections$Set12' 'java.util.ImmutableCollections$SetN'

運行結(jié)果是 Markdown 格式的,展示如下

運行結(jié)果

在上圖中的類名/接口名Fully Qualified Name
AbstractCollectionjava.util.AbstractCollection
AbstractImmutableCollectionjava.util.ImmutableCollections$AbstractImmutableCollection
AbstractImmutableSetjava.util.ImmutableCollections$AbstractImmutableSet
Collectionjava.util.Collection
Iterablejava.lang.Iterable
Serializablejava.io.Serializable
Setjava.util.Set
Set12java.util.ImmutableCollections$Set12
SetNjava.util.ImmutableCollections$SetN

例7: 生成java.util.JumboEnumSet和java.util.RegularEnumSet的類圖

當我們調(diào)用 EnumSet.of(...) 方法時,會得到以下兩個類的實例 

  • java.util.JumboEnumSet
  • java.util.RegularEnumSet

請運行以下命令以生成對應(yīng)的內(nèi)容 

java ClassDiagramGenerator 'java.util.JumboEnumSet' 'java.util.RegularEnumSet'

運行結(jié)果是 Markdown 格式的,展示如下

運行結(jié)果

在上圖中的類名/接口名Fully Qualified Name
AbstractCollectionjava.util.AbstractCollection
AbstractSetjava.util.AbstractSet
Cloneablejava.lang.Cloneable
Collectionjava.util.Collection
EnumSetjava.util.EnumSet
Iterablejava.lang.Iterable
JumboEnumSetjava.util.JumboEnumSet
RegularEnumSetjava.util.RegularEnumSet
Serializablejava.io.Serializable
Setjava.util.Set

例8: 生成ThreadPoolExecutor的類圖

請運行以下命令以生成對應(yīng)的內(nèi)容 

java ClassDiagramGenerator 'java.util.concurrent.ThreadPoolExecutor'

運行結(jié)果是 Markdown 格式的,展示如下

運行結(jié)果

在上圖中的類名/接口名Fully Qualified Name
AbstractExecutorServicejava.util.concurrent.AbstractExecutorService
AutoCloseablejava.lang.AutoCloseable
Executorjava.util.concurrent.Executor
ExecutorServicejava.util.concurrent.ExecutorService
ThreadPoolExecutorjava.util.concurrent.ThreadPoolExecutor

到此這篇關(guān)于一文詳解Java如何自動生成簡單的Mermaid類圖的文章就介紹到這了,更多相關(guān)Java生成Mermaid類圖內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • JVM之方法返回地址詳解

    JVM之方法返回地址詳解

    這篇文章主要介紹了JVM之方法返回地址詳解,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-02-02
  • SpringSecurity集成第三方登錄過程詳解(最新推薦)

    SpringSecurity集成第三方登錄過程詳解(最新推薦)

    在ThirdAuthenticationFilter 類的attemptAuthentication()方法中,我們通過authType類型,然后創(chuàng)建對應(yīng)的Authentication實現(xiàn)來實現(xiàn)不同方式的登錄,下面給大家分享SpringSecurity集成第三方登錄過程,感興趣的朋友一起看看吧
    2024-05-05
  • Java 確保某個Bean類被最后執(zhí)行的幾種實現(xiàn)方式

    Java 確保某個Bean類被最后執(zhí)行的幾種實現(xiàn)方式

    這篇文章主要介紹了Java 確保某個BeanDefinitionRegistryPostProcessor Bean被最后執(zhí)行的幾種實現(xiàn)方式,幫助大家更好的理解和學(xué)習(xí)使用Java,感興趣的朋友可以了解下
    2021-03-03
  • SpringBoot中基于JWT的單token授權(quán)和續(xù)期方案步驟詳解

    SpringBoot中基于JWT的單token授權(quán)和續(xù)期方案步驟詳解

    在前后端分離架構(gòu)中,用戶登錄后,后端生成JWT?Token返給前端存于LocalStorage,每次請求攜帶Token驗證身份,后端校驗其有效性,本文給大家介紹SpringBoot中基于JWT的單token授權(quán)和續(xù)期方案步驟詳解,感興趣的朋友一起看看吧
    2024-09-09
  • SpringBoot根據(jù)目錄結(jié)構(gòu)自動生成路由前綴的實現(xiàn)代碼

    SpringBoot根據(jù)目錄結(jié)構(gòu)自動生成路由前綴的實現(xiàn)代碼

    本文介紹如何根據(jù)目錄結(jié)構(gòu)給RequestMapping添加路由前綴,具體實現(xiàn)方法,本文通過示例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2021-08-08
  • Java命名規(guī)范

    Java命名規(guī)范

    本文主要介紹了Java命名規(guī)范。具有一定的參考價值,下面跟著小編一起來看下吧
    2017-01-01
  • MyBatis分頁插件PageHelper深度解析與實踐指南

    MyBatis分頁插件PageHelper深度解析與實踐指南

    在數(shù)據(jù)庫操作中,分頁查詢是最常見的需求之一,傳統(tǒng)的分頁方式通常有兩種內(nèi)存分頁和SQL分頁,MyBatis作為優(yōu)秀的ORM框架,本身并未提供統(tǒng)一的分頁解決方案,這正是PageHelper誕生的背景,下面小編給大家詳細說說MyBatis分頁插件PageHelper,需要的朋友可以參考下
    2025-05-05
  • Mybatis返回數(shù)組的兩種實現(xiàn)方式

    Mybatis返回數(shù)組的兩種實現(xiàn)方式

    這篇文章主要介紹了Mybatis返回數(shù)組的兩種實現(xiàn)方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-03-03
  • Java數(shù)據(jù)庫連接池之proxool_動力節(jié)點Java學(xué)院整理

    Java數(shù)據(jù)庫連接池之proxool_動力節(jié)點Java學(xué)院整理

    Proxool是一種Java數(shù)據(jù)庫連接池技術(shù)。方便易用,便于發(fā)現(xiàn)連接泄漏的情況
    2017-08-08
  • springboot整合TDengine全過程

    springboot整合TDengine全過程

    這篇文章主要介紹了springboot整合TDengine全過程,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-06-06

最新評論

逊克县| 荔浦县| 三明市| 定安县| 延边| 宝应县| 绥阳县| 永州市| 同德县| 肇州县| 金溪县| 天峨县| 大安市| 虎林市| 武乡县| 临漳县| 宝坻区| 家居| 九台市| 南通市| 南汇区| 锡林浩特市| 玉溪市| 澄城县| 花莲市| 平泉县| 呼伦贝尔市| 万全县| 新宁县| 罗山县| 泾源县| 泊头市| 天门市| 五莲县| 永定县| 高邮市| 米泉市| 石阡县| 乐都县| 会同县| 修文县|