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]