您的位置:首页 > 职场人生

黑马程序员——Java基础—面向对象(四)

2015-04-03 08:01 176 查看
———Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ———

一内部类

二匿名内部类

三异常机制

面向对象(四)

一、内部类

1.内部类的定义

将一个类定义在另一个类的内部,这个内部的类就被成为内部类(内置类,嵌套类)。

2.内部类的特点

1)内部类可以直接访问外部类的成员,包括私有成员(成员前省略了
外部类名.this.
);

2)外部类要访问内部类的成员,必须建立内部类的对象,通过内部类对象访问

示例代码:

package com.heisejiuhuche;

public class TestInnerClass {
public static void main(String[] args) {
Outer out = new Outer();
out.methodOut();
}
}

class Outer {
//声明私有成员变量x
private int x = 3;

//声明内部类
class Inner {
void methodIn() {
//内部类直接调用外部类成员x
System.out.println("Inner: " + x);
}
}

void methodOut() {
//外部类要访问内部类的成员,必须先创建内部类对象
Inner in = new Inner();
//由内部类对象调用内部类成员
in.methodIn();
}
}


程序输出结果为:

Inner: 3


3)当内部来在外部类的成员位置上时,可以被
private
关键字修饰,进行封装

示例代码:

package com.heisejiuhuche;

public class TestInnerClass {
public static void main(String[] args) {

}
}

class Outer {
//声明私有内部类,内部类在成员位置上时,可以被private关键字修饰
private class Inner {
void methodIn() {

}
}
}


4)外部其他类直接访问内部类成员(内部类声明在外部来成员位置上,且非私有)

示例代码:

package com.heisejiuhuche;

public class TestInnerClass {
public static void main(String[] args) {
//直接访问内部类成员格式
Outer.Inner oi = new Outer().new Inner();
oi.methodIn();
}
}

class Outer {
//声明成员变量x
int x = 3;
//声明内部类
class Inner {
void methodIn() {
//内部类直接调用外部类成员x
System.out.println("Inner: " + x);
}
}
}


5)不涉及特有数据的时候,内部类可以被
static
关键字修饰,具备静态特性

内部类被静态修饰后,只能访问外部类的静态成员,有访问局限性。外部其他类直接访问静态内部类的非静态成员的方式为:

new 外部类名.内部类名().静态内部类的非静态成员;


示例代码:

package com.heisejiuhuche;

public class TestInnerClass {
public static void main(String[] args) {
//访问静态内部类的非静态成员的格式
new Outer.Inner().methodIn();
}
}

class Outer {
//声明成员变量x
static int x = 3;
//声明静态内部类
static class Inner {
void methodIn() {
System.out.println("Inner: " + x);
}
}
}


外部其他类直接访问静态内部类的静态成员的方式为:

package com.heisejiuhuche;

public class TestInnerClass {
public static void main(String[] args) {
//访问静态内部类的静态成员的格式
Outer.Inner.methodIn();
}
}

class Outer {
//声明成员变量x
static int x = 3;
//声明静态内部类
static class Inner {
static void methodIn() {
System.out.println("Inner: " + x);
}
}
}


6)内部类中若声明了静态成员,该内部类必须是静态的

7)外部类的静态方法访问内部类时,内部类必须是静态的

8)重名变量注意事项

示例代码:

package com.heisejiuhuche;

public class TestInnerClass {
public static void main(String[] args) {
Outer out = new Outer();
out.methodOut();
}
}

class Outer {
//声明成员变量x
int x = 3;

//声明内部类
class Inner {
int x = 4;
void methodIn() {
int x = 5;
//内部类直接调用外部类成员x
System.out.println("Inner: " + x);
}
}

void methodOut() {
//外部类要访问内部类的成员,必须先创建内部类对象
Inner in = new Inner();
//由内部类对象调用内部类成员
in.methodIn();
}
}


程序输出结果为:

Inner: 5


如果要输出4,输出语句应为
System.out.println("Inner: " + this.x);


如果要输出3,输出语句应为
System.out.println("Inner: " + Outer.this.x);


9)内部类可以被定义在局部位置上

内部类定义在局部位置上的示例及特点

示例代码:

package com.heisejiuhuche;

public class TestInnerClass2 {
public static void main(String[] args) {
new Outer().methodOut();
}
}

class Outer {
int x = 3;

void methodOut() {
//声明内部类于外部类的方法中
class Inner {
void methodIn() {
//同样可以直接访问外部类成员
System.out.println("Inner: " + x);
}
}
//创建Inner()匿名对象调用methodIn()方法
new Inner().methodIn();
}
}


