文件管理 · 2022年8月17日

分析java文件|java工作原理

1. 急!急!急!急!急! 在一个文件夹目录下 如果是.java文件就分析出有效代码行数、空行数、注释行数。接下面

我们以前在学校的时候也做过这个,还要用Swing做界面。不过今天是我从新做出来的

JavaSourceUtil.java

importjava.io.BufferedReader;importjava.io.File;importjava.io.FileInputStream;importjava.io.FileNotFoundException;importjava.io.FileOutputStream;importjava.io.IOException;importjava.io.InputStreamReader;importjava.util.ArrayList;importjava.util.List;classJavaSourceUtil{ publicstaticvoidmain(String[]args){ //统计文件路径 StringfolderPath="C:\Users\xmi\Desktop\AnzDoc\123\BatchAssistant\src\dcb\"; //路径文件 Filefolder=newFile(folderPath); //源文件统计工具 JavaSourceUtilutil=newJavaSourceUtil(); //根据路径得到统计结果列表 List<SourceBean>cntList=util.countJavaSource(folder); //根据统计行数计算注释率、空行率、有效代码率的结果 StringBufferresultSbuf=util.outputCountResult(cntList); //输出统计结果 System.out.println(resultSbuf.toString()); //保存结果到文件 util.saveFile(resultSbuf,"D:\java_source_cnt.txt"); } (List<SourceBean>listBean){ StringBuffersbuf=newStringBuffer(); SourceBeantotalCntBean=newSourceBean("全部文件统计"); for(SourceBeanbean:listBean){ inttolCnt=bean.getTotalLine(); if(tolCnt==0){ continue; } //注释率、空行率、有效代码率的结果算出来 sbuf.append(bean.fileName+"代码统计:").append("
"); sbuf.append("空行率:").append(bean.blankLine*1.0/tolCnt) .append("
"); sbuf.append("注释率:") .append((bean.singlgCmtLine+bean.multCmtLine)*1.0 /tolCnt).append("
"); sbuf.append("有效代码率:").append(bean.codeLine*1.0/tolCnt) .append("

"); totalCntBean.blankLine+=bean.blankLine; totalCntBean.codeLine+=bean.codeLine; totalCntBean.documtLine+=bean.documtLine; totalCntBean.multCmtLine+=bean.multCmtLine; totalCntBean.singlgCmtLine+=bean.singlgCmtLine; } sbuf.append(totalCntBean.fileName+"代码统计:").append("
"); sbuf.append("总空行率:").append(totalCntBean.blankLine*1.0/totalCntBean.getTotalLine()) .append("
"); sbuf.append("总注释率:") .append((totalCntBean.singlgCmtLine+totalCntBean.multCmtLine)*1.0 /totalCntBean.getTotalLine()).append("
"); sbuf.append("总有效代码率:").append(totalCntBean.codeLine*1.0/totalCntBean.getTotalLine()) .append("

"); returnsbuf; } /** *Java代码统计 *@paramfolder基本路径 *@return统计结果 */ publicList<SourceBean>countJavaSource(Filefolder){ List<SourceBean>cntList=newArrayList<SourceBean>(); if(!folder.exists()||!folder.isDirectory()){ returncntList; } File[]files=folder.listFiles(); for(inti=0;i<files.length;i++){ if(files[i].isDirectory()){ cntList.addAll(countJavaSource(folder)); }else{ SourceBeancntBean=countCodeLine(files[i]); if(cntBean!=null){ cntList.add(cntBean); } } } returncntList; } /** *单个文件代码统计 *@paramjavaFile.java文件 *@return统计结果 */ publicSourceBeancountCodeLine(FilejavaFile){ if(!javaFile.exists()||!javaFile.isFile()||!javaFile.getName().endsWith(".java")){ returnnull; } SourceBeancntBean=newSourceBean(javaFile.getAbsolutePath()); //代码状态 intstatus=0; try{ InputStreamReaderisr=newInputStreamReader(newFileInputStream(javaFile)); Stringstr=""; BufferedReaderbufReader=newBufferedReader(isr); while((str=bufReader.readLine())!=null){ str=str.trim(); if(str.startsWith("/**")){ //文档注释 status=10; }elseif(str.startsWith("/*")){ //多行注释 status=20; } if(isEmpty(str)){ //空白航 cntBean.blankLine++; }elseif(status==10){ //文档注释 cntBean.documtLine++; }elseif(status==20){ //多行注释 cntBean.multCmtLine++; }elseif(str.startsWith("//")){ //单行注释 cntBean.singlgCmtLine++; }else{ //代码行 cntBean.codeLine++; } if(str.endsWith("*/")){ //单行或文本注释结束 status=0; } } bufReader.close(); }catch(FileNotFoundExceptione){ //TODOAuto-generatedcatchblock e.printStackTrace(); }catch(IOExceptione){ //TODOAuto-generatedcatchblock e.printStackTrace(); } returncntBean; } /** *空行判断 *@paramstrValue *@return是否为空行 */ publicbooleanisEmpty(StringstrValue){ if(strValue==null||strValue.trim().equals("")){ returntrue; } returnfalse; } /** *读取文本文件 *@parampath *@return */ publicvoidsaveFile(StringBufferbuilder,Stringpath){ try{ FileOutputStreamfos=newFileOutputStream(path); fos.write(builder.toString().getBytes("utf-8")); fos.flush(); fos.close(); }catch(FileNotFoundExceptione){ //TODOAuto-generatedcatchblock e.printStackTrace(); }catch(IOExceptione){ //TODOAuto-generatedcatchblock e.printStackTrace(); } }}

SourceBean.java

publicclassSourceBean{ //空白行 publicintblankLine; //单行注释 publicintsinglgCmtLine; //多行注释 publicintmultCmtLine; //代码行数 publicintcodeLine; //文挡注释 publicintdocumtLine; //文件名 publicStringfileName; publicSourceBean(StringfileName){ this.fileName=fileName; } publicintgetTotalLine(){ inttotalLine=blankLine+singlgCmtLine+multCmtLine+codeLine +documtLine; returntotalLine; }}

是不是很简单!

2. 关于对“.Java”文件的分析

用Java提供的 ClassLoader 就可以完成的,将一个Class类装载,然后反射得到方法就行。或者用正则表达式直接解析Java文件

3. java工作原理

作为一名Java使用者,掌握JVM的体系结构也是必须的。说起Java,人们首先想到的是Java编程语言,然而事实上,Java是一种技术,它由四方面组成:Java编程语言、Java类文件格式、Java虚拟机和Java应用程序接口(Java API)。它们的关系如下图所示:

运行期环境代表着Java平台,开发人员编写Java代码(.java文件),然后将之编译成字节码(.class文件),再然后字节码被装入内存,一旦字节码进入虚拟机,它就会被解释器解释执行,或者是被即时代码发生器有选择的转换成机器码执行。

Java平台由Java虚拟机和Java应用程序接口搭建,Java语言则是进入这个平台的通道,用Java语言编写并编译的程序可以运行在这个平台上。

在Java平台的结构中, 可以看出,Java虚拟机(JVM) 处在核心的位置,是程序与底层操作系统和硬件无关的关键。它的下方是移植接口,移植接口由两部分组成:适配器和Java操作系统, 其中依赖于平台的部分称为适配器;JVM 通过移植接口在具体的平台和操作系统上实现;在JVM 的上方是Java的基本类库和扩展类库以及它们的API, 利用Java API编写的应用程序(application) 和小程序(Java applet) 可以在任何Java平台上运行而无需考虑底层平台, 就是因为有Java虚拟机(JVM)实现了程序与操作系统的分离,从而实现了Java 的平台无关性。

JVM在它的生存周期中有一个明确的任务,那就是运行Java程序,因此当Java程序启动的时候,就产生JVM的一个实例;当程序运行结束的时候,该实例也跟着消失了。下面我们从JVM的体系结构和它的运行过程这两个方面来对它进行比较深入的研究。

1、Java虚拟机的体系结构

·每个JVM都有两种机制:

①类装载子系统:装载具有适合名称的类或接口

②执行引擎:负责执行包含在已装载的类或接口中的指令

·每个JVM都包含:

方法区、Java堆、Java栈、本地方法栈、指令计数器及其他隐含寄存器

对于JVM的学习,在我看来这么几个部分最重要:

Java代码编译和执行的整个过程

JVM内存管理及垃圾回收机制

下面分别对这几部分进行说明:

2、Java代码编译和执行的整个过程

也正如前面所说,Java代码的编译和执行的整个过程大概是:开发人员编写Java代码(.java文件),然后将之编译成字节码(.class文件),再然后字节码被装入内存,一旦字节码进入虚拟机,它就会被解释器解释执行,或者是被即时代码发生器有选择的转换成机器码执行。

(1)Java代码编译是由Java源码编译器来完成,也就是Java代码到JVM字节码(.class文件)的过程。

(2)Java字节码的执行是由JVM执行引擎来完成。

Java代码编译和执行的整个过程包含了以下三个重要的机制:

·Java源码编译机制

·类加载机制

·类执行机制

(1)Java源码编译机制

Java 源码编译由以下三个过程组成:

①分析和输入到符号表

②注解处理

③语义分析和生成class文件

最后生成的class文件由以下部分组成:

①结构信息:包括class文件格式版本号及各部分的数量与大小的信息

②元数据:对应于Java源码中声明与常量的信息。包含类/继承的超类/实现的接口的声明信息、域与方法声明信息和常量池

③方法信息:对应Java源码中语句和表达式对应的信息。包含字节码、异常处理器表、求值栈与局部变量区大小、求值栈的类型记录、调试符号信息

(2)类加载机制JVM的类加载是通过ClassLoader及其子类来完成的,类的层次关系和加载顺序可以由下图来描述:

①Bootstrap ClassLoader

负责加载$JAVA_HOME中jre/lib/rt.jar里所有的class,由C++实现,不是ClassLoader子类

②Extension ClassLoader

负责加载java平台中扩展功能的一些jar包,包括$JAVA_HOME中jre/lib/*.jar或-Djava.ext.dirs指定目录下的jar包

③App ClassLoader

负责记载classpath中指定的jar包及目录中class

④Custom ClassLoader

属于应用程序根据自身需要自定义的ClassLoader,如tomcat、jboss都会根据j2ee规范自行实现ClassLoader

加载过程中会先检查类是否被已加载,检查顺序是自底向上,从Custom ClassLoader到BootStrap ClassLoader逐层检查,只要某个classloader已加载就视为已加载此类,保证此类只所有ClassLoader加载一次。而加载的顺序是自顶向下,也就是由上层来逐层尝试加载此类。

(3)类执行机制

JVM是基于堆栈的虚拟机。JVM为每个新创建的线程都分配一个堆栈.也就是说,对于一个Java程序来说,它的运行就是通过对堆栈的操作来完成的。堆栈以帧为单位保存线程的状态。JVM对堆栈只进行两种操作:以帧为单位的压栈和出栈操作。

JVM执行class字节码,线程创建后,都会产生程序计数器(PC)和栈(Stack),程序计数器存放下一条要执行的指令在方法内的偏移量,栈中存放一个个栈帧,每个栈帧对应着每个方法的每次调用,而栈帧又是有局部变量区和操作数栈两部分组成,局部变量区用于存放方法中的局部变量和参数,操作数栈中用于存放方法执行过程中产生的中间结果。栈的结构如下图所示:

3、JVM内存管理及垃圾回收机制

JVM内存结构分为:方法区(method),栈内存(stack),堆内存(heap),本地方法栈(java中的jni调用),结构图如下所示:

(1)堆内存(heap)

所有通过new创建的对象的内存都在堆中分配,其大小可以通过-Xmx和-Xms来控制。操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样代码中的delete语句才能正确的释放本内存空间。但由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。这时由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便。另外,在WINDOWS下,最好的方式是用VirtualAlloc分配内存,它不是在堆,也不是在栈,而是直接在进程的地址空间中保留一块内存,虽然这种方法用起来最不方便,但是速度快,也是最灵活的。堆内存是向高地址扩展的数据结构,是不连续的内存区域。由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。

(2)栈内存(stack)

在Windows下, 栈是向低地址扩展的数据结构,是一块连续的内存区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在WINDOWS下,栈的大小是固定的(是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小。只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。 由系统自动分配,速度较快。但程序员是无法控制的。

堆内存与栈内存需要说明:

基础数据类型直接在栈空间分配,方法的形式参数,直接在栈空间分配,当方法调用完成后从栈空间回收。引用数据类型,需要用new来创建,既在栈空间分配一个地址空间,又在堆空间分配对象的类变量 。方法的引用参数,在栈空间分配一个地址空间,并指向堆空间的对象区,当方法调用完成后从栈空间回收。局部变量new出来时,在栈空间和堆空间中分配空间,当局部变量生命周期结束后,栈空间立刻被回收,堆空间区域等待GC回收。方法调用时传入的literal参数,先在栈空间分配,在方法调用完成后从栈空间收回。字符串常量、static在DATA区域分配,this在堆空间分配。数组既在栈空间分配数组名称,又在堆空间分配数组实际的大小。

如:

(3)本地方法栈(java中的jni调用)

用于支持native方法的执行,存储了每个native方法调用的状态。对于本地方法接口,实现JVM并不要求一定要有它的支持,甚至可以完全没有。Sun公司实现Java本地接口(JNI)是出于可移植性的考虑,当然我们也可以设计出其它的本地接口来代替Sun公司的JNI。但是这些设计与实现是比较复杂的事情,需要确保垃圾回收器不会将那些正在被本地方法调用的对象释放掉。

(4)方法区(method)

它保存方法代码(编译后的java代码)和符号表。存放了要加载的类信息、静态变量、final类型的常量、属性和方法信息。JVM用持久代(Permanet Generation)来存放方法区,可通过-XX:PermSize和-XX:MaxPermSize来指定最小值和最大值。

垃圾回收机制

堆里聚集了所有由应用程序创建的对象,JVM也有对应的指令比如 new, newarray, anewarray和multianewarray,然并没有向 C++ 的 delete,free 等释放空间的指令,Java的所有释放都由 GC 来做,GC除了做回收内存之外,另外一个重要的工作就是内存的压缩,这个在其他的语言中也有类似的实现,相比 C++ 不仅好用,而且增加了安全性,当然她也有弊端,比如性能这个大问题。

(3)分析java文件扩展阅读

Java虚拟机的运行过程示例

上面对虚拟机的各个部分进行了比较详细的说明,下面通过一个具体的例子来分析它的运行过程。

虚拟机通过调用某个指定类的方法main启动,传递给main一个字符串数组参数,使指定的类被装载,同时链接该类所使用的其它的类型,并且初始化它们。例如对于程序:

编译后在命令行模式下键入: java HelloApp run virtual machine

将通过调用HelloApp的方法main来启动java虚拟机,传递给main一个包含三个字符串"run"、"virtual"、"machine"的数组。现在我们略述虚拟机在执行HelloApp时可能采取的步骤。

开始试图执行类HelloApp的main方法,发现该类并没有被装载,也就是说虚拟机当前不包含该类的二进制代表,于是虚拟机使用ClassLoader试图寻找这样的二进制代表。如果这个进程失败,则抛出一个异常。类被装载后同时在main方法被调用之前,必须对类HelloApp与其它类型进行链接然后初始化。链接包含三个阶段:检验,准备和解析。检验检查被装载的主类的符号和语义,准备则创建类或接口的静态域以及把这些域初始化为标准的默认值,解析负责检查主类对其它类或接口的符号引用,在这一步它是可选的。类的初始化是对类中声明的静态初始化函数和静态域的初始化构造方法的执行。一个类在初始化之前它的父类必须被初始化。

4. 求解析java代码,最好逐行解释

publicstaticvoidreadTxtFile(StringfilePath){try{Stringencoding="GBK";Filefile=newFile(filePath);if(file.isFile()&&file.exists()){//判断文件是否存在InputStreamReaderread=newInputStreamReader(newFileInputStream(file),encoding);//考虑到编码格式BufferedReaderbufferedReader=newBufferedReader(read);StringlineTxt=null;while((lineTxt=bufferedReader.readLine())!=null){System.out.println(lineTxt.split("|||||||||||||")[0].split("|")[0]);System.out.println(lineTxt.split("|||||||||||||")[0].split("|")[1]);System.out.println(lineTxt.split("|||||||||||||")[0].split("|")[2].replace("|||||||||||||",""));}}read.close();}else{System.out.println("找不到指定的文件");}}catch(Exceptione){System.out.println("读取文件内容出错");e.printStackTrace();}}

5. java源文件解析

建一个Student实体类封装数据public static List<Student> readXml() { List<Student> list = new ArrayList<Student>(); //定义一个<a href="https://www..com/s?wd=dom%E8%A7%A3%E6%9E%90&tn=44039180_cpr&fenlei=_5y9YIZ0lQzqlpA-" target="_blank" class="-highlight">dom解析</a>器工厂实例 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); try { //由工厂实例得到一个<a href="https://www..com/s?wd=dom%E8%A7%A3%E6%9E%90&tn=44039180_cpr&fenlei=_5y9YIZ0lQzqlpA-" target="_blank" class="-highlight">dom解析</a>器 DocumentBuilder dom = factory.newDocumentBuilder(); //找到<a href="https://www..com/s?wd=xml%E6%96%87%E6%A1%A3&tn=44039180_cpr&fenlei=_5y9YIZ0lQzqlpA-" target="_blank" class="-highlight">xml文档</a> File file=new File("src/com/jereh/ch05/Students.xml"); Document doc=dom.parse(file); // Element root = doc.getDocumentElement(); NodeList stuNodeList = root.getChildNodes(); for (int i = 0; i < stuNodeList.getLength(); i++) { Node stu = stuNodeList.item(i); Student student = new Student(); if (stu != null && stu.getNodeType() == Node.ELEMENT_NODE) { // System.out.println(stu); Element stuElement = (Element) stu; student.setNo(stuElement.getAttribute("id")); // stu.getAttributes().getNamedItem(null); // Element stu=(Element)stuNodeList NodeList info = stuElement.getChildNodes(); for (int j = 0; j < info.getLength(); j++) { info.item(j).getNodeName(); Node n = info.item(j); if ("name".equals(n.getNodeName())) { // n.getFirstChild().getNodeValue(); student.setName(n.getLastChild().getNodeValue()); } else if ("age".equals(n.getNodeName())) { student.setAge(Integer.parseInt(n.getFirstChild() .getNodeValue())); } list.add(student); } } } } catch (ParserConfigurationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SAXException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } // System.out.println(root.getNodeValue()); return list; }

6. 有什么好的解析java文件的方法

java读取word文档时,虽然网上介绍了很多插件poi、java2Word、jacob、itext等等,poi无法读取格式(新的API估 计行好像还在处于研发阶段,不太稳定,做项目不太敢用);java2Word、jacob容易报错找不到注册,比较诡异,我曾经在不同的机器上试过

7. java语法错误,进行分析时已经到达文件结尾

原因:

分析已达到文抄件结尾一般是括号没有闭合,或者缺少了分号

解决方案:

手工查看括号闭合情况

使用带自动对齐功能的编辑器如eclipse,notepad++

建议平时编程时多注意积累错误经验,语法错误不应当耗费太多时间

拓展资料:

Java的组成:

Java编程语言

Java类文件格式

Java虚拟机

Java应用程序接口

当编辑并运行一个Java程序时,需要同时涉及到这四种方面。使用文字编辑软件(例如记事本、写字板、UltraEdit等)或集成开发环境(Eclipse、MyEclipse等)在Java源文件中定义不同的类 ,通过调用类(这些类实现了Java API)中的方法来访问资源系统,

把源文件编译生成一种二进制中间码,存储在class文件中,然后再通过运行与操作系统平台环境相对应的Java虚拟机来运行class文件,执行编译产生的字节码,调用class文件中实现的方法来满足程序的Java API调用

8. 解析java文件为什么出现后缀为bak的文件

用UltraEdit编辑JAVA文件就会自动生成这样的.bak文件,是备份文件,可以在UltraEdit的高级–>配置–>文件处理–>备份里更改默认的选项就可以了。

9. Java是什么文件

JAVA一种编程语言,带有这样的扩展名的文件是JAVA编译出来的源文件(就是代码文件)。JAVA一般存在两种文件格式,如下:1.*.java文件是保存源代码的文本文件(*代表类名)使用javac*.java可以编译该文件使用java*可以运行该类2.*.class是用于保存Java类的二进制编码以及Class对象,每一个Java类都有一个解释该类特征的Class对象。*.jar文件是一种压缩文件格式

10. 如何分析websphere中间件生成的javacore文件

通过Javacore提供的信息对JVM进行一个全面的分析,除了了解垃圾回收情况、JVM相关配置信息外,分析重点可放在线程执行情况上,分析哪些线程在等待,哪些在执行,以便快速缩小问题范围。IBM Thread and Monitor Dump Analyzer for Java分析工具可以让我们清晰的分析Javacore文件,在IBM Thread and Monitor Dump Analyzer for Java工具中,请求线程可分为以下几种状态:1.死锁,Deadlock(重点关注)2.执行中,Runnable(重点关注)3.等待资源,Waiting on condition(重点关注)4.等待监控器检查资源,Waiting on monitor5.暂停,Suspended6.对象等待中,Object.wait()7.阻塞,Blocked(重点关注)8.停止,ParkedDeadlock:死锁线程:一般指多个线程调用间,进入相互资源占用,导致一直等待无法释放的情况。Runnable:一般指该线程正在执行状态中,该线程占用了资源,正在处理某个请求,有可能正在传递SQL到数据库执行,有可能在对某个文件操作,有可能进行数据类型等转换。Waiting on condition:等待资源,如果堆栈信息明确是应用代码,则证明该线程正在等待资源,一般是大量读取某资源,且该资源采用了资源锁的情况下,线程进入等待状态,等待资源的读取。又或者,正在等待其他线程的执行等。Blocked:线程阻塞,是指当前线程执行过程中,所需要的资源长时间等待却一直未能获取到,被容器的线程管!