一、内部类
1、内部类:一个类定义在另外一个类的内部,那么该类就称作为内部类。
2、内部类的class文件名: 外部类$内部类
好处:便于区分该class文件是属于哪个外部类的。
3、内部类的类别
① 成员内部类
◆ 成员内部类的访问方式:
◇ 方式一:在外部类提供一个方法创建内部类的对象进行访问。
◇ 方式二:在其他类直接创建内部类的对象。
格式:外部类.内部类 变量名 = new 外部类().new 内部类();
◆ 注意: 如果是一个静态内部类,那么在其他类创建的格式:外部类.内部类 变量名 = new 外部类.内部类();
//外部类
class Outer{
//成员变量
int x = 100; // Outer.class文件被加载到内存的时候存在内存中。静态的成员数据是不需要对象存在才能访问。
//成员内部类
static class Inner{
static int i = 10;
public void print(){
System.out.println("这个是成员内部类的print方法!"+i);
}
}
//在外部的方法中创建了内部类的对象,然后调用内部方法。
public void instance(){
Inner inner = new Inner();
inner.print();
}
}
//其他类
class Demo12.1{
public static void main(String[] args){
System.out.println(Outer.Inner.i);
Outer outer = new Outer();
outer.instance();
Outer.Inner inner = new Outer().new Inner();
inner.print();
Outer.Inner inner = new Outer.Inner();
inner.print();
}
}
② 局部内部类:在一个类的方法内部定义另外一个类,那么另外一个类就称作为局部内部类。
◆ 局部内部类要注意的细节:
◇ 如果局部内部类访问了一个局部变量,那么该局部变量必须使用final修饰、
class Outer{
String name= "外部类的name";
public void test(){
//局部变量
final int y = 100;
//局部内部类
class Inner{
int x = 10;
public void print(){
System.out.println("这个是局部内部类的print方法.."+y);
}
}
Inner inner = new Inner();
inner.print();
}
}
class Demo12.2{
public static void main(String[] args){
Outer outer = new Outer();
outer.test();
}
}
③ 匿名内部类
匿名内部类:没有类名的类就称作为匿名内部类。
匿名内部类的好处:简化书写。
匿名内部类的使用前提:必须存在继承或者实现关系才能使用。
匿名内部类一般是用于实参。
abstract class Animal{
public abstract Animal run();
public abstract void sleep();
}
class Outer{
public void print(){
//需求:在方法内部定义一个类继承Animal类,然后调用run方法与sleep()
/*//局部内部类
class Dog extends Animal{
public void run(){
System.out.println("狗在跑..");
}
public void sleep(){
System.out.println("狗趴在睁开眼睛睡..");
}
}
//创建对象
Dog d = new Dog();
d.run();
d.sleep();
*/
//匿名内部类 :匿名内部类只是没有类名,其他的一概成员都是具备的
//匿名内部类与Animal是继承的关系,目前是创建Animal子类的对象
/*
new Animal(){
public void run(){
System.out.println("狗在跑..");
}
}.run();
*/
Animal a = new Animal(){ //多态
//匿名内部的成员
public Animal run(){
System.out.println("狗在跑..");
return this;
}
public void sleep(){
System.out.println("狗趴在睁开眼睛睡..");
}
//特有的方法
public void bite(){
System.out.println("狗在咬人..");
}
};
a.run();
a.sleep();
}
}
class Demo12.3{
public static void main(String[] args){
Outer outer = new Outer();
outer.print();
}
}
4、内部类的应用场景: 我们在描述A事物的时候,发现描述的A事物内部还存在另外一个比较复杂的事物B时候,而且这个比较复杂事物B还需要访问A事物的属性等数据,那么这时候我们就可以使用内部类描述B事物。
5、内部类的好处:内部类可以直接访问外部类的所有成员。
6、内部类要注意的细节
① 如果外部类与内部类存在同名的成员变量时,在内部类中默认情况下是访问内部类的成员变量。但是可以通过”外部类.this.成员变量名” 指定访问外部类的成员。
② 私有的成员内部类只能在外部类提供一个方法创建内部类的对象进行访问,不能在其他类创建对象了。
③ 成员内部类一旦出现了静态的成员,那么该类也必须使用static修饰。
二、异常处理
1、异常体系
Throwable[ Error(错误)、Exception(异常:运行时异常、编译时异常) ]
① Throwable 异常或者错误类的超类
②
◆ Error 错误 :错误一般是用于jvm或者是硬件引发的问题,所以我们一般不会通过代码去处理错误的。
◆ Exception 异常:是需要通过代码去处理的。
2、Throwable常用的方法
① toString():返回当前异常对象的完整类名+病态信息。
② getMessage():返回的是创建Throwable传入的字符串信息。
③ printStackTrace(): 打印异常的栈信息。
class Demo12.4{
public static void main(String[] args){
//创建了一个Throwable对象。
Throwable t = new Throwable("头晕,感冒..");
String info = t.toString();
String message = t.getMessage();
System.out.println("toString: "+ info); // java.lang.Throwable 包名+类名 = 完整类名
System.out.println("message: "+ message);
test();
}
public static void test(){
Throwable t = new Throwable();
t.printStackTrace();
}
}
3、区分错误与异常
◆ 如果程序出现了不正常的信息,如果不正常的信息的类名是以Error结尾的,那么肯定是一个错误。
◆ 如果是以Exception结尾的,那么肯定就是一个异常。
4、异常的处理
① 方式一:捕获处理
◆ 捕获处理的格式:
try{
可能发生异常的代码;
}catch(捕获的异常类型 变量名){
处理异常的代码....
}
◆ 捕获处理要注意的细节
◇ 如果try块中代码出了异常经过了处理之后,那么try-catch块外面的代码可以正常执行。
◇ 如果try块中出了异常的代码,那么在try块中出现异常代码后面的代码是不会执行了。
◇ 一个try块后面是可以跟有多个catch块的,也就是一个try块可以捕获多种异常的类型。
◇ 一个try块可以捕获多种异常的类型,但是捕获的异常类型必须从小到大进行捕获,否则编译报错。
② 方式二:抛出处理
◆ 抛出处理要注意的细节
◇ 如果一个方法的内部抛出了一个编译时异常对象,那么必须要在方法上声明抛出。
◇ 如果调用了一个声明抛出编译时异常的方法,那么调用者必须要处理异常。
◇ 如果一个方法内部抛出了一个异常对象,那么throw语句后面的代码都不会再执行了(一个方法遇到了throw关键字,该方法也会马上停止执行的)。
◇ 在一种情况下,只能抛出一种类型异常对象。
class Demo12.5{
public static void main(String[] args){
try{
int[] arr = null;
div(4,0,arr); //调用了一个声明抛出异常类型的方法
}catch(Exception e){
System.out.println("出现异常了...");
e.printStackTrace();
}
}
public static void div(int a, int b,int[] arr) throws Exception,NullPointerException {
if(b==0){
throw new Exception(); //抛出一个异常对象...
}else if(arr==null){
throw new NullPointerException();
}
int c = a/b;
System.out.println("c="+c);
}
}
③ throw与throws两个关键字
◆ throw关键字是用于方法内部的,throws是用于方法声声明上的。
◆ throw关键字是用于方法内部抛出一个异常对象的,throws关键字是用于在方法声明上声明抛出异常类型的。
◆ throw关键字后面只能有一个异常对象,throws后面一次可以声明抛出多种类型的异常。
5、自定义异常类
步骤: 自定义一个类继承Exception即可。
/*
需求:模拟你去吃木桶饭,如果带钱少于了10块,那么就抛出一个没有带够钱的异常对象,如果带够了,那么就可以吃上香喷喷的地沟油木桶饭.
*/
//定义没钱的异常
class NoMoneyException extends Exception {
public NoMoneyException(String message){
super(message);
}
}
class Demo12.6{
public static void main(String[] args){
try{
eat(9);
}catch(NoMoneyException e){
e.printStackTrace();
System.out.println("洗碗一个月!");
}
}
public static void eat(int money) throws NoMoneyException{
if(money<10){
throw new NoMoneyException("吃霸王餐");
}
System.out.println("吃上了香喷喷的地沟油木桶饭!!");
}
}
6、finally块
① finally块的使用前提是必须要存在try块才能使用。
② finally块的代码在任何情况下都会执行的,除了jvm退出的情况。
③ finally非常适合做资源释放的工作,这样子可以保证资源文件在任何情况下都会被释放。
/*
fianlly释放资源的代码
*/
import java.io.*;
class Demo12.7{
public static void main(String[] args){
FileReader fileReader = null;
try{
//找到目标文件
File file = new File("f:\\a.txt");
//建立程序与文件的数据通道
fileReader = new FileReader(file);
//读取文件
char[] buf = new char[1024];
int length = 0;
length = fileReader.read(buf);
System.out.println("读取到的内容:"+ new String(buf,0,length));
}catch(IOException e){
System.out.println("读取资源文件失败....");
}finally{
try{
//关闭资源
fileReader.close();
System.out.println("释放资源文件成功....");
}catch(IOException e){
System.out.println("释放资源文件失败....");
}
}
}
}
7、try块的三种组合方式
◆ 第一种: 比较适用于有异常要处理,但是没有资源要释放的。
try{
可能发生异常的代码
}catch(捕获的异常类型 变量名){
处理异常的代码
}
◆ 第二种:比较适用于既有异常要处理又要释放资源的代码。
try{
可能发生异常的代码
}catch(捕获的异常类型 变量名){
处理异常的代码
}finally{
释放资源的代码;
}
◆ 第三种: 比较适用于内部抛出的是运行时异常,并且有资源要被释放。
try{
可能发生异常的代码
}finally{
释放资源的代码;
}