特点:

1> 不可以被成员修饰符修饰,如
private


2> 仍持有外部类的引用,仍可以直接访问外部类的成员

3> 如果要访问其所在局部的局部变量,要用
final
修饰该变量

3.内部类的应用

描述事物的时候,如果事物内部还包含有事物。由于该内部事物在使用外部事物的内容,所以该内部的事物用内部类来描述。如描述人体的时候,人体由器官组成,包括心脏;心脏有属性(成员变量),行为(成员方法),比较复杂(应声明成一个类),心脏又和人体其他器官有直接的联系(需要直接访问外部类的成员),那么应将心脏作为对象封装,形成人体的内部类,并私有,对外提供方法访问。

二、匿名内部类

1.定义

没有名字的内部类叫做匿名内部类,即内部类的简写格式

2.匿名内部类使用的前提

内部类必须继承一个类或者实现接口

示例代码:

package com.heisejiuhuche;

public class TestAnonymousInnerClass {
public static void main(String[] args) {
new Outer2().methodOut();
}
}

abstract class Abs {
abstract void show();
}

class Outer2 {
int x = 3;

public void methodOut() {
//匿名内部类继承Abs类
new Abs() {
void show() {
System.out.println("Anonymous Inner: " + x);
}
}.show();
}
}


3.匿名内部类是一个匿名子类对象,是一个带内容的对象,是将定义类和创建对象封装为一体的表现方式,为了简化书写,方便方法调用而存在

匿名内部类就是一个子类继承父类的类体,除了复写父类的方法,还能在匿名内部类中定义子类的特有方法(面试用)

示例代码:

package com.heisejiuhuche;

public class TestAnonymousInnerClass {
public static void main(String[] args) {
new Outer2().methodOut();
}
}

abstract class Abs {
abstract void show();
}

class Outer2 {
int x = 3;

public void methodOut() {
//匿名内部类继承Abs类
new Abs() {
void show() {
System.out.println("Anonymous Inner Class: " + x);
}

void run() {
System.out.println("Anonymous Inner Class run...")
}
}.run();
}
}


匿名内部类中的方法不要超过3个

4.匿名内部类的应用

示例代码:

package com.heisejiuhuche;

public class TestAnonymInnerClassUse {

public static void main(String[] args) {
/*
* 使用匿名内部类作为参数
*/
show(new Inter() {
public void method() {
System.out.println("Run...");
}
});
}

/* 调用一个方法,这个方法需要接收一个接口对象作为参数
* 并且这个接口里面的方法不超过3个
* 那么就可以用匿名内部类
*/
static void show(Inter in) {
in.method();
}
}

interface Inter {
public abstract void method();
}


5.匿名内部类练习

根据
main
方法中的代码,补全其他代码

示例代码:

package com.heisejiuhuche;

/**
* 根据main方法中的代码,补全Outer类
* @author jeremy
*
*/

public class TestAnonymInner {
public static void main(String[] args) {
/*
* 从这行代码分析:
* 1.由于由类名直接调用,所以function()方法是一个静态方法
* 2.由于method()一定是被一个对象所调用,所以Outer类在调用function()方法之后,返回值一定是一个对象
* 3.由于method()方法在Inter接口中,那么一定是一个类实现了Inter接口,然后复写了method()方法,并调用
*   该类的对象一定是Inter类型的对象,所以function()方法的返回值为Inter类型
*/
Outer.function().method();
}
}

interface Inter {
public abstract void method();
}

class Outer {

static Inter function() {
return new Inter() {
public void method() {
System.out.println("Anonymous Inner Class run...");
}
};
}
}


小扩展(面试用):

没有实现接口,也没有继承任何父类,仍然可以使用匿名内部类调用方法;只需使用所有类的父类
Object
类即可

示例代码:

class InnerTest {
public static void main(String[] args) {
new Object() {
public void method() {
System.out.println("Run...");
}
}.method();
}
}


三、异常机制

1.定义

异常是程序在运行(非编译)过程中出现的不正常情况。异常用来描述生活中出现的问题,也是一个对象。

2.问题的分类

Java对于问题的描述分为两大类,有严重与非严重之分。对于严重的问题,Java用
Error
类来描述,称为错误;对于非严重的问题,Java用
Exception
类进行描述,称为异常。

1)对于
Error
,一般不编写针对性的代码进行处理;

2)对于
Exception
,可以针对性的编写代码进行处理

