JAVA類體系圖生成器

weixin_33905756發表於2018-01-17

layout: post
title: JAVA類體系圖生成器
categories: Java
description: JAVA類體系圖生成器
keywords:
url: https://lichao890427.github.io/ https://github.com/lichao890427/


簡介

  由於是java新手,知道的東西較少,有時候要用到某個功能,而該功能在某個特定類裡,而這個類你不一定清楚是什麼,該用哪個類一般需要在網上現查,這個工具就是用來快速列舉類的所有派生類超類的,與java的反射機制剛好相反,反射機制讓你能找到他的父類或父介面。舉個例子:現在要讀取檔案而且分行讀取,假設你只記得一些常識性的東西,例如讀取檔案要用基於InputStream的類,但是檢視InputStream的說明後你會發現該類只能按byte[]讀,而分行讀這種高階功能一定是派生於InputStream的某個類,但是就是想不起來,因為繼承於BufferedReader的有:

  • ByteArrayInputStream
  • FileInputStream
  • BufferedInputStream
  • DataInputStream
    等等很多,真相見圖:

  該工具用於檢視所有類及介面的繼承關係,介面可以看成一種特殊的類,java不支援多重繼承也就是隻能由一個父類,但是可以繼承於多個介面,介面是隻有成員函式而無成員變數的類而已,所以在這個角度說,也可以看成java是多重繼承的,事實上在程式中我已經這麼做了,因為檢視父介面也是很重要的,不過這樣就導致生成樹會有重複部分。這個工具最後做了2分,第一份是包括jdk帶的所有執行時庫,%JAVA_HOME%\jre\lib 和%JAVA_HOME%\jre\lib\ext 下的所有jar檔案解壓出來以後不重複的class檔案有4W個之多,大家知道一個class對應一個類,現在知道java有多龐大了吧。
  最後花了20分鐘吧所有類解析出來繼承關係並生成類樹,4M的config.txt是根據這些資訊生成的,用於下次啟動直接載入不用再次解析,不過由於龐大的數量,完全載入也花了快10分鐘。最後由於太多,顯然java的JTree出了問題,因為很多都沒顯示出來了。第二份是rt.jar裡的java和javax資料夾,就目前情況而言匯入基本上用的都是這裡的東西。匯入不到半分鐘,生成的config.txt有1W行,很快就見到JTree在跳動了。。。如果有第三方庫要匯入類圖,需要解壓jar到相應位置,程式啟動以後會先從config.txt匯入資料,然後遍歷指定目錄檔案加入生成樹,每個檔案都是一個類,對每個類都要迭代其父類直到父類為null停止,這樣就構成了樹。對於不支援檢視類資訊的類生成排除列表。此工具還可在類圖形成後進行關鍵字搜尋,搜到的詞放到一個JList裡,選擇後可以直接定位到JTree中,十分方便。

Coding

package test;

import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.PrintStream;

import java.util.LinkedList;
import java.util.Queue;

import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
public class classtree extends JFrame {
    private static final long serialVersionUID = 1L;
    private static Queue<String> myqueue = null;
    private JTextField toSearch = null;
    private JList<String> result = null;
    private JTree tree = null;
    public HashTreeNode root = null;
    public HashTreeNode exception = null;
    private String folderpath = "C:/Users/Administrator/Desktop/rt";
    private boolean datachanged = false; //????????
    private String tofind = null;
    private LinkedList<Integer> select = null;
    private LinkedList<String> excluded = null;
    JScrollPane scrollPane = null;
    DefaultMutableTreeNode uiroot = null;

