JavaSE,包括面向对象,异常等基础知识

方法调用

静态方法、非静态方法

/*

* 有static的变量,方法。用来修饰的方法可以直接用 类名.变量名/方法名 来调用。而没有static变量、方法则不能通过 类名.变量名/方法名 调用,只能通过声明对象的方式,使用对象来调用
*

* static和类一起加载,没有static的变量,方法在类实例化(new 对象)之后才存在

*/

//静态方法 有static

//非静态方法 没有static

形参、实参

public class Demo03 {

    public static void main(String[] args) {
        
        //实际参数和形式参数的类型要一致
        int a = new Demo03().add1(7, 8);    //7, 8 是实际参数,是真实的值
        int b = Demo03.add2(6,8);
        System.out.println(a);
        System.out.println(b);
    }

    public int add1(int a, int b){
        return a + b;
    }

    public static int add2(int a, int b){   //int a, int b 就是形式参数
        return a + b;
    }
}

值传递、引用传递

牢记:Java的8大基本类型是值传递,其他如对象等都是引用传递

//值传递
public class Demo04 {
    public static void main(String[] args) {
        int a = 1;
        System.out.println("执行了main方法体前的a:" + a);  //a为1

        Demo04.f(a);            //值传递,将main中a的值1传给f中a
        System.out.println("执行了main方法体后的a:" + a);  //打印出来的还是main中的a,因为是值传递,所有main中a并未改变

    }

    public static void f(int a){
        System.out.println("未执行方法体前f中的a:" + a);
        a = 10;
        System.out.println("执行方法体后f中的a:" + a);

    }
}
//引用传递:对象,本质还是值传递
public class Demo05 {
    public static void main(String[] args) {
        Person person = new Person();
        System.out.println("调用f方法之前person.name:" + person.name);    //null
        Demo05.f(person);
        System.out.println("调用f方法之后person.name:" + person.name);    //zwx
    }

    public static void f(Person person){
        System.out.println("未执行方法体前f中的person.name:" + person.name);
        //person是一个对象,这是一个具体的人可以改变属性
        person.name = "zwx";
        System.out.println("未执行方法体前f中的person.name:" + person.name);
    }
}

class Person{
    String name;
}

类与对象

创建与初始化对象

使用new关键字创建对象

构造器,也叫构造方法,在创建对象时必须要调用。构造方法有以下两个特点:

  • 方法名和类名必须相同
  • 不能有返回值,也不能写void

构造器总结

构造器:

​ 1 和类名相同

​ 2 没有返回值,不能写void

作用:

​ 1 new本质就是调用构造方法

​ 2 初始化对象的值

注意点:

​ 如果定义了有参构造,则最好要写出无参构造,如public Person(){}

生成构造器快捷键:

alt + insert

​ this.name = name 中前者是类里面的,后者是参数传进来的

public class Person {
    //一个类即使什么都不写,也会存在一个方法---显示的定义构造方法

    String name;

    //无参构造方法

    /*构造器两大核心作用
    1、 使用new关键字,本质是在调用构造器,因此必须要有构造器
     */
    public Person(){
        //this.name = "zwx";    
    }

    /*构造器两大核心作用
    2、 有参构造:一旦定义了有参构造,就必须写出无参构造器,否则报错
     */

    public Person(String name){
        this.name = name;  //name是参数传递下来的,this.name是指类中的name
    }
}