Error
Exception
都是
Throwable
的子类

3.异常的处理

Java提供了特定的语句对异常进行处理:

示例代码:

try {
运行时可能会出现异常的代码;
} catch() {
处理异常的代码;
} finally {
一定会执行的语句;
}


示例代码:

package com.heisejiuhuche;

public class TestException {
public static void main(String[] args) {
/* try catch语句,用于检测异常,并做出相应处理 */
try {
int x = Divide.div(7, 1);
System.out.println(x);
} catch(Exception e) {
System.out.println("Divide by zero...");
}
System.out.println("End...");
}
}

/* 除法类,有一个方法,返回两个int类型参数相除的结果 */
class Divide {
public static int div(int a, int b) {
return a / b;
}
}


4.异常对象常见方法

1)getMessage()

示例代码:

//显示异常信息
System.out.println(e.getMessage());
/ by zero


2)toString()

示例代码:

//显示异常名称+异常信息
System.out.println(e.toString());
java.lang.ArithmeticException: / by zero


3)printStackTrace()(JVM默认异常处理机制调用该方法)

示例代码:

//显示异常名称+异常信息+异常出现的位置
e.printStackTrace();
java.lang.ArithmeticException: / by zero
at com.heisejiuhuche.Divide.div(TestException.java:20)
at com.heisejiuhuche.TestException.main(TestException.java:7)


5.throws关键字

由于编写功能代码的时候,不知道调用者会不会传入非法参数,导致异常。那么,开发者应该在功能上,通过
throws
关键字先声明,这个功能可能会抛出异常。

示例代码:

package com.heisejiuhuche;

public class TestException {
public static void main(String[] args) {
int x = Divide.div(7, 0);
System.out.println(x);
System.out.println("End...");
}
}

class Divide {
public static int div(int a, int b) throws Exception {
return a / b;
}
}


throws
关键字表示该方法的调用者一定要处理这个异常,否则编译失败。上述代码,在主函数中没有对可能出现的异常做任何处理,程序编译报错:

Exception in thread "main" java.lang.Error: Unresolved compilation problem:
Unhandled exception type Exception
at com.heisejiuhuche.TestException.main(TestException.java:6)


处理
throws
关键字有两种方式:

1)抛出异常

示例代码:

package com.heisejiuhuche;

public class TestException {
//在main方法上也加上throws声明
public static void main(String[] args) throws Exception {
int x = Divide.div(7, 1);
System.out.println(x);
System.out.println("End...");
}
}

class Divide {
public static int div(int a, int b) throws Exception {
return a / b;
}
}


在调用
div()
方法的主函数上,也加上
throws
关键字,将可能出现的异常抛出给虚拟机。抛给虚拟机之后,虚拟机启用默认异常处理机制,如果有异常,直接终止程序,打印异常信息。

2)捕捉异常

示例代码:

package com.heisejiuhuche;

public class TestException {
public static void main(String[] args) {
//用try catch捕捉异常并处理
try {
int x = Divide.div(7, 1);
System.out.println(x);
} catch(Exception e) {
System.out.println(e.printStackTrace());
}
System.out.println("End...");
}
}

class Divide {
public static int div(int a, int b) throws Exception {
return a / b;
}
}


预先编写处理代码
try catch
,对可能出现的异常进行处理。

6.多异常处理

1)一个功能可能出现多个异常,那么在用
throws
关键字声明异常的时候,应该声明多个;并且声明更为具体的异常,便于处理

声明具体异常示例代码:

package com.heisejiuhuche;

public class TestException {
public static void main(String[] args) {
try {
int x = Divide.div(7, 1);
System.out.println(x);
} catch(ArithmeticException e) {
System.out.println(e.printStackTrace());
}
System.out.println("End...");
}
}

class Divide {
//声明具体的ArithmeticException
public static int div(int a, int b) throws ArithmeticException {
return a / b;
}
}


将异常声明为更加具体的
ArithmeticException
,那么在处理的时候直接处理这个具体异常即可。

声明多个异常示例代码:

package com.heisejiuhuche;

import javax.management.openmbean.ArrayType;

public class TestException {
public static void main(String[] args) {
try {
int x = Divide.div(3, 1);
System.out.println(x);
} catch(ArithmeticException e) { //处理ArithmeticException
System.out.println(e.toString());
System.out.println("Divide by zero...");
} catch(ArrayIndexOutOfBoundsException e) { //处理ArrayIndexOutOfBoundsException
System.out.println(e.toString());
System.out.println("Index out of bounds...");
}
System.out.println("End...");
}
}

