第六章 内部类与异常类
6.1 内部类
java中支持在一个类中声明另一个类,这样的类称为内部类,而包含内部类的类称为内部类的外嵌类。
内部类与外嵌类的重要关系如下:
(1)内部类的外嵌类的成员变量在内部类中仍然有效,内部类中的方法也可以调用外部类中的方法。
(2)在内部类的类体中不可以声明类变量和类方法,在外嵌类的类体中可以用内部类声明对象作为外嵌类的成员。
内部类访问规则:
1,内部类可以直接访问外部类的成员,包括私有;
之所以可以直接访问外部类中的成员,是因为内部类中持有了一个外部类的引用,格式:外部类名.this
2,外部类要访问内部类,必须建立内部类对象;
访问格式:
1,当内部类定义在外部类的成员位置上,而且非私有,可以在外部其他类中,可以直接建立内部类对象。
格式:
外部类名.内部类名 变量名=外部对象.內部对象
例如:outer.Inner in=new outer().new Inner();
2,当内部类在成员位置上,就可以被成员修饰符所修饰。
比如,private 将内部类在外部类中进行封装;
static 内部类就具备了static的特性。
当内部类被static修饰后,只能直接访问外部类中的static成员,出现了访问局限。
在外部其他类中,如何直接访问static内部类的非静态成员呢?
new outer.Inner().function();
在外部其他类中,如何直接访问static内部类的静态成员呢?
outer.Inner.function();
注意:当内部类中定义了静态变量,该内部类必须是static的
外部类中的静态方法访问内部类时,内部类也必须是静态的。
当描述事物时,事物的内部还有事物,该事物就用内部类来描述
因为内部类事物在使用外部事物的内容。
</pre><pre class="java" name="code">class outer
{
private static int x=3;
static class Inner//内部类
{
//int x=4;
static void function(){
//int x=6;
System.out.println("inner:"+x);//此时访问的是int x=4;
}
}
/*void method(){
Inner in=new Inner();//创建nner对象
in.function();
}
}
/*class outer2
{
class Inner
{
}
}*/
class Inner2
{
void show(){
System.out.priintln("inner2 show");
}
}
public static void method(){
Inner.function();
}
class InnerClassDemo
{
public static void main(String args[]){
Out.method();
//outer.Inner.function();
//new outer.Inner().function();
//outer out=new outer();
//out.method();
//直接访问内部类中的成员
//outer.Inner in=new outer().new Inner();
//in.function();
}
}
内部类定义在局部时:
1,不可以被成员修饰符修饰;
2,可以直接访问外部类中的成员,因为还持有外部类中的引用,
但是不可以访问它所在的局部中的变量,只能访问final修饰的变量。
内部类仅供它的外嵌类使用,其他类不可以用某个类的内部类声明对象。
例6.1
RedCowFarm.java
public class RedCowForm {
static String formName;
RedCow cow; //内部类声明对象
RedCowForm() {
}
RedCowForm(String s) {
cow = new RedCow(150,112,5000);
formName = s;
}
public void showCowMess() {
cow.speak();
}
class RedCow { //内部类的声明
String cowName = "红牛";
int height,weight,price;
RedCow(int h,int w,int p){
height = h;
weight = w;
price = p;
}
void speak() {
System.out.println("偶是"+cowName+",身高:"+height+"cm 体重:"+
weight+"kg,生活在"+formName);
}
} //内部类结束
}
Example6.1.java
<strong>public class Example6_1 {
public static void main(String args[]) {
RedCowForm form = new RedCowForm("红牛农场");
form.showCowMess();
form.cow.speak();
}
}
</strong>
需要特别注意的是,java编译器生成的内部类的字节码文件的名字和通常的类不同,内部类对应的字节码文件的名字格式是”外嵌类名$内部类名“,例如上例中内部类的字节码文件是RedCowFarm$RedCow.class.
6.2匿名类
6.2.1和类有关的匿名类
java用户允许用户直接使用一个类的子类的类体创建一个子类对象,在创建子类对象时,除了使用父类的构造方法外还有类体,此类体被认为是一个子类去掉类声明后的类体,称为匿名类。匿名类就是一个子类,由于无名可用,所以不能用匿名类声明对象,但却可以用匿名类创建一个对象。
假设People 是类,那么下列代码就是用People类的一个子类(匿名类)创建对象:
new People(){
匿名类的类体
};
因此,匿名类可以继承父类的方法,也可以重写父类的方法。匿名类一定是内部类,匿名类可以访问外嵌类的成员变量和方法,匿名类的类体中不可以声明static成员和static 方法。
例6.2
Example6_2
6.2..2和接口有关的匿名类
假设Computable是一个接口,那么,java允许直接用接口名和一个类体创建一个匿名对象,此类被认为是实现了 Computable接口的类去掉类声明后的类体,称为匿名类。下列代码用实现了Computable接口的类(匿名类)创建对象。
new Computable(){
实现接口的匿名类的类体
};
如果某个方法的参数是接口类型,那么可以使用接口名和类体组合创建一个匿名对象传递给方法的参数,但类体必须重写接口中的所有方法。
例如:
void f(Computable x)
其中,参数x是接口,那么在调用f时,可以向f的参数x传递一个匿名对象,例如:
f(new Computable(){
实现接口的类体
})
例6.3
6.3 异常类
1,异常:就是程序在运行时出现的不正常情况;(就是对问题的描述,将问题进行封装)
异常体系:
Throwable
——Eroor
____Exception
____RuntimeException
异常体系的特点:异常体系中的所有类以及建立的对象都具有可抛性,也就是说,可以被throw和throws关键字所操作。只有异常体系具备这个特点。
throw和throws的用法:
throw定义在函数内,用于抛出异常对象,而throws用于抛出异常类,可以抛出多个用逗号隔开。
当函数内容有throw抛出异常对象,并未进行try处理,必须要在函数上声明,否则编译失败。
注意:
runtimeException除外,也就是说,函数内抛出的RuntimeException异常,函数上可以不用声明。
如果函数声明了异常,调用者需要进行处理。处理方式可throw可try。
异常有两种:
编译时被检测异常,该异常在编译时,如果没有处理,编译失败。该异常被标识,代表可以被处理。
运行时异常(编译时不检测)
在编译时,不需要处理,编译器不检查。
该异常发生,建议不处理,让程序停止,需要对代码进行修正。
异常处理语句:
try{
需要被检测代码
}
catch{
处理异常的代码
}
finally{
一定会被执行的代码
}
有三种结合格式:
1,
try{}
finally{}
2,
try{}
catch{}
3,
try{}
catch{}
finally{}
注意:1finally中定义的通常是关闭资源代码,因为资源必须释放。
2,finally只有一种情况不被执行,当执行到System.exit(0)——(系统退出时)
/*有一个圆形和长方形,都可以获取面积,对于面积如果出现非法的数值,视为是获取面积出现问题,问题通过异常来表示。
现有对这个程序进行基本设计
*/
</pre></div><div style="top: 62px;"><pre class="java" name="code">
</pre></div><div style="top: 62px;"><pre class="java" name="code">如果长度为负数,原来的处理方法:
interface Shape
{
void getArea();
}
class Rec implements Shape
{
private int Len,wid;
Rec(int Len,int wid){
if(Len<=0||wid<=0)
System.out.println("错啦");
else{
this.Len=Len;
this.wid=wid;
}
}
public void getArea(){
System.out.println(Len*wid);
}
}
class ExceptionTest1
{
public static void main(String args[]){
Rec r=new Rec(-3,4);
r.getArea();
}
}
/*有一个圆形和长方形,都可以获取面积,对于面积如果出现非法的数值,视为是获取面积出现问题,问题通过异常来表示。
现有对这个程序进行基本设计
*/
class NovalueException extends RuntimeException
{
NovalueException(String message){
super(message);
}
}
interface Shape
{
void getArea();
}
class Rec implements Shape
{
private int Len,wid;
Rec(int Len,int wid)//throws NovalueException
{
if(Len<=0||wid<=0)
throw new NovalueException("出现非法值");
this.Len=Len;
this.wid=wid;
}
public void getArea(){
System.out.println(Len*wid);
}
class Circle implements Shape
{private int radius;
public static final double PI=3.14;
Circle(int radius)
{if(radius<=0)
throw new RuntimeException("非法");
this.radius=radius;
}
public void getArea()
{
System.out.println(radius*radius*PI);
}
}
}
class ExceptionTest1
{
public static void main(String args[]){
Rec r=new Rec(3,4);
r.getArea();
Circle c =new Circle(-8);
System.out.println("over");
}
}
class Demo
{
int div(int a,int b){
return a/b;
}
}
class ExceptionDemo
{
public static void main(String args[]){
Demo d=new Demo();
try
{
int x=d.div(4,0);
System.out.println("x="+x);
}
catch (Exception e)
{
System.out.println("除零啦");
}
System.out.println("over");
}
}
public class Example6_4
{
public static void main(String args[]){
int n=0,m=0,t=6666;
try{
m=Integer.parseInt("8888");
n=Integer.parseInt("ab85");
t=9999;
}
catch(NumberFormatException e){
System.out.println("发生异常:"+e.getMessage());
n=123;
}
System.out.println("n="+n+",m="+m+",t="+t);
}
}
<strong><span style="font-size:18px;">3,对捕获到的异常对象进行常见方法操作。</span></strong>
<strong><span style="font-size:18px;">String getMessage();</span></strong>
</pre><pre class="java" name="code">
<span style="font-size:18px;"><strong>6.3.2自定义异常类</strong></span>
<strong><span style="font-size:18px;">我们也可以扩展Exception类定义自己的异常类,然后规定哪些方法产生这样的异常。一个方法在声明时可以使用throws关键字声明要产生的若干个异常,并在该方法的方法体中具体给出产生异常的操作,即用相应的异常类创建对象,并使用throw关键字抛出该异常对象,导致该方法结束执行。</span></strong>
<strong><span style="font-size:18px;">程序必须在try-catch块语句中调用能发生异常的方法,其中,catch的作用就是捕获throw方法抛出的异常对象。</span></strong>
<strong><span style="font-size:18px;"><span style="color:#ff0000;">注意</span>:throw是java的关键字,作用就是抛出异常,throw和throws是两个不同的关键字。</span></strong>
<strong><span style="font-size:18px;">例6.5</span></strong>
<span style="font-size:18px;">
</span>
<span style="font-size:18px;">
</span>
<span style="font-size:24px;"><strong>6.4 finally语句</strong></span>
<strong><span style="font-size:24px;">语法格式如下:</span></strong>
<span style="font-size:24px;"></span><pre class="java" name="code">try{}
catch(ExceptionSubClass e){}
finally{}
<strong><span style="font-size:18px;"><span style="color:#ff0000;">注意</span>以下两种特殊情况:</span></strong>
<strong><span style="font-size:18px;">1,如果在try-catch语句中执行了return语句,那么finally子语句任然会被执行。</span></strong>
<strong><span style="font-size:18px;">2,如果在try-catch语句中执行了程序退出代码,即执行了System.exit(0),将不执行finally字语句(当然包括其后的所有语句)</span></strong>
<strong><span style="font-size:18px;">例6.6</span></strong>
<pre class="java" name="code"><span style="font-size:18px;"><strong>DangerException.java
public class DangerException extends Exception {
final String message = "超重";
public String warnMess() {
return message;
}
}
CargoBoat.java
public class CargoBoat {
int realContent; //装载的重量
int maxContent; //最大装载量
public void setMaxContent(int c) {
maxContent = c;
}
public void loading(int m) throws DangerException {
realContent += m;
if(realContent>maxContent) {
throw new DangerException();
}
System.out.println("目前装载了"+realContent+"吨货物");
}
}
Example6_6.java
public class Example6_6 {
public static void main(String args[]) {
CargoBoat ship = new CargoBoat();
ship.setMaxContent(1000);
int m = 600;
try{
ship.loading(m);
m = 400;
ship.loading(m);
m = 367;
ship.loading(m);
m = 555;
ship.loading(m);
}
catch(DangerException e) {
System.out.println(e.warnMess());
System.out.println("无法再装载重量是"+m+"吨的集装箱");
}
finally {
System.out.printf("货船将正点启航");
}
}
}
<span style="font-size:24px;">6.5断言语句</span>
断言语句在调试代码阶段非常有用,断言语句一般用于程序不准备通过捕获异常来处理的错误。</strong></span>
<span style="font-size:18px;"><strong>例如,当发生某个错误时,要求程序必须立即停止执行,在调试代码阶段让断言语句发挥作用,这样可以发现一些致命的错误,当程序正式运行时就可以关闭断言语句,但任把断言语句保留在源代码中,如果以后应用程序又需要调试,可以重新启用断言语句。</strong></span>
<span style="font-size:18px;"><strong>
</strong></span>
<span style="font-size:18px;"><strong>使用关键字assert声明一条断言语句,断言语句有以下两种格式:</strong></span>
<span style="font-size:18px;"><strong>assert booleanExpression;</strong></span>
<span style="font-size:18px;"><strong>assert booleanExpression.messageException;</strong></span>
<span style="font-size:18px;"><strong>其中,booleanEXpression必须是值为boolean型的表达式;</strong></span>
<span style="font-size:18px;"><strong> messageException可以是值为字符串的表达式。</strong></span>
<span style="font-size:18px;">
</span>
<span style="font-size:18px;"><strong>如果使用assert booleanExpression;形式的断言语句,当booleanExpression的值是false时,程序从断言处停止执行,当booleanExpression的值是true时,程序从断言处语句继续执行。</strong></span>
<span style="font-size:18px;">
</span>
<span style="font-size:18px;"><strong>如果使用assert booleanExpression.messageException;形式的断言语句,当booleanExpression的值是flase时,程序从断言语句处停止执行,并输出messageException的表达式的值,提示用户出现了怎样的问题;当booleanExpression的值是true时,程序从断言处继续执行。</strong></span>
<span style="font-size:18px;">
</span>
<span style="font-size:18px;"><strong>当使用java解释器直接运行应用程序时,默认关闭断言语句,在调试程序时可以用—ea启用断言语句,例如:</strong></span>
<span style="font-size:18px;"><strong>Java—ea mainclass</strong></span>
<span style="font-size:18px;"><strong>
</strong></span>
<span style="font-size:18px;"><strong>例6.6
</strong></span>
</pre><pre class="java" name="code">
</pre></div><div style="top: 62px;"><pre class="java" name="code">
</pre></div><div style="top: 62px;"><pre class="java" name="code">
<span style="font-size:24px;"><strong>自定义异常:</strong></span>
异常的好处:
1,将问题进行封装;
2,将正常流程代码和问题处理代码相分离,方便于阅读;
异常的处理原则:
1,处理方式有两种:try或者throw
2,调用到抛出异常的功能时,抛出几个,就处理几个。
一个try对应多个catch;
3,多个catch,父类的catch放到最下面;
4,catch内,需要定义针对性的处理方式,不要简单的定义printStackTrace,输出语句,也不要不写。
当捕获到的异常,本功能处理不了时可以继续在catch中抛出。
try
{
throw new AException();
}
catch(AException e)
{
throw e;
}
如果该异常处理不了,但并不属于该功能出现的异常,可以讲异常转换后,再抛出和给功能相关的异常。
或者异常可以处理,当需要将异常产生的和本功能相关的问题提供出去,当调用者知道,并处理,也可以将捕获异常处理后,转换新的异常。
try
{throw new AException();
}
catch (AException e)