在听课的时候听到自定义异常时,视频上讲的定义异常的时候如果是带参构造器需要显示调用父类异常的带参构造器,原因是什么呢?

首先我们需要看一下Exception和ERROR的父类Throwable的源码:

package java.lang;
import java.io.*;
/**
*
* Throwable是所有Error和Exceptiong的父类
* 注意它有四个构造函数:
* Throwable()
* Throwable(String message)
* Throwable(Throwable cause)
* Throwable(String message, Throwable cause)
*
*/
public class Throwable implements Serializable {private static final long serialVersionUID = -3042686055658047285L;/*** Native code saves some indication of the stack backtrace in this slot.*/private transient Object backtrace; /*** 描述此异常的信息*/private String detailMessage;/*** 表示当前异常由那个Throwable引起* 如果为null表示此异常不是由其他Throwable引起的* 如果此对象与自己相同,表明此异常的起因对象还没有被初始化*/private Throwable cause = this;/*** 描述异常轨迹的数组*/private StackTraceElement[] stackTrace;/*** 构造函数,起因对象没有被初始化可以在以后使用initCause进行初始化* fillInStackTrace可以用来初始化它的异常轨迹的数组*/public Throwable() {fillInStackTrace();}/*** 构造函数*/public Throwable(String message) {//填充异常轨迹数组fillInStackTrace();//初始化异常描述信息detailMessage = message;}/*** 构造函数,cause表示起因对象*/public Throwable(String message, Throwable cause) {fillInStackTrace();detailMessage = message;this.cause = cause;}/*** 构造函数*/public Throwable(Throwable cause) {fillInStackTrace();detailMessage = (cause==null ? null : cause.toString());this.cause = cause;}/*** 获取详细信息*/public String getMessage() {return detailMessage;}/*** 获取详细信息*/public String getLocalizedMessage() {return getMessage();}/*** 获取起因对象*/public Throwable getCause() {return (cause==this ? null : cause);}/*** 初始化起因对象,这个方法只能在未被初始化的情况下调用一次*/public synchronized Throwable initCause(Throwable cause) {//如果不是未初始化状态则抛出异常if (this.cause != this)throw new IllegalStateException("Can't overwrite cause");//要设置的起因对象与自身相等则抛出异常if (cause == this)throw new IllegalArgumentException("Self-causation not permitted");//设置起因对象this.cause = cause;//返回设置的起因的对象return this;}/*** 字符串表示形式*/public String toString() {     String s = getClass().getName();        String message = getLocalizedMessage();      return (message != null) ? (s + ": " + message) : s;}/*** 打印出错误轨迹*/public void printStackTrace() { printStackTrace(System.err);}/*** 打印出错误轨迹*/public void printStackTrace(PrintStream s) {synchronized (s) {//调用当前对象的toString方法s.println(this);//获取异常轨迹数组StackTraceElement[] trace = getOurStackTrace();//打印出每个元素的字符串表示for (int i=0; i < trace.length; i++)s.println("\tat " + trace[i]);//获取起因对象Throwable ourCause = getCause();//递归的打印出起因对象的信息if (ourCause != null)ourCause.printStackTraceAsCause(s, trace);}}/*** 打印起因对象的信息* @param s 打印的流* @param causedTrace 有此对象引起的异常的异常轨迹 */private void printStackTraceAsCause(PrintStream s,StackTraceElement[] causedTrace){//获得当前的异常轨迹StackTraceElement[] trace = getOurStackTrace();//m为当前异常轨迹数组的最后一个元素位置, //n为当前对象引起的异常的异常轨迹数组的最后一个元素int m = trace.length-1, n = causedTrace.length-1;//分别从两个数组的后面做循环,如果相等则一直循环,直到不等或数组到头while (m >= 0 && n >=0 && trace[m].equals(causedTrace[n])) {m--; n--;}//相同的个数int framesInCommon = trace.length - 1 - m;//打印出不同的错误轨迹s.println("Caused by: " + this);for (int i=0; i <= m; i++)s.println("\tat " + trace[i]);//如果有相同的则打印出相同的个数if (framesInCommon != 0)s.println("\t... " + framesInCommon + " more");//获得此对象的起因对象,并递归打印出信息Throwable ourCause = getCause();if (ourCause != null)ourCause.printStackTraceAsCause(s, trace);}/*** 打印出错误轨迹*/public void printStackTrace(PrintWriter s) { synchronized (s) {s.println(this);StackTraceElement[] trace = getOurStackTrace();for (int i=0; i < trace.length; i++)s.println("\tat " + trace[i]);Throwable ourCause = getCause();if (ourCause != null)ourCause.printStackTraceAsCause(s, trace);}}/*** 打印起因对象的信息*/private void printStackTraceAsCause(PrintWriter s,StackTraceElement[] causedTrace){// assert Thread.holdsLock(s);// Compute number of frames in common between this and causedStackTraceElement[] trace = getOurStackTrace();int m = trace.length-1, n = causedTrace.length-1;while (m >= 0 && n >=0 && trace[m].equals(causedTrace[n])) {m--; n--;}int framesInCommon = trace.length - 1 - m;s.println("Caused by: " + this);for (int i=0; i <= m; i++)s.println("\tat " + trace[i]);if (framesInCommon != 0)s.println("\t... " + framesInCommon + " more");// Recurse if we have a causeThrowable ourCause = getCause();if (ourCause != null)ourCause.printStackTraceAsCause(s, trace);}/*** 填充异常轨迹*/public synchronized native Throwable fillInStackTrace();/*** 返回当前的异常轨迹的拷贝*/public StackTraceElement[] getStackTrace() {return (StackTraceElement[]) getOurStackTrace().clone();}/*** 获取当前的异常轨迹*/private synchronized StackTraceElement[] getOurStackTrace() {//如果第一次调用此方法则初始化异常轨迹数组if (stackTrace == null) {//获得异常轨迹深度int depth = getStackTraceDepth();//创建新的异常轨迹数组,并填充它stackTrace = new StackTraceElement[depth];for (int i=0; i < depth; i++)stackTrace[i] = getStackTraceElement(i);//获取指定位标的异常轨迹}return stackTrace;}/*** 设置异常轨迹*/public void setStackTrace(StackTraceElement[] stackTrace) {//拷贝设置参数StackTraceElement[] defensiveCopy =(StackTraceElement[]) stackTrace.clone();//如果设置参数有空元素则抛出异常for (int i = 0; i < defensiveCopy.length; i++)if (defensiveCopy[i] == null)throw new NullPointerException("stackTrace[" + i + "]");//设置当前对象的异常轨迹this.stackTrace = defensiveCopy;}/*** 异常轨迹的深度,0表示无法获得*/private native int getStackTraceDepth();/*** 获取指定位标的异常轨迹*/private native StackTraceElement getStackTraceElement(int index);private synchronized void writeObject(java.io.ObjectOutputStream s)throws IOException{getOurStackTrace();s.defaultWriteObject();}
}

可以看见Throwable定义了一个私有属性detailMessage来存储异常信息,虽然是私有属性,但是在子类的内存中也是会存在的,而且从父类继承的toString、getmessage等方法也需要用到这个私有属性,如何对子类对象中的父类属性进行初始化?那就只能调用父类的构造器了。如下:

public class MyException extends Exception {public MyException(String message) {
super(message);
}
}

这样才能使得继承的toString等到方法打印出你自己的错误信息。

转载于:https://www.cnblogs.com/JSD1207ZX/p/9386232.html

关于自定义异常中为什么带参构造器需要显示调用父类异常的带参构造器相关推荐

