一、面向对象——内部类访问规则
1、内部类概念: 将一个类定义在另一个类的里面,对里面那个类就称为内部类(内置类、嵌套类)。 2、访问特点: A、内部类可以直接访问外部类中的成员,包括私有成员;(之所以可以直接访问外部类中的成员,是因为内部类中持有了一个外部类的引用,格式是:外部类名.this.) B、外部类要访问内部类中的成员必须要建立内部类的对象。 3、外部其他类访问格式: 当内部类定义在外部类的成员位置上,而且非私有,可以在外部其他类中直接建立内部类对象。 格式: 外部类名.内部类名 变量名 = 外部类对象.内部类对象。例如: Outer.Inner in = new Outer().new Inner(); 4、注意: 内部类可以被 private 修饰,因为内部类是外部类的成员。此时,将内部类封装在外部类中。 示例:class InnerClassDemo { public static void main(String[] args) { //调用内部类的方式一: Outer out = new Outer(); out.method(); //调用内部类的方式二: Outer.Inner in = new Outer().new Inner(); in.function(); //调用内部类的方式三: new Outer().new Inner().function(); } } class Outer { private int x = 3; //private class Inner //内部类可以被私有 class Inner { int x = 4; void function() { int x = 6; System.out.println("inner:x1="+x);//打印6 System.out.println("inner:x2="+this.x);//打印4 System.out.println("inner:x3="+Outer.this.x);//打印3 } } void method() { Inner in = new Inner(); in.function(); } }
二、面向对象——静态内部类
1、概念:
内部类是外部类的成员时,可以被 static 修饰,此时内部类就是静态内部类。
2、特点:
内部类被 static 修饰后,就具备 static 的特性,只能直接访问外部类中的 static 成员。出现了访问局限。
3、访问规则:
A、在外部其他类中,直接访问 static 内部类中的非静态成员的方式:
new Outer.Inner().function();
B、在外部其他类中,直接访问 static 内部类中的静态成员的方式:
Outer.Inner.function();
4、注意:
A、当内部类中定义了静态成员,该内部类必须是 static 的。
B、当外部类中的静态方法访问内部类时,内部类也必须是 static 的。
示例:class InnerClassDemo { public static void main(String[] args) { Outer.Inner in = new Outer.Inner();//创建静态内部类规则; in.function(); //new Outer.Inner().function();//当内部类静态时,访问内部类非静态方法的格式; Outer.Inner.function();//当内部类方法静态时,可直接访问; } } class Outer { private static int x = 3; static class Inner { //当内部类中定义了静态成员,该内部类必须是静态的 static void function() { System.out.println("inner:x="+x);//x相当于out.x } } public static void method() { new Inner().function(); } }
三、面向对象——内部类定义原则
1、什么时候定义内部类?
当描述事物时,事物的内部还有事物,该事物用内部类来描述。因为内部事物在使用外部事物的内容。
示例:class Body { private class Heart { } public Heart show() { return new Heart(); } }
四、面向对象——局部/匿名内部类
(1)局部内部类:
1、内部类不仅可以定义在外部类成员位置上,也可以定义在局部位置上。
补充:一般内部类不会被 public 修饰,内部接口除外。
2、局部内部类的特点:
A、可以直接访问外部类中的成员,因为还持有外部类中的引用;
B、局部内部类不可以被 private 和 static 修饰;
C、局部内部类中的内部成员也不可以被 private 和 static 修饰;
D、局部内部类只能访问被 final 修饰的局部变量;
示例:class InnerClassDemo3 { public static void main(String[] args) { Outer out = new Outer(); out.method(5); out.method(6); } } class Outer { int x = 3; void method(final int z) { final int NUM = 4; class Inner { void function() { //z++;//z 被final修饰,不能重新赋值。 System.out.println("x="+x); System.out.println("NUM="+NUM); System.out.println("z="+z); } } new Inner().function();//建立对象提供访问 } }
(2)匿名内部类:
1、匿名内部类是内部类的简写格式。
2、定义匿名内部类的前提:
内部类必须是继承一个类或者实现接口。
3、匿名内部类的格式:
new 父类或者接口(){定义子类内容,复写父类方法};
4、其实匿名内部类就是一个匿名子类对象,这个对象有具体内容。
5、匿名内部类中定义的方法一般不超过3个。
示例:class InnerClassDemo4 { public static void main(String[] args) { Outer out = new Outer(); out.function(); } } abstract class AbsDemo { abstract void method(); } class Outer { int x = 4; public void function() { AbsDemo d = new AbsDemo() { final int num = 9; void method() { System.out.println("x="+x);//x=4 System.out.println("num="+num);//num=9 } void show() { System.out.println("haha"); } }; d.method(); //d.show();//编译失败,因为父类中没有show方法 //但是可以按如下方法调用 new AbsDemo() { void method() { System.out.println("method"); } void show() { System.out.println("show"); } }.show(); } }
(3)练习一:根据以下代码补足Test类中的代码/* class InnerClassTest { public static void main(String[] args) { Test.function().method(); } } interface Tnter { public abstract void method(); } class Test { //补足代码 } */ class InnerClassTest { public static void main(String[] args) { Test.function().method(); //Test.function(): Test类中有一个静态的方法function; //.method(): function这个方法运算后的结果的一个对象,而且是一个Inter类型的对象,该对象用来调用method(); } } interface Inter { public abstract void method(); } class Test { /* //方法一:非匿名,内部类 static class Inner implements Inter { public void method() { System.out.println("method run"); } } static Inter function() { return new Inner(); } */ //方法二:匿名内部类 static Inter function() { return new Inter() { public void method() { System.out.println("method run"); } }; } }
(4)练习二: 什么时候使用匿名内部类?例如:interface Inter { void method(); } class InnerClassTest2 { public static void main(String[] args) { //调用show方法时使用匿名内部类的方式 show(new Inter() { public void method() { System.out.println("method show run"); } }); } public static void show(Inter in) { in.method(); } }
(5)面试题:class InnerTest { public static void main(String[] args) { new Object()//Object obj = new Object() { public void function(){} }.function();//OK,子类直接调用 //obj.function();//编译失败,因为父类中没有function方法。 } }
五、面向对象——异常概述
1、异常体系
Throwable
Error
通常出现重大问题:如运行的类不存在或者内存溢出等;
不编写针对代码对其处理。
Exception
在运行时出现的情况,可以通过 try catch finally
2、 Exception 和 Error 的子类名都是以父类名作为后缀。
3、理解:
异常:就是程序在运行时出现不正常情况。
异常由来:问题也是现实生活中一个具体的事物,也可以通过java的类的形式进行描述。并封装成对象。异常其实就是java对不正常情况进行描述后的对象体现。
对于问题的划分:两种:一种是严重的问题,一种非严重的问题。
对于严重的,java通过 Error 类进行描述。对于 Error 一般不编写针对性的代码对其进行处理。
对与非严重的,java通过 Exception 类进行描述。对于 Exception 可以使用针对性的处理方式进行处理。
无论 Error 或者 Exception 都具有一些共性内容。比如:不正常情况的信息,引发原因等。所以可以对其进行抽取出一个父类。六、面向对象——异常 try - catch
1、异常处理:
java 提供了特有的语句处理异常:
try
{
需要被检测的代码;
}
catch ()
{
处理方式;
}
finally
{
一定会执行的语句;
}
2、常见的异常处理方法:class Demo { public int div(int a, int b) { return a/b; //new ArithmeticException() } } class ExceptionDemo { public static void main(String[] args) { Demo d = new Demo(); try { int x = d.div(4,0);//new ArithmeticException() System.out.println("x="+x); } catch (Exception e)//Exception e = new ArithmeticException() { System.out.println(e.getMessage()); // / by zero System.out.println(e.toString());// 异常名称: 异常信息 e.printStackTrace();// 异常名称: 异常信息;异常出现的位置。//JVM默认异常处理方式。 } System.out.println("over"); } }
3、对捕获到的异常对象进行常见方法操作:
String getMessage();
String toString();
printStackTrace();
注意:
在输出语句中可以不用写 toString()方法,因为会自动调用。七、面向对象——异常声明
1、如果程序运行过程中, try 中的代码不出现问题,则 catch 中的代码不会执行,而是继续向下运行。
2、在编写一个功能时,如果该功能有可能会出现异常;那么就必须在该功能上做一个标示,并通过 throws 关键字声明出该异常,以便调用者在调用该功能时知道该功能可能会出现的异常。
3、调用者对于接收到声明了有可能出现问题的程序时,就需要通过 try catch 处理,或者继续抛出。否则编译失败。class Demo { int div(int a, int b)throws Exception //在功能上通过throws关键字声明了该功能有可能出现问题 { return a/b; } } class ExceptionDemo2 { public static void main(String[] args) //throws Exception //或者继续抛出异常 { Demo d = new Demo(); try //抛出异常时,尝试运行 { int x = d.div(4,0); System.out.println("x="+x); } catch (Exception e) //异常处理方式 { System.out.println(e.toString()); } System.out.println("over"); } }
八、面向对象——多异常处理
1、声明异常时,建议声明更为具体的异常,这样可以处理得更具体。
2、处理原则:
A、对方声明几个异常,就对应有几个 catch 块进行针对性处理;不要定义多余的 catch 块。
B、如果多个 catch 块中的异常出现继承关系,父类异常 catch 块放在最下面。
3、在进行 catch 处理时, catch 中一定要定义具体的处理方式;不要定义简单的输出信息。class Demo { int div(int a, int b)throws ArithmeticException , ArrayIndexOutOfBoundsException { int[] arr = new int[a]; System.out.println(arr[4]); return a/b; } } class ExceptionDemo3 { public static void main(String[] args) { Demo d = new Demo(); try { int x = d.div(4,0); System.out.println("x="+x); } catch (ArithmeticException e) { System.out.println(e.toString()); } catch (ArrayIndexOutOfBoundsException e) { System.out.println(e.toString()); } /* catch (Exception e) { System.out.println(e.toString()); } */ System.out.println("over"); } }
九、面向对象——自定义异常
1、由来:
项目中会出现特有的问题,而这些问题并未被java所描述并封装成对象。所以对于这些特有问题,可以按照java对问题封装的思想,将特有的问题进行自定义的异常封装。
2、当在函数内部出现了 throw 抛出异常对象,那么就必须要给对应的处理动作。
要么在内部 try catch 处理。
要么在函数上声明让调用者处理。
一般情况下,函数内出现异常,函数上需要声明。 RuntimeException 除外。
3、如何定义异常信息呢?
因为父类中已经把异常信息的操作都完成了。
所以子类只要在构造时,将异常信息传递给父类通过 super 语句。
那么就可以直接通过 getMessage() 方法获取自定义的异常信息。
4、自定义异常,必须是自定义类继承 Exception 。
5、继承 Exception 的原因:
异常体系有一个特点:因为异常类和异常对象都被抛出。他们都具备可抛性。
这个可抛性是 Throwable 这个体系中独有特点。只有这个体系中的类和对象才可以被 throws 和 throw 操作。
====== java定义好的异常可以自动创建异常对象抛出,自定义异常需要手动创建异常对象并抛出。
====== 在编译时,先报告的是语法错误,异常问题最后报告。class FuShuException extends Exception { //private String msg; private int value; FuShuException(String msg, int value) { super(msg); //this.msg = msg; this.value = value; } public int getValue() { return value; } /* public String getMessage() { return msg; }*/ } class Demo { int div(int a, int b)throws FuShuException //函数内出现异常,函数上需要声明 { if (b<0) { throw new FuShuException("/ by minus", b);//手动通过throw关键字抛出一个自定义异常对象。同时让程序跳转。 } return a/b; } } class ExceptionDemo4 { public static void main(String[] args) { Demo d = new Demo(); try { int x = d.div(4,-2); System.out.println("x="+x); } catch (FuShuException e) { System.out.println(e.toString()); System.out.println("除数: "+e.getValue()); } System.out.println("over"); } }
Throwable 以及 Exception 对message的定义思想体现:class Throwable { private String message; Throwable(String message) { this.message = message; } public String getMessage() { return message; } } class Exception extends Throwable { Exception(String message) { super(message); } }
十、面向对象—— throw 和 throws 的区别
throws 和 throw 的区别:
throws 使用在函数上。
throw 使用在函数内。
throws 面跟的是异常类;可以跟多个。用逗号隔开。
throw 后跟的是异常对象。十一、面向对象—— RuntimeException
1、 Exception 中有一个特殊的子类异常 RuntimeException 运行时异常。
2、 RuntimeException 异常的特点:
A、如果在函数内容抛出该异常,函数上可以不用声明,编译一样通过。
B、如果在函数上声明了该异常。调用者可以不用进行处理。编译一样通过;
原因:之所以不用在函数声明,是因为不需要让调用者处理。而应该在该异常发生时,希望程序停止。
因为在运行时,出现了无法继续运算的情况,希望停止程序后,对代码进行修正。
3、自定义异常时:如果该异常的发生,无法在继续进行运算,就让自定义异常继承 RuntimeException 。
4、对于异常分两种:
A,编译时被检测的异常。
B,编译时不被检测的异常(运行时异常: RuntimeException 及其子类)
5、 RuntimeException 子类举例:
RuntimeException
-ArithmeticException
-NullPointerException
-IndexOutOfBoundsException
-ArrayIndexOutOfBoundsException
-StringIndexOutOfBoundsException
代码一:class FuShuException extends RuntimeException //希望发生该异常时,让程序停止 { FuShuException(String msg) { super(msg); } } class Demo { int div(int a, int b) //throws FuShuException, ArithmeticException 函数内抛出,函数上可以不用抛出 { if(b<0) throw new FuShuException("//by minus"); if(b==0) throw new ArithmeticException("by zore ---"); return a/b; } } class ExceptionDemo5 { public static void main(String[] args) //throws FuShuException, ArithmeticException 接收了可能存在问题的该异常,可以不用处理 { Demo d = new Demo(); int x = d.div(4,0); System.out.println("x="+x); System.out.println("over"); } }
NullPointerException 举例:class Person { private String name; Person(String name) { this.name = name; } public boolean checkName(String name) { //if(name.equals("lisi")) //当传入null时,会发生NullPointerException if("lisi".equals(name))//修改技巧 //if(name!=null && name.equals("lisi")) return true; else return false; } } class Demo { public static void main(String[] args) { Person p = new Person("lisi"); boolean bl1 = p.checkName(null); System.out.println(bl1); boolean bl2 = p.checkName("lisi"); System.out.println(bl2); } }
十二、面向对象——异常练习
需求:
毕老师用电脑上课。
分析:
名词提炼法。
思考上课时,可能出现的异常:
电脑问题:
电脑蓝屏;
电脑冒烟
当冒烟发生后,出现讲课进度无法继续;就出现了新问题——课时计划无法完成。
代码:class BlueException extends Exception { //定义异常类,该异常可处理 BlueException(String message) { super(message); } } class MaoYanException extends Exception { //定义异常类,该异常不可以处理 MaoYanException(String message) { super(message); } } class NoPlanException extends Exception { NoPlanException(String message) { super(message); } } class Computer { private int state = 1;//1代表正常,2代表蓝屏,3代表冒烟 public void run(int num)throws BlueException,MaoYanException { state = num; if(state==1) System.out.println("computer run"); else if(state==2) throw new BlueException("电脑蓝屏"); else if(state==3) throw new MaoYanException("电脑冒烟"); else System.out.println("传入非法值"); } //重启电脑 public void reset() { state = 1; System.out.println("computer reset"); } } class Teacher { private String name; private Computer cmpt; Teacher(String name) { this.name = name; cmpt = new Computer(); } public void prelect()throws NoPlanException { try { //设置电脑运行时可能出现的各种状况 cmpt.run(3); } catch (BlueException e) { System.out.println(e.getMessage()); cmpt.reset(); } catch (MaoYanException e) { System.out.println(e.getMessage()); test(); throw new NoPlanException("no plan: "+e.getMessage()); } System.out.println(name+": prelect"); } public void test() { System.out.println("test"); } } class ExceptionTest { public static void main(String[] args) { Teacher t = new Teacher("bilaoshi"); try { t.prelect(); } catch (NoPlanException e) { System.out.println(e.toString()); System.out.println("放假"); } } }
注意:
throw 单独存在时,下面不可以写语句, throw 是函数的结束标示,它一结束,下面的语句执行不到。