面向对象总结

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/L6_6LXXX/article/details/96445205

面向对象

什么是面向对象

面向对象和面向过程对比

面向对象:

面向对象是宏观的上为用户解决功能需求,用户只需要知道怎么用对象实现功能就好了,具体底层如何实现不用操心,不过面向对象的最底层还是以面向过程的方式实现,但面向对象对比面向过程,减少了学习成本。

面向过程:

面向对象是微观下对要实现的功能进行详细设计。

类和对象的关系

类:

类是对象的抽象,是将对象的相同部分提取出来

对象:

对象是对类的具象化的体系

先有类还是先有对象:

在编写过程中,是先有类,再有对象。

类加载

  • 1:调用当前类中的静态方法时

  • 2:创建当前类的实例对象时

构造器

构造器

在类中用来创建对象那个的方法称之为构造器

  1. 方法名与类名相同
  2. 没有返回值
  3. 允许方法重载
  4. 在默认情况下会自动生成无参构造器,但如果你写了构造器在不会生成。
构造器的调用:
  1. 通过new对象,自动调用构造器
  2. 通过 this() 或 super() 分别调用当前类的构造方法和其父类的的构造方法。

this的方法

this.

​ 当前对象的属性或方法

​ 可省略:使用的范围内,没有同名变量时(无异议时)

​ 不可省略:区分同名变量,局部变量和成员变量(有异议时)

this()

​ 构造器之间的互相调用

​ this()一定要在构造器的首行

在这里插入图片描述

继承

继承的优势:
  • 在一定程度上提高了代码的复用性
继承编写:
  • 子类 extends 父类 子类拥有父类中的所有的属性以及方法 (根据修饰确定是否能够全部继承)
什么是继承:

将多个类中的共性再一次抽取,抽取为一个父类。父类的作用就是用来将一些重复的内容不再多次编写(提高代码复用性)

注意事项:
  • java中只支持单继承 一个子类有且只能有一个父类 复用性的提高是有限的
多继承好还是单继承好
  • 多继承 :极大提高代码复用性 但是代码调用的复杂度也提升了
  • 单继承:代码调用的复杂度比较低,但是复用性比较有限
假设在应用场景中:
  • A->B 后期随着业务不断扩展,导致A需要继承C时一般的解决办法:A->B->C
  • 但是该种解决办法随着后期业务的不断升级,导致整个继承连会变得极其复杂,既不利于后期维护以及拓展。
  • 能不能用继承就别用继承。

super的用法

​ 当创建子类对象时 会先执行父类的构造器
​ super: 和this的用法一模一样

super.
  • 当前对象的父类对象的
super. 可省略的:
  • super和this的用法是重复的 都可以省略(就是没有同名时)
super. 不可省略
  • 如果子类和父类中出现了同名变量或者是同名方法
super()
  • 调用父类的构造器,默认情况下调用的父类的无参构造器(默认情况下每个类中都存再一个无参构造器 哪怕不写也存在)
  • 当父类中存在其他构造器时,无参构造器不存在,此时如果再子类中没有通过super()显示的指定调用的构造器会导致程序报错。
  • 在构造器中this()和super()不能同时出现,如果两个都不存在,则默认存在super()。

在这里插入图片描述

方法重写

在子类中定义了和父类中同名的方法 我们将该方法称之为重写方法(覆盖)

为什么需要重写?
  • 父类的功能不能满足子类的需求。子类在父类的基础上进行了扩展。
如何确定一个方法是重写方法?
  • 在子类的方法上加入@Overried 注解 如果不报错 证明是重写
重写的前提:
  • 一定要发生继承关系。并且子类的方法名和父类的方法名同名
  • 参数列表要一样
  • 返回类型要一样

Object

Object: 是所有类的根基类 超类 父类
  • 当一个类没有显式的继承关系的时候,默认情况下他的父类都是Object
