• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
tyrantblue
博客园    首页    新随笔    联系   管理    订阅  订阅
Java学习笔记(五)面向对象和异常

学习笔记5

面向对象

一、初识面向对象

1. 面向对象思想

  1. 步骤清晰简单,第一步做什么,第二部做什么……
  2. 面对过程是和处理一些比较简单的问题。

2. 面向对象思想

  1. 物以类聚,分类的思维模式,思考问题首先会解决问题需要哪些分类,然后对这些分类进行单独思考,最后,才对某个分类下的细节进行面向过程的思索。
  2. 面向对象是和处理复杂的问题,是和处理需要多人协作的问题。

3. 什么是面向对象

  1. 面向对象编程(Object-Oriented Programming,OOP)

  2. 面向对象编程的本质就是:以类的方式组织代码,以对象的形式组织(封装)数据。

  3. 抽象:要把相似的东西抽取出来

  4. 三大特性:

    • 封装
    • 继承
    • 多态
  5. 从认识论角度考虑是先有对象后有类。对象是具体的事物,类是抽象的,是对对象的抽象。

  6. 从代码运行的角度考虑是先有类后有对象。类是对象的模板。

二、方法回顾与加深

1. 方法的定义

  1. 修饰符
  2. 返回类型
  3. break:跳出switch,结束循环和return的区别。
  4. 方法名:注意规范就OK,见名知意。
  5. 参数列表:(参数类型,参数名)……
  6. 异常抛出:后续讲解
package com.oop.demo01;

import java.io.IOException;

//Demo01类
public class Demo01 {

    //main方法
    public static void main(String[] args) {

    }

    /**
     修饰符 返回值类型 方法名(……){
        //方法体
        //return 返回值;
     }
     */
    public String sayHello(){
        return "hello, world";
    }
    public void print(){
        return;
    }
    public int max(int a, int b){
        return a>b ? a:b;
    }
    //数组下标越界异常:Arrayindexoutofbounds
    public void feadFile(String file) throws IOException{

    }
}

2. 方法的调用

  1. 静态方法
  2. 非静态方法
  3. 形参和实参
  4. 值传递和引用传递
  5. this关键字
  6. 例:
package com.oop.demo01;

public class Demo02 {
    public static void main(String[] args) {
        Students.say();
        //实例化这个类 new
        //对象类型 对象名 = 对象值;

        Students students = new Students();
        students.study();

    }

    //static和类一起加载的
    public static void a(){
//        b();
    }
    //非static是类实例化之后才存在,所以static不可调用非static类
    public void b(){

    }

}

package com.oop.demo01;

//学生类
public class Students {

    //静态方法
    public static void say(){
        System.out.println("学生说话了");
    }
    //非静态方法
    public void study(){
        System.out.println("学生在学习");
    }

}
package com.oop.demo01;

public class Demo03 {
    public static void main(String[] args) {

        //实际参数和形式参数的类型要对应!!!
        int add = add(1,2);
        System.out.println(add);
    }

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

}
package com.oop.demo01;

public class Demo04 {
    public static void main(String[] args) {
        int a = 1;
        System.out.println(a);//1

        change(a);

        System.out.println(a);//1

    }

    //返回值为空
    public static void change(int a){
        a = 10;
    }

}
package com.oop.demo01;

//引用传递:对象,本质还是值传递
public class Demo05 {
    public static void main(String[] args) {

        Person person = new Person();

        System.out.println(person.name);

        change(person);

        System.out.println(person.name);

    }

    //person是一个对象:指向的--->Person person = new Person();这是一个具体的人,可以改变属性
    public static void change(Person person){
        person.name = "tyrantblue";
    }
}

//定义了一个Person类,有一个属性:name
class Person{
    String name;//默认值为null

}

三、对象的创建分析

1. 类与对象的关系

  1. 类是一种抽象的数据类型,它是对某一类事物的整体描述/定义,但是并不能代表某一个具体的事物。
    • 动物、植物、手机、电脑……
    • Person类、Pet类、Car类等等,这些类都是用来描述/定义某一类具体的事物应该具备的特点和行为
  2. 对象是抽象概念的具体实例
    • 张三就是人的一个具体实例,张三家的旺财就是狗的一个具体实例。
    • 能够体现出特点,展现出国能的是具体的实例,而不是一个抽象的概念。
  3. 例:创建类和初始化对象//使用new
package com.oop.demo02;

//学生类
public class Student {

    //属性: 字段
    String name;//null
    int age;//0

    //方法
    public void study(){
        System.out.println(this.name+"在学习");//this代表当前这个类
    }

}
package com.oop.demo02;

//一个项目应该只存一个main方法
public class Application {
    public static void main(String[] args) {

        //类:抽象的,实例化
        //类实例化后会返回一个自己的对象
        //student对象就是一个Student类的具体实例!
        Student xiaoming = new Student();
        Student xiaohong = new Student();

        xiaoming.name = "小明";
        xiaoming.age = 3;

        xiaohong.name = "小红";
        xiaohong.age = 3;

        System.out.println(xiaoming.name);
        System.out.println(xiaoming.age);
        System.out.println(xiaohong.name);
        System.out.println(xiaohong.age);
    }
}

2. 创建和初始化对象

  1. 使用new关键字创建对象
  2. 使用new关键字创建的时候,除了分配内存空间之外,还会给创建好的对象进行默认的初始化以及对类中构造器的调用。
  3. 类中的构造器也称为构造方法,是在进行创建对象的时候必须要调用的。并且构造器有以下两个特点:
    1. 必须和类的名字相同
    2. 必须没有返回类型,也不能写void
  4. 构造器必须要掌握。
  5. 例:构造器
package com.oop.demo02;

public class Person {

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

    String name;
    int age;

    //实例化初始值
    //1. 使用new关键字,本质是再调用构造器
    //2. 用来初始化值
    public Person(){
        this.name = "tyrantblue";
    }

    //有参构造:一旦定义了有参构造,无参就必须显示定义
    //方法的重载
    public Person(String name){
        this.name = name;
    }

    //alt+insert
    //一键生成构造器

}

/*
 public class Application {
    public static void main(String[] args) {

        Person person = new Person();
        Person person1 = new Person("tyrantblue");

        System.out.println(person.name);

    }
 }
 */

构造器:

  1. 和类名相同
  2. 没有返回值

构造器作用:

  1. new 本质在调用构造方法
  2. 初始化对象的值

构造器注意点:

  1. 定义有参构造后,如果想使用无参构造,要显示地定义一个无参的构造

  2. alt + insert 一键生成构造器

3. 创建对象内存分析

  1. 首先将main方法压入栈,在方法区存入Application的main方法和一些常量
  2. new时调用构造器,将模板放入方法区,将引用变量名压入栈,在堆中调用方法区中的模板创建一个具体的对象
  3. 把值赋给对象
  4. 再次new一个新的对象过程重复2,在堆中不同的地址中创建具体的对象
  5. 方法区中有一个静态区static,可以直接调用
  6. 方法区也在堆中
  7. 示例代码:
package com.oop.demo02;

public class Pet {
    public String name;
    public int age;

    //无参构造

    public void shout(){
        System.out.println("叫了一声");
    }
}

/**
 public class Application {
 public static void main(String[] args) {

 Pet dog = new Pet();
 dog.name = "wangcai";
 dog.age = 3;
 dog.shout();

 System.out.println(dog.name);
 System.out.println(dog.age);

 Pet cat = new Pet();

 }
 }
 */

4. 小结

  1. 类与对象
    • 类是一个模板:抽象
    • 对象是一个具体的实例
  2. 方法
    • 定义和调用
  3. 对象的引用
    • 引用类型:对应的基本类型(8),除了基本类型全是引用类型
    • 对象是通过引用来操作的:在栈中引用堆
  4. 属性:字段Field 或者叫成员变量
    • 默认初始化:
      • 数字: 0 , 0.0
      • char :u0000
      • boolean:false
      • 引用:null
    • 修饰符 属性类型 属性名 = 属性值;
  5. 对象的创建和使用
    • 必须使用new关键字创建对象,而且需要构造器 //Person tyrantblue = new Person();
    • 对象的属性 tyrantblue.name
    • 对象的方法 tyrantblue.sleep()
  6. 类
    • 静态的属性 属性
    • 动态的方法 方法

