要求:实现一个简单的源程序特征统计
待测代码如下:
1 package aim; 2 3 public class MyAim { 4 5 public static void main(String[] args) { 6 7 Circle c = new Circle(4); 8 System.out.println("name is:" + c.getName()); 9 try { 10 System.out.println("name is:" + c.getArea()); 11 } catch (Exception e1) { 12 // TODO 自动生成的 catch 块 13 e1.printStackTrace(); 14 } 15 16 Rectangle r = new Rectangle(5,6); 17 System.out.println("name is:" + r.getName()); 18 try { 19 System.out.println("name is:" + r.getArea()); 20 } catch (Exception e) { 21 // TODO 自动生成的 catch 块 22 e.printStackTrace(); 23 } 24 25 } 26 } 27 28 abstract class Shape { 29 30 public String getName() { 31 return this.getClass().getSimpleName(); 32 } 33 34 public abstract double getArea() throws Exception; 35 36 } 37 38 class Circle extends Shape { 39 private double r; 40 41 public Circle(double r) { 42 this.r = r; 43 } 44 @Override 45 public double getArea() throws Exception { 46 return Math.PI * Math.pow(r, 2); 47 } 48 } 49 50 class Rectangle extends Shape { 51 private double l,w; 52 53 public Rectangle(double l,double w) { 54 this.l = l; 55 this.w = w; 56 } 57 58 @Override 59 public double getArea() throws Exception { 60 return l*w; 61 } 62 63 }
这个程序实现求圆形和矩形面积的功能。
简单的测试一下:
运行结果:
下面编写一个源程序特征统计程序:
1 import java.io.BufferedReader; 2 import java.io.FileInputStream; 3 import java.io.FileNotFoundException; 4 import java.io.FileReader; 5 import java.io.IOException; 6 import java.lang.reflect.Constructor; 7 import java.lang.reflect.Field; 8 import java.lang.reflect.Method; 9 import java.util.ArrayList; //这里有些没用到我下面会解释 10 import java.util.List; 11 12 import aim.*; 13 14 15 public class textAim { 16 17 public static void main(String[] args) 18 throws ClassNotFoundException, IOException{ 19 20 //用反射查看类的成员 21 Class<?> clazz = Class.forName("aim.MyAim"); 22 System.out.println("类名:" + clazz.getCanonicalName()); 23 24 Constructor<?>[] constructors = clazz.getConstructors(); 25 System.out.println("类的构造方法:"); 26 if (constructors.length != 0) { 27 for (Constructor<?> constructor : constructors) { 28 System.out.println("\t" + constructor);// 输出构造方法 29 } 30 } else { 31 System.out.println("\t无"); 32 } 33 34 Field[] fields = clazz.getDeclaredFields(); 35 System.out.println("类的非继承域变量:"); 36 if (fields.length != 0) { 37 for (Field field : fields) { 38 System.out.println("\t" + field);// 输出非继承域 39 } 40 } else { 41 System.out.println("\t无"); 42 } 43 44 Method[] methods = clazz.getDeclaredMethods(); 45 System.out.println("类的非继承方法:"); 46 if (methods.length != 0) { 47 for (Method method : methods) { 48 System.out.println(method);// 输出非继承方法 49 } 50 } else { 51 System.out.println("\t无"); 52 } 53 54 //统计代码字数,行数,字符数 55 String count = null ; 56 String line= null; 57 int numline = 0; 58 59 FileReader in = null; 60 try { 61 in = new FileReader 62 ("D:\\java\\aim\\src\\aim\\MyAim.java"); //这里是需要统计的代码路径 63 } catch (FileNotFoundException e) { 64 System.out.println("并找不到文件"); 65 System.exit(-1); 66 } 67 68 //这里为了硬盘不爆炸所以需要BufferedReader 69 BufferedReader bf = new BufferedReader(in); 70 line = bf.readLine(); 71 while(line != null){ 72 numline ++; 73 count = count+line; 74 line = bf.readLine(); 75 } 76 System.out.println("字数为"); // 输出字数 77 System.out.println(count.split("\\s+").length); 78 System.out.println("行数为"); 79 System.out.println(numline); 80 81 82 byte[] buff=count.getBytes(); 83 int f=buff.length; 84 System.out.println("字节数" ); //输出字节数 85 System.out.println(f); 86 } 87 }
先通过反射机制可以查看待测程序里类的构造方法,类的非继承域变量,类的非继承方法。这些都是API文档里给出的方法,我们只需拿出来用即可。
然后是统计待测程序的单词数,行数和字节数。方法是找到目标代码的路径,用BufferedReader一行一行的读进自己定义的字符串中,每读一次行数+1,然后用split("\\s+").length(正则表达式,用法请见http://bbs.csdn.net/topics/390082730)统计单词数。将字符串赋值给字节数组buff,所以字节长度为buff.length。
运行结果:
附录一
遇到的困难:拿来这个问题我首先想到的是使用List接口,打算先得到目标程序,创建list集合,用add()方法向集合中添加元素,然后遍历集合中的元素,遍历次数即为单词数(浪费了一个小时)。但可能因为自己水平不够或者方法本身就不可行,尝试好多次都没成功(这就是为什么程序开头导入了那么多没用到的包)。然后我使用FileReader,用read()读数据,后来想一想read()只能从输入流读下一个字节并且返回的是0~255范围内的int字节值,就算都出来我想要的内容以后操作也不好处理。因此我想到了BufferedReader,readline()可以读一行数据这样就比较符合需求。至于统计单词数,我记得数据结构老师上课时好像说过但因为时间太久也没专门去记所以一直没想起来,后来参照百度才解决,具体方法可以参照上面的链接。