Object:
  • toString : 输出对象 全限定名(包名.类名)@16进制hash值
  • 输出一个对象的时候默认情况下会调用当前对象的toString
  • getClass:获取当前类的Class对象 反射
  • == 比较基本数据类型比较的是值 比较引用类型比较的是地址
  • equals:如果没有对equals方法进行重写,则比较的是引用类型的变量所指向的对象的地址;诸如String、Date等类对equals方法进行了重写的话,比较的是所是否是同一类型的对象(不一定是同一对象),内容是否相等。
  • Object中的比较是通过==比较的

封装

权限修饰符

权限修饰符 本类 同包下子类 同包下无关类 异包子类 异包下无关类
public
protected ×
默认的 × ×
private × × × ×

注意:

  1. 对于class的权限修饰只可以用publicdefault(默认的)

状态修饰符

static(静态的)

  1. 可以修饰成员变量,成员方法,不能修饰类(除了内部类),不能修饰构造方法。
    被修饰的变量,方法可以通过类名进行调用。
  2. 可以修饰静态代码块 静态方法 静态变量 静态常量
  3. 静态方法不可以直接调用调用非静态方法 可以创建对象调用
  4. 非静态方法可以调用静态方法
  5. 静态内容共享的 被所有类和对象共享 修改之后都可见
  6. 静态内容可以通过类名. 或者是对象.
  7. 类加载就会被加载 只被加载一次
  8. 不可以使用this.和super.
  9. 静态内容调用时会导致类被加载

final(最终的)

可以修饰类,成员变量,成员方法,不能修饰构造方法。
修饰的类不能被继承,被修饰的变量是常量,被修饰的方法不能被继承。

抽象修饰符

abstract(抽象的)

不能修饰构造方法,不能修饰成员变量,可以修饰类(接口),成员方法

被修饰的类(接口)不能被实例化,只能被继承,被修饰的成员方法在子类中必须被重写

总结

修饰符 成员变量 成员方法 接口 构造方法
public
protected x(外部类) ×
default(默认的)
private x(外部类) ×
static(静态的) √(内部类) × ×
final(最终的) × ×
abstract(抽象的) × ×

单例模式

单例模式

一个类只能产生一个实例对象

如何编写

  • 1:构造器私有
  • 2:对外提供过去对象的方法
  • 3:声明一个static的成员变量 类加载的时候创建当前单例对象
  • 4:在获取对象方法中返回成员变量的值
饿汉式
优缺点分析
  • 优点: 天然线程安全
  • 缺点: 不能做到延迟加载
public class Single {
    // 声明一个Single对象
    public static Single single = new Single();
    //1:将构造器私有
    private Single() {
    }
    /**
    * public : 外界一定是通过该方法获取当前类的实例对象 所以对外一定要可见
    * static : 构造器都私有了 外部肯定无法获取到当前类的实例对象 所以只能用static修饰 属于类的 	可以通
    过类名调用
    * 不加static要通过对象调用 对象没有
    * 返回值 : 当前类的实例
    *
    */
    public static Single getInstance() {
    	return single;
    }
    public static void add() {
    }
}
懒汉式
优缺点分析
  • 优点: 能够做到延迟加载
  • 缺点: 但是线程不安全
public class Lazy {
    private static Lazy lazy = null;
    private Lazy() {
    }
    public static Lazy getInstance() {
    	if(lazy==null) {
    		lazy = new Lazy();
    	}
    	return lazy;
	}
}

多态

多种形态

多态前提

  1. 继承关系
  2. 父类变量指向了子类对象
  3. 一定要有方法的重写

类的加载顺序

{} 代码块:
局部代码块:
  • 声明在方法中的代码块
  • 缩减局部变量的生命周期 提高内存是使用率
成员代码块:
  • 声明在方法外 类中的代码块 初始化块

  • 初始化块在类加载的时候是不会执行的

  • 在创建对象之前会被调用(对于对象中的一些初始进行初始化操作)

静态代码块:
  • 声明在类中 方法外 且使用static修饰
  • 类加载的时候就会被加载 并且只加载1次 静态内容