四、面向对象三大特性

1. 封装

  1. 该露的露,该藏得藏

    我们程序设计要追求高内聚,低耦合。高内聚就是类的内部数据操作细节自己完成,不允许外部干涉;低耦合:尽保禄少量的方法给外部使用。

  2. 封装(数据的隐藏)

    通常,应禁止直接访问一个对象中数据的实际表示,而应通过操作接口来访问,这称为信息隐藏。

  3. 记住这句话:

    属性私有,get/set

  4. 封装的意义

    1. 提高程序的安全性,保护数据
    2. 隐藏代码的实现细节
    3. 统一接口
    4. 系统可维护性增加了
  5. 示例代码:

package com.oop.demo03;

//类
public class Student {

    private String name;//名字
    private int id;//学号
    private char sex;//性别
    private int age;//年龄

    // 提供一些可以操作这个属性的方法
    // 提供一些public的get、set方法

    //get方法 获得这个数据
    public String getName(){
        return this.name;
    }

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

    //alt + insert


    public void setId(int id) {
        this.id = id;
    }

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

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

    }

    public int getId() {
        return id;
    }

    public char getSex() {
        return sex;
    }

    public int getAge() {
        return age;
    }
}

/*
public class Application {
    public static void main(String[] args) {

        Student student = new Student();
        student.setName("tyrantblue");
        student.setId(123456);
        student.setSex('n');
        student.setAge(1000);//不合法的
        System.out.println(student.getName());
        System.out.println(student.getId());
        System.out.println(student.getSex());
        System.out.println(student.getAge());
    }
}
 */

2. 继承

- 继承
  1. 继承的本质是对某一批类的抽象,从而实现对现实世界更好的建模。
  2. extends的意思是"拓展",子类是父类的扩展。
  3. JAVA中类只有单继承,没有多继承 //一个儿子只能有一个爸爸,一个爸爸可以有多个儿子
  4. 继承是类和类之间的一种关系,除此之外,类和类之间的关系还有依赖、组合、聚合等。
  5. 继承关系的两个类,一个为子类(派生类),一个为父类(基类)。子类继承父类,使用关键字extends来表示。
  6. 子类和父类之间,从意义上讲应该具有"is a"的关系。
  7. 示例代码:
package com.oop.demo04;

//在java中,所有的类,都默认继承Object类
//Person 人: 父类
public class Person {

    //public
    //protected
    //private
    //default

    private int money = 10_000_000;

    public void say(){
        
        System.out.println("说了一句话");
    }
}

package com.oop.demo04;

//学生 is 人 :派生类,子类
//子类继承了父类,就会拥有父类的全部方法
public class Student extends Person {

    //Chrl + H
}

/*
import com.oop.demo04.Student;
public class Application{
    public static void main(String[] args) {

        Student student = new Student();

        student.say();
        //System.out.println(student.money);
    }
}
 */
- super
  • 注意点
  1. super调用父类的构造方法,必须在构造方法的第一个
  2. super 必须只能出现在子类的方法或者构造方法中
  3. super和 this 不能同时调用构造方法
  • 和this的不同
  1. 代表的对象不同:

    • this: 本身调用者这个对象
    • super:代表父类对象的应用
  2. 前提:

    • this:没有继承也可以使用

    • super:只能在继承条件下才可以使用

  3. 构造方法:

    • this():本类的构造
    • super():父类的构造
  • 示例代码
package com.oop.demo04;

//在java中,所有的类,都默认继承Object类
//Person 人: 父类
public class Person {

    //public
    //protected
    //private
    //default

    protected String name = "xuehualinran";
    private int money = 10_000_000;

    public void say(){

        System.out.println("说了一句话");
    }

    public void print(){
        System.out.println("Person");
    }

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


package com.oop.demo04;

//学生 is 人 :派生类,子类
//子类继承了父类,就会拥有父类的全部方法
public class Student extends Person {