  1. java中,子类初始化时一定要调用父类的构造方法,不调用行吗?

    一定会调用 原因是这样的: 因为子类继承了父类,那么就默认地含有父类的公共成员方法和公共成员变量,这些方法和变量在子类里不再重复声明.如果你初始化子类的时候,不初始化父类,那么你通过子类调用父类方法或 ...

  2. uni-app 唤醒调用第三方app并传参(一 显示调用)

    1.离线打包设置 包名:  com.xxx.xxxAPP(其实只需要包名就行) 执行activity:io.dcloud.PandoraEntry 2.调用方代码 //判断app是否存在 if(plu ...

  3. Java05-day05【方法(概述、调用过程图解)、带参方法、带返回值方法、重载、方法参数传递(基本类型、引用类型)】

    java零基础入门到精通(2019版)[黑马程序员] 视频+资料:[链接:https://pan.baidu.com/s/1MdFNUADVSFf-lVw3SJRvtg   提取码:zjxs] &qu ...

  4. 在C++中子类继承和调用父类的构造函数方法

    构造方法用来初始化类的对象,与父类的其它成员不同,它不能被子类继承(子类可以继承父类所有的成员变量和成员方法,但不继承父类的构造方法).因此,在创建子类对象时,为了初始化从父类继承来的数据成员,系统需 ...

  5. java中子类怎样调用父类的属性_java的继承、重载(overload)、覆盖(override)的总结...

    java为了解决相似属性和行为能共用相同的代码,也是为了便于标准模块化.减少相同代码要多次重复编写的问题,提供了继承.重载和覆盖的功能.继承是针对类,重载和覆盖是针对方法的. 一.继承:为了便于理解. ...

  6. 子类调用父类构造器的几种情况

    在调用子类构造器之前,会先调用父类构造器,当子类构造器中没有使用"super(参数或无参数)"指定调用父类构造器时,是默认调用父类的无参构造器,如果父类中包含有参构造器,却没有无参 ...

  7. 子类调用父类构造器《转载》

    有时我们在写子类的时候会出现如下所示的报错: Implicit super constructor AbstractClass() is undefined for default construct ...

  8. Java中关于子类调用父类无参还是有参构造方法的各个类型

    1.子类和父类都定义了带参和无参构造方法,且在子类中第一行写了super(xx);并且测试类里面实例化的是子类的带参构造方法,那么,此时不会先调用父类的无参构造方法,而是先调用父类有参构造方法再调用子 ...

  9. Python编程语言学习:for循环中常用方法经验技巧(利用enumerate函数对列表实现自带索引等)之详细攻略

    Python编程语言学习:for循环中常用方法经验技巧(利用enumerate函数对列表实现自带索引等)之详细攻略 目录 for循环中常用方法经验技巧 1.利用enumerate函数对列表实现for循 ...

最新文章

  1. 用Numpy搭建神经网络第二期:梯度下降法的实现
  2. vue与php通过axios进行数据交互
  3. 第13章 程序的动态加载和执行(三,核心代码)
  4. LeetCode 405. 数字转换为十六进制数
  5. UnrealEngine4 学习总结备忘
  6. 子类构造器Constructor是否可被Override(重写)
  7. 如何在sql存储过程中打log_SQL语句优化
  8. linux关机机器语言,Linux 核心源代码分析 - 第十章 开机 关机 [续二] [超星]...
  9. python小白从哪来开始-小白学python(1)——从selenium开始
  10. C# dataTable实用例
  11. 流媒体协议(二):RTMP协议
  12. 利用Python查询IP地址
  13. 向日葵 远程开机 linux,教你使用向日葵开机棒轻松实现远程开机
  14. unity 别踩白块儿
  15. 你管这叫操作系统源码(十五)
  16. 免费企业邮箱怎么注册申请
  17. 人这一辈子,都在为选择买单
  18. 深圳计算机专业中专学校,深圳中专学校
  19. 因子完备数c语言,编写函数输出完备数及其所有约数
  20. 【CXY】JAVA基础 之 异常概述

热门文章

  1. PyYAML和configparser模块讲解
  2. java并发编程(二)synchronized
  3. POI导入数据的过程中,遇到读取以科学计数法显示的数据
  4. 《游戏人工智能编程》读书笔记 —— 向量的归一和点乘
  5. 将执行文件转化为bat批处理文件的工具(批处理文件方式提供)
  6. 数据结构上机实践第14周项目1(2) - 验证算法(分块查找)
  7. 人工智能学习(三)Anaconda与PyCharm的结合
  8. [冲啊!!!!!]小白SLAM相关基础知识
  9. nmap扫描ipv6端口_web渗透测试系列 之 扫描(3)
  10. OSG仿真案例(8)——读取FBX格式文件并显示(无动画)