class Divide {
//功能可能抛出ArithmeticException和ArrayIndexOutOfBoundsException
public static int div(int a, int b) throws ArithmeticException, ArrayIndexOutOfBoundsException {
int[] arr = new int[a];
System.out.println(arr[7]);
return a / b;
}
}


功能代码中抛出的所有异常,调用者要逐一进行具体捕捉,并处理。

2)注意,如果
catch
的异常出现继承关系,父类异常放在最下面(不建议这么做,具体处理最好,不要直接处理
Exception


示例代码:

catch(ArithmeticException e) {
System.out.println(e.toString());
System.out.println("Divide by zero...");
} catch(ArrayIndexOutOfBoundsException e) {
System.out.println(e.toString());
System.out.println("Index out of bounds...");
} catch(Exception e) {
System.out.println(e.toString());
System.out.println("Over...");
}


3)现实开发异常处理

现实开发中,开发者不会将错误信息打印在屏幕上,这没有意义。开发中应该将错误信息,保存在硬盘某个文件里,由开发者及时查阅,并修正程序。

7.自定义异常

实际开发中,程序会出现特有的问题,而这些问题没有被Java描述到并封装成对象。那么对于这些问题,可以按照Java对问题的封装思路,对特有问题进行自定义封装。例如,如果在一个程序(功能)中,除数不能为0,同时除数不能是负数,如果是负数,也视为异常。这个异常,就需要开发者自定义。

Java已经描述并封装成对象的异常,开发者可以选择由程序自动抛出,也可以选择手动抛出;而自定义异常,开发者只能选择手动抛出。手动抛出异常,用
throw
关键字。

1)定义异常类

示例代码:

package com.heisejiuhuche;

class NegativeException extends Exception {

}

class Divide {
public static int div(int a, int b) throws NegativeException {
if(b < 0) {
//通过throw关键字,手动抛出自定义异常对对象
throw new NegativeException();
}
return a / b;
}
}


当方法内出现
throw
抛出的异常对象,就必须要给出相应的处理。要么在方法内部
try catch
;要么在方法上声明异常,让调用者处理(运行时异常除外)。一般情况下,方法内部出现异常,方法上需要声明异常。那么主函数(方法调用者)必须对异常进行处理(运行时异常除外)。

示例代码:

public class TestException {
public static void main(String[] args) throws Exception {
try {
int x = Divide.div(7, 1);
System.out.println(x);
} catch(NegativeException e) {
System.out.println("Negative divisor...")
}
System.out.println("End...");
}
}


程序输出结果为:

com.heisejiuhuche.NegativeException
Negative divisor...
End...


2)定义异常信息

由于
Throwable
类中已经对异常信息进行了操作(初始化,获取等),所以子类只需要在构造函数中调用父类的构造方法,将异常信息传递给父类,即可使用。

Throwable
类对异常信息的基本处理代码示例:

class Throwable {
pricate String message;

Throwable(String message) {
this.message = message;
}

public String getMessage() {
return message;
}
}


因此,子类自定义异常信息代码示例:

package com.heisejiuhuche;

public class CutomizeException {
public static void main(String[] args) {
try {
int x = Divide1.div(3, -1);
System.out.println(x);
} catch(NegativeException e) { //捕捉自定义异常
System.out.println(e.toString());
}
System.out.println("End...");
}
}

class Divide1 {
public static int div(int a, int b) throws NegativeException {
if(b < 0) {
//抛出自定义异常
throw new NegativeException("Negative divisor...");
}
return a / b;
}
}

class NegativeException extends Exception {
//定义异常信息
NegativeException(String msg) {
//调用父类的构造方法,获取自定义异常信息
super(msg);
}
}


程序输出结果为:

com.heisejiuhuche.NegativeException: Negative divisor...
End...


3)自定义异常方法

上述代码中,定义一个异常方法,获取出错的负数值。

示例代码:

package com.heisejiuhuche;

public class CutomizeException {
public static void main(String[] args) {
try {
int x = Divide1.div(3, -10);
System.out.println(x);
} catch(NegativeException e) {
System.out.println(e.toString());
System.out.println("Wrong divisor is: " + e.getNum());//打印错误值
}
System.out.println("End...");
}
}

class Divide1 {
public static int div(int a, int b) throws NegativeException {
if(b < 0) {
throw new NegativeException("Negative divisor...", b);
}
return a / b;
}
}