    private String name = "tyrantblue";

    public void test(String name){
        System.out.println(name);//雪化凛然
        System.out.println(this.name);//tyrantblue
        System.out.println(super.name);//xuehualinran
        //System.out.println(super.money);//不能调用私有的属性

    }

    public void print(){
        System.out.println("Student");
    }

    public void test1(){
        print();
        this.print();
        super.print();
    }

    public Student() {
        //隐藏代码:调用了父类的无参构造器
        super();//调用父类的构造器,必须要在子类构造器的第一行
        System.out.println("Student无参构造执行了");
    }
//Chrl + H
}

/*
import com.oop.demo04.Student;
public class Application{
    public static void main(String[] args) {

        Student student = new Student();

        //student.say();
        //System.out.println(student.money);

        //student.test("雪化凛然");
        student.test1();

    }
}
 */
- 重写

需要有继承关系,是子类重写父类的方法

  1. 方法名必须相同
  2. 参数列表必须相同
  3. 修饰符:范围可以扩大: public>protected>default>private
  4. 抛出的异常:范围可以被缩小,但不能扩大:ClassNotFoundException-->Exctption(大)

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

为什么需要重写:

  1. 父类的功能子类不一定需要或者不一定满足
    1. Alt + Insert Override;

示例代码:

package com.oop.demo04;

public class B {
    public void test(){
        System.out.println("B=>test()");
    }
}

package com.oop.demo04;

//继承
public class A extends B{
//
//    //重写都是方法的重写,和属性无关
//    public void test(){
//        System.out.println("A=>test");
//    }

    //Override  重写
    @Override //注解:有功能的注释
    public void test() {
        System.out.println("A=>test()");
    }
}


import com.oop.demo04.*;


public class Application{
    public static void main(String[] args) {

        //静态方法和非静态的方法区别很大
            //静态方法:

        //方法的调用只和左边,即定义的数据类型有关
        A a = new A();
        a.test();//调用的A类的静态方法

        //父类的引用指向了子类
        B b = new A();
        b.test();

    }
}

3. 多态

- 多态
  1. 可以实现动态编译:类型:可扩展性

  2. 即同一方法可以根据发送对象的不同而采用多种不同的行为方式。

  3. 一个对象的实际类型是确定的,但可以指向对象的引用的类型有很多(父类,有关系的类)

  4. 注意事项:

    1. 多态是方法的多态,属性没有多态
    2. 父类和子类有联系,类型转换异常: ClassCastException
    3. 存在条件:继承关系,方法需要重写,父类引用指向子类对象 Father fi = new Son();
    4. 无法重写的:
      1. static 方法,属于类,不属于实例
      2. final 是常量无法重写
      3. private 方法无法重写
    5. 示例代码:
package com.oop.demo05;

public class Person {

    public void run(){
        System.out.println("run");
    }
}

package com.oop.demo05;

public class Student extends Person {
    public void run(){
        System.out.println("son");
    }
    public void eat(){
        System.out.println("eat");
    }

}

/*
import com.oop.demo05.*;

public class Application{
    public static void main(String[] args) {

        //一个对象的实际类型是确定的
        //new Student();
        //new Person();

        //可以指向的引用类型就不确定了:父类的引用指向子类
        //Student 能调用的方法都是自己的或者父类的
        Student s1 = new Student();
        //Person 父类型可以指向子类,但是不能调用子类独有的方法
        Person s2 = new Student();
        Object s3 = new Student();

        s1.run();
        s2.run();//子类重写了父类的方法,执行了子类的方法

        s1.eat();
        //s2.eat();

    }
}
 */
- instanceof和类型转换
  1. 父类引用指向子类的对象
  2. 把子类转化为父类,向上转型
  3. 把父类转化为子类,向下转型,强制转换
  4. 方便方法的调用,减少重复的代码,使代码变得简洁
  5. 示例代码:
package com.oop.demo06;

public class Person {

    public void run(){
        System.out.println("run");
    }

}


package com.oop.demo06;

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

}