创建对象内存分析

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VcswHHiH-1684735763604)(https://gitee.com/zwx0203/cloudimage/raw/master/%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20230518111227.jpg)]

小总结

1 类与对象

​ 类是一个模板,抽象。对象是一个类的具体的实例

2 方法

​ 定义、调用

3 值传递,引用传递

​ 值传递: 8大基本类型

​ 引用传递:除8大基本类型都是引用传递,如对象就是引用传递

4 属性:字段Field 成员变量

​ 默认初始化:

​ 数字: 0 0.0

​ char: u0000

​ boolean: false

​ 引用: null

​ 修饰符 属性类型 属性名 = 属性值

5 对象的创建和使用

​ 必须使用new关键字创建对象 Person zwx = new Person()

​ 要会使用构造器

​ 调用对象的属性 zwx.name

​ 调用对象的方法 zwx.sleep()

6 类

类里只有属性和方法

封装、继承、多态

封装

封装大多数是针对属性来的,针对方法的一般比较少,只需记住属性私有,get/set

使用alt + insert 自动生成get,set方法

public class Student {
    //封装只需记住一句话:属性私有,get/set,set方法中有时会做一些安全性的验证,判断。
    //alt + insert 自动生成get,set方法
    //封装:禁止直接访问对象中的属性,而是通过get,set来访问
    /*封装的意义
    1 提高程序安全性,保护数据
    2 隐藏代码的实现细节
    3 统一接口
    4 提升系统可维护性
     */
    
    
    //属性方法
    private String name;//名字
    private int styid;//学号
    private char sex;//性别
    private int age; //年龄



    //get,set 提供一些可以操作这些属性的方法
    //get 获得这个数据
    public String getName(){
        return this.name;
    }

    //set 给这个数据设值
    public void setName(String name){
        this.name = name;
    }



    public int getStyid() {
        return styid;
    }

    public void setStyid(int styid) {
        this.styid = styid;
    }

    public char getSex() {
        return sex;
    }

    public void setSex(char sex) {
        this.sex = sex;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        if(age < 120 && age > 0){
            this.age = age;
        }else {
            this.age = 3;
        }

    }
}

继承 extends

在Java中只有单继承,没有多继承。一个儿子只能有一个爸爸,但一个爸爸可以有多个儿子

public 一般让子类继承的一些属性和方法,都设置为public,但一般属性都是私有的
protected 受保护的,访问范围是:当前包所有的类+当前包以外的子类。
default 什么修饰符都没写就是default 默认的
private 一般来说属性都是私有的

Person类 父类(基类)

package com.oop.demo05;

//父类 基类
public class Person /*extends Object*/ {

    /*
    public  一般让子类继承的一些属性和方法,都设置为public,但一般属性都是私有的
    protected 访问范围是:当前包所有的类+当前包以外的子类。
    default 什么修饰符都没写就是default 默认的
    private 一般来说属性都是私有的
     */

    //在Java中,所有类都默认直接或间接继承Object类

    //在Java中只有单继承,没有多继承。一个儿子只能有一个爸爸,但一个爸爸可以有多个儿子
    private int money = 10_0000_0000;

    private String happy = "very happy";    //私有属性,无法被子类继承
    public void say(){
        System.out.println("说了一句话!");
    }

    public int getMoney() {
        return money;
    }

    public void setMoney(int money) {
        this.money = money;
    }

    public String getHappy() {
        return happy;
    }

    public void setHappy(String happy) {
        this.happy = happy;
    }
}


Student类 子类(派生类)

//学生 是 人 : 派生类,子类
//子类继承了父类,就会拥有父类的全部方法和属性(前提修饰符是public)
public class Student extends Person {

}

Teacher类 子类(派生类)

//老师 是 人
public class Teacher extends Person {

}

final修饰的类不能被继承

final之后断子绝孙了!!啊哈哈!

public final class Person {}	//父类,若父类用了final修饰,表示常量,不可以被修改
public class Student extends Person {}	//子类,直接报错
object类

在Java中,所有类都默认直接或间接继承Object类

super,this关键字

super注意点:

​ 1. super()调用父类的构造方法和this()调用本类构造方法,都必须在子类构造方法里最前面

​ 2. super(),this() 不能同时调用构造方法(由1可推出)

​ 3. super只能出现在子类的方法或构造方法中

super Vs this:
代表的对象不同:
this:代表本身这个对象
super:代表父类对象
前提
this:没继承也能使用
super:只能在继承后才能使用
构造方法
this(): 本类的构造方法
super(): 父类的构造

public class Person /*extends Object*/ {
    protected String name = "zwx";

    public Person() {
        System.out.println("Person无参构造执行");
    }

    //私有方法或属性均无法被继承
    public void print(){
        System.out.println("Person");
    }
}

public class Student extends Person {

    //隐藏代码:默认调用了父类的无参构造
    public Student() {
        super(); //调用父类的构造器,必须在子类构造器最前面(默认调用父类的无参构造)
        System.out.println("Student无参构造执行");
    }

    //有参构造
    public Student(String name) {
        this.name = name;
    }

    private String name = "周文星";


    public void print(){
        System.out.println("Student");
    }
    
    public void test(String name){
        System.out.println(name);	//形参name	htt
        System.out.println(this.name);	//本类的name 周文星
        System.out.println(super.name);	//父类的name zwx
    }

    public void test1(){
        print(); //Student
        this.print();  //Student
        super.print();  //Person
    }
}
public class Application {

    public static void main(String[] args) {

        Student s1 = new Student();

        s1.test("htt");
        s1.test1();
    }
}

输出:
Person无参构造执行
Student无参构造执行
htt
周文星
zwx
Student
Student
Person

方法重写
不能被重写的方法:
  		1. static 修饰的方法,属于类,它不属于实例,不能被重写
  		1. final  修饰的方法,常量,不能被重写
  		1. private 修饰的方法,私有方法,不能被重写

重写:需要有继承关系,而且是子类重写父类的方法(重写只针对非静态方法,也就是子类不能重写带有static修饰符的父类方法)

​ 1. 方法名必须相同

​ 2. 参数列表必须相同(重载是在同一个类里写多个方法名一样的方法,列表,返回值等可以不同)

​ 3. 修饰符:范围可以扩大: public > Protected > Default > Private

​ 4. 重写可能会抛出异常,抛出的异常:范围可以被缩小,但不能扩大;ClassNotFoundException(小) --不能–> Exception(大)

重写 子类的方法和父类的方法必须要一致,方法体可不同!

为什么需要重写:
父类的功能,子类不一定需要,或者不满足

快捷键:alt + insert:override

image-20230518160052174

public class Person {
    public void run(){
        System.out.println("父亲跑起来了!");
    }
}
public class Student extends Person{
    @Override   //子类重写了父类的方法,则父类引用子类执行的是子类的方法
    public void run() {
        System.out.println("儿子跑起来了!");
    }

    public void eat(){
        System.out.println("吃饭!");
    }
}
public class Application {

    public static void main(String[] args) {

        //一个对象的实际类型是确定的
        //但可以指向的引用类型就不确定了

        //Student 能调用的方法都是自己的或者是继承过来的
        Student s1 = new com.oop.demo06.Student();

        //Person 父类型,可以指向子类,但不能调用子类独有的方法
        Person s2 = new com.oop.demo06.Student();//父类的引用指向子类
        //Student s3 = new Person(); 报错,因为子类的引用不能指向父类
        Object s3 = new com.oop.demo06.Student();

        s2.run();
        //如果子类重写了父类方法则调用子类方法,没重写则调用父类方法,运行时看右边类型

        //对象能执行哪些方法,主要看对象左边的类型,和右边new 类型关系不大
        //s2.eat();   //父类中没有eat方法,不能调用
        ((Student)s2).eat();//强制类型转换,把Person类型转成Student类型
        s1.run();
        s1.eat();

    }
}

多态

多态的功能

1多态可以使同一方法根据调用对象的不同,导致方法行为不同

2 多态可以实现动态编译,就是类型在执行过程中才可以确定,写代码时确定不了,提升程序可扩展性

即同一方法根据对象的不同而采用不同的行为方式

一个对象的实际类型是确定的,但可以指向对象的引用类型很多

多态总结

多态注意事项:

多态是方法的多态,属性没有多态

父类和子类,有联系 类型转换异常! ClassCastException

多态存在条件缺一不可:

有继承关系(extends)

有方法重写(子类重写父类方法),alt + insert 中 override

父类引用指向子类,如Person s2 = new Student()

注意:编译期间(写代码期间)看左边类型,运行期间看右边类型

Object object = new Student(); //这里X是object对象,X的左边类型是Object,x的右边类型是Student

不能被重写的方法:

  1. static 修饰的方法,属于类,它不属于实例,不能被重写
  1. final  修饰的方法,常量,不能被重写
  1. private 修饰的方法,私有方法,不能被重写
instanceof 关键字

语法:

X instanceof Y	//X一定得是对象,Y一定得是类 否则编译报错
  
//例如
Object object = new Student();  
//这里X是object对象,X的左边类型是Object,x的右边类型是Student
Student student = new Student();


object instanceof Student;  //true
object instanceof Teacher;	//false
object instanceof String;  //false
student instanceof Student;	//true
student instanceof Teacher;	//编译不通过
student instanceof String;  //编译不通过

//详细分析情况请见下面代码中的注释

作用:判断类与类之间是否存在关系

左边是引用类型(编译报不报错看左边,也就是编译时看X的左边类型与Y类是否有直系关系

右边是实际类型(返回ture or false看右边,运行时看X的右边类型与Y类是否有直系关系)

//Object > String
//Object > Person > Student
//Object > Person > Teacher

这里 Object与Person、Student、Teacher、String均有直系关系

但Student、Teacher、String三者之间没有任何关系

public static void main(String[] args) {


        //Object  > String
        //Object  > Person > Student
        //Object  > Person > Teacher


        Object object = new Student();  //左边是引用类型(能不能编译通过看左边),右边是实际类型(返回ture or false看右边,运行时看右边)
        //Object  > Person > Student
        System.out.println(object instanceof Student);//true
        System.out.println(object instanceof Person);//true
        System.out.println(object instanceof Object);//true
        //Object  > Person > Teacher  而Student与这条线无关
        System.out.println(object instanceof Teacher);//false。因为左边Object类与Teacher有直系关系所有可以通过编译;又因为右边Student类与Teacher类没有直系关系所有返回false
        //Object  > String  而Student与这条线无关
        System.out.println(object instanceof String);//false。因为左边Object类与String有直系关系所有可以通过编译;又因为右边Student类与String类没有直系关系所有返回false


        Person person = new Student();
        System.out.println(person instanceof Student);//true
        System.out.println(person instanceof Person);//true
        System.out.println(person instanceof Object);//true
        //Object  > Person > Teacher  而Student与这条线无关
        System.out.println(person instanceof Teacher);//false。因为左边Person类与Teacher有直系关系所以可以通过编译;又因为右边Student类与Teacher类没有直系关系所有返回false
    
        
        System.out.println(person instanceof String);//编译报错。因为左边Person类与String类没有直系关系

        Student student = new Student();
        System.out.println(student instanceof Student);//true
        System.out.println(student instanceof Person);//true
        System.out.println(student instanceof Object);//true
       
        System.out.println(student instanceof Teacher);//编译报错。因为左边Student类与Teacher类没有直系关系
      
        System.out.println(student instanceof String);//编译报错。因为左边Student类与String类没有直系关系


    //总结总结总结总结!!!!
    //System.out.println(X instanceof Y); //编译取决于X的左边类型和Y类型之间是否有直系关系。true、false取决于x对象右边类型和Y类型是否有直系关系
    }
类型转换

1 子类转父类,低转高,直接转就行

Student student = new Student();
Person person = student;把子类对象赋给父类叫向上转型,不强制转换,会丢失子类特有方法。前父后子,不强制

2 父类转子类,高转低,强制转换

Person s1 = new Student();

((Student) s1).go();

//上面这句代码等于后面这两句,后第一句就是强制转换

Student s2 = (Student) s1; //把指向子类对象的父类引用s1赋给子类引用s2叫向下转型,要强制转型。前子后父,强制

s2.go();

代码实例:

public class Person {
    public void run(){
        System.out.println("父亲跑起来了!");
    }
}

public class Student extends Person{
    public void go(){
        System.out.println("student gogogo!");
    }
}

public class Application {

    public static void main(String[] args) {
        //类型之间的转换:

    //父类转子类  ((Student) s1).go();======================================================================
        //高                    低
        Person s1 = new Student();

        s1.go(); //s1无法调用Student类中go方法,解决方法:把s1这个对象类型转成Student类型,就可以使用Student类中的go()方法

        //Person转成Student是高转低,要强制类型转换,语法如下:
        Student s2 = (Student) s1;
        s2.go();

        //上面两句代码可以合成下面这一句代码:
        ((Student) s1).go();

   //子类转父类 转成以后会丢失子类本来独有的方法=======================================================================
        Student student = new Student();
        student.go();
        Person person = student;//把子类对象赋给父类叫向上转型,不强制转换,会丢失子类特有方法
        person.go(); //转成父类之后,丢失了子类独有的方法

    }
}
static关键字详解

加了static 成为类属性/方法,用类可以调用。

补充: 建议使用类名去操作静态变量,这样很清楚的知道其是静态变量
静态变量对于类,在内存中只有一个,供类的所有实例(对象)一起使用

非静态方法与静态使用上的区别: 前提–在同一个类里
1 非静态方法可以直接调用静态方法/属性
2 静态方法可以调用静态方法/属性
3 静态方法不可以调用非静态方法/属性

package com.oop.demo07;

import com.sun.xml.internal.ws.addressing.WsaActionUtil;

//static总结
public class Student extends Person {//b

    private static int age; //静态变量  多线程会用到!
    private double score;   //非静态变量


    //加了static 成为类变量,用类可以调用。
    //补充: 建议使用类名去操作静态变量,这样很清楚的知道其是静态变量
    //      静态变量对于类,在内存中只有一个,供类的所有实例(对象)一起使用


    非静态方法与静态使用上的区别:      前提--在同一个类里
    //非静态方法可以直接调用静态方法/属性
    //静态方法可以调用静态方法/属性
    //静态方法不可以调用非静态方法/属性

    public void run(){
        System.out.println("run");
        go();						//非静态方法可以调用静态方法
        eat();						//非静态方法可以调用非静态方法
        System.out.println(age);	//非静态方法可以调用静态属性
        System.out.println(score);	//非静态方法可以调用非静态属性
    }
    
    
    public void eat(){}
    
    public static void go(){
        System.out.println("go");
    }

    public static void main(String[] args) {
        Student s1 = new Student();
									//在同一个类里	
        System.out.println(age);	//静态方法中可以调用静态变量
        System.out.println(score);  //静态方法中不能调用非静态属性,报错
		go();						//静态方法中可以调用静态方法
        run();						//静态方法中不可以调用非静态方法,报错
        
        
        System.out.println(s1.age);
        System.out.println(Student.age);//类变量用类调用。
        //补充: 建议使用类名去操作静态变量,这样很清楚的知道其是静态变量
        //      静态变量对于类,在内存中只有一个,供类的所有实例(对象)一起使用
        System.out.println(s1.score);
        //System.out.println(Student.score);//报错,没加static 不是类变量,不能用类调用


        Student.run();  //报错,run()不是静态方法,不能用类名来调用
        new Student().run();
        new Student().go();
        Student.go();


    }

}

抽象类,接口,内部类

抽象类(用的不多)

何为抽象类,抽象方法

用abstract来修饰的类就叫抽象类

用abstract来修饰的方法就叫抽象方法

二者区别与联系

1 抽象类不能实例化,故不能new抽象类,只能靠子类继承它实现它里面的抽象方法

2 抽象类里面可以写非抽象方法,但有抽象方法的类一定是抽象类

3 抽象方法,只有方法的声明,没有方法的实现,它是用来让子类实现的

4 子类继承抽象类,就必须重写抽象类的抽象方法,否则该子类也要声明为抽象类

思考?

1 抽象类不能实例化(不能new),那还存在构造器嘛? —存在

2 抽象类存在的意义? —把共有方法抽象出来~ 提升开发效率,扩展性

3 抽象类为什么用的没有接口多? —抽象类本质是类,需要用extends继承,但java中继承只能单继承,导致抽象类用的没那么多。 (接口可以多继承)

接口(用的多)

关键字:interface

普通类:只有具体实现

抽象类:具体实现和规范(抽象方法)都有

接口:只有规范。 实现约束和实现分离:面向接口编程

接口的作用:

​ 1 约束
​ 2 定义一些方法,让不同的人实现
​ 3 接口中的方法都是 public abstract, 常用
​ 4 接口中的属性都是 public abstract final,但一般不怎么用
​ 5 接口不能被实例化(不能new,因为接口中没有构造方法。况且抽象类都不能实例化,比抽象类还抽象的接口那肯定不能实例化)
​ 6 通过implement关键字可以实现多个接口,中间用逗号隔开
​ 7 实现接口必须要重写接口里面的所有方法

//UserService接口
public interface UserService {
    
    //接口中的所以定义的属性都是常量,都是public static final。但一般没有人在接口里面定义常量
    public static final int AGE = 99;

    //接口中的所以定义的方法都是抽象的,都是 public abstract。常用
    
    void add(String name);

    void delete(String name);

    void update(String name);

    void query(String name);
}
//TimeService接口
public interface TimeService {

    void time();
}
//实现UserService接口和TimeService接口
public class UserServiceImpl implements UserService,TimeService {

    @Override
    public void add(String name) {

    }

    @Override
    public void delete(String name) {

    }

    @Override
    public void update(String name) {

    }

    @Override
    public void query(String name) {

    }

    @Override
    public void time() {

    }
}

内部类(奇葩)

内部类就是在一个类的内部定义一个类。如,A类中定义一个类名叫B的类,那么B类就是A的内部类,A类就是B的外部类

内部类最强大的点:内部类可以访问外部类的私有变量

内部类分为:

​ 1 成员内部类—成员内部类可以访问外部类的私有变量

public class Outer {

    private int id = 10;

    public void out(){
        System.out.println("这是外部类的方法");
    }

    public  class Inner{
        public void in(){
            System.out.println("这是内部类的方法");
        }

        //成员内部类可以访问外部类的私有变量
        public void getID(){
            System.out.println(id);
        }
    }
}

​ 2 静态内部类—静态内部类访问不了外部类的私有变量

public static class Inner{	//内部类前面加了static
        public void in(){
            System.out.println("这是内部类的方法");
        }

        //静态内部类访问不了外部类的私有变量
        public void getID(){
            System.out.println(id);//报错,静态内部类访问不了外部类的私有变量
        }
    }

​ 3 局部内部类

public void method(){
        //局部内部类
        class InnerTwo{
            public void in(){
                
            }
        }
    }

​ 4 匿名内部类

public class Test {

    public static void main(String[] args) {
        //没有名字初始化类,不用将实例保存到变量中
        new Apple().eat();
        
        new UserService(){
            @Override
            public void hello() {
                
            }
        };
    }
}

class Apple{
    public void eat(){
        System.out.println("1");
    }
}

interface UserService{
    void hello();
}

异常

什么是异常

异常指程序运行中出现的不期而至的各种状况,如:文件找不到,网络连接失败,非法参数等

异常发送在程序运行期间,影响正常程序执行流程

异常简单分为三类

​ 1 检查性异常 由用户错误导致

​ 2 运行时异常 编译时看不到,只有运行时才能看到,也是最容易被程序员避免的异常

​ 3 错误error 错误不是异常,一般不是程序员造成的,可能是栈溢出了等导致的,在编译时也检查不到

异常体系结构

Java把异常当作对象来处理,基类java.lang.Throwable为所有异常的超类

Java中定义的异常类分为两大类,错误Error(无法预见)和异常Exception(可以预到)

示例图如下:

c1840daf93eff0f2e00d79c1d5b76c2

Error类对象由Java虚拟机生成并抛出,一般与程序员无关。

Exception 一般是由程序逻辑错误引起,与程序员有关

​ Exception由一个重要的子类RuntimeException 运行时异常,其他的异常统称为 非运行时异常

Error 与 Exception区别:

​ Error通常是致命的错误,程序无法控制和处理Error,当出现Error时,Java虚拟机(JVM)一般会终止线程

​ Exception通常是可以被程序处理的,并且在程序中应该尽可能去处理

Java异常处理机制

抛出异常

throw //主动抛出异常

捕获异常

try{

}catch(){

}finally{

}

public class Test {


    public static void main(String[] args) {

        int a = 1;
        int b = 0;

        //假设要捕获多个异常,必须从小到大(先子类再父类)去捕获,否则编译会报错

        //try{}catch(){}是必须要的,finally{}可以不要
        //finally   IO流中资源的关闭统一放着finally中(善后工作)
        try {//监控区域,在这里面的代码有异常就可以捕获的到
            System.out.println(a / b);
            //new Test().a();
        }catch (Error e){ //catch(想要捕获的异常类型) 捕获异常
            System.out.println("Error");
        }catch (Exception e){
            System.out.println("Exception");
        }catch (Throwable e){   //超类写后面,子类写前面
            System.out.println("Throwable");
        }finally {  //处理善后工作,无论有没有异常,finally中的代码始终都会执行。如 IO流中资源的关闭统一放着finally中(善后工作)
            System.out.println("finally");
        }

    }

    public void a(){b();}
    public void b(){a();}

}

异常处理五个关键字:try(尝试)、catch(捕获)、finally(无论执不执行都会走的)、throw(抛出异常)、throws (抛出异常)

捕获异常的意义:如果异常不捕获,程序会停止运行;异常被捕获后,程序会接着运行下去。

假设要捕获多个异常,必须从小到大(先子类再父类)去捕获,否则编译会报错

自定义异常

用户自定义异常类,只需继承Exception类即可

在程序中使用自定义异常类,大体可分为以下几个步骤:

​ 1 创建自定义异常类

​ 2 在方法中通过throw关键字抛出异常对象

​ 3 如果在当前抛出异常的方法中处理异常,可以使用try-catch语句捕获并处理;否则在方法的声明处通过throws关键字指明要抛出给方法调用者的异常,继续进行下一步操作

​ 4 在出现异常方法的调用者中捕获并处理异常

//自定义异常类,若数字>10则异常
public class MyException extends Exception {

    //传递数字,若数字>10则抛出异常
    private int detail;

    public MyException(int a) {
        this.detail = a;
    }

    //toString:异常的打印信息
    @Override
    public String toString() {

        return "MyException{" + "detail=" + detail + '}';
    }
}

//测试类
public class Test {

    //可能会存在异常的方法
    static void test(int a) throws MyException {
        
        System.out.println("传递的参数为:" + a);
        
        if (a > 10){
            throw new MyException(a);   //抛出
        }
        
        System.out.println("ok");
    }
    
    
    public static void main(String[] args)  {
        try {
            test(11);
        } catch (MyException e) {
            //增加一些处理异常的代码
            
            System.out.println("MyException=>" + e);
        }
    }
}

实际应用总结

处理运行时异常时,采用逻辑规避同时辅助try-catch处理

在多重catch块后面加一个最大的catch(Exception e)来处理可能被遗漏的异常

对不确定的代码,也可以加上try-catch,处理潜在异常

尽量去处理异常,尽量不要只调用printStackTrace()打印输出

根据不同的业务处理不同的异常

尽量添加finally语句去释放占用的资源,如IO~Scanner

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值