volley源码解析-Throwable类源码解析

时间:2023-03-09 19:23:23
volley源码解析-Throwable类源码解析

前提知识点:

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所示。

volley源码解析-Throwable类源码解析

图1 Error类的常见子类

2.Exception类

  有些异常在编写程序时无法预料的,如中断异常、非法存取异常等。为了保证程序的健壮性,Java要求必须对这些可能出现的异常进行捕获,并对其进行处理。

  Exception类的常见子类如图2所示。

volley源码解析-Throwable类源码解析

图2 Exception类的常见子类

3.RuntimeException类

  RuntimeException类是Exception类的子类。RuntimeException类的常见的子类如图3所示。

volley源码解析-Throwable类源码解析

图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*/public 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("\tat " + 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("\tat " + trace[i]);
177 //如果有相同的则打印出相同的个数
178 if (framesInCommon != 0)
179 s.println("\t... " + 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("\tat " + 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("\tat " + trace[i]);
222 if (framesInCommon != 0)
223 s.println("\t... " + 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}