内部类(Inner class)
1.内部类的作用 : 一般用于服务于外部类
(1),内部类提供了更好的封装,可以把内部类隐藏在外部类之内,不允许同一个包中的其他类访问该类。
(2),内部类成员可以直接访问外部类的私有数据;但外部类不能访问内部类的实现细节,如内部类的成员变量;
(3),匿名内部类适合用于创建仅需使用一次的类。
2.概念
内部类也就是定义在类内部的类。
内部类是一个编译时的概念。
编译成功:外部类内部类名.class (OuterInner.class)
3. 内部类的分类:
- (1) 成员内部类(Member inner class)、
- (2) 局部内部类(Local inner class)、
- (3) 静态内部类(Static inner class)、
- (4) 匿名内部类(Anonymous inner class)
1. 成员内部类
class A{
int a =10;
class B{}
}
1. 静态内部类
class A{
static int a =10;
static class B{}
}
1. 局部内部类
class A{
public void fun(){
int a =10;
class B{}
}
}
2. 匿名内部类
new A(new B(){
public void fun(){//重写B接口(抽象类)的方法
}
});
(1)成员内部类(Member Inner Classes)
特征:
(a)、相当于外部类中的一个普通成员方法;
(b)、相当于外部类中的一个普通成员属性;
成员定义:
不能在成员内部类中定义静态属性和静态方法。
特征:为什么成员内部类中不能定义静态成员?
* 因为外部类被加载时,成员内部类还没有被加载。
从外到内:
(a)、非静态方法:
必须创建内部类的对象,然后通过对象方法,则可以访问内部类中的所有属性和方法
(b)、静态方法 和 其他的类:
必须先创建外部类的对象,然后通过外部类对象再创建内部对象。
Inner inner = new Outer().new Inner();
从内到外:
(a)、成员内部类可以访问外部类中所有的属性和方法;
(b)、外部类、内部类、内部类的方法中出现同名
temp
this.temp
Outer.this.temp
-
示例:
//成员变量、成员方法、成员内部类 === 为外部类服务
public class Outer {//成员变量 public int a = 10; //成员方法 public void fun1(){} //成员内部类 class Inner{ //内部类的 成员变量 //内部类的成员方法 }
}
//测试
public class TestInnerClass {
public static void main(String[] args) {
Outer outer = new Outer();outer.a =20; //成员变量: 对象名.变量名 outer.fun1(); //成员方法: 对象名.方法名 outer.new Inner(); //内部类对象 new Inner(); //成员内部类: 外部类对象.内部类对象 }
}
(2)静态成员内部类(Static Inner Class)
特征:
(a)、相当于外部类中的一个静态成员方法;
(b)、相当于外部类中的一个静态成员属性;
成员定义:
可以在成员内部类中定义静态属性和静态方法。
从外到内:
(a)、非静态方法 和 静态方法:
必须创建静态内部类的对象,然后通过对象方法,则可以访问静态内部类中的所有属性和方法;
(b)、other其他的类:
Inner inner = new Inner();
Inner inner = new Outer.Inner();
从内到外:
(a)、非静态方法:
只能访问外部类中的静态属性和静态方法;
(b)、静态方法:
只能访问外部类中的静态属性和静态方法;
public class Outer {
static int x = 10;
static class Inner{}
}
public class TestStaticInnerClass {
public static void main(String[] args) {
Outer outer = new Outer();
Outer.x = 50;
//创建静态内部类对象
Outer.Inner inner = new Outer.Inner();
}
}
(3)局部内部类(Local Inner Classes):
定义在某个方法中类, 把局部内部类看作为某个方法中一个普通变量。
特征:
* 1、不能被4种访问控制符所修饰,也不能被static修饰,
* 但是可以被final、abstract所修饰。
* 2、局部内部类中不能定义静态成员(方法和属性)。
非静态方法
特征:
相当于一个普通的方法。
// 成员定义:
// 可以在成员内部类中定义静态属性和静态方法。
从内到外:
(a)、可以作为一个普通的方法,访问外部类中的所有的成员属性和成员方法;
(b)、如果局部内部类要访问所在方法中的定义的变量,则该变量必须为常量;
从外到内:
必须通过外部类的方法(作为入口),并且一定要在方法结束之前将局部内部类的对象创建完成,然后局部内部类中的方法;
静态方法
特征:
相当于一个静态的方法;
成员定义:
可以在成员内部类中定义静态属性和静态方法。
从内到外:
(a)、可以作为一个静态的方法,访问外部类中的所有的静态属性和静态方法;
(b)、如果局部内部类要访问所在方法中的定义的变量,则该变量必须为常量;
从外到内:
必须通过外部类的方法(作为入口),并且一定要在方法结束之前将局部内部类的对象创建完成,然后局部内部类中的方法;
(4)匿名内部类(Anonymous Inner Calsses):
是一个特殊的局部内部类。
分析:
怎么使用匿名内部类继承一个父类?
怎么使用匿名内部类实现一个接口?
答:直接new 父类或者接口。
在使用匿名内部类时,要记住以下几个原则:
·匿名内部类不能有构造方法。
·匿名内部类不能定义任何静态成员、方法和类。
·匿名内部类不能是public,protected,private,static。
·只能创建匿名内部类的一个实例。
·一个匿名内部类一定是在new的后面,用其隐含实现一个接口或实现一个类。
·因匿名内部类为局部内部类,所以局部内部类的所有限制都对其生效。
匿名类和内部类中的中的this :
有时候,我们会用到一些内部类和匿名类。当在匿名类中用this时,这个this则指的是匿名类或内部类本身。这时如果我们要使用外部类的方法和变量的话,则应该加上外部类的类名。
public class MainBoard {
public MainBoard(Cpu cpu){
}
}
public interface Cpu {
public void cpuRun();
}
public class DellCpu implements Cpu {
@Override
public void cpuRun() {
}
}
public class TestCpu {
public static void main(String[] args) {
Cpu cpu = new DellCpu();
MainBoard mainBoard1 = new MainBoard(cpu);
//匿名内部类
new MainBoard(new Cpu(){
@Override
public void cpuRun() {
}
});
}
}
异常
1. 异常的分类
Throwable有两个子类:Error和Exception。
(1) Error: 硬件故障,程序员无法解决 。一个Error对象表示一个程序错误,指的是底层的、低级的、不可恢复的严重错误。此时程序一定会退出,因为已经失去了运行所必须的物理环境。对于Error错误我们无法进行处理,因为我们是通过程序来应对错误,可是程序已经退出了。
(2)Exception 程序员疏忽造成, 我们可以处理的Throwable类中只有Exception类的对象(例外/异常)。
抛出一个异常,就是抛出该异常的对象,如果不对其进行捕捉,就由JVM来捕捉,JVM捕捉到该异常后, 就把异常信息打印到控制台。
Exception有两类:
(a)Runtime exception(运行时异常)可以在编程时避免,可处理可不处理. 。总是由虚拟机 接管。比如:我们从来没有人去处理过NullPointerException 异常,它就是运行时异常,并且这种异常还是最常见的异常之一。
(b) checked exception(编译时异常)必须进行处理。对于这种异常, JAVA 编译器强制要求我们必需对出现的这些异常进行catch 。所以,面对这种异常不管我们是否愿意,只能自己去写一大堆catch 块去处理可能的异常
-
注意:
当一个方法中出现了异常,没有进行异常处理,方法就会把异常对象作为返回值返回。如果有异常进入虚拟机,那么虚拟机就会立刻中止程序的执行。
-
常见异常:
(1)、ArrayIndexOutOfBoundsException 数组越界异常
(2)、NullPointerException 空指针引用异常(引用对象指向空)
(3)、ArithmeticException 除数为0异常
二.自定义异常
示 例
/**
- 银行系统异常的超级父类
*/
public class BankSystemException extends RuntimeException{
public BankSystemException(){
super("银行系统有异常");
}
public BankSystemException(String message){
super(message);
}
}
/**
*银行系统中的异常子类,账户余额不足异常
*/
public class BalanceNotEnoughException extends BankSystemException{
public BalanceNotEnoughException(){
super("账户余额不足");
}
public BalanceNotEnoughException(String message) {
super(message);
}
}
/**
* 银行账户类
*/
public class Account {
//取款
public Account withdraw(double money) throws BalanceNotEnoughException{
if(this.accBalance < money)
throw new BalanceNotEnoughException("账户余额不足,请重新输入取款金额");
else
this.accBalance -= money;
return this;
}
//转账
public Account transferAccount(Account account,double money) throws BalanceNotEnoughException {
if(this.accBalance < money)
throw new BalanceNotEnoughException("账户余额不足,请重新输入转账金额");
else
System.out.println("执行转账业务....");
return this;
}
}
测试类中:
Account account = new Account();
account.setAccBalance(1000);
account.withdraw(1300);
account.transferAccount(null,1200);
1. 自定义异常类:在进行程序开发的过程中,自定义异常类遵循以下四个步骤:
1)首先创建自定义异常类,语法格式:a. 自定义编译时异常类名 extends Exception。
b.自定义运行时异常类名 extends RuntimeException。
2)在方法中通过关键字throw抛出异常对象。
3)若是在当前抛出异常的方法中处理异常,可以用try-catch语句捕获并处理;若不是,在方法的声明处通过关键字throws指明要抛出给方法调用的异常。
4)在出现异常方法的调用中捕获并处理异常。
2. throws关键字
(1)在定义一个方法的时候,可以使用throws关键字声明,使用throws声明的方法表示此方法不处理异常,而是交给方法的调用处去处理。
(2)throws使用格式:
public 返回值类型 方法名称(参数列表)throws 异常类{}
3. throw关键字
throw关键字的作用是在程序抛出一个异常,抛出的是一个异常类的实例化对象。
与throws不同的是,可以直接使用throw抛出一个异常。抛出的时候直接抛出异常类的实例化对象即可。
4. 异常的处理
处理原则: 自己的问题 自己处理。
(1)抛给调用方处理,在方法处throws XXException
(2)使用try-catch处理
5. 异常处理try-catch-finally
(1)、try{} 把可能会出现异常的代码放入try块中。
(2)、catch(XX xx){} 捕获异常,并进行相应处理。
A.一个try{} 多个catch{}
B.万能捕捉器 Exception
C.注意使用万能捕捉器的顺序,先子类后父类
(3)finally :写资源释放的代码 。
6. 语法使用:
try{} 和catch(){},catch(){}
try{} 和catch(){}及finally{}
try{} 和finally{}
try{} 和catch(){} .....try{} 和catch(){}
try{
//捕捉异常的语句
}catch(异常类 异常对象){
//异常的处理语句
}catch(异常类 异常对象){
//异常的处理语句
}
[finally{
//一定会执行的语句
}]
-
注意:
try{
}catch(…Exception e){
}
try{
}catch(…Exception e){
}
public void transfer(Account anotherAccount,double money) throws AccountNotFoundException, ParseException{} try { account1.transfer(account2, 1000000); }catch (AccountNotFoundException e){ //异常处理 } catch (ParseException e) { //异常处理 }
-
try{
try{}catch(){
}
}catch(){
}
(1).catch块一定要与try块一起使用,不能够单独使用catch语句块;
(2).一个try块可以有多个catch块,但是,多个catch块的排序必须是从特殊到一般异常子类后一个一般是Exception类;
(3).如果不发生异常,catch语句块永远不会执行;
(4).一旦某个catch块被执行后,其他catch就都会被忽略;
(5).try-catch结构是可以嵌套使用的;finally:【出现try之后,资源释放的代码 】。
a)、try 或者 catch代码块执行完成之后。
b)、finally后的代码块是无论如何都会被执行的代码。
一般finally()代码块在写释放资源的代码。
c)finally 代码块中最好不要出现返回语句(return);每个异常出现之后,会在程序中产生一个异常类来实例化对象,之后用
此对象与catch中的异常类型相匹配,如果匹配成功,则执行catch中的内容,
否则向下继续匹配,如果无法成功,程序就出现中断执行的问题。finally 始终能被执行的代码。
面试题:final\finally\finalize分别用在声明场合? -
-
finally 与 return
public 基本数据类型 | 引用数据类型 fun(){
try{
//…
return value;
}catch(…){
//…
return value;
}finally{
value = 新值;
}
}
- (1)finally 与return 谁先执行
- finally: 用于释放资源,节省内存,语法上无论是否有异常,都会执行
- return : 方法结束
- 先执行return ,再执行finally
- (2)在finally中,修改return 的返回值变量,最后返回值究竟有没有发生改变?
-
(1)返回值:基本数据类型,finally 中修改返回值变量,返回值不会改变
- 【值传递】
-
a -----> 10 return ---->10 (copy)
-
(2)返回值:引用数据类型,finally 中修改返回值变量,返回值会改变
- 【地址传递】
-
stu 、return ----->Student("name",'M')
-