内部类
- 内部类就是在一个类的内部再定义一个类,比如在A类中定义一个B类,那么B类相对于A类就是一个内部类了。它分为很多种:
- 成员内部类
- 静态内部类
- 局部内部类
- 匿名内部类
- 成员内部类,定义一个Outer类(外部类的意思)
public class Outer {
private int id;
public void out(){
System.out.println("这是外部类的方法");
}
class Inner{
public void in(){
System.out.println("这是内部类的方法");
}
}
}
- 然后我们想办法测试他一下,外部类是通过new关键词实现的,内部类通过外部类来实例化。
public class Application {
public static void main(String[] args) {
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
}
}
- 看看能不能打印出内部类的方法,比如内部类还可以直接访问外部类的一些私有变量和方法。
- 还有一种静态内部类,现在的类是通过public去修饰他。但是可以通过public static去修饰就变成静态的了。这个id就拿不到了
- 静态内部类无法访问非静态的属性。
- 下面这样写也叫做内部类,相当于他在java文件里面写了两个不同的类。
- 一个java文件只能有一个public class,但是能有多个class类
- 局部内部类,像方法里面定义的类就是局部内部类。
public class Outer {
public void method(){
class Inner{
}
}
}
- 还可以写一些没有名字的类,这些类实例出来是没有名字的,就相当于把他给实现出来。不用把实例保存在变量中
public class Test {
public static void main(String[] args) {
//没有名字初始化类
new Apple().eat();
}
}
class Apple{
public void eat(){
System.out.println("1");
}
}
- 假设是接口
public class Test {
public static void main(String[] args) {
//没有名字初始化类
new Apple().eat();
UserService userService = new UserService(){
@Override
public void hello() {
}
};
}
}
class Apple{
public void eat(){
System.out.println("1");
}
}
interface UserService{
void hello();
}
异常机制
- java的异常机制Exception。在生活中,开车上班一般不会迟到,但是今天车坏了或限行了,你改做公交就有可能会迟到,这就是属于异常情况。
- 实际工作中写的代码,正常来说用户应该输入一个数字,但是他输入了字符串或汉字,不一定符合我们的要求。包括程序要打开某个文件,但文件不存在。又或者程序跑着跑着内存满了,也是不行的。
public class demo01 {
public static void main(String[] args) {
new demo01().a();
}
public void a(){
b();
}
public void b(){
a();
}
}
- 程序报error了,并不是异常。
- 我们还可以输出11/0,0是不能成为被除数的。
- 有些错误要等程序跑起来才知道。有可能是jvm造成的,也有可能是因为程序员的问题。
- 异常指程序运行中出现的不期而至的各种状况:文件找不到、网络连接失败、非法参数等。
- 总共来说可以分为以下三大类:
- 检查性异常:最具代表性的是检查性异常,用户错误或问题引起的异常,这是程序员无法预见的。例如打开一个不存在的文件,一个异常就发生了。这些异常不能再编译时简单地被忽略。
- 运行时异常:运行时异常可能被程序员避免的异常。与检查性异常相反,运行时异常可以再编译时被忽略。
- 错误:错误不是异常,而是脱离程序员控制的问题。错误在代码中通常被忽略。例如栈溢出时,一个错误就发生了,他在编译也检查不到的。
- java提出了异常处理框架的思想,所有的异常都可以用一个异常类来表示。
- 异常体系结构:java把异常当做对象来处理,并定义一个基类java.lang.Throwable作为所有异常的超类,就是一个顶层,所有的都会在里面。
- Java API中已经定义了许多异常类,这些异常类分为两大类,错误Error和异常Exception。error是无法预见的,exception可以预见。
- 所有的异常都是Throwable的子类,Error主要是虚拟机错误和AWT错误(GUI)。一旦程序发生错误,后果比较严重。
- 异常有IO异常和运行时异常:空指针异常,数组下标越界异常,未知类型异常。当这个异常出来之后我们要捕获他。
Error
- Error类对象由Java虚拟机生成并抛出,大多数错误和代码编写者执行的操作无关。比如内存溢出、JVM直接就终止了。
- 还有就是虚拟机想去跑一些应用的时候,突然类定义错误,他就会抛出NoClassDefFoundError、LinkAgeError错误。写代码觉察不到,并不在应用程序控制范围之内。
Exception
- 运行时异常会帮程序运行的时候自定义一些异常:ArrayIndexOutOfBoundsException、NullPointerException、ArithmeticException、MissingResourceException、ClassNotFoundException。这些异常是不检查异常,程序可以选择捕获处理,也可以不处理。
- 这些异常一般由程序逻辑错误引起,程序应该从逻辑角度避免发生。
- 上面可以统称非运行时异常。这些异常是必须进行处理的,不处理的话编译都不通过。
- 错误一般是灾难性的error,jvm会强行关掉。Exception处理异常就好了。
异常处理机制
- 异常分为:抛出异常和捕获异常
- 异常处理五个关键字:try(尝试处理)、catch(捕获)、finally(无论执不执行都会走的)、throw(抛出异常)、throws(从方法中抛出异常)
- 像1除以0会报错,我怎么捕获异常然后返回一些信息呢?try代码区可以监控区域,只要在这里的代码有了异常就能捕获。catch捕获异常你首先要知道异常的类型。在catch里面只要捕获到上面的错误就打印一句话。finally无论怎么样都会执行,一般是用来处理一些善后的工作的。
public class Test {
public class Test {
public static void main(String[] args) {
int a = 1;
int b = 0;
try{
System.out.println(a/b);
}catch (ArithmeticException e){
System.out.println("程序出现异常,变量b不能为0");
}finally{
System.out.println("finally");
}
}
}
- 红色的东西没有了,异常被捕获了。
- try和catch是这里面必须要有的东西,finally可以不要。
- 后面会学一些io流,假如资源要关闭,关闭的操作就放在scanner里面。
- 其他异常,假如栈溢出,试下用Throwable能不能抓到他。
public class Test {
public static void main(String[] args) {
int a = 1;
int b = 0;
try{
new Test().a();
}catch (Throwable e){
System.out.println("程序出现异常,栈溢出");
}finally{
System.out.println("finally");
}
}
public void a(){
b();
}
public void b(){
a();
}
}
- 可以发现Throwable可以捕获栈溢出,因为最高就是Throwable,几乎所有东西都能够被捕获到。
- java里面可以捕获多个异常,就跟if else一样层层递进。你要把最大的异常放在最下面
public class Test {
public static void main(String[] args) {
int a = 1;
int b = 0;
try{
System.out.println(a/b);
}catch(Error e){
System.out.println("error");
}catch(Exception e){
System.out.println("exception");
}catch(Throwable t){
System.out.println("Throwable");
}finally{
System.out.println("finally");
}
}
public void a(){
b();
}
public void b(){
a();
}
}
- 但是假如将exception和throwable调换一下位置就会报错了
- 假设要捕获多个异常,就必须从小到大地捕获。
- 有时候我们想对一行代码自动生成try catch 。选中当前代码,ctrl + alt + t (command + alt + t)
public class Test2 {
public static void main(String[] args) {
int a = 1;
int b = 0;
try {
System.out.println(a/b);
} catch (Exception e) {
e.printStackTrace();
} finally {
}
}
}
- 这里有句话 e.printStackTrace();打印栈信息,打印错误的栈信息。
- 也可以让程序自己结束
- 假设有代码可能错误,可以加个if语句,然后主动地抛出异常
try{
if (b==0){
throw new ArithmeticException();
}
System.out.println(a/b);
- 结果运行后,抛出异常这里什么都没有做,所以抛出异常一般会在方法里面用
- 写除数的方法
public class Test {
public static void main(String[] args) {
new Test().test(1,0);
}
public void test(int a ,int b ){
if (b==0){
throw new ArithmeticException();
}
System.out.println(a/b);
}
}
- 他抛出了异常,假设不要方法体,正常应该没有做除法,但是他主动抛出异常了。
- 有时候我们明明知道方法有异常,但是我们可以主动往外抛,抛到更高级。
- 主动抛出后程序不会中断,会正常往下执行,这就是好处
public class Test {
public static void main(String[] args) {
try {
new Test().test(1,0);
} catch (ArithmeticException e) {
e.printStackTrace();
}
}
public void test(int a ,int b )throws ArithmeticException{
if (b==0){
throw new ArithmeticException();
}
System.out.println(a/b);
}
}
自定义异常
- java和其他开源框架已经有很多定义了的异常,所以自定义异常并不常见。你不去写开源框架或大型系统,很少会用到这个。
- Java内置的异常类可以描述在变成时出现的大部分异常情况,自己写的异常类处理小问题也可以使用它。用户自定义异常类,只需继承Exception类即可。
- 创建自定义异常类
- 在方法中通过throw关键字爬出异常对象。
- 写一个自己的异常类
- 他必须继承Exception类,一旦继承了他就是异常类了。
- 查一下这个异常
- 数组下标越界继承了其他异常类
- 这个又继承了运行时异常
- 一直到这里才继承到Exception类
- 异常他是这样写的,他首先有个构造方法,里面是空参的
- 构造方法也可以接受下标
- 这里又调用了父类的方法
- 这里是一个message
- 说白了就是打印这个message
- 咱们写一个,传递数字,如果数字大于10就抛出异常。抛出异常需要给人提示信息。
public class MyException extends Exception{
//传递数字>10
private int detail;
public MyException(int a) {
this.detail = a;
}
//toString:异常的打印信息
@Override
public String toString() {
return "MyException{" +
"detail=" + detail +
'}';
}
}
- 再来写一个测试类
public class Test {
// 可能会存在异常的方法
static void test(int a) throws MyException {
System.out.println("传递的参数为:"+a);
if(a>10){
throw new MyException(a); //抛出
}
System.out.println("OK");
}
public static void main(String[] args) {
try {
test(1);
} catch (MyException e) {
System.out.println("MyExcetpion=>"+e);;
}
}
}
- 如果传递11
总结
- 处理运行异常时,才用逻辑去合理规避同时辅助try-catch处理
- 在多重catch块后面,可以加一个catch(Exception)来处理可能会被遗漏的异常。
- 对于不确定的代码,也可以加上try-catch,处理潜在的异常
- 尽量去处理异常,切忌只是简单的调用printStackTrace()去打印输出
- 具体如何处理异常,要根据不同的业务需求和异常类型取决定
- 尽量添加finally语句块去释放占用的资源