类中的执行顺序:
  • 1:首先执行静态内容(加载) 静态代码块
  • 2:初始化块
  • 3:构造器

类型转换

引用类型也有类型转换:
自动转换
  • 父类型 变量名 = 子类对象;(new 子类对象 或 子类对象的变量)
强制转换
  • 子类型 变量名 = (子类型)父类变量;
  • 事先确定了父类变量中实际存储的对象是什么类型,相同类型才能转 ,不然报 ClassCastException 类型转换异常错误

final

  • final修饰的变量称之为最终常量 在程序运行期间其值不可发生改变
  • final修饰的类不可以被继承:太监类
  • final修饰的方法不可以被重写

final修饰静态常量经过方法

  • final 修饰的基本数据类型变量 无法进行修改其值。
  • final 修饰的引用类型的变量 只保证地址不变 对象中的内容可以发生改变

final修饰的静态常量不会导致类加载

  • 静态成员常量不会导致类加载
  • 静态成员常量的值在加载前无法确定 那么会导致类加载(如下代码)
public class Test02 {
    final static int num  = (int)(Math.random()*33);//10;
    static {
    	System.out.println("我是静态代码块");
    }
    public static void main(String[] args) {
   		System.out.println(Test02.num);
    }
}

public class Test03 {
    public static void main(String[] args) {
    	System.out.println(Test02.num);
	}
}

类的加载顺序

分析:

  1. 先加载静态内容 -> 静态代码块

  2. 由于父子关系 所以子类加载之前需要先加载父类

  3. 执行的父类的初始化块和构造器(因为子类构造器中有一个super)

  4. 然后执行子类的初始化块和构造器

加载顺序:

  • 父类的静态代码块
  • 子类的静态代码块
  • 父类的初始化块
  • 父类的构造器
  • 子类的初始化块
  • 子类的构造器

在这里插入图片描述

abstract 抽象类

抽象类基础概念

​ 1: 父类中定义的方法不需要具体的实现步骤 子类都不按照父类的做

​ 2: 父类中定义这个方法的目的是告诉子类 一定要保证存在该方法

对于类的要求:

​ 1:父类中不需要定义方法的实现步骤

​ 2:子类必须要重写

抽象类:

​ 包含了抽象方法的的类称之为抽象类。

​ 被abstract修饰的类称之为抽象了

抽象方法:

​ 只要方法的声明,没有方法体。 通过abstract修饰的方法称之为抽象方法

为什么需要抽象类?

​ 避免子类的随意设计 提高了代码可读性 提高了子类的健壮性

深入理解抽象类

1:抽象类中只能包含抽象方法吗?

​ 既可以定义抽象方法也可以定义普通方法

2:是否可以定义构造器

​ 抽象类可以存在构造器但是无法实例化

​ 抽象类中的构造器是给子类准备的

​ 抽象类就是用来被继承的 抽象方法就是被重写的

3:子类继承了抽象了之后一定要重写所有的抽象方法

接口

接口是一个规范 是一套标准 比抽象类还抽象

接口的简单定义

  • 修饰符 interface 接口名{}

  • 接口中的变量都是公开的 静态的最终常量值 默认情况下变量都是public static final修饰

  • 接口中可以定义静态方法(不建议1.8)

  • 接口中定义的对象方法都是抽象方法 接口中的方法默认就是通过abstract修饰的

  • 接口中的默认方法从1.8之后才开始被使用 允许在接口中定义default方法 而且存在方法体

深入理解接口

接口深入:

  • 类和接口直接通过implements 发生关系 类实现接口
  • 类必须要实现接口中的所有抽象方法
  • 一个类可以实现多个接口 类名 implements 接口1,接口2。。。。。
  • 一个类实现了接口之后 要将当前接口以及接口的父接口中的所有抽象方法全部重写
  • 接口可以多继承
  • 接口无法实例化
  • 接口没有构造器
  • 接口中也可以使用多态

Tips:

接口就是一套规则,用来定义具体要做哪些事情,但是所有事情的具体实现都会延迟到实现类中完成。接口只需要定义has-a的关系,如果你是什么,则你具备了什么能力。

equals方法

equals方法就是用来比较两个对象是否相等的,默认Object的equals方法比较是两个对象的地址。

  • java.lang.NullPointerException 空指针异常 对象为null

  • ClassCastException 类型转换异常

  • null可以强转为任意类型

  • null用instanceof 跟任何类型比较时都是false

内部类

普通内部类

外部类中如何使用内部类的属性以及方法

在外部类中创建内部类对象,就可以调用内部类功能、属性

内部类中使用外部类的属性以及方法

可以直接使用

其它类中调用内部类中的属性和方法:

第一种:

​ a:导包 包名.外部类.内部类

​ b:内部类类型 变量名= new 外部类对象().new 内部类对象

​ Inner01 in = new Outer01().new Inner01();

第二种:

​ 外部类.内部类 变量名= new 外部类对象().new 内部类对象

​ Outer01.Inner01 in = new Outer01().new Inner01();

静态内部类

静态内部类:

通过static修饰的内部类称之为静态内部类

​ a:外部类中如何使用静态内部类的属性以及方法

​ 创建对象,调用对象的属性以及方法

​ b:静态内部类中使用外部类的属性以及方法

​ 创建外部类的对象 调用对象的属性以及方法

​ c:其它类中调用内部类中的属性和方法:

​ 第一种:

​ a:导包 包名.外部类.内部类

​ b:内部类类型 变量名= new 外部类. 内部类对象()

​ Inner01 in = new Outer02.Inner01();

​ 第二种:

​ 外部类.内部类 变量名= new 外部类. 内部类对象()

​ Outer01.Inner01 in =new Outer02.Inner01();

编写静态内部类完成单例模式创建

线程安全问题: 天然线程安全

延迟加载: 能做到延迟加载

类何时被加载: 调用静态内容 创建对象

类加载的时候 首先将静态内容加载大内存中

public class Single {  
      
    static class SingleHolder{  
        private static Single single = new Single();  
    }  
      
    private Single() {  
          
    }  
      
    public static Single getInstance() {  
        return SingleHolder.single;  
    }  
      
    public static void add() {  
          
    }  
  
    public static void main(String[] args) {  
        Single.add();  
        Single s1 = getInstance();  
    }  
}  

局部内部类

局部内部类,这种内部类是局部的,实际上和局部变量有点类似,是定义在方法中的,不过在实际开发中,对于局部内部类的使用是很少的。

匿名内部类

通过匿名内部类可以产生一个接口/抽象了的 实现类对象/子类对象

数组

什么是数组:

一组数 (数据) 的集合

官方定义:

​ 在内存中 通过连续的存储单元 存储相同数据类型的 有序集合

如何定义数组:

​ 数据类型[] 变量名;

如何初始化数组:

​ 变量名 = new 数据类型[数组的长度];

​ arrs = new int[10]

获取数组中的元素

​ 数组变量[索引] (索引从0开始 到 长度-1 结束)

获取数组中的长度:

​ 数组变量.length

编写ArrayList类

package com.mage.arrays;

public class ArrayList {
	private Object[] arrs;
	private int size; //数组实际存储元素个数
	private int capacity;//底层arrs数组的长度,也就是开的内存空间大小
	private static final int DEFAULT_CAPACITY = 10;
	
	public ArrayList() {
		this(DEFAULT_CAPACITY);
	}
	
	public ArrayList(int capacity) {
		arrs = new Object[capacity];
		this.capacity = capacity;
	}
	
	/**
	 * @return 返回数组实际存储的元素个数
	 */
	public int size(){
		return this.size;
	}
	
	/**
	 * @return 返回当前ArrayList底层数组的容量
	 */
	public int opacity() {
		return arrs.length;
	}
	
	/**
	 * @return 返回当前数组是否为null
	 */
	public boolean isEmpty() {
		return this.size==0;
	}
	
