前提知识点:
1.Serializable接口
作用:表示可序列化的语义。就是Java提供的通用数据保存和读取接口。任何类型实现了Serializeable接口,就可以被保存到文件中,或者作为数据流通过网络发送到别的地方,也可以用管道来传输到系统的其他地方。在Java中的序列化,只需要实现serializable接口,然后,你可以使用objectOutputStream将该对象保存到文件或者发送到其他主机,所有的non-transient和non-static字段都将被序列化,所有我们想自己处理的字段都因该声明为transient。
2.defaultWriteObject()和defaultReadObject(),他们做的是默认的序列化进程。
3.printWriter和printStream的区别:
printWriter主要用来操作字符流,printStream主要用来操作byte流。如果我们要读取文本文件最好用前者。String缺省都是用UNICODE进行编码,是16bit,因此printWriter写入的字符串的跨平台性好一些,用printStream可能会出现乱码。
Trowable类的作用:
在Java中,根据错误性质将运行错误分为两类:错误和异常。
在Java程序的执行过程中,如果出现了异常事件,就会生成一个异常对象。生成的异常对象将传递Java运行时系统,这一异常的产生和提交过程称为抛弃(throw)异常。
当Java运行时系统得到一个异常对象时,它将会沿着方法的调用栈逐层回溯,寻找处理这一异常的代码。找到能够处理这类异常的方法后,运行时系统把当前异常对象交给这个方法进行处理,这一过程称为捕获(catch)异常。
Java中的所有异常都是由Throwable类的子类生成的对象,所有的异常类都是Throwable类的子类或子类的子类。Throwable类是Object类的直接子类,Error类和Exception类是Throwable类的两个直接子类。
1.Error类
Error类包括一些严重的程序不能处理的系统错误类,如内存溢出、虚拟机错误、栈溢出等。这类错误一般与硬件有关,与程序本身无关,通常由系统进行处理,程序本身无法捕获和处理。
Error类的常见子类如图1所示。
图1 Error类的常见子类
2.Exception类
有些异常在编写程序时无法预料的,如中断异常、非法存取异常等。为了保证程序的健壮性,Java要求必须对这些可能出现的异常进行捕获,并对其进行处理。
Exception类的常见子类如图2所示。
图2 Exception类的常见子类
3.RuntimeException类
RuntimeException类是Exception类的子类。RuntimeException类的常见的子类如图3所示。
图3 RuntimeException类的常见的子类
Throwable类解析:包含五个成员变量,四个构造函数,多个成员函数。
五个成员变量:
1.serialVesionUID(通过类名,接口名,成员方法及属性等生成的64位的哈希字段),作用:序列化是为保持版本的兼容性,即在版本升级时反序列化仍然保持对象的唯一性。
2.backtrace 当本地代码保存在slot中的一些栈的回溯指针。
3.detailMessage 描述异常信息。
4.cause 表示当前异常由那个Throwable引起,如果为null,表示不为其他异常引起,如果对象与自己相同表示此异常还未初始化。
5.strackTrace 描述异常轨迹数组。
四个构造函数:
1.无参构造函数:用于初始化异常轨迹数组。
2.带有一个String类型的message参数的构造函数:除了要初始化异常轨迹数组,还要初始化异常描述信息。
3.带有一个String类型的message和一个Trowable类型的cause,除了要初始化异常轨迹数组,和异常描述信息,还要初始化起因对象。
4.带有一个Trowable类型的cause。初始化异常轨迹数组,初始化起因对象,将起因对象的.toString()赋值给detailMessage。
其他成员函数的作用有:获取详细的异常描述信息,获取起因对象,初始化起因对象,字符串的表现形式(类名+异常描述信息),打印错误轨迹,打印错误轨迹的起因对象信息,填充异常轨迹,异常轨迹的深度的获取(0表示无法获取),获取指定位标的异常轨迹,获取异常轨迹数组信息并保存。
Java代码 1package java.lang; 2import java.io.*; 3/** 4* 5* Throwable是所有Error和Exceptiong的父类 6* 注意它有四个构造函数: 7* Throwable() 8* Throwable(String message) 9* Throwable(Throwable cause) 10* Throwable(String message, Throwable cause) 11* 12*/ 13public class Throwable implements Serializable { 14 private static final long serialVersionUID = -3042686055658047285L; 15 16 /** 17 * Native code saves some indication of the stack backtrace in this slot. 18 */ 19 private transient Object backtrace; 20 21 /** 22 * 描述此异常的信息 23 */ 24 private String detailMessage; 25 26 /** 27 * 表示当前异常由那个Throwable引起 28 * 如果为null表示此异常不是由其他Throwable引起的 29 * 如果此对象与自己相同,表明此异常的起因对象还没有被初始化 30 */ 31 private Throwable cause = this; 32 33 /** 34 * 描述异常轨迹的数组 35 */ 36 private StackTraceElement[] stackTrace; 37 38 /** 39 * 构造函数,起因对象没有被初始化可以在以后使用initCause进行初始化 40 * fillInStackTrace可以用来初始化它的异常轨迹的数组 41 */ 42 public Throwable() { 43 fillInStackTrace(); 44 } 45 46 /** 47 * 构造函数 48 */ 49 public Throwable(String message) { 50 //填充异常轨迹数组 51 fillInStackTrace(); 52 //初始化异常描述信息 53 detailMessage = message; 54 } 55 56 /** 57 * 构造函数,cause表示起因对象 58 */ 59 public Throwable(String message, Throwable cause) { 60 fillInStackTrace(); 61 detailMessage = message; 62 this.cause = cause; 63 } 64 65 /** 66 * 构造函数 67 */ 68 public Throwable(Throwable cause) { 69 fillInStackTrace(); 70 detailMessage = (cause==null ? null : cause.toString()); 71 this.cause = cause; 72 } 73 74 /** 75 * 获取详细信息 76 */ 77 public String getMessage() { 78 return detailMessage; 79 } 80 81 /** 82 * 获取详细信息 83 */ 84 public String getLocalizedMessage() { 85 return getMessage(); 86 } 87 88 /** 89 * 获取起因对象 90 */ 91 public Throwable getCause() { 92 return (cause==this ? null : cause); 93 } 94 95 /** 96 * 初始化起因对象,这个方法只能在未被初始化的情况下调用一次 97 */ 98 public synchronized Throwable initCause(Throwable cause) { 99 //如果不是未初始化状态则抛出异常 100 if (this.cause != this) 101 throw new IllegalStateException("Can't overwrite cause"); 102 103 //要设置的起因对象与自身相等则抛出异常 104 if (cause == this) 105 throw new IllegalArgumentException("Self-causation not permitted"); 106 107 //设置起因对象 108 this.cause = cause; 109 //返回设置的起因的对象 110 return this; 111 } 112 113 /** 114 * 字符串表示形式 115 */ 116 public String toString() { 117 String s = getClass().getName(); 118 String message = getLocalizedMessage(); 119 return (message != null) ? (s + ": " + message) : s; 120 } 121 122 /** 123 * 打印出错误轨迹 124 */ 125 public void printStackTrace() { 126 printStackTrace(System.err); 127 } 128 129 /** 130 * 打印出错误轨迹 131 */ 132 public void printStackTrace(PrintStream s) { 133 synchronized (s) { 134 //调用当前对象的toString方法 135 s.println(this); 136 //获取异常轨迹数组 137 StackTraceElement[] trace = getOurStackTrace(); 138 139 //打印出每个元素的字符串表示 140 for (int i=0; i < trace.length; i++) 141 s.println(" at " + trace[i]); 142 143 //获取起因对象 144 Throwable ourCause = getCause(); 145 146 //递归的打印出起因对象的信息 147 if (ourCause != null) 148 ourCause.printStackTraceAsCause(s, trace); 149 } 150 } 151 152 /** 153 * 打印起因对象的信息 154 * @param s 打印的流 155 * @param causedTrace 有此对象引起的异常的异常轨迹 156 */ 157 private void printStackTraceAsCause(PrintStream s, 158 StackTraceElement[] causedTrace) 159 { 160 //获得当前的异常轨迹 161 StackTraceElement[] trace = getOurStackTrace(); 162 //m为当前异常轨迹数组的最后一个元素位置, 163 //n为当前对象引起的异常的异常轨迹数组的最后一个元素 164 int m = trace.length-1, n = causedTrace.length-1; 165 //分别从两个数组的后面做循环,如果相等则一直循环,直到不等或数组到头 166 while (m >= 0 && n >=0 && trace[m].equals(causedTrace[n])) { 167 m--; n--; 168 } 169 170 //相同的个数 171 int framesInCommon = trace.length - 1 - m; 172 173 //打印出不同的错误轨迹 174 s.println("Caused by: " + this); 175 for (int i=0; i <= m; i++) 176 s.println(" at " + trace[i]); 177 //如果有相同的则打印出相同的个数 178 if (framesInCommon != 0) 179 s.println(" ... " + framesInCommon + " more"); 180 181 //获得此对象的起因对象,并递归打印出信息 182 Throwable ourCause = getCause(); 183 if (ourCause != null) 184 ourCause.printStackTraceAsCause(s, trace); 185 } 186 187 /** 188 * 打印出错误轨迹 189 */ 190 public void printStackTrace(PrintWriter s) { 191 synchronized (s) { 192 s.println(this); 193 StackTraceElement[] trace = getOurStackTrace(); 194 for (int i=0; i < trace.length; i++) 195 s.println(" at " + trace[i]); 196 197 Throwable ourCause = getCause(); 198 if (ourCause != null) 199 ourCause.printStackTraceAsCause(s, trace); 200 } 201 } 202 203 /** 204 * 打印起因对象的信息 205 */ 206 private void printStackTraceAsCause(PrintWriter s, 207 StackTraceElement[] causedTrace) 208 { 209 // assert Thread.holdsLock(s); 210 211 // Compute number of frames in common between this and caused 212 StackTraceElement[] trace = getOurStackTrace(); 213 int m = trace.length-1, n = causedTrace.length-1; 214 while (m >= 0 && n >=0 && trace[m].equals(causedTrace[n])) { 215 m--; n--; 216 } 217 int framesInCommon = trace.length - 1 - m; 218 219 s.println("Caused by: " + this); 220 for (int i=0; i <= m; i++) 221 s.println(" at " + trace[i]); 222 if (framesInCommon != 0) 223 s.println(" ... " + framesInCommon + " more"); 224 225 // Recurse if we have a cause 226 Throwable ourCause = getCause(); 227 if (ourCause != null) 228 ourCause.printStackTraceAsCause(s, trace); 229 } 230 231 /** 232 * 填充异常轨迹 233 */ 234 public synchronized native Throwable fillInStackTrace(); 235 236 /** 237 * 返回当前的异常轨迹的拷贝 238 */ 239 public StackTraceElement[] getStackTrace() { 240 return (StackTraceElement[]) getOurStackTrace().clone(); 241 } 242 243 244 /** 245 * 获取当前的异常轨迹 246 */ 247 private synchronized StackTraceElement[] getOurStackTrace() { 248 //如果第一次调用此方法则初始化异常轨迹数组 249 if (stackTrace == null) { 250 //获得异常轨迹深度 251 int depth = getStackTraceDepth(); 252 //创建新的异常轨迹数组,并填充它 253 stackTrace = new StackTraceElement[depth]; 254 255 for (int i=0; i < depth; i++) 256 stackTrace[i] = getStackTraceElement(i);//获取指定位标的异常轨迹 257 } 258 259 return stackTrace; 260 } 261 262 /** 263 * 设置异常轨迹 264 */ 265 public void setStackTrace(StackTraceElement[] stackTrace) { 266 //拷贝设置参数 267 StackTraceElement[] defensiveCopy = 268 (StackTraceElement[]) stackTrace.clone(); 269 270 //如果设置参数有空元素则抛出异常 271 for (int i = 0; i < defensiveCopy.length; i++) 272 if (defensiveCopy[i] == null) 273 throw new NullPointerException("stackTrace[" + i + "]"); 274 275 //设置当前对象的异常轨迹 276 this.stackTrace = defensiveCopy; 277 } 278 279 /** 280 * 异常轨迹的深度,0表示无法获得 281 */ 282 private native int getStackTraceDepth(); 283 284 /** 285 * 获取指定位标的异常轨迹 286 */ 287 private native StackTraceElement getStackTraceElement(int index); 288 289 290 private synchronized void writeObject(java.io.ObjectOutputStream s) 291 throws IOException 292 { 293 getOurStackTrace(); 294 s.defaultWriteObject(); 295 } 296}