⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 debug.java

📁 培训考试系统代码
💻 JAVA
📖 第 1 页 / 共 2 页
字号:

  /**
   * 输出对象数组内容。
   * @param prefix 输出前缀。
   * @param depth 最大dump深度。
   * @param objs 输出的对象数组。
   */
  private static final void dump(String prefix,int depth,Vector checkCircuit,Object[] objs) {
    if (objs==null) {
      dump(prefix,"null");
      return;
    }
    dumpBegin(prefix,checkCircuit,objs);
    for (int i=0;i<objs.length;i++) {
      dump(indent(prefix) + '[' + i + "] ",depth,checkCircuit,objs[i]);
    }
    dumpEnd(prefix,checkCircuit,objs);
  }

  /**
   * 对一般对象的dump行为是把传入对象的成员变量(包括私有)全部显示出来。
   * @param prefix 输出前缀。
   * @param depth 最大dump深度。
   * @param checkCircuit 保存递归层次中经过的所有对象的地址,防止循环递归。
   * @param obj需要dump的对象。
   */
  private static void dump(String prefix,int depth,Vector checkCircuit,Object obj) {
    if (obj==null) {
      dump(prefix,"null");
      return;
    }
    try {
      //对于这些常用数据类型,有他们自己的dump方法。
      if ((obj instanceof String)    || (obj instanceof Number) ||
          (obj instanceof Character) || (obj instanceof Boolean)) {
        dump(prefix,obj.toString());
        return;
      } else if(checkCircuit.contains(new Integer(System.identityHashCode(obj)))) {
        StringBuffer sb = new StringBuffer();
        sb.append(formatClassName(obj.getClass(),obj));
        sb.append(" @");
        sb.append(System.identityHashCode(obj));
        sb.append(' ');
        dump(prefix," {Circle recursion!}");
        return;
      } else if(getDepth(prefix)>depth) {//递归层数太多
        String str = formatClassName(obj.getClass(),obj) +
                     " @" + System.identityHashCode(obj);
        if (prefix.trim().endsWith(str.trim())) {
          str = "";
        }
        String toStr;
        try {
          toStr = obj.toString();
          if (toStr.indexOf((int)'@')>0) {
            toStr = " {Stack overflow!}";
          }
        } catch (StackOverflowError t) {
          toStr = " {Stack overflow!}";
        }
        dump(prefix,str + toStr);
        return;
      } else if (obj instanceof Vector) {
        dump(prefix,depth,checkCircuit,(Vector)obj);
        return;
      } else if (obj instanceof Map) {
        dump(prefix,depth,checkCircuit,(Map)obj);
        return;
      } else if (obj instanceof Enumeration) {
        dump(prefix,depth,checkCircuit,(Enumeration)obj);
        return;
      } else if (obj instanceof Object[]) {
        dump(prefix,depth,checkCircuit,(Object[]) obj);
        return;
      } else if (obj instanceof Throwable) {
        dump(prefix,(Throwable) obj);
        return;
      } else if (obj instanceof byte[]) {
        dump(prefix,(byte[]) obj);
        return;
      } else if (obj.getClass().isArray()) { //基本数据类型的数组
        int len = Array.getLength(obj);
        dumpBegin(prefix,checkCircuit,obj);
        StringBuffer content = new StringBuffer();
        for (int i=0;i<len;i++) {
          content.append(fixLength(Array.get(obj,i).toString(),4));
          if (i%8==7 && i<len-1) {
            content.append(lineSeparator + indent(prefix));
          }
        }
        dump(indent(prefix),content.toString());
        dumpEnd(prefix,checkCircuit,obj);
        return;
      } else if (Class.forName("javax.servlet.ServletRequest").isInstance(obj)) {
        dumpServletRequest(prefix,obj);
        return;
      }
    } catch (ClassNotFoundException ex) {
      //ex.printStackTrace(out);
    }

    //其他对象
    dumpBegin(prefix,checkCircuit,obj);
    Class c = obj.getClass();
    Field[] f;
    while (c!=null) {
      try {
        f = c.getDeclaredFields();
      } catch (SecurityException ex2) { //如果没有执行getFields()的权限
        dump(indent(prefix),"Can't dump object member for security reason.");
        return;
      }
      //输出成员变量
      for (int i=0;i<f.length;i++) {
        String m = Modifier.toString(f[i].getModifiers()); //修饰符
        if (m.indexOf("static")>0)
          continue;
        String n = f[i].getName(); //变量名
        Object v = "[unkonwn]";    //变量值
        try { //消除访问修饰符的限制
          f[i].setAccessible(true);
        } catch (SecurityException ex) {}
        try {
          v = f[i].get(obj); //变量值
          if (v!=null) {
            if (v instanceof String) { //给字符串加引号
              v = "\"" + v + '\"';
            } else if (v instanceof Character) { //给字符加单引号
              char cv = ((Character)v).charValue();
              if (cv<' ') {
                StringBuffer sbv = new StringBuffer();
                sbv.append("\\u");
                sbv.append(Integer.toHexString((int)cv));
                while(sbv.length()<6) { //补前导零
                  sbv.insert(2,'0');
                }
                v = sbv;
              }
              v = "\'" + v + '\'';
            }
          }
        }catch (Exception ex) {}
        Class ct = f[i].getType(); //变量类型
        String t = formatClassName(ct,v);//变量类型名称
        dump(indent(prefix) + (m + ' ' + t + ' ' + n).trim() + " = ",
                depth,checkCircuit,v);
      }
      c = c.getSuperclass();
    } //while end
    dumpEnd(prefix,checkCircuit,obj);
  }

  /**
   * 输出调试开始信息。
   * @param prefix 输出前缀。
   * @param dump的对象。
   */
  private static void dumpBegin(String prefix,Vector checkCircuit,Object obj) {
    String className = formatClassName(obj.getClass(),obj);
    int address = System.identityHashCode(obj);
    checkCircuit.addElement(new Integer(address));
    if (obj instanceof Array) {
      className = className.substring(2) + '[' + Array.getLength(obj) + "] ";
    }
    if (className.startsWith("java.lang.")) { //去掉缺省的包名
      className = className.substring(10);
    }
    if (prefix.trim().endsWith("@" + address)) {
      out.println(prefix + " {");
    } else {
      out.println(prefix + className + " @" + address + " {");
    }
  }

  /**
   * 对于复合对象,输出dump结束位置的大括号。
   * @param prefix 输出前缀。
   */
  private static void dumpEnd(String prefix,Vector checkCircuit,Object obj) {
    checkCircuit.removeElement(new Integer(System.identityHashCode(obj)));
    int p = prefix.lastIndexOf(indentString);
    if (p>0) {
      prefix = prefix.substring(0,p) + indentString;
    }
    for (int i=0;i<prefix.length();i++) {
      char c = prefix.charAt(i);
      if (c=='\t'|| c==' ') {
        out.print(c);
      } else {
        break;
      }
    }
    out.println("}");
    out.flush();
  }

  /**
   * 用于定位调用堆栈层次中调用本类某个方法(或者更高层次)时的位置。
   * @param esc 调用堆栈中需要剔除的层次中的字符串,传入null表示无剔除层次。
   * @return 位置信息(类、函数、代码行)。
   */
  public static String locate(String esc) {
    StringWriter sw = new StringWriter();
    new Exception().printStackTrace(new PrintWriter(sw));
    for (StringTokenizer st = new StringTokenizer(sw.toString(),"\n");
            st.hasMoreTokens();) {
      String str = st.nextToken();
      if (str.indexOf("Exception")!=-1) { //异常描述,跳过
        continue;
      } else if (str.indexOf(Debug.class.getName())!=-1) { //调用栈最里层,跳过
        continue;
      } else if (esc!=null && str.indexOf(esc)!=-1) { //传入参数指定的层,跳过
        continue;
      } else if (esc==fullInfo) { //一个内部使用的特殊标记
        return str;
      } else {
        int i = str.indexOf('(');
        int j = str.indexOf(')');
        if (i!=-1 && j!=-1) {
          return str.substring(i,j+1);
        }
        break;
      }
    }
    return "";
  }

  /**
   * 将整数按16进制字符编码放到字节数组某个位置(0~9,a~f小写字母)。
   * @param src 保存16进制字符的字节数组。
   * @param lowByte 最低字节的位置(注意是最低字节的位置,在地址高字节端)。
   * @param value 待转换成16进制数的整数值。
   */
  private static void setHex(byte[]src, int lowByte, int value) {
    for (int i=0;i<8;i++) {
      src[lowByte-i] = hexNumber[value & 0xf]; //取低4位
      value >>>= 4; //将value逻辑右移4bit
      if (value==0) {
        break;
      }
    }
  }

  /** 16进制编码函数setHex()使用的内部常量。*/
  private static final byte[] hexNumber = {
    (byte)'0',(byte)'1',(byte)'2',(byte)'3',(byte)'4',(byte)'5',(byte)'6',
    (byte)'7',(byte)'8',(byte)'9',(byte)'a',(byte)'b',(byte)'c',(byte)'d',
    (byte)'e',(byte)'f'
  };

  /**
   * 缩进一级。
   * @param prefix原来的前缀。
   * @return 缩进后的前缀。
   */
  private static String indent(String prefix) {
    int p = prefix.lastIndexOf(indentString);
    if (p>0) {
      prefix = prefix.substring(0,p) + indentString;
    }
    StringBuffer sb = new StringBuffer();
    for (int i=0;i<prefix.length();i++) {
      char c = prefix.charAt(i);
      if (c=='\t'|| c==' ') {
        sb.append(c);
      } else {
        break;
      }
    }
    sb.append(indentString);
    return sb.toString();
  }

  /**
   * 将类名格式化成符合Java语言风格。
   * @param c 要格式化的类。
   * @return 格式化后的类名。
   */
  private static String formatClassName(Class c,Object obj) {
    String t = c.getName();

    //去掉末尾分号
    if (t.charAt(t.length()-1)==';') {
      t = t.substring(0,t.length()-1);
    }

    //数组类型处理
    boolean isArray = false;
    boolean firstDimension = true;
    while (t.startsWith("[")) {
      isArray = true;
      if (firstDimension && obj!=null) { //是第一维
        t = t.substring(1) + '[' + Array.getLength(obj) + ']';
        firstDimension = false;
      } else {
        t = t.substring(1)+"[]";
      }
    }
    if (isArray) {
      char ch = t.charAt(0);
      t = t.substring(1);
      switch (ch) {
        case 'B':
          t = "byte" + t; break;
        case 'C':
          t = "char" + t; break;
        case 'F':
          t = "float" + t; break;
        case 'I':
          t = "int" + t; break;
        case 'J':
          t = "long" + t; break;
        case 'S':
          t = "short" + t; break;
        case 'Z':
          t = "boolean" + t; break;
      }
    }
    if (t.startsWith("java.lang.")) { //去掉缺省包名
      t = t.substring(10);
    } else if (t.startsWith("class ")) {
      t = t.substring(7);
    }
    return t;
  }

  /**
   * 将字符串长度变为固定长(后面补空格),若长度已经等于或超过期望长度则
   * 补成期望长度的整数倍。
   * @param str 期望改变长度的字符串。
   * @param len 期望的长度。
   * @return 改变长度后的字符串。
   */
  private static String fixLength(String str,int len) {
    StringBuffer sb = new StringBuffer(len);
    sb.append(str);
    int n = len - str.length()%len;
    for (int i=0;i<n;i++) {
      sb.append(' ');
    }
    return sb.toString();
  }

  /**
   * 外界调用dump时输出的头部信息。
   * @return 头部信息。
   */
  private static String dumpHead() {
    StringBuffer sb = new StringBuffer();
    sb.append(sdf.format(new Date()));
    sb.append(locate(null));
    sb.append(' ');
    return sb.toString();
  }

  /**
   * 根据前缀取得当前递归深度。
   * @param prefix 输出前缀。
   * @return 递归深度(最小为1)。
   */
  private static int getDepth(String prefix) {
    int count = 0;
    int indentLen = indentString.length();
    int i=-indentLen;
    while (true) {
      count ++;
      i = prefix.indexOf(indentString,i+indentLen);
      if (i<0) {
        return count;
      }
    }
  }
  /** 输出调试信息时间的格式。*/
  private static SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS");

  /** 无任何意义,locate内部定位标志。*/
  public static final String fullInfo = "!@*#~^?'/\""; //给locate使用的内部标记。
}

/**
 * 断言失败时抛出的错误。只是简单从Error类继承。错误不是异常,系统不应该捕获的。
 * 若系统抛出该错误说明有BUG。
 */
class AssertFailed extends Error {}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -