8.3 内部类&异常
内部类
内部类:定义在一个类的内部的类.内部类的地位与外部类的成员变量,成员方法平等,内部类也可以看做是外部类的成员,成员之间可以相互调用
内部类的作用:
1.间接实现了多继承
2.方便定义
3.只有外部类可以访问创建的内部类的属性和方法,包括私有方法
4.同一个包中其他的类不可见,有了很好的封装性
注意:除了new Object类是匿名对象,其他所有类的匿名对象本质上都是匿名子类对象.
class Outer{
int age;
//内部类
class Inner{
int height;
public void run(){
System.out.println("Inner-run");
}
}
public void show(){
System.out.println("Outer-show");
Inner inner = new Inner();
inner.run();
}
}
调用内部类的方法的方式
第一种:借助于外部类的方法实现
//show是外部类的方法
public void show(){
System.out.println("Outer-show");
Inner inner = new Inner();
inner.run();
}
第二种:直接在这里调用
引用:外部类.内部类
构成:外部类对象的引用.new 内部类的构造方法
外部类.内部类=外部类对象的引用.new 内部类的构造方法
Outer.Inner inner = outer.new Inner();
//当通过import将Inner直接导入后,可以直接使用Inner,不推荐
内部类实现多继承
class A{
}
class B{
}
要求:要让X同时继承来自A和B的内容,并且A和B没有关系.
我们可以通过内部类让java间接实现多继承
class X extends A{
class Y extends B{
}
}
成员内部类
局部内部类
局部内部类:定义在一个类方法中的类
作用范围:从定义开始到当前的方法结束
了解:局部内部类所在的方法中局部变量的使用.
局部变量的作用域:定义变量开始到函数结束
final:被final修饰的变量会被放在常量区,而常量区的值存在的时间要大于局部变量所在的方法,相当于从原来的基础上扩大了作用域
原理:
当方法中同时存在局部内部类与局部变量时,局部变量的使用范围就会从原来的基础上进行扩大.
原因:在当前程序执行时,程序会默认让final去修饰height.所以当局部变量所在的方法结束的时候,变量没有被释放,保存的值还在.
关于变量前面的final:
前提:变量必须与局部内部类同时存在.并且在局部内部类中使用了当前的局部变量
在jdk1.7之前要想保住局部变量的值,要手动添加final
在jdk1.7之后,程序执行时,java的内部机制已经在变量的前面默认添加了final
class Outer1{
int age;
public void show(){
System.out.println("Outer-show");
//隐藏final
int height=0;
//局部内部类
class Inner{
public void run(){
System.out.println("Inner-run"+height);
}
}
Inner inner = new Inner();
inner.run();
}
}
局部内部类应用
public class Demo4 {
public static void main(String[] args) {
Outer4 outer4 = new Outer4();
outer4.show();
outer4.eat();
}
}
//外部类
class Outer4{
Object object = null;
public void show() {
/*
* 了解内容:
*
* final:被final修饰的变量会被放在常量区,而常量区的值的存在时间要大于当前的方法,相当于扩大了原来局部变量的作用域,
* 即方法执行完了,变量也不会被释放
*
*
* 只要将下面的结论记住就可以
*
* 前提:方法中使用了局部内部类
* 在jdk1.7之前,要想保住这个值必须手动添加final
* 在jdk1.8及之后,java的内部机制已经在变量的前面默认添加了final
*/
int age = 6;
class Inner{//局部内部类
public void run() {
System.out.println("跑"+age);
}
@Override
public String toString() {
// TODO Auto-generated method stub
return "toString "+age;
}
}
//show的内部使用局部内部类
object = new Inner();//利用多态
}
public void eat(){
System.out.println(object.toString());
System.out.println("eat");
}
}
静态内部类
public class Demo5 {
public static void main(String[] args) {
// Out out = new Out();
// Out.Inn inn = out.new Inn();
//创建静态内部类对象
//构成: new + 外部类名字.内部类的构造方法
Out.Inn inn = new Out.Inn();
//调用方法
inn.play();
//调用静态方法
// inn.show();
Out.Inn.show();
}
}
class Out{
static int age;
//静态内部类不一定有静态方法,有静态方法的一定是静态内部类
static class Inn{//静态内部类
public void play() {
System.out.println("play");
}
public static void show() {
System.out.println("show");
}
}
}
匿名内部类
-
匿名内部类(对象):定义在一个类方法中的匿名子类对象,属于局部内部类
-
匿名子类对象:
-
匿名内部类对象:
-
创建匿名内部类对象注意点:1.匿名内部类对象必须有父类或者接口
匿名内部类对象的作用:
-
1.当只用到当前子类的一个实例对象的时候,定义好马上使用,使用完立刻释放
-
2.当不好起名字的时候
-
3.可以更好的定义运行时的回调(知道即可)
构成: new + 父类的名字/接口的名字 + () + {写当前子类的成员} + ;
{是子类的内部}
若是接口需要再{里面重写接口方法}
class Test1{
public void show(){
//匿名内部类
new Animal(){
@Override
public void eat() {
System.out.println("匿名子类对象-eat");
}
}.eat();
}
//匿名内部类使用
//普通的匿名对象作为参数
public void canShuTest(){
System.out.println(new Animal());
}
//匿名内部类作为参数
public void canShuTest1(){
System.out.println(new Animal(){
@Override
public void eat() {
System.out.println("eat");
}
});
}
异常
异常:程序中出现的不正常的情况
异常的由来:程序在运行时出现了不正常的情况,java提取了对应的属性,名字,原因等,形成了异常对象,进而形成了各种的异常类
异常的分类:
throwable异常和错误的超类
1.Error:(错误):运行中出现的严重错误,不需要我们进行更改.
2.Exception(异常):运行中出现的不严重的错误,我们可以尝试去更改.
Exception:分类:
第一种分类:系统异常:系统提前定义好的,我们直接使用
自定义异常:需要我们自己定义.
第二种分类:编译异常:在编译阶段抛出异常,处理异常
运行时异常:在运行阶段抛出异常,处理异常.
异常的特点:程序出现异常的时候,会打印异常的信息并中断程序,所以当有多个异常同时出现的时候,默认只能执行第一个.
异常的常用结构
catch会对try里面的代码进行监听,如果try里面的代码没有发生异常,catch不会执行,会直接执行后面的代码.
如果try里面的代码发生了异常,catch会立刻捕获(效果:try里面的代码会立刻中断,直接执行catch)
try{
可能发生异常的代码
}catch(Exception e){ //捕获异常 e就是要捕获的异常
对当前异常的处理
}
public class Demo9 {
public static void main(String[] args) {
Math1 math = new Math1();
try {
math.div(3,0);//3.这里也没有处理异常的能力,所以会继续往上抛,抛给他所在的方法
//只有try里面的代码没有发生异常,这里的代码才能执行
System.out.println("try");
}catch (ArithmeticException e){
//e.printStackTrace(); 获取异常的位置,原因,名字
System.out.println(e.getMessage());//原因
System.out.println("catch");
}
System.out.println("go on");
}
}
class Math1{
public int div(int a,int b){//2.这里也没有处理异常的能力,所以会继续往上抛,抛给调用这个方法的位置
return a/b;//1.在这里创建一个异常的对象(new ArithmeticException()) 因为这里没有处理异常的能力,所以会将异常往上抛,抛给他所在的方法
}
}
多异常处理
catch会对try里面的代码进行监听,如果try里面的代码没有发生异常,catch不会执行,会直接执行后面的代码.
如果truy里面的代码发生了异常,catch会立刻捕获(效果:try里面的代码会立刻终端,直接执行catch)
try{
可能发生异常的代码
}catch(异常一 e){ //捕获异常 e就是要捕获的异常
对当前异常的处理
}catch(异常二 e){ //捕获异常 e就是要捕获的异常
对当前异常的处理
}catch(Exception e){ //捕获异常 e就是要捕获的异常
对当前异常的处理
}
try {
math2.div(3, 0);
} catch (ArithmeticException e) {//除数为零异常
e.printStackTrace();
} catch (NullPointerException e) {
e.printStackTrace();
} catch (Exception e) {//注意:Exception异常必须放在最后一个catch
e.printStackTrace();
}
e.getMessage()//原因
e.printStackTrace()//输出异常位置和类型
try finaly
-
try{
-
可能发生异常的代码
-
}catch(Exception e){ //捕获异常 e就是要捕获的异常
-
对当前异常的处理
-
}finally{
-
//必须执行的代码:主要用于资源的释放:比如关闭数据库,关闭流,关闭锁等
-
}
-
这个结构跟异常没有关系
-
try{
-
获取资源
-
}finally{
-
释放资源
-
}