	/**
	 * 	 添加元素到指定的位置上
	 * @param value 添加的元素
	 * @param index 添加的位置
	 */
	public void add(Object value,int index) {
		if(index<0||index>size) {
			System.out.println("错误参数:index");
			return;
		}
		//存满了
		if(size==arrs.length) {
			resize(size*2);
		}
		
		for(int i=size-1;i>=index;i--) {
			arrs[i+1]=arrs[i];
		}
		arrs[index]=value;
		size++;
	}
	
	/**
	 *  	添加首元素
	 * @param value 添加的元素值
	 */
	public void addFirst(Object value) {
		add(value,0);
	}
	
	
	/**
	 *  	添加尾元素
	 * @param value
	 */
	public void addLast(Object value) {
		add(value,size);
	}
	/**
	 *  	查询指定元素在当前数组中的索引位置(只找一个)  
	 * @param value
	 * @return 查找的元素的索引 如果不存在返回-1
	 */
	public int getIndexByValue(Object value) {
		for(int i=0;i<size;i++) {
			if(arrs[i]==value) {
				return i;
			}
		}
		return -1;
	}
	
	/**
	 *      返回指定索引位置上的元素
	 * @param index 索引
	 * @return 元素    如果返回null代表当前数组的入参有误
	 */
	public Object get(int index) {
		if(index<0||index>=size) {
			System.out.println("参数有误:index");
			return null;
		}
		return this.arrs[index];
		
	}
	
	
	/**
	 *       	修改数组中指定位置上的元素
	 * @param index  指定的索引
	 * @param value  修改之后的值
	 * @return  修改之前的值 如果索引有问题 返回null
	 */
	public Object set(int index,Object value) {
		if(get(index)==null) {
			return null;
		}
		Object oldValue=arrs[index];
		arrs[index]=value;
		return oldValue;
		
	}
	
	/**
	 * 	根据索引删除元素
	 * @param index 索引
	 * @return 删除的元素   如果索引有误 返回null
	 */
	
	public Object remove(int index) {
		if(get(index)==null) {
			return null;
		}
		Object oldValue = arrs[index];
		for(int i=index;i<size-1;i++) {
			arrs[i]=arrs[i+1];
		}
		size--;
		arrs[size]=null;
		if(size==arrs.length/4&&arrs.length/2>0) {
			resize(arrs.length/2);
		}
		return oldValue;
		
	}
	
	
	/**
	 *  	删除第一个元素
	 * @return
	 */
	public Object removeFirst() {
		return remove(0);
	}
	
	/**
	 *  	删除最后元素
	 * @return
	 */
	public Object removeLast() {
		return remove(size-1);
	}
	
	/**
	 * 数组扩容操作
	 * @param capacity 新数组的容量
	 */
	private void resize(int capacity) {
		Object[] newArrs = new Object[capacity];
		copyOf(arrs,newArrs);
		arrs = newArrs;
	}
	
	/**
	 *  	数组复制
	 * @param src 源数组
	 * @param dest 目标数组
	 */
	private void copyOf(Object[] src,Object[] dest) {
		for(int i=0;i<this.size;i++) {
			dest[i]=src[i];
		}
	}

	/**
	 * 获取当前ArrayList的内容
	 */
	public String toString() {
		StringBuffer sb = new StringBuffer();
		sb.append("size:"+this.size+"\topacity:"+this.arrs.length+"\t");
		sb.append("[");
		for(int i = 0;i<size;i++) {
			sb.append(arrs[i]);
			if(i!=size-1) {
				sb.append(",");
			}
		}
		sb.append("]");
		return sb.toString();
	}
}

测试类

package com.mage.arrays;