    public classtree() {
        super("");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        getContentPane().setLayout(null);
        toSearch = new JTextField();
        toSearch.setBounds(107, 630, 247, 21);
        getContentPane().add(toSearch);
        toSearch.setColumns(10);
        JLabel label = new JLabel("\u8981\u641C\u7D22\u7684\u76EE\u6807\uFF1A");
        label.setBounds(10, 633, 87, 15);
        getContentPane().add(label);
        JButton search = new JButton("\u641C");
        search.setBounds(364, 629, 100, 23);
        getContentPane().add(search);
        scrollPane = new JScrollPane();
        scrollPane.setBounds(0, 0, 584, 496);
        getContentPane().add(scrollPane);
        tree = new JTree();
        tree.setScrollsOnExpand(true);
        tree.setFocusable(true);
        tree.setAutoscrolls(true);
        tree.setModel(new DefaultTreeModel(
                uiroot = new DefaultMutableTreeNode("JAVAHOME")));
        scrollPane.setViewportView(tree);
        JScrollPane scrollPane_1 = new JScrollPane();
        scrollPane_1.setBounds(0, 497, 584, 123);
        getContentPane().add(scrollPane_1);
        result = new JList<String>();
        scrollPane_1.setViewportView(result);
        JButton outputfile = new JButton("\u751F\u6210\u6587\u4EF6");
        outputfile.setBounds(474, 629, 100, 23);
        getContentPane().add(outputfile);
        setSize(600, 700);
        setVisible(true);
        root = new HashTreeNode("???");
        exception = root.AddChild("??");
        myqueue = new LinkedList<String>();
        select = new LinkedList<Integer>();
        excluded = new LinkedList<String>();
        excluded.add("com.sun.management.OperatingSystem");
        excluded.add("com.sun.org.apache.xml.internal.serialize.HTMLdtd");
        excluded.add("sun.awt.windows.WBufferStrategy");
        excluded.add("sun.font.FreetypeFontScaler");
        excluded.add("sun.java2d.cmm.lcms.LCMS");
        excluded.add("sun.jdbc.odbc.JdbcOdbcPlatform");
        excluded.add("sun.org.mozilla.javascript.internal.SecureCaller");
        excluded.add("sun.plugin.extension.ExtensionUtils");
        excluded.add("sun.plugin2.main.client.WDonatePrivilege");
        excluded.add("sun.plugin2.main.server.IExplorerPlugin");
        excluded.add("sun.plugin2.main.server.MozillaPlugin");
        excluded.add("sun.plugin2.os.windows.Windows");
        excluded.add("sun.plugin2.main.server.ProxySupport");
        excluded.add("sun.reflect.misc.Trampoline");
        excluded.add("sun.security.krb5.SCDynamicStoreConfig");
        excluded.add("oracle.jrockit.jfr.Process");
        excluded.add("oracle.jrockit.jfr.Timing");
        excluded.add("com.sun.deploy.uitoolkit.impl.awt.AWTClientPrintHelper");
        excluded.add("com.sun.glass.ui.mac");
        excluded.add("com.sun.glass.ui.x11.X11Timer");
        excluded.add("com.sun.javafx.logging.LoggingSupport");
        try {
            if (new File("config.txt").exists()) {
                FileReader fr = new FileReader("config.txt");
                BufferedReader br = new BufferedReader(fr);
                FileInputStream fis = new FileInputStream("config.txt");
                String line = "";
                while ((line = br.readLine()) != null) {
                    //                                           System.out.println(line);
                    AddNodeByString(line.substring(1, line.length() - 1)
                                        .split(","));
                }
                br.close();
                fr.close();
            }
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        result.addListSelectionListener(new ListSelectionListener() {
                public void valueChanged(ListSelectionEvent e) {
                    for (int i = 0; i < tree.getRowCount(); i++) {
                        tree.expandRow(i);
                    }
                    int i = select.get(result.getSelectedIndex());
                    tree.setSelectionRow(i);
                    Rectangle rect = tree.getRowBounds(i);
                    tree.scrollRectToVisible(rect);
                }
            });
        search.addMouseListener(new MouseAdapter() {
                Thread searchthread = null;
                @Override
                public void mouseClicked(MouseEvent e) {
                    searchthread = new Thread() { //????????
                                @Override
                                public void run() {
                                    try {
                                        result.setModel(new DefaultListModel<String>());
                                        tofind = toSearch.getText();
                                        for (int i = 0; i < tree.getRowCount();
                                                i++) {
                                            tree.expandRow(i);
                                        }
                                        select = new LinkedList<Integer>();
                                        for (int i = 0; i < tree.getRowCount();
                                                i++) {
                                            String obj = tree.getPathForRow(i)
                                                             .toString();
                                            if (obj.contains(tofind)) {
                                                ((DefaultListModel<String>) result.getModel()).addElement(obj);
                                                select.add(i);
                                            }
                                        }
                                    }
                                    catch (Exception e) {
                                        e.printStackTrace();
                                    }
                                }
                            };
                    try {
                        searchthread.start();
                        searchthread.join();
                    }
                    catch (Exception exc) {
                        exc.printStackTrace();
                    }
                }
            });
        final Thread filethread = new Thread() { //????????
                @Override
                public void run() {
                    FindClassInfo(folderpath, "");
                    datachanged = true;
                }
            };
        filethread.start();
        new Thread() { //????????
                @Override
                public void run() {
                    try {
                        filethread.join();
                        while (true) {
                            if (myqueue.isEmpty()) {
                                Thread.sleep(500);
                                if (datachanged) {
                                    uiroot = new DefaultMutableTreeNode(
                                            "JAVAHOME");
                                    tree.setModel(new DefaultTreeModel(uiroot));
                                    AddUItree(root, uiroot);
                                    datachanged = false;
                                }
                                else {
                                    for (int i = 0; i < tree.getRowCount();
                                            i++) {
                                        tree.expandRow(i);
                                    }
                                }
                            }
                            else {
                                if (filethread.isAlive()) {
                                    filethread.join();
                                }
                                AddOneNode(myqueue.poll());
                            }
                        }
                    }
                    catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }.start();
        outputfile.addMouseListener(new MouseAdapter() {
                @Override
                public void mouseClicked(MouseEvent e) {
                    OutputFile();
                }
            });
        addWindowListener(new WindowAdapter() { //??????????
                @Override
                public void windowClosing(WindowEvent e) {
                    OutputFile();
                }
            });
    }
    public synchronized void AddNodeByString(String[] allpath) {
        HashTreeNode node = root;
        for (int i = 1; i < allpath.length; i++) {
            node = node.AddChild(allpath[i].trim());
        }
    }
    public synchronized LinkedList<HashTreeNode> AddOneNode(String classpath) //????
     { //???????
        LinkedList<HashTreeNode> result = new LinkedList<HashTreeNode>();
        try {
            //                         System.out.println(classpath);
            for (String exc : excluded) {
                if (classpath.contains(exc)) {
                    result.add(exception.AddChild(classpath));
                    return result;
                }
            }
            //??????
            java.lang.reflect.Type curtype = Class.forName(classpath)
                                                  .getGenericSuperclass();
            LinkedList<java.lang.reflect.Type> type = new LinkedList<java.lang.reflect.Type>();
            if (curtype != null) {
                type.add(curtype);
            }
            else {
                result.add(root.AddChild(classpath));
            }
            for (java.lang.reflect.Type curtype1 : Class.forName(classpath)
                                                        .getGenericInterfaces()) {
                type.add(curtype1);
            }
            for (java.lang.reflect.Type curtype2 : type) {
                String classstr = curtype2.toString();
                if (classstr.contains("interface") ||
                        classstr.contains("class")) {
                    classstr = classstr.substring(classstr.indexOf(' ') + 1);
                }
                if (classstr.indexOf('<') > -1) {
                    classstr = classstr.substring(0, classstr.indexOf('<'));
                }
                for (HashTreeNode node1 : AddOneNode(classstr)) {
                    result.add(node1.AddChild(classpath));
                }
            }
            return result;
        }
        catch (Exception e) {
            System.out.println("error:" + classpath);
            result.add(exception.AddChild(classpath));
            return result;
        }
    }
    public static void FindClassInfo(String dir, String classpath) {
        try {
            File file = new File(dir);
            if (file.isFile()) {
                if ((classpath.indexOf('$') < 0) &&
                        (classpath.indexOf(".class") > -1)) {
                    String obj = classpath.replace(".class", "");
                    myqueue.add(obj);
                    System.out.println(obj);
                }
            }
            else if (file.isDirectory()) {
                for (String dirstr : file.list()) {
                    String newclasspath = classpath.equals("") ? dirstr
                                                               : (classpath +
                        "." + dirstr);
                    FindClassInfo(dir + "/" + dirstr, newclasspath);
                }
            }
        }
        catch (Exception e) {
            System.out.println("error");
        }
    }
    public void FindAllMatchClass(HashTreeNode node) {
        try {
            String dest = tofind.substring(tofind.lastIndexOf('.') + 1);
            if (node.nodename.contains(dest)) {
                ((DefaultListModel<String>) result.getModel()).addElement(node.nodename);
            }
            for (HashTreeNode cur : node.children) {
                FindAllMatchClass(cur);
            }
        }
        catch (Exception e) {
            System.out.println("error");
        }
    }
    public void AddUItree(HashTreeNode curnode, DefaultMutableTreeNode uinode) {
        try {
            for (int i = 0; i < curnode.children.size(); i++) {
                HashTreeNode cur = curnode.children.get(i);
                DefaultMutableTreeNode newnode = new DefaultMutableTreeNode(cur.nodename);
                uinode.add(newnode);
                AddUItree(cur, newnode);
            }
        }
        catch (Exception e) {
            System.out.println("error");
        }
    }
    public void OutputFile() {
        try {
            for (int i = 0; i < tree.getRowCount(); i++) {
                tree.expandRow(i);
            }
            FileOutputStream fos = new FileOutputStream("config.txt");
            for (int i = 0; i < tree.getRowCount(); i++) {
                String obj = tree.getPathForRow(i).toString() + "\n";
                fos.write(obj.getBytes());
            }
            fos.close();
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }
    public static void main(String[] args) throws FileNotFoundException {
        //System.setOut(new PrintStream("abcd.txt"));
        new classtree();
    }
    public class HashTreeNode {
        public String nodename;
        public LinkedList<HashTreeNode> children;
        public HashTreeNode(String name) {
            nodename = name;
            children = new LinkedList<HashTreeNode>();
        }
        public synchronized HashTreeNode AddChild(String name) {
            HashTreeNode newnode = null;
            for (int i = 0; i < children.size(); i++) {
                if (name.equals(children.get(i).nodename)) {
                    return children.get(i);
                }
                else if (name.compareTo(children.get(i).nodename) < 0) //name < node
                 {
                    newnode = new HashTreeNode(name);
                    children.add(i, newnode);
                    return newnode;
                }
            }
            newnode = new HashTreeNode(name);
            children.add(newnode);
            return newnode;
        }
    }
}

Config.txt樣例部分

[JAVAHOME]
[JAVAHOME, java.applet.AppletContext]
[JAVAHOME, java.applet.AppletContext, java.beans.BeansAppletContext]
[JAVAHOME, java.applet.AppletStub]
[JAVAHOME, java.applet.AppletStub, java.beans.BeansAppletStub]
[JAVAHOME, java.applet.AudioClip]
[JAVAHOME, java.awt.ActiveEvent]
[JAVAHOME, java.awt.ActiveEvent, java.awt.SentEvent]
[JAVAHOME, java.awt.ActiveEvent, java.awt.SequencedEvent]
[JAVAHOME, java.awt.ActiveEvent, java.awt.event.InvocationEvent]
[JAVAHOME, java.awt.Adjustable]
[JAVAHOME, java.awt.Adjustable, java.awt.ScrollPaneAdjustable]
[JAVAHOME, java.awt.Adjustable, java.awt.Scrollbar]
[JAVAHOME, java.awt.Adjustable, javax.swing.JScrollBar]
[JAVAHOME, java.awt.Composite]
[JAVAHOME, java.awt.Composite, java.awt.AlphaComposite]

10152172-525821151b971023.png
old_blog_0.png

10152172-0d0d7b2665e106bc.png
old_blog_1.png
10152172-d1e13003b8201729.png
old_blog_2.png
10152172-004799cde76d5425.png
old_blog_3.png
10152172-a9fb9c0dceb32511.png
old_blog_4.png
10152172-8af5b14a12ca2a64.png
old_blog_5.png
10152172-d4f5fa2bc1cc9fd0.png
old_blog_6.png
10152172-4682e8f1790cbfd0.png
old_blog_7.png
10152172-4c07dc3b0cd9cfd9.png
old_blog_8.png
10152172-02207cf70964d109.png
old_blog_9.png
10152172-3a57d3fb30e3beef.png
old_blog_10.png

相關文章