package com.oop.demo06;

public class Teacher extends Person{
}



package com.oop;

import com.oop.demo06.*;

public class Application{
    public static void main(String[] args) {
        //类型的转换: 父  子

        //子类转换为父类,可能丢失自己本来的一些方法

        //高             低
        Person obj = new Student();
        Student obj1 = (Student) obj;
        ((Student) obj).go();

        Student student = new Student();
        student.go();
        Person person = student;
        //person.go();//丢失一些子类本来的方法

    }
}



//    public static void main(String[] args) {
//
//        //Object > Person > Student
//        //Object > Person > Teacher
//        //Object > String
//        Object object = new Student();//爸爸的爸爸类
//
//        //System.out.println(X instanceof Y);//能不能编译通过
//
//        System.out.println(object instanceof Student);//ture
//        System.out.println(object instanceof Person);//ture
//        System.out.println(object instanceof Object);//ture
//        System.out.println(object instanceof Teacher);//false
//        System.out.println(object instanceof String);//false
//
//        System.out.println("===================");
//
//        Person person = new Student();
//        System.out.println(person instanceof Student);//ture
//        System.out.println(person instanceof Person);//ture
//        System.out.println(person instanceof Object);//ture
//        System.out.println(person instanceof Teacher);//false
//        //System.out.println(person instanceof String);//编译报错//一条分支下可以判断,不同分支不能判断
//
//        System.out.println("===================");
//
//        Student student = new Student();
//        System.out.println(student instanceof Student);//ture
//        System.out.println(student instanceof Person);//ture
//        System.out.println(student instanceof Object);//ture
//        //System.out.println(student instanceof Teacher);//编译报错
//        //System.out.println(person instanceof String);//编译报错
//    }
- static关键字

示例代码如下:

package com.oop.Demo07;

public class Person {

    //2:赋初值
    {
        //代码块(匿名代码块)
        System.out.println("匿名代码块");
    }

    //1: 只执行一次
    static{
        //静态代码块
        System.out.println("静态代码块");
    }

    //3
    public Person() {
        System.out.println("构造方法");
    }

    public static void main(String[] args) {
        Person person1 = new Person();
        System.out.println("======================");
        Person person2 = new Person();
    }

}

package com.oop.Demo07;

public class Student {
    private static int age;//静态的变量
    private double score;//非静态的变量

    public void run(){

    }

    public static void go(){

    }

    public static void main(String[] args) {

        go();//和类一起被加载,且只加载一次
        //run();//和对象创建一起被加载



        Student s1 = new Student();

        System.out.println(Student.age);
        System.out.println(s1.age);
        System.out.println(s1.score);
        //System.out.println(Student.score);


    }
}

package com.oop.Demo07;

//import java.lang.Math.random;
//静态导入包
import static java.lang.Math.random;

public class Test {

    public static void main(String[] args) {
        System.out.println(Math.random());
    }
}

当类被 final 修饰时不能被继承 ( 断子绝孙 )

五、抽象类和接口

1. 抽象类

  1. abstract修饰符可以用来修饰方法以可以修饰类,如果修饰方法,那么该方法就是抽象方法,如果修饰类,那么该类就是抽象类
  2. 抽象类中可以没有抽象方法,但是有抽象方法的类一定要慎名为抽象类。
  3. 抽象类不能使用new关键字来创建对象,它是用来让子类继承的
  4. 抽象方法,只有方法的声明没有方法的实现,它是用来让子类实现的
  5. 子类继承抽象类,那么就必须要实现抽象类没有实现的抽象方法,否则该子类也要声明为抽象类
  6. 示例代码:
package com.oop.demo08;

//abstract 抽象类:本质是一个类,使用关键字extends,是单继承
//接口能实现单继承
public abstract class Action {

    //约束——有人帮忙实现
    //抽象方法,只有方法名字,没有方法实现
    public abstract void doSomething();

    //1. 不能new这个抽象类,只能靠子类去实现它:约束
    //2. 抽象类中可以写普通方法
    //3. 抽象方法必须在抽象类中
    //就是抽象的抽象,只是一个约束

    //思考题: 不能new对象,存在构造器吗?——存在构造器
                //存在的意义是什么?——提高开发效率,后期的可扩展性高

}



package com.oop.demo08;

//抽象类的所有方法,继承了它的子类,都必须要实现它的方法
public class A extends Action {
    @Override
    public void doSomething() {

    }
}



package com.oop;

import com.oop.demo08.*;

public class Application{

    public static void main(String[] args) {

        //抽象类不能被实例化
        //new Action();//'Action' is abstract; cannot be instantiated
    }

}

2. 接口

  1. 普通类:只有具体实现
  2. 抽象类:具体实现和规范(抽象方法)都有
  3. 接口:只有规范,自己无法写方法——是专业的约束
  4. 接口就是一种规范,定义的是一组规则,体现了现实世界中"如果你是...则必须要..."
  5. 面向对象的精髓,是对对象的抽象,最能体现这一点的就是接口
  6. 示例代码:
package com.oop.demo09;

//interface: 定义接口的关键字
public interface UserService {
    //接口的定义都是抽象的 public abstract

    //在接口中定义的变量都是常量: public static final
    int AGE = 99;

    void add();
    void delete();
    void update();
    void query();


}


package com.oop.demo09;

public interface TimeService {

    void timer();
}


package com.oop.demo09;

//抽象类使用 extends
//类可以实现接口,需要重写接口中的方法
//多继承——利用接口实现多继承

public class UserServiceImp1 implements UserService,TimeService{

    @Override
    public void add() {

    }

    @Override
    public void delete() {

    }

    @Override
    public void update() {

    }

    @Override
    public void query() {

    }

    @Override
    public void timer() {

    }
}

  • 总结
    1. 约束
    2. 定义一些方法,让不同的人实现
    3. 定义的方法修饰为public sbstract
    4. 定义的变量修饰为public static final
    5. 接口不能被实例化,且接口中没有构造方法
    6. implements可以实现多个接口
    7. 实现接口必须需要重写接口中的方法

六、内部类

示例代码:

package com.oop.demo10;

public class Outer {

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

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

        //获得外部类的私有属性
        public int getId() {
            return id;
        }
    }

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

    }

}

//一个java文件中可以有多个class类,但是只能有一个public类


package com.oop.demo10;

import com.oop.demo09.UserService;

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

        UserService userService = new UserService() {
            @Override
            public void add() {

            }

            @Override
            public void delete() {

            }

            @Override
            public void update() {

            }

            @Override
            public void query() {

            }
        };
    }
}

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

异常

一、什么是异常

  1. 软件在运行过程中,可能遇到一系列异常问题,我们称之为异常,英文是:Exception,意思是例外,这些例外情况,或者叫异常,怎么让我们写的程序作出合理的处理,而不至于程序崩溃?
  2. 异常值程序运行中出现的不期而至的各种状况,如:文件找不到,网络连接失败,非法参数等。
  3. 异常发生在程序运行期间,它影响了正常的程序执行流程。

二、简单分类

  1. 要理解Java异常处理是如何工作的,你需要掌握以下三种类型的异常:

    • 检查性异常:最具代表性宜昌市用户错误或问题引起的异常,这是程序员无法预见的,例如要打开一个不存在文件时,一个异常就发生了,这些异常在编译时不能被简单地忽略。
    • 运行时异常:运行时异常是可能被程序员避免的异常,与检查性异常相反,运行时异常可以在编译时被忽略
    • 错误ERROR:错误不是异常,而是脱离程序员控制的问题。错误在代码中通常被忽略,例如,当栈溢出时,一个错误就发生了,他们在编译时是也检查不到的。
  2. 异常处理框架

    • java把异常当作对象来处理,并定义一个基类java.lang.Throwable作为所有异常的超类
    • 在java API中已经定义了许多异常类,这些异常分为两大类,错误Error和异常Exception
      • Error
        • Error类对象由java虚拟机生成并抛出,大多数错误与代码编写者所执行的操作无关。
        • java虚拟机运行错误(Virtual MachineError)当JVM不再有继续执行操作所需的内存资源时,将出现OutMemoryError。这些异常发生时,JVM一般会选择线程终止。
        • 还有发生在虚拟机试图执行应用时,如类定义错误(NoClassDefFoundError)、链接错误(LinkageError)。这些错误是不可查的,因为他们在应用程序的控制和处理能力之外,而且绝大多数是程序运行时不允许出现的状况。
      • Exception
        • RuntimeException(运行时异常): ArrayIndexOutofBoundsException(数组下标越界),NullPointerExcepton(空指针异常),ArithmeticException(算数异常),MissingResourceException(丢失资源),ClassNotFoundException(找不到类)等异常,这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。
        • 这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生;
        • Error和Exception的区别:Error通常是灾难性的致命的错误,是程序无法控制和处理的,当出现这些异常时,Java虚拟机(JVM)一般会选择终止线程;Exception通常情况下是可以被程序处理的,并且在程序中应该尽可能地去处理这些异常。