public class TestArrayList {
	public static void main(String[] args) {
		
		// ArrayList存储数据的对象
		ArrayList arrayList = new ArrayList();// size = 0 capacity 10   
		
		//测试增加不同类型值
		arrayList.addFirst('a');
		arrayList.addFirst("哈哈");
		arrayList.addFirst(44);
		System.out.println(arrayList.toString());
		
		//测试在最后位置加值
		arrayList.addLast(33);
		System.out.println(arrayList.toString());
		
		//测试元素加满了,内存扩容。
		arrayList.addLast(33);
		arrayList.addLast(33);
		arrayList.addLast(33);
		arrayList.addLast(33);
		arrayList.addLast(33);
		arrayList.addLast(44);
		arrayList.addLast(55);
		System.out.println(arrayList.toString());
		
		//测试移除增加元素会撤回扩容嘛
		arrayList.remove(0);
		System.out.println(arrayList.toString());
		
		//测试元素个数为原来的四分之一会压缩一半内存嘛
		arrayList.remove(0);
		arrayList.remove(0);
		arrayList.remove(0);
		arrayList.remove(0);
		arrayList.remove(0);
		System.out.println(arrayList.toString());
		
		//测试修改
		arrayList.set(1, "被修改了");
		System.out.println(arrayList.toString());
	}
}

在这里插入图片描述

排序

冒泡排序

第一种
	public static void bubbleSort01(int[] arrs) {
		System.out.println("原数组:"+toString(arrs));
		for(int i=0;i<arrs.length-1;i++) {//控制趟数
			System.out.println("第"+(i+1)+"趟");
			for(int j=0;j<arrs.length-1;j++) {//次数
				if(arrs[j]>arrs[j+1]) {
					int temp = arrs[j];
					arrs[j] = arrs[j+1];
					arrs[j+1] = temp;
				}
				System.out.println("第"+(j+1)+"次:"+toString(arrs));
			}
		}
	}

在这里插入图片描述
在这里插入图片描述

第二种
public static void bubbleSort02(int[] arrs) {
		System.out.println("原数组:"+toString(arrs));
		for(int i=0;i<arrs.length-1;i++) {//控制趟数
			System.out.println("第"+(i+1)+"趟");
			for(int j=0;j<arrs.length-1-i;j++) {//次数
				if(arrs[j]>arrs[j+1]) {
					int temp = arrs[j];
					arrs[j] = arrs[j+1];
					arrs[j+1] = temp;
				}
				System.out.println("第"+(j+1)+"次:"+toString(arrs));
			}
		}
		
	}

在这里插入图片描述
在这里插入图片描述

第三种
public static void bubbleSort03(int[] arrs) {
		System.out.println("原数组:"+toString(arrs));
		for(int i=0;i<arrs.length-1;i++) {//控制趟数
			//声明一个是否排好序
			boolean isSorted = true;
			System.out.println("第"+(i+1)+"趟");
			for(int j=0;j<arrs.length-1-i;j++) {//次数
				if(arrs[j]>arrs[j+1]) {
					isSorted = false;
					int temp = arrs[j];
					arrs[j] = arrs[j+1];
					arrs[j+1] = temp;
				}
				System.out.println("第"+(j+1)+"次:"+toString(arrs));
			}
			//判定
			if(isSorted) {
				break;
			}
		}
	}
	

在这里插入图片描述

第四种
public static void bubbleSort04(int[] arrs) {
		System.out.println("原数组:"+toString(arrs));
		//基准点
		int index = arrs.length-1;
		for(int i=0;i<arrs.length-1;i++) {//控制趟数
			//声明一个是否排好序
			boolean isSorted = true;
			
			int tmp = 0; 
			System.out.println("第"+(i+1)+"趟");
			for(int j=0;j<index;j++) {//次数
				if(arrs[j]>arrs[j+1]) {
					isSorted = false;
					int temp = arrs[j];
					arrs[j] = arrs[j+1];
					arrs[j+1] = temp;
					tmp = j;
				}
				System.out.println("第"+(j+1)+"次:"+toString(arrs));
			}
			index = tmp;
			//判定
			if(isSorted) {
				break;
			}
		}
	}

在这里插入图片描述

快速查找

	public static void SelsctSort(int[] arrs) {
		
		for(int i=0;i<arrs.length-1;i++) {
			int min = i;
			for(int j=i+1;j<arrs.length;j++) {
				if(arrs[min]>arrs[j]) {
					min=j;
				}
			}
			if(arrs[i]!=arrs[min]) {
				int tmp = arrs[min];
				arrs[min] = arrs[i];
				arrs[i]=tmp;
			}
		}
			
	}

二分查找

	public static int bSearch(int[] arrs,int value) {
		//声明索引
		int max = arrs.length-1;
		int min = 0;
		int mid = 0;
		//循环判定
		while(min<=max) {
			mid = (max+min)/2;
			if(arrs[mid]>value) {
				max = mid-1;
			}else if(arrs[mid]<value) {
				min = mid+1;
			}else {
				return mid;
			}
		}
		return -1;
	}

异常

try-catch

语法结构:

​ try{

​ //有可能出现异常的代码块

​ }catch(声明异常){

​ 异常解决办法

​ }

执行顺序:

1:执行try块中的内容

2:如果try块中内容出现异常,执行catch块

3:匹配catch中声明的异常信息 ,如果匹配上,则执行catch中的代码

4:继续执行后续代码

5:如果catch中的异常信息没有匹配到 那么此时交由jvm处理该异常

注意:

catch:中的类型一定要能够捕获到try快中实际出现的异常信息 如果忘记了具体的异常信息可以通过使用Exception去捕获异常信息,不要再catch块中做业务逻辑判定

	try {
        System.out.println(1/0);
    }catch(ArithmeticException e) {
        System.out.println("输入的数据有误。。。。。");
    }
	System.out.println("我是try-catch外的代码");

在这里插入图片描述

try多层catch

语法结构:

​ try{

​ //可能出现异常的代码段

​ }catch(异常1){

​ //异常 的解决办法

​ }catch(异常2){

​ //异常 的解决办法

​ }…{

​ }

try多层catch执行顺序:

1:执行try块 如果出现异常 new出当前异常对象

2:逐一匹配catch中的异常内容

3:如果匹配上 执行对应的catch中的代码 整个try-catch执行结束

4:如果匹配上 jvm去解决当前异常信息

注意事项:

1:在多重catch中一般情况下会在最后一个catch语句中编写exception 用来捕获可能未被识别的异常信息

2:不要再第一个catch中编写父类异常 屏蔽所有子类异常

异常对象的常见方法:

toString: 当前异常类型以及原因描述

在这里插入图片描述

printStackTrace:打印堆栈信息 异常类型以及原因描述 异常位置

在这里插入图片描述

getMessage:异常原因

在这里插入图片描述

	Scanner input = new Scanner(System.in);
    try {
        System.out.println("请输入第一个数:");
        int num1 = input.nextInt();
        System.out.println("请输入第二个数:");
        int num2 = input.nextInt();

        int result = num1/num2;
        System.out.println(num1+"/"+num2+"="+result);
    }catch(ArithmeticException e) {
        System.out.println("除数不能为0");
        //System.out.println(e.toString());
        //e.printStackTrace();
        //System.out.println(e.getMessage());
    }catch(InputMismatchException e) {
        System.out.println("用户输入有误");
    }catch(Exception e) {
        System.out.println("网络加载问题!!!");
    }

    System.out.println("后续代码。。。");

在这里插入图片描述

try-catch-finally

语法结构:

​ try{

​ //可能出现异常的代码

​ }catch(异常1){

​ //处理办法

​ }…{

​ }finally{

​ //代码块

​ //关闭资源的代码

​ }

测试如何让finally不执行

retrun 语句不会让finally不执行

finally先于return语句执行

代码中存在System.exit() 可以让finally不执行 但是一般不这么干

执行顺序:

1:执行try块 如果出现异常 new出当前异常对象

2:逐一匹配catch中的异常内容

3:如果匹配上 执行对应的catch中的代码

4:如果未匹配上 jvm去解决当前异常信息

