一. 设计模型之模板模型
-
定义
- 使用接口制定规则,然后子类根据实现不同的方法内部代码
- 实现类暴露的可用方法必须和接口中相同
-
案例
- 执行汽车接口,里面规定的是汽车的基本要素
- 子类根据规则,实现成不同功能的模板
二. 成员内部类
-
定义
- 内部类就是在类的内部定义另一个类
-
使用
-
内部类可以直接访问外部类的成员,包括私有
- 外部类名.this.成员
-
外部类调用内部类方法,必须先创建对象
- 内部类名 对象 = 内部类对象
- 内部类 对象名 = new 内部类()
public class Outer { //外部类非静态方法 public void outerMethod(){ System.out.println("外部类方法"); //外部类调用内部类方法 必须先创建内部类对象 Inner inner = new Inner(); inner.innerMethod(); } class Inner{ //内部类非静态方法 public void innerMethod(){ //内部类调用外部类非静态方法 //Outer.this.outerMethod(); //如果没有相同的方法 可以省略前缀 outerMethod(); } } }
-
别的类要访问内部类的成员,就必须创建对象
- 外部类名.内部类名 对象名 = 外部类对象.内部类对象
- 外部类.内部类 对象名 = new 外部类().new 内部类()
public static void main(String[] args) { //创建内部类对象 , 必须要先创建外部类对象 Outer.Inner inner = new Outer().new Inner(); //调用内部类的方法 inner.innerMethod(); }
-
-
内部类的权限
- 内部类的权限和成员方法一样,可以有 private 默认 protected public
- 外部类只能是public 和 默认的
- private 效果等同于私有化方法,别的类无法无法直接调用,但是外部类可以调用,可以通过方法return回去
- 我们完全可以把内部类当作是一个类中的方法来看待
- 内部类同时具有方法和类的所有权益
-
演示
public class Outer { //外部类非静态方法 public void outerMethod(){ //私有的内部类只能在外部类中使用 Inner inner = new Inner(); inner.innerMethod(); } //只能在内部使用 private class Inner{ //内部类非静态方法 public void innerMethod(){ } } } public static void main(String[] args) { Outer.Inner inner = new Outer().new Inner(); //报错 }
-
测试题
- 判断输出结果
public class Outer { public void method(){ System.out.println("外部类method方法"); method2(); } public void method2(){ System.out.println("外部类method2方法"); } public class Inner{ public void method(){ System.out.println("内部类method方法"); method2(); } public void method2(){ System.out.println("内部类method2方法"); Outer.this.method2(); } } } public static void main(String[] args) { Outer.Inner inner = new Outer().new Inner(); inner.method(); }
三. 静态内部类
-
定义
- 使用static关键字修饰内部类
-
使用
-
调用静态内部类内部的非静态方法
- 外部类名.内部类名 对象名 = new 外部类名.内部类名();
public class Outer { //静态内部类 public static class Inner{ //静态内部类的非静态方法 public void innerMethod(){ } } } public static void main(String[] args) { //创建内部类对象 Outer.Inner inner = new Outer.Inner(); //调用内部类的方法 inner.innerMethod(); }
-
调用静态内部类内部的静态方法
- 外部类名.内部类名.方法()
public class Outer { //静态内部类 public static class Inner{ //静态内部类的静态方法 public static void innerMethod(){ } } } public static void main(String[] args) { //类名调用 Outer.Inner.innerMethod(); }
-
静态内部类调用外部类的非静态方法
- 必须先new出外部类然后才能调用
public class Outer { //外部类非静态方法 public void outerMethod(){ System.out.println("外部类的非静态方法"); } //静态内部类 public static class Inner{ //静态内部类非静态方法 public void innerMethod(){ //必须先创建外部类的对象 new Outer().outerMethod(); } } }
-
-
注意事项
- 内部类中如果有静态方法,那么内部类就必须也是静态的
- 内部类是静态的,并不意味着内部类中的方法都是静态的,只是说明我们可以绕过外部类对象直接找到内部类来使用
-
测试题
- 判断错误位置
public class Outer { public void outerMethod(){ Inner.innerMethod(); } public static class Inner{ public void innerMethod(){ } } } public static void main(String[] args) { Outer outer = new Outer(); outer.outerMethod(); }
四. 局部内部类
-
定义
- 定在在类中的方法中的内部类叫做局部内部类(用的很少)
-
使用
- 局部内部类的作用范围仅限于本方法中
- 局部内部类在访问他所在方法中的局部变量必须用final修饰
- 局部内部类想要使用局部变量, 那么, 变量必须变成常量
- 因为当调用这个方法时,局部变量如果没有用final修饰,他的生命周期和方法的生命周期是一样的,当方法弹栈,这个局部变量也会消失,那么如果局部内部类对象还没有马上消失想用这个局部变量,就没有了,如果用final修饰会在类加载的时候进入常量池,即使方法弹栈,常量池的常量还在,也可以继续使用
- jdk 1.8 取消的这个定义 , 其实不是取消了, 是设置为了隐式的
-
演示
public static void main(String[] args) { //局部内部内使用局部变量必须是final的 final String name = "小红"; //局部内部类 class Inner{ public void method(){ System.out.println("局部内部类"); } public String method2(){ return name + "我爱你"; } } Inner inner = new Inner(); inner.method(); inner.method2(); }
-
测试题
- 设计程序, 验证局部内部类所创建的对象在方法弹栈后还能继续使用
五. 匿名内部类
-
定义
- 匿名内部类就是局部内部类的简写形式,相当于是一个没有名字的子类
- 匿名内部类用于定义接口的或者类的子类
-
使用
- 前提是必须存在一个类,或者接口
- 这里的类可以是具体的类也可以是抽象类
- 相当于是有一个没有名字的子类继承或者实现一个类或接口,然后重写里面的方法,本质是一个继承了该类或者实现了该接口的匿名子类对象
- 多用于规则简单,子类使用很少的接口应用中
-
格式
new 类名或者接口名(){
重写方法;
}
-
演示
public static void main(String[] args) { //匿名部内部类 MyInterface mi = new MyInterface() { @Override public void method() { System.out.println("重写接口的方法"); } }; }
-
测试题
- 定义一个匿名内部类并创建3个对象,存储于数组中?是否可完成
- 不行, 匿名内部类只能创建一个对象
六. 异常
-
定义
- 异常是指java程序在运行过程中出现的错误 Throwable
-
分类
- Error 错误 致命的错误 比如数据库崩溃服务器宕机
- Exception 异常 局部行的错误 警报 告诉开发者程序有问题或可能出现问题
- 编译时异常
- 因为语法不规范,对代码没有进行预制处理导致的异常,编译器可以检查出来,如果不处理,编译无法通过
- 运行时异常 导致程序停止运行
- 编译时期不报错,运行时报错
- 常见的角标越界,空指针等都是运行时异常,也就是只有运行起来才能发现的,这是程序员犯得的错误
-
演示
public static void main(String[] args) { int i = 0; //java.lang.ArithmeticException: / by zero int num = 10/i; }
-
测试题
- 列举常用的Exception, 并说出导致的原因
七. 异常的处理
-
jvm是如何处理异常的
- 运行时出现异常 , jvm打印异常信息, 并停止运行
-
手动处理异常的两种方式
- 抓取异常并处理
- 对异常进行处理后, 程序依然可以继续执行
- 手动抛出异常
- 程序会在抛出异常的点上停止运行并将异常信息抛出
- 抓取异常并处理
-
抓取处理方式
-
try { } catch (异常类型){}
public static void main(String[] args) { int i = 0; try { //将可能出现异常的代码包裹起来 int num = 10/i; } catch (Exception e) { //对相应类型的异常信息进行处理 e.printStackTrace(); //打印异常信息 } }
-
try{ }catch(异常类型) { } catch(异常类型) { }...
public static void main(String[] args) { int i = 0; try { //将可能出现异常的代码包裹起来 int num = 10/i; } catch (ArithmeticException e) { //对相应类型的异常信息进行处理 e.printStackTrace(); //打印异常信息 } catch (Exception e) { e.printStackTrace(); } }
-
try{ }catch(异常类型){ }finally{ }
public static void main(String[] args) { int i = 0; try { //将可能出现异常的代码包裹起来 int num = 10/i; } catch (ArithmeticException e) { //对相应类型的异常信息进行处理 e.printStackTrace(); //打印异常信息 } catch (Exception e) { e.printStackTrace(); }finally { //最后一定会执行的代码 System.out.println("这个体系中最后执行的代码"); } }
-
-
抛出异常方式
- 使用 throws 关键字在方法声明后抛出异常
- 接收到异常的方法要么抛出要么处理
- 方法声明上的异常类型必须大于等于程序中出现的异常类型才能抛出
-
注意事项
- 多个catch处理异常时, 遵循从上往下的原则, 上面如果有catch可以处理, 下面将不再执行, 所有我们应当将小的异常放在上面, 大的异常放在下面
- 无论什么情况, 只要try ...catch体系执行了, finally中的代码一定会执行的,除非虚拟机退出: System.exit(0)
- finally主要是用于释放资源
-
测试题
- final 和 finally 和 finalize 的关系 ?
- 思考, 如果catch中出现了return , 那么finally中的代码是否会执行, 如果执行是在return之前呢还是之后?
八. 自定义异常(了解)
-
定义
- 在项目中我们有时需要处理一些逻辑的问题, 比如说性别不能输入中性, 这些在java中不被认为是异常, 但是在实际的业务中却是异常
- 自定义异常时有名称的, 所以比单纯的状态值更好记忆
- 自定义异常类, 可以携带更多的信息供我们使用
- 抛出异常的方式不会破坏方法的格式
-
自定义异常
- 继承Exception 必须抛出,需要在编译前处理
- 继承RuntimeException 不需要抛出,编译前不需要处理
-
演示
//自定义编译时异常 public class MyException extends Exception{ //定义空参构造 public MyException(){} //定义有参构造 public MyException(String message){ //将信息传递过父类处理 super(message); } } //自定义运行时异常 public class MyException extends RuntimeException{ //定义空参构造 public MyException(){} //定义有参构造 public MyException(String message){ //将信息传递过父类处理 super(message); } }
总结:
- 模板模型
- 实现类和接口中的内容保持一致
- 好处: 提高了代码的扩展性
- 成员内部类
- 当类中的成员过多时, 使用成员内部类再次分组
- 成员内部类一般来说时为外部类服务的
- 特性
- 内部类可以直接调用外部类的成员
- 外部类需要先创建对象才能调用内部类的成员
- 内外部类都可以调用对方的私有化成员
- 创建内部类对象前必须先创建外部类对象
- 静态内部类
- 基本用法和成员内部类相似
- 就是给内部类加上static关键字, 唯一的作用是可以让用户跳过外部类直接访问到内部类
- 内部类是静态的,绝不能认为内部类中的成员也是静态的,这些成员还是原先的调用方式
- 如果内部类中有静态成员,那么这个内部类也必须是静态的
- 局部内部类
- 当一个类只能在当前方法中被用到时,我们没有必要将他写道外部去, 可能会干扰其他类的使用
- 局部内部类中如果使用局部变量, 那么,这个变量要变成常量
- 匿名内部类
- 创建某个类或接口的子类对象, 类只被使用异常
- new 父类 () { } ;
- 异常
- 异常在Java中普遍存在, 并且有存在的意义
- 可能发生异常的地方 ?
- 运行时
- 代码警告
- 语法错误(自己改)
- 解决异常的办法
- 抛出
- try...catch处理
- 代码可以继续运行 ,手动书写处理过程
- 自定义异常
- 异常最终要的是类名
- 继承Exception就是编译时异常
- 继承RuntimException就是运行时异常
作业
-
第一题
- 使用模板模型定义手机, 手机必须具有上网,打电话的功能
-
第二题
- 创建一个内部类, 外部类中有两个方法method1和method2 ,
- 内部类中定义三个方法 method1 ,method2 和 静态方法method3
- 创建测试类,调用 内部类的method1方法 实现执行顺序
- 内部类的method1 ===> 外部类的method1 ===> 内部类的method2 ===> 外部类的method2 ===> 内部类的method3
-
第三题
- 定义学生类, 有姓名, 年龄属性, 从键盘录入信息通过构造方法存入学生对象中
- 在学生类的构造方法中定义判断, 如果录入的学生年龄小于1大于150就抛出年龄超限异常
- 主方法抓取异常并打印异常信息
package com.huwenlong.day11; //定义一个学生类 public class Student { private String name; private int age; public Student(String name,int age) throws AgeOutOfBoundException{ this.name = name; if(age>=1&&age<=150) this.age = age; else throw new AgeOutOfBoundException("年龄不得小于1或大于150"); } }
package com.huwenlong.day11; public class AgeOutOfBoundException extends Exception { public AgeOutOfBoundException(String message) { super(message); } }
package com.huwenlong.day11; public class Test03 { public static void main(String[] args) { try { Student st = new Student("小红", 0); }catch (AgeOutOfBoundException e){ e.printStackTrace(); } } }
-
扩展题
-
功能效果图:
喝不起汤!!!
吃不上饭!!!
-
思路
-
定义吃饭功能,需要钱。(例如:eat(double money)
-
如果钱不够是不能吃,有异常。
-
自定义NoFoodException();继承Exception 提供有参构造
-
自定义NoSoupException();继承Exception 提供有参构造
-
调用eat方法进行判断
//小于10块, throw new NoFoodException("吃不上饭!!!"); //小于2块, throw new NoSoupException("喝不起汤!!!");
-
-
网友评论