class NegativeException extends Exception {
private int num; //声明私有变量,用于存储错误数据

NegativeException(String msg, int num) {
super(msg);
this.num = num; //初始化错误数据
}

public int getNum() {
return num; //获取错误值
}
}


程序输出结果为:

com.heisejiuhuche.NegativeException: Negative divisor...
Wrong divisor is: -10
End...


8.throws和throw关键字的区别

1)
throws
使用在方法上;
throw
使用在方法内;

2)
throws
后面跟异常类,可以跟多个;
throw
后面跟异常对象

9.运行时异常(RuntimeException)

1)异常的分类

1> 编译时被检测的异常(非运行时异常及其子类)

方法中抛出了非运行时异常及其子类,方法上必须声明;方法上声明了非运行时异常及其子类,调用者必须进行捕捉处理

2> 编译时不被检测的异常(运行时异常及其子类)

2)运行时异常定义

RuntimeException
(运行时异常)是
Exception
里一个很特殊的异常。其特点有:

1> 运行时异常在方法内抛出,方法上不需要声明;

2> 运行时异常在方法上声明,调用者可以不用进行处理

示例代码:

package com.heisejiuhuche;

public class CutomizeException {
public static void main(String[] args) {
//运行时异常无须调用者进行处理,可以没有try catch,编译通过
int x = Divide1.div(3, 0);
System.out.println(x);
System.out.println(e.toString());
}
System.out.println("End...");
}
}

class Divide1 {
public static int div(int a, int b) {
if(b < 0) {
//运行时异常无须在方法上声明,直接抛出即可,编译通过
throw new ArithmeticException("Negative divisor...");
}
return a / b;
}
}


因为运行时异常,不需要让调用者处理。当运行时异常发生时,出现了无法继续运行的情况,虚拟机希望程序停止,由调用者对程序进行修正,排除异常。

如果自定义异常发生时,程序无法再进行运算,那么就让该自定义异常继承
RuntimeException


示例代码:

class NegativeException extends RuntimeException {
NegativeException(String msg) {
super(msg);
}
}


10.异常练习

老师需要用电脑上课,电脑会出现蓝屏和温度过高烧毁这两个异常。利用异常机制,对每个异常进行处理。

示例代码:

package com.heisejiuhuche;

public class ExceptionTest {
/* 将main方法想像成教育机构的老板,老板命令老师教课 */
public static void main(String[] args) {
Teacher teacher = new Teacher("Glen");
try {
teacher.teach();
} catch(TeachingPlanFailException e) { /* 如果出现电脑烧毁,教学计划失败,老板就炒了老师鱿鱼! */
System.out.println(e.toString());
System.out.println("Glen is fired... 'Cause he broke a computer...");
}
}
}

class Teacher {
private String name;
private Computer computer;

/* 老师初始化时有名字和一台电脑 */
Teacher(String name) {
this.name = name;
computer = new Computer();
}

public void teach() throws TeachingPlanFailException {
try {
computer.run();
} catch(BlueScreenException e) { /* 蓝屏的话,打印蓝屏信息,重启电脑 */
System.out.println(e.toString());
computer.restart();
} catch(BurntException e) { /* 烧毁的话,打印烧毁信息,抛出教学计划失败异常 */
System.out.println(e.toString());
throw new TeachingPlanFailException("Teaching plan fials...");
}
System.out.println("Teacher teaching..."); /* 正常情况,老师上课 */
}
}

class Computer {

/* 电脑状态,1为正常,0为蓝屏,-1为烧毁 */
private int state = -1;

/* 电脑启动方法 */
public void run() throws BlueScreenException, BurntException {
/* 判断状态值,决定正常运行还是抛出相应异常对象 */
if(state == 1) {
System.out.println("Computer run...");
} else if(state == 0) {
throw new BlueScreenException("Blue screen occured...");
} else if(state == -1) {
throw new BurntException("Computer is down...");
}
}

/* 电脑重启方法 */
public void restart() {
state = 1;
System.out.println("Computer restarting...");
}
}

/* 电脑蓝屏异常 */
class BlueScreenException extends Exception {
BlueScreenException(String message) {
super(message);
}
}

/* 电脑烧毁异常 */
class BurntException extends Exception {
BurntException(String message) {
super(message);
}
}

/* 不能直接将烧毁异常抛给老板,老板处理不了,电脑烧毁了,
* 老师会出现教学计划失败异常,应该将这个异常封装成异常类
* 再抛给老板,让老板处理
*/
class TeachingPlanFailException extends Exception {
TeachingPlanFailException(String message) {
super(message);
}
}


———Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ———
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: