面向对象:
面向对象是宏观的上为用户解决功能需求,用户只需要知道怎么用对象实现功能就好了,具体底层如何实现不用操心,不过面向对象的最底层还是以面向过程的方式实现,但面向对象对比面向过程,减少了学习成本。
面向过程:
面向对象是微观下对要实现的功能进行详细设计。
类:
类是对象的抽象,是将对象的相同部分提取出来
对象:
对象是对类的具象化的体系
先有类还是先有对象:
在编写过程中,是先有类,再有对象。
1:调用当前类中的静态方法时
2:创建当前类的实例对象时
在类中用来创建对象那个的方法称之为构造器
- 方法名与类名相同
- 没有返回值
- 允许方法重载
- 在默认情况下会自动生成无参构造器,但如果你写了构造器在不会生成。
构造器的调用:
- 通过new对象,自动调用构造器
- 通过 this() 或 super() 分别调用当前类的构造方法和其父类的的构造方法。
this.
当前对象的属性或方法
可省略:使用的范围内,没有同名变量时(无异议时)
不可省略:区分同名变量,局部变量和成员变量(有异议时)
this()
构造器之间的互相调用
this()一定要在构造器的首行
继承的优势:
- 在一定程度上提高了代码的复用性
继承编写:
- 子类 extends 父类 子类拥有父类中的所有的属性以及方法 (根据修饰确定是否能够全部继承)
什么是继承:
将多个类中的共性再一次抽取,抽取为一个父类。父类的作用就是用来将一些重复的内容不再多次编写(提高代码复用性)
注意事项:
- java中只支持单继承 一个子类有且只能有一个父类 复用性的提高是有限的
多继承好还是单继承好
- 多继承 :极大提高代码复用性 但是代码调用的复杂度也提升了
- 单继承:代码调用的复杂度比较低,但是复用性比较有限
假设在应用场景中:
- A->B 后期随着业务不断扩展,导致A需要继承C时一般的解决办法:A->B->C
- 但是该种解决办法随着后期业务的不断升级,导致整个继承连会变得极其复杂,既不利于后期维护以及拓展。
- 能不能用继承就别用继承。
当创建子类对象时 会先执行父类的构造器
super: 和this的用法一模一样super.
- 当前对象的父类对象的
super. 可省略的:
- super和this的用法是重复的 都可以省略(就是没有同名时)
super. 不可省略
- 如果子类和父类中出现了同名变量或者是同名方法
super()
- 调用父类的构造器,默认情况下调用的父类的无参构造器(默认情况下每个类中都存再一个无参构造器 哪怕不写也存在)
- 当父类中存在其他构造器时,无参构造器不存在,此时如果再子类中没有通过super()显示的指定调用的构造器会导致程序报错。
- 在构造器中this()和super()不能同时出现,如果两个都不存在,则默认存在super()。
在子类中定义了和父类中同名的方法 我们将该方法称之为重写方法(覆盖)
为什么需要重写?
- 父类的功能不能满足子类的需求。子类在父类的基础上进行了扩展。
如何确定一个方法是重写方法?
- 在子类的方法上加入@Overried 注解 如果不报错 证明是重写
重写的前提:
- 一定要发生继承关系。并且子类的方法名和父类的方法名同名
- 参数列表要一样
- 返回类型要一样
Object: 是所有类的根基类 超类 父类
- 当一个类没有显式的继承关系的时候,默认情况下他的父类都是Object
Object:
- toString : 输出对象 全限定名(包名.类名)@16进制hash值
- 输出一个对象的时候默认情况下会调用当前对象的toString
- getClass:获取当前类的Class对象 反射
- == 比较基本数据类型比较的是值 比较引用类型比较的是地址
- equals:如果没有对equals方法进行重写,则比较的是引用类型的变量所指向的对象的地址;诸如String、Date等类对equals方法进行了重写的话,比较的是所是否是同一类型的对象(不一定是同一对象),内容是否相等。
- Object中的比较是通过==比较的
权限修饰符 | 本类 | 同包下子类 | 同包下无关类 | 异包子类 | 异包下无关类 |
---|---|---|---|---|---|
public | √ | √ | √ | √ | √ |
protected | √ | √ | √ | √ | × |
默认的 | √ | √ | √ | × | × |
private | √ | × | × | × | × |
注意:
- 对于class的权限修饰只可以用public和default(默认的)。
static(静态的)
- 可以修饰成员变量,成员方法,不能修饰类(除了内部类),不能修饰构造方法。
被修饰的变量,方法可以通过类名进行调用。- 可以修饰静态代码块 静态方法 静态变量 静态常量
- 静态方法不可以直接调用调用非静态方法 可以创建对象调用
- 非静态方法可以调用静态方法
- 静态内容共享的 被所有类和对象共享 修改之后都可见
- 静态内容可以通过类名. 或者是对象.
- 类加载就会被加载 只被加载一次
- 不可以使用this.和super.
- 静态内容调用时会导致类被加载
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;
}
}
多种形态
- 继承关系
- 父类变量指向了子类对象
- 一定要有方法的重写
{} 代码块:
局部代码块:
- 声明在方法中的代码块
- 缩减局部变量的生命周期 提高内存是使用率
成员代码块:
声明在方法外 类中的代码块 初始化块
初始化块在类加载的时候是不会执行的
在创建对象之前会被调用(对于对象中的一些初始进行初始化操作)
静态代码块:
- 声明在类中 方法外 且使用static修饰
- 类加载的时候就会被加载 并且只加载1次 静态内容
类中的执行顺序:
- 1:首先执行静态内容(加载) 静态代码块
- 2:初始化块
- 3:构造器
引用类型也有类型转换:
自动转换
- 父类型 变量名 = 子类对象;(new 子类对象 或 子类对象的变量)
强制转换
- 子类型 变量名 = (子类型)父类变量;
- 事先确定了父类变量中实际存储的对象是什么类型,相同类型才能转 ,不然报 ClassCastException 类型转换异常错误
- 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);
}
}
类的加载顺序
分析:
先加载静态内容 -> 静态代码块
由于父子关系 所以子类加载之前需要先加载父类
执行的父类的初始化块和构造器(因为子类构造器中有一个super)
然后执行子类的初始化块和构造器
加载顺序:
- 父类的静态代码块
- 子类的静态代码块
- 父类的初始化块
- 父类的构造器
- 子类的初始化块
- 子类的构造器
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方法就是用来比较两个对象是否相等的,默认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
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(声明异常){
异常解决办法
}
执行顺序:
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(异常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(异常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
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);
}
}