5:不论是否匹配成功 都会执行finally中内容

注意:

finally中一般情况下编写关闭资源的操作

jdk1.7之后对于try-catch-finally的改变

可以通过对于流、网络连接对象的创建声明在try的()中,后续无序通过使用finally显式的关闭资源

​ try(资源1;资源2.。。。){

​ //可能出现的异常信息

​ }catch(异常1){

​ //解决办法

​ }。。。。。{

​ }

	Scanner input = new Scanner(System.in);
    try {
        System.out.println("请输入第一个数:");
        int num1 = input.nextInt();
        System.out.println("请输入第二个数:");
        int num2 = input.nextInt();
        int result = num1/num2;
        System.out.println(num1+"/"+num2+"="+result);
        input.close();
    }catch(InputMismatchException e) {
        System.out.println("输入有误");
    }catch(ArithmeticException e) {
        System.out.println("除数不能为0");
    }catch(Exception e) {
        System.out.println("网络加载有误。。");
    }finally {
        // 一定会被执行
        System.out.println("我是finally块中的代码");
        input.close();
    }
    System.out.println("后续代码。。。。");

在这里插入图片描述

throw-throws

throw

1:throw 声明当前代码块中可能存在的异常信息 并且将当前异常信息抛出给调用者。

对于调用者而言 通过try-catch捕获异常

如果调用者也不管当前异常交由jvm解决

2:throw会导致当前程序中断掉 后续代码不执行

throws

  • 在方法外对外抛出某个异常,调用者解决当前异常。main方法中对外抛出的异常全部都交由jvm做。

  • throws抛出异常 是异常解决的一种办法定义在方法的外部 形式参数后 可以抛出多个异常通过","分割

  • 一般会将throws和throw在一起使用,throw 声明的异常是检查时异常需要和throws一起使用,但是throws可以单独使用

public class Test09 {
	public static void main(String[] args) {
        //创建student对象
		Student stu1 = new Student();
		stu1.setName("李四");
		try {
			stu1.setAge(-1);
		} catch (RuntimeException e) {
			System.out.println("参数有误");
		}
		System.out.println(stu1);
		try {
			info();
		}catch(FileNotFoundException e){
			System.out.println("找不到文件!");
		}
	}
	
	public static void info() throws FileNotFoundException{
		//try {
			new FileInputStream(new File(""));
		/*}catch(FileNotFoundException e) {
			System.out.println(e);
		}*/
	}
}

class Student{
	
	private String name;
	private int age;
	
	public Student() {
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}
	
	/**
	 * 
	 * @param age
	 * @throws RuntimeException 当前方法对外会抛出异常 如果参数有误
	 */
	public void setAge(int age)/* throws FileNotFoundException */{
		if(age<0||age>150) {
			throw new RuntimeException();//throw new FileNotFoundException
		}
		this.age = age;
	}

	@Override
	public String toString() {
		return "Student [name=" + name + ", age=" + age + "]";
	}
	

在这里插入图片描述

自定义异常

1:jdk中提供的异常信息不满足目前的使用

2:如何自定义异常:

​ a:声明一个自定义异常类

​ b:继承Exception

​ c:编写两个构造器 一个空 一个带字符串的构造器

使用自定义异常

class User{
	private int age;
	public User() {
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) throws AgeException{
		if(age<0||age>150) {
			throw new AgeException("年龄输入有误");
		}
		this.age = age;
	}
	@Override
	public String toString() {
		return "User [age=" + age + "]";
	}
}

自定义异常类

public class AgeException extends Exception{
	public AgeException() {
	}
	public AgeException(String msg) {
		super(msg);
	}
}

测试类

public class Test10 {
	public static void main(String[] args){
		User u = new User();
		try {
			u.setAge(-1);
		}catch(AgeException e) {
			System.out.println(e.getMessage());
		}
		System.out.println(u);
		
	}
}

在这里插入图片描述

展开阅读全文

没有更多推荐了,返回首页