Unsupported major.minor version 51.0解决办法
具体步骤
解决:项目------>右键------>属性------>JavaCompiler------>Compiler ComplianceLevel------>选择你使用的JDK版本------>应用
myeclipse出现Could not find the main class原因分析
做如下检查:
编译环境检查 window->preferences->installed JREs
编译级别检查 右击工程名->properties->java compiler
编译路径检查 右击工程名->build path->coufiguration build path
执行clean project->clean
运行环境大于等于编译器版本
用JAVA写一个单例类:
饿汉式单例:
public class Singleton{
private Singleton(){
private static Singleton instance = new Singleton();
public static Singleton getInstance(){
return instance;
}
}
}
懒汉式单例:
public class Singleton{
private static Singleton instance = null;
private Singleton(){}
public static synchronized Singleton getInstance(){
if(instance == null) {
instance = new Singleton();
}
return instance;
}
}
注意:实现一个单例有两点注意事项,(1)将构造器私有,不允许外界通过构造器创建对象;(2)通过公开的静态方法向外界返回类的唯一实例。
spring的IoC容器可以为普通的类创建单例,它是怎么做到的呢?
DAO设计模式:
DAO(Data Access Object)【数据访问对象】是一个为数据库或者其他持久化机制提供了抽象接口的对象,在不暴露底层持久化方案实现细节的前提下提供了各种数据的访问操作。在实际的开发中,应该将所有对数据源的访问操作进行抽象化后封装在一个公共API中。用程序设计语言来说,就是建立一个接口,接口中定义了此应用程序中将会用到的所有事务方法。在这个应用程序中,当需要和数据源进行交互的时候则使用这个接口,并且编写一个单独的类来实现这个接口,在逻辑上该类对应一个特定的数据存储。DAO模式实际上包含了两个模式,一是Data Accessor(数据访问器),二是Data Object(数据对象),前者要解决如何访问数据的问题,而后者要解决的是如何用对象封装数据。
DAO 模式被用来分离低层次数据访问和高级业务逻辑操作
DAO模式中包含的元素:
1.Data Access Object Interface )— 定义了一个model类上标准的操作方法的接口
2.Data Access Object concrete class — 实现了上面接口的类。这个类负责从数据存储区(数据库、xml)中取得数据
3.Model Object or Value Object — 这是一个简单地POJO(plain OldJavaObject)包含了getter和setter方法。由DAO类进行存取
实现:
创建一个Student类代表了Model或value对象。StudentDao是一个Dao接口。StudentDaoImpl是一个实现StudentDao的类。
public interface StudentDao{
public List<Student> get AllStudents();
public Student getStudent(int id);
public void updateStudent(Student student);
public void deleteStudent(Student student);
}
选择排序:
public static void selectSort (int [ ] arr){
for(int x = 0; x <arr.length-1;x++){
for(int y = x+1; y< arr.length;y++){
if(arr[x]>arr[y]){
int temp = arr[x];
arr[x] = arr[y];
arr[y] = temp;
}
}
}
}
public static void main(String[] args){
int [ ] arr = [1,5,4,2,9,6];
printArray(arr);
selectSort(arr);
printArray(arr)
}
public static void printArray( int [ ] arr){
for(int x = 0; x<arr.length;x++){
if(x!=arr.length-1){
System.out.println(arr[x]+",");
}
else{
System.out.println(arr[x]);
}
}
}
冒泡排序:相邻的两个元素进行比较,如果符合条件就进行换位
public static void bubleSort(int [ ] arr){
for(int x = 0 ; x < arr.length -1 ; x ++){
for(int y = 0 ; y < arr.length -x -1 ; y++){
if( arr[y] > arr[y+1]){
int temp = arr[y];
arr[y] = arr[y+1];
arr[y+1] = temp;
}
}
}
}
//-x:让每一次比比较的元素减少;-1:避免角标越界
public static void printArray( int [ ] arr){
for(int x = 0; x<arr.length;x++){
if(x!=arr.length-1){
System.out.println(arr[x]+",");
}
else{
System.out.println(arr[x]);
}
}
}
public static void main(String[] args){
int [ ] arr = [1,5,4,2,9,6];
printArray(arr);
bubleSort(arr);
printArray(arr)
}
无论什么排序,都需要对满足条件的位置进行置换,所以可以把这部分相同的代码提取出来,单独封装成一个函数
public static void swap( int [] arr ,int a, int b){
int temp = arr[a];
arr[a] = arr [b] ;
arr[b] = temp;
}
折半查找:提高效率,但是必须要保证该数组是有序的数组
public static int halfsearch( int [ ] arr,int key ){
int max,min,mid;
min = 0;
max = arr.length - 1;
mid = (min + max)/2;
while(key!=arr[mid]){
if(key>arr[mid]){
min = mid + 1;
}
else if(key < arr[mid]){
max = mid -1;
}
if(mix>max)
return -1;
mid = (max+min)/2;
}
return mid;
}
折半查找的第二种方式:
public static int halfsearch(int arr[ ] ,int key){
int min = 0 , max = arr.length-1, mid;
while(min < =max){
mid = (max + min)>>1;
if(key>arr[mid])
min = mid +1;l
else if(key<arr[mid]){
max = mid -1 ;
else
return mid;
}
}
}
十进制转为二进制:
public static void toBin(int num){
while(num>0){
System.out.println(num%2);
num = num /2;
}
}
十进制转为十六进制:
public static void toHex(int num){
StringBuffer sb = new StringBuffer();
for( int x= 0; x < 8; x++){
int temp = num &15;
if(temp>9){
sb.append((char)(temp -10+'A'));
else
sb.append(temp);
num = num >>>4;
}
System.out.println(sb.reverse());
}
}
S2SH在一些实体类的例子里,有的没有写构造方法,有的有写构造方法,有参数和无参数都有,是因为:(1)创建java时会提供一个默认的无参构造方法,但是不会显示出来;(2)根据业务的需求用户可以自己定义带参数的构造方法;(3)至于参数几个,可以根据对应的业务需求,制定加上相应的参数。
构造函数是一种特殊的函数,主要功能是用来创建对象时初始化帝乡,即为对象成员变量赋初始值,总与bew运算符一起使用在创建对象的语句中,构造函数与类名相同,可重载多个不同的构造函数。
Integer.parseInt(String)就是将String字符类型数据转换为Integer整型数据。
Integer.parseInt(String)遇到一些不能被转换为整型的字符时,会抛出异常。
一个例子
str=bf.readLine() ;//bf是一个Buffer流,str是一个字符串
num=Integer.parseInt(str) ;//此处将str字符串转换为整型并存储到int类型的num中
其作用在于,若读取的str不为整型,则会报错,可以抛出异常解决此问题
try{
str=brd.readLine() ;
num=Integer.parseInt(str) ;
}
catch(Exception e)
{
System.out.println("对不起,只能输入整数,请重新输入。") ;
}
如此,再次输入h,a等非整型字符时,则会提示你输入整数
查表法:将所有的元素临时存储起来,建立对应关系。每一次&15后的值作为索引去查建立好的表,都可以找对应的元素
类和对象的关系:
类:对现实生活中事物的描述;对象:就是这类事物,实实在在存在的个体
属性对应类中变量,行为对应类中的函数(方法)
其实定义类就是在描述事物,就是在定义属性和行为。属性和行为共同成为类中的成员(成员变量和方法)
堆内存中的变量默认初始化值----null
成员变量和局部变量:成员变量作用于整个类中,局部变量作用于函数中,或者语句中;在内存中的位置,成员变量在堆内存中,因为对象的存在才在内存总存在,而局部变量存在于栈内存中
匿名对象使用方式一:当对象的方法只调用一次时可以用匿名对象来完成,这样写比较简化;如果对一个对象进行多个成员调用,必须给这个对象起个名字
匿名对象的使用方式二:可以将匿名对象作为实际参数进行传递
封装:指隐藏对象的属性和实现细节,仅对外提供公共访问方式;好处:将变化隔离、便于使用、提高重用性、提高安全性;封装原则:将不需要对外提供的内容都隐藏起来;把属性都隐藏,提供公共方法对其访问
private:私有,权限修饰符;用于修饰类中的成员(成员变量,成员函数),私有只在本类中有效,类以外即使建立了对象也不能直接访问
私有仅仅是封装的一种表现形式;之所以对外提供访问方式,就因为可以在访问方式中加入逻辑判断等语句,对方问的数据进行操作,提高代码的健壮性
构造函数:
特点:函数名与类名相同;不同定义返回值类型;不可以写return语句;
作用:给对象进行初始化;
注意:默认构造函数的特点;多个构造函数是以重载的形式存在的;当一个类中没有定义构造函数时,系统会默认给该类加入一个空参数的构造函数;当在类中自定义了构造函数后,默认的构造函数就没有了
重载:函数名相同,但是参数列表不同
构造函数和一般函数在写法上有不同,在运行上也有不同;构造函数是在对象一建立就运行,给对象初始化,一般方法是对象调用才执行,是给对象添加对象具备的功能;一个对象建立,构造函数只运行一次;而一般方法可以被该对象调用多次
构造代码块
作用:给对象进行初始化;对象一建立就运行,而且优先于构造函数执行;
与构造函数的区别:构造代码块是给所有对象进行统一初始化;而构造函数是给对应的对象进行初始化
构造代码块中定义的是不同对象的共性的初始化内容
this:用于区分局部变量和成员变量同名的情况;
特点:代表本类的对象;代表它所在函数所属对象的引用;简单说,哪个对象在调用this所在的函数,this就代表哪个对象
this的应用:当定义类中功能时,给函数内部要用到调用该函数的额对象时,这时用this来表示这个对象。但凡本类功能内部使用了本类对象,都用this表示
this语句:用于构造函数之间进行互相调用;只能定义在构造函数的第一行(第一个语句),因为初始化动作要先执行。
static(静态)关键字:用于修饰成员(成员变量和成员函数);被修饰后的成员具备以下特点:随着类的加载而加载;优先于对象存在;可以直接被类名所调用;被所有对象共享;当成员被静态修饰后,就多了一个调用方式,除了可以被对象调用外,还可以直接被类名调用:类名.静态成员
实例变量和类变量的区别:
1.存放位置:类变量随着类的加载而存在于方法区中;实例变量随着对象的建立而存在于堆内存中
2.生命周期:类变量生命周期最长,随着类的消失而消失;实例变量生命周期随着对象的消失而消失
静态的使用注意事项:1.静态方法只能访问静态成员;非静态方法既可以访问静态也可以访问非静态;2.静态方法中不可以定义this.super关键字,因为静态优先于对象存在,所以静态方法总不可以出现this;3.主函数是静态的
静态的利与弊:
利:对对象的共享数据进行单独空间的存储,节省空间,没有必要每一个对象总都存储一份,可以直接被类名调用
弊:生命周期过长,访问出现局限性(静态虽好,只能访问静态)
主函数是一个特殊的函数,可以被jvm调用,作为程序的入口;
主函数:
public:代表着该函数的访问权限是最大的
static:代表着主函数随着类的加载就已经存在了
void:主函数没有具体的返回值
main:不是关键字,但是是一个特殊的单词,可以被jvm识别
函数的参数:(String[]args):函数的参数,参数的类型是一个数组,该数组中的元素是字符串。字符串类型的数组
主函数是固定格式的:jvm识别
jvm在调用主函数时,传入的是new String[0];
因为静态修饰的内容有成员变量和函数。
当对象中出现共享数据时,该数据被静态所修饰。
对象中的特有数据要定义成非静态存在于堆内存中
当功能内部没有访问到非静态数据(对象的特有数据)该功能可以定义成静态的
静态的应用:
每一个应用程序中都有共性的功能,可以将这些功能进行抽取,独立封装,以便复用
虽然可以通过建立ArrayTool的对象使用这些工具方法,对数组进行操作,但是发现了下面这些问题:
1.对象是用于封装数据的,可是ArrayTool对象并未封装特有数据
2.操作数组的每一个方法都没有用到ArrayTool对象中的特有数据
所以这是不需要对象的,因此可以将ArrayTool中的方法都定义成static,直接通过类名调用即可
将方法都静态后,可以方便于使用,但是该类还是可以被其他程序建立对象的,为了更为严谨,强制让该类不能建立对象,可以通过将构造函数私有化完成
class ArrayTool{
private ArrayTool(){}
...........(方法集合)
}
默认打的构造函数的权限是随着类的变化而变化
静态代码块:
特点:随着类的加载而执行,只执行一次,用于给类进行初始化
格式:
static
{
静态代码块中的执行语句
}
省略前面一些代码
Person p = new Person("zhangsan",20);
该句话执行的内容:
1.因为new用到了Person.calss,所以会先找到Person.class文件并加载到内存中;
2.执行该类中的static代码块,如果有的话,给Person.class类进行初始化
3.在堆内存中开辟空间,分配内存地址
4.在堆内存中建立对象的特有属性,并进行默认初始化
5.对属性进行显示初始化
6.对对象进行构造代码块初始化
7.对对象进行对应的构造函数初始化
8.将内存地址赋给内存中的p变量
设计模式:
解决某一类问题最行之有效的方法;
单例设计模式:解决一个类在内存中只存在一个对象;想要保证对象唯一,1.为了避免其他程序过多建立该对象,先控制禁止其他程序建立该对象;2.为了让其他程序可以访问到该对象,只好在本类中自定义一个对象;3。为了方便其他程序对自定义对象的访问,可以对外提供一些访问方式,实现方式:
1.将构造函数私有化
2.在类中创建一个本类对象
3.提供一个方法可以获取到该对象
饿汉模式:single类一进内存,就已经创建好了对象
class Single{
private Single(){ }
private static Single s = new Single();
public static Single getInstance()
{
return s;
}
}
class SingleDemo{
public static void main(String[]args){
Single ss = Single.getInstance();
}
}
对于事物该怎么描述还是怎么描述,当需要将该事物的对象保证在内存中唯一时,就将以上的三步加上即可
下面这个为
懒汉模式:对象是方法被调用时,才初始化,也叫做对象的延时加载;single类进内存,对象还没有存在,只有调用了getInstance方法,才建立对象
class Single{
private Single(){ }
private static Single s = null;
public static Single getInstance()
{
if(s==null){
synchronized(Single.class)
{
if(s==null)
s=new Single();
}
}
return s;
}
}
原则:定义单例时,使用饿汉式
继承:
1.提高代码的复用性
2.继承让类与类之间产生了关系,有了这个关系,才有了多态的特性剪坏
注意:千万不要为了获取其他类的功能,简化代码而继承。必须是类与类之间有所属关系才可以继承。所属关系 is a.
java只支持单继承,不支持多继承,因为多继承容易带来安全隐患,当多个父类中定义了相同功能,但是功能内容不同时,不确定运行哪一个,但是java保留了这种机制,并用另一种体现形式来完成表示,多实现
java支持多层继承,也就是一个继承体系,想要使用体系,先查阅体系中父类的描述,因为父类中定义的是该体系中共性功能。通过了解共性功能,就可以知道该体系的基本功能,那么这个体系已经可以基本使用了。 在具体调用时,要创建最子类的对象,因为(1)有可能父类不能创建对象,(2)创建子类对象可以使用更多的功能,包括基本的,也包括特有的
查阅父类功能,创建子类对象使用功能
聚集:has a
聚合,组合:
当子类继承父类,沿袭了父类的功能,到子类中,但是子类虽然有这个功能,但是功能的内容却和父类不一致,这时,没有必要定义新功能,而是使用覆盖保护,保留父类的功能定义,并重写功能内容
覆盖:
子类覆盖父类,必须保证子类权限大于等于父类权限,才可以覆盖,否则编译失败
静态只能覆盖静态
记住:重载只看同名函数的参数列表,重写看字符类方法样一模一样,返回值类型也要一样
final可以修饰类,方法,变量
final修饰的类不可以被继承
final修饰的方法不可以覆盖
final修饰的变量是一个常量,只能被赋值一次
内部类只能访问被final修饰的局部变量
抽象的特点:
1.抽象方法一定在抽象类中
2.抽象方法和抽象类都必须被abstract关键字修饰
3.抽象类中不可以用new创建对象,因为调用抽象方法没意义
4.抽象类中的方法要被使用,必须由子类复写其所有的抽象方法后,建立子类对象调用。如果子类只覆盖了部分抽象方法,那么该子类还是一个抽象类
抽象类和一般类没有太大的不同,该如何描述失误,就如何描述事物,只不过,该事物出现了一些看不懂的东西,这些不确定的部分也是该事物的功能,需要明确出来,无法定义主体,通过抽象方法来表示
抽象类比一般类多了抽象函数;抽象类不可以实例化,就是在类中可以定义抽象方法
抽象类中可以不定义抽象方法,这样做仅仅是不让该类建立对象
接口中的成员修饰符是固定的:
成员常量:public static final
成员函数:public abstract
接口的出现,将“多继承”通过另一种形式体现出来,即“多实现”
接口(interface):初期理解,可以认为是一个特殊的抽象类;当抽象 类中的方法都是抽象的,那么该类可以通过接口的形式来表示
class用于定义类;interface用于定义接口;接口中的成员都是public的
接口是不可以创建对象的,因为有抽象方法,需要被子类实现,子类对接口中的抽象方法全都覆盖后,子类才可以实例化,否则子类是一个抽象类
接口是对外暴漏的规则;是程序的功能扩展;可以用来多实现;类与接口之间是实现关系,而且类可以继承一个类的同时实现多个接口;接口与接口之间可以有继承关系
多态:可以理解为事物存在的多种体现形态
1.多态的体现:父类的引用指向了自己的子类对象;父类的引用也可以接收自己的子类对象。
2.多态的前提
必须是类与类之间有关系,要么继承,要么实现;通常还有一个前提,就是覆盖
3.多态的好处
多态的出现大大的提高了程序的扩展性
弊端:只能使用父类的引用访问父类的成员
4.多态的应用
5.多态使用的注意事项
我们能转换的是父类引用指向了自己的子类对象,该应用可以被提升,也可以被强制转换
在多态中成员函数的特点:
在编译时期:参阅引用型变量所属的类中是否有调用的方法。如果有,编译通过,如果没有编译失败
在运行时期:参阅对象所属的类中是否有调用的方法。
简单总结:成员函数在多态调用时,编译看左边,运行看右边
在多态中,成员变量的特点,无论编译和运行,都参考左边(引用型变量所属的类型)
在多态中,静态成员函数的特点:无论编译和运行,都参考左边
主板案例:
Interface PCI
{
public void open();
public void close();
}
class MainBoard
{
public void run()
{
System.out.println("MainBoard run");
}
public void usePCI(PCI p)
{
p.open();
p.close();
}
}
class NetCard implements PCI
{
public void open()
{
System.out.println("run");
}
public void close()
{
System.out.println("close");
}
}
class ZhuBan
{
public static void main(String[] args)
{
MainBoard mb = new MainBoard();
mb.run();
mb.usePCI(NetCard);
}
}
Object是所有对象的直接或者间接父类,传说中的上帝;该类中定义的是所有对象都具备的功能。
Object类中已经提供了对对象是否相同的比较方法,如果自定义类中也有比较相同的功能,没有必要重新定义,紫瑶演戏父类中的功能,建立自己特有的内容即可,这就是覆盖
内部类可以直接访问外部类中的成员,包括私有成员(之所以可以直接访问外部类中的成员,是因为内部类中持有了一个外部类的引用,格式:外部类名.this);而外部类要访问内部类中的成员必须要建立内部类的对象
访问格式:
1.当内部类定义在外部类的成员位置上,而且非私有,可以在外部其他类中,直接建立内部类对象:
格式:
外部类名.内部类名 变量名 = 外部类对象.内部类对象;
2.当内部类在成员位置上,就可以被成员修饰符所修饰
比如:private:将内部类在外部类中进行封装;static:内部类就具备static的特性
当内部类被static修饰后,只能访问外部类中的static成员,出现了访问局限
在外部其他类中,直接访问static内部类的非静态成员:
new Outer.Inner().function();
在外部其他类中,直接访问static内部类的静态成员:
Outer.Inner.function();
注意:当内部类中定义了静态成员,该内部类必须是静态的;当外部类中的静态方法访问内部类时,内部类也必须是static的
当描述事物时,事物的内部还有事物,该事物用内部类来描述。
因为内部事务在使用外部事物的内容
内部类定义在局部时:1.不可以被成员修饰符修饰;2.可以直接访问外部类中的成员,因为还持有外部类中的引用。但是不可以访问它所在的局部中的变量。只能访问被final修饰的局部变量
匿名内部类:
1.匿名内部类就是内部类的简写格式
2.定义匿名内部类的前提:内部类必须继承一个类或者实现接口
3.匿名内部类的格式:new 父类或者接口(){定义子类的内容}
4.其实匿名内部类就是一个匿名子类对象。而且这个对象有点胖,可以理解为带内容的对象
5.匿名内部类中定义的方法最好不要超过3个
异常
异常的体系:
Throwable
Error :通常出现重大问题如:运行的类不存在或者内存溢出等;不编写针对代码对其处理
Exception:在运行时运行出现的一些情况,可以通过try catch finally
Exception和Error的子类名都是以父类名作为后缀
异常就是程序在运行时出现的不正常情况
异常的由来:问题也是现实生活中一个具体的事物,也可以通过java的类的形式进行描述,并封装成对象,其实就是java对不正常情况进行描述后的对象体现
对于问题的划分,分为:一种是严重的问题,一种是非严重的问题
try
{ 需要被检测的代码}
catch(异常类 变量)
{处理异常的代码;(处理方式)}
finally{一定会执行的语句}
对捕获到的异常对象进行常见方法操作:
其实jvm默认的异常处理机制,就是在调用printStackTrace方法,打印异常的堆栈的跟踪信息。
在功能上通过throws的关键字声明了该功能有可能出现的问题
对捕获到的异常对象进行常见方法操作; String getMessage():获取异常信息
在函数上声明异常:便于提高安全性,让调用出进行处理,不处理编译失败
对多异常的处理:
1.声明异常时,建议声明更为具体的异常,这样处理的可以更具体
2.对方声明几个异常,就对应有几个catch块;如果多个catch中的异常出现继承关系,父类异常catch块 放在最下面,不要定义多余的catch块
3.建议在进行catch处理时,catch中一定要定义具体处理方式,不要简单定义一句e.printStackTrace(),也不要简单的就书写一条输出语句
因为项目中会出现特有 的问题,而这些问题并未被java锁描述并封装对象,所以对于这些特有的问题可以按照java对问题封装的思想对特有的问题,进行自定义的异常封装
自定义异常:必须继承Exception;继承exception的原因,异常体系的特点,因为异常对象和异常类都会被抛出,因为他们都具备可抛性,这个可抛性是Throwable这个体系中的独有特点,只有这个体系中的类和对象才可以被throws和throw操作,
当在函数内部出现了throw抛出异常对象,那么就必须要给对应的处理动作:
1.要么在内部try ncatch处理
2.要么在函数上声明让调用者处理
一般情况下,函数内出现异常,函数上需要声明
throw和throws的区别:throws使用在函数上,throw使用在函数内;throws后面跟的是函数类,可以跟多个,用逗号隔开;throw后面跟的是函数对象
Exception中有一个特殊的子类异常RuntimeException运行时异常;如果在函数内抛出该异常,函数上可以不用声明,编译一样通过,如果在函数上声明了该异常,调用者可以不用进行处理,编译一样通过
自定义异常时,如果该异常的发生,无法再继续进行运算,就让自定义异常继承RuntimeException
对于异常分为两种:
1.编译时被检测的异常;
2.编译时不被检测的异常(运行时异常,RuntimeException以及其子类)
finally代码块:一定执行的代码块,通常用于关闭资源;finally只有一种情况不会执行,当执行到System.exit(0);finally不会执行
catch是用于处理异常,如果没有catch就代表异常没有被处理过,如果该异常是检测时异常,那么必须声明。
1.子类在覆盖父类时,如果父类的方法抛出异常,那么子类的覆盖方法,只能抛出父类的异常或者该异常的子类
2.如果父类方法抛出多个异常,那么子类在覆盖该方法时,只能抛出父类异常的子集
3.如果父类或者接口的方法中没有异常抛出,那么子类在覆盖方法时也不可以抛出异常,如果子类方法发生了异常就必须要进行try处理,绝对不能抛
异常的好处:
1.将问题进行封装
2.将正常流程代码和问题处理代码相分离,方便于阅读
异常的处理原则:
1.两种:try或者抛
2.调用到配偶出异常的功能时,抛出几个,就处理几个
3.多个catch,父类的catch放到最下面
4.catch内需要定义针对性的处理方式,不要简单的定义printstacktrace,或者输出语句,也不要不写;当捕获到的异常,本功能处理不了的时候,可以继续在catch中抛出;如果该异常处理不了,但并不属于该功能出现的异常,可以将异常转化后再抛出和该功能相关的异常或者异常可以处理但需要将异常产生后和本功能相关的问题提供出去,让调用者知道并进行处理,也可以将捕获异常处理后转换新的异常