三、异常处理机制

  1. 抛出异常
  2. 捕获异常
  3. 异常处理五个关键字
    • try
    • catch
    • finally
    • throw
    • throws
  4. 示例代码
package com.exception;

public class Test {

    public static void main(String[] args) {

        int a = 1;
        int b = 0;

//        try{//try监控区域
//            System.out.println(a/b);
//        } catch(ArithmeticException e){
//            System.out.println("程序出现异常,变量b不能为0");
//        }finally{//用来处理善后工作//可以不要,一般用来关闭IO
//            System.out.println("finally");
//        }

        try {
            Test test = new Test();
            test.a();
        } catch (Throwable e) {
            System.out.println("异常信息");
        } finally {
            System.out.println("结束");
        }

    }

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



package com.exception;

public class Test02 {
    public static void main(String[] args) {
        int a = 1;
        int b = 0;

        //Ctrl + Atl + T

        try {
            if (b == 0){//throw   //throws一般用于方法中
                throw new ArithmeticException();//主动抛出异常
            }

            System.out.println(a/b);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
        }
    }
}

四、自定义异常

  1. 使用Java内置的异常类可以描述在编程时出现的大部分异常情况。除此之外,用户还可以自定义异常。用户自定义异常类,只需继承Exception类即可。
  2. 在程序中使用自定义异常类,大体可分为以下几个步骤:
    1. 创建自定义异常类
    2. 在方法中通过throw关键字抛出异常对象
    3. 如果在当前抛出异常的方法中处理异常,可以用try-catch语句捕获并处理,否则在方法的声明处通过throws关键字指明要跑出给方法调用者的异常,继续进行下一步操作。
    4. 在出现异常方法的调用者中捕获并处理异常。
  3. 示例代码:
package com.exception.demo02;

//自定义的异常类
public class MyException extends Exception{

    private int detail;

    //当数大于10则抛出异常
    public MyException(int a) {
        this.detail = a;
    }

    //toString: 异常的打印信息
    @Override
    public String toString() {
        return "MyException{" +
                "detail=" + detail +
                '}';
    }
}



package com.exception.demo02;

public class Test {
    public static void main(String[] args) {
        test(11);


    }

    static void test(int a) {
        System.out.println("传递的参数为" + a);

        if (a>10){
            try {
                throw new MyException(a);
            } catch (MyException e) {
                //增加一些处理异常的代码块
                e.printStackTrace();
            }
        }else {
            System.out.println("ok");
        }
    }

}

  1. 实际应用中的经验总结
    1. 处理运行时异常时,可以加一个catch(Exception)来处理可能会被遗漏的异常
    2. 在多重catch块后面,可以加一个catch(Exception)来处理可能会被遗漏的异常
    3. 对于不确定的代码,也可以加上try-catch,处理潜在的异常
    4. 尽量去处理异常,切忌只是简单地调用printStackTrace()去打印输出
    5. 具体如何处理异常,要根据不同的业务需求和异常类型去决定
    6. 尽量添加finally语句块去释放占用的资源
posted on 2023-03-07 16:55  雪化凛然  阅读(60)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3