Java第四课 Java中内部类的理解、运用与掌握,Java中的异常处理。
2012-02-19 08:57
471 查看
内部类
1.在一个类中定义另外一个类,这个类就叫做内部类或内置类 (inner class) 。
2.
内部类可以让我们将逻辑上相关的一组类组织起来,并由外部类(outer class)来控制内部类的可见性。
3.
当我们建立一个inner class时,其对象就拥有了与外部类对象之间的一种关系,这是通过一个特殊的this reference形成的,使得内部类对象可以随意的访问外部类中所有的成员。
4在方法中定义的内部类,如果要访问方法中定义的本地变量或方法的参数,则变量必须被声明final。
5.
内部类可以声明为private或protected;还可以声明为abstract或final。
6.
内部类可以声明为static的,但此时就不能再使用外部类的非static的成员变量和非static的成员方法;
7.非static的内部类中的成员不能声明为static的,只有在顶层类或static的内部类中才可声明static成员。
内部类实现接口
用内置类实现C++多继承才能实现的功能
我们为什么使用内部类
1、在内部类(inner class)中,可以随意的访问外部类的成员,这可以让我们更好地组织管理我们的代码,增强代码的可读性。
2、内部类可以用于创建适配器类,适配器类是用于实现接口的类。使用内部类来实现接口,可以更好地定位与接口关联的方法在代码中的位置。
3、内部类的更多用法。
异常处理
1.打开一个不存在的文件、网络连接中断、数组下标越界、正在加载的类文件丢失等都会引发异常。
2.Java中的异常类定义了程序中遇到的轻微的错误条件。
3.Java中的错误类定义了程序中不能恢复的严重错误条件。如内存溢出、类文件格式错误等。这一类错误由Java运行系统处理,不需要我们去处理。
4.Java程序在执行过程中如出现异常,会自动生成一个异常类对象,该异常对象将被提交给Java运行时系统,这个过程称为抛出(throw)异常。
5.当Java运行时系统接收到异常对象时,会寻找能处理这一异常的代码并把当前异常对象交给其处理,这一过程称为捕获(catch)异常。
6.如果Java运行时系统找不到可以捕获异常的方法,则运行时系统将终止,相应的Java程序也将退出。
7.try/catch/finally语句。
8.对于RuntimeException,通常不需要我们去捕获,这类异常由Java运行系统自动抛出并自动处理。
9.如果父类中的方法抛出多个异常,则子类中的覆盖方法要么抛出相同的异常,要么抛出异常的子类,但不能抛出新的异常(注:构造方法除外)。
10.我们可以在方法声明时,声明一个不会抛出的异常,Java编译器就会强迫方法的使用者对异常进行处理。这种方式通常应用于abstract base class和interface中。
Java编程规范
1.package的命名
package 的名字由全部小写的字母组成,例如:cn.mybole。
2.class和interface的命名
class和interface的名字由大写字母开头而其他字母都小写的单词组成,例如:Person,RuntimeException。
3.class变量的命名
变量的名字用一个小写字母开头,后面的单词用大写字母开头,例如:index,currentImage。
4.class方法的命名
方法的名字用一个小写字母开头,后面的单词用大写字母开头,例如:run(),getBalance()。
5.static final变量的命名
static final变量的名字所有字母都大写,并且能表示完整含义。例如:PI,PASSWORD。
6.参数的命名
参数的名字和变量的命名规范一致。
7.数组的命名
数组应该总是用这样的方式来命名:byte[] buffer。
JVM 规格描述
JVM指令系统
JVM指令系统同其他计算机的指令系统极其相似。Java指令也是由操作码和操作数两部分组成。操作码为8位二进制数,操作数紧随在操作码的后面,其长度根据需要而不同。操作码用于指定一条指令操作的性质(在这里我们采用汇编符号的形式进行说明),如iload表示从存储器中装入一个整数,anewarray表示为一个新数组分配空间,iand表示两个整数的“与”,ret用于流程控制,表示从对某一方法的调用中返回。当长度大于8位时,操作数被分为两个以上字节存放。JVM采用了“big endian”的编码方式来处理这种情况,即高位bits存放在低字节中。这同
Motorola及其他的RISC CPU采用的编码方式是一致的,而与Intel采用的“little endian ”的编码方式即低位bits存放在低位字节的方法不同。 Java指令系统是以Java语言的实现为目的设计的,其中包含了用于调用方法和监视多线程系统的指令。
JVM寄存器
所有的CPU均包含用于保存系统状态和处理器所需信息的寄存器组。如果虚拟机定义较多的寄存器,便可以从中得到更多的信息而不必对栈或内存进行访问,这有利于提高运行速度。然而,如果虚拟机中的寄存器比实际CPU的寄存器多,在实现虚拟机时就会占用处理器大量的时间来用常规存储器模拟寄存器,这反而会降低虚拟机的效率。针对这种情况,JVM只设置了4个最为常用的寄存器。它们是: pc程序计数器 optop操作数栈顶指针 frame当前执行环境指针 vars指向当前执行环境中第一个局部变量的指针 所有寄存器均为32位。pc用于记录程序的执行。optop,frame和vars用于记录指向Java栈区的指针。
JVM栈结构
作为基于栈结构的计算机,Java栈是JVM存储信息的主要方法。当JVM得到一个Java字节码应用程序后,便为该代码中一个类的每一个方法创建一个栈框架,以保存该方法的状态信息。每个栈框架包括以下三类信息: 局部变量 执行环境 操作数栈 局部变量用于存储一个类的方法中所用到的局部变量。vars寄存器指向该变量表中的第一个局部变量。 执行环境用于保存解释器对Java字节码进行解释过程中所需的信息。它们是:上次调用的方法、局部变量指针和操作数栈的栈顶和栈底指针。执行环境是执行一个方法的控制中心。例如:如果解释器要执行iadd(整数加法),首先要从frame寄存器中找到当前执行环境,而后便从执行环境中找到操作数栈,从栈顶弹出两个整数进行加法运算,最后将结果压入栈顶。
操作数栈用于存储运算所需操作数及运算的结果。
JVM碎片回收堆
Java类的实例(对象)所需的存储空间是在堆上分配的。解释器具体承担为类实例分配空间的工作。解释器在为一个实例分配完存储空间后,便开始记录对该实例所占用的内存区域的使用。一旦对象使用完毕,便将其回收到堆中。 在Java语言中,除了new语句外没有其他方法为一对象申请和释放内存。对内存进行释放和回收的工作是由Java运行系统承担的。这允许Java运行系统的设计者自己决定碎片回收的方法。在SUN公司开发的Java解释器和Hot Java环境中,碎片回收用后台线程的方式来执行。这不但为运行系统提供了良好的性能,而且使程序设计人员摆脱了自己控制内存使用的风险。
JVM存储区
JVM有两类存储区:常量缓冲池和方法区。常量缓冲池用于存储类名称、方法和字段名称以及串常量。方法区则用于存储Java方法的字节码。对于这两种存储区域具体实现方式在JVM规格中没有明确规定。这使得Java应用程序的存储布局必须在运行过程中确定,依赖于具体平台的实现方式。
1.在一个类中定义另外一个类,这个类就叫做内部类或内置类 (inner class) 。
2.
内部类可以让我们将逻辑上相关的一组类组织起来,并由外部类(outer class)来控制内部类的可见性。
3.
当我们建立一个inner class时,其对象就拥有了与外部类对象之间的一种关系,这是通过一个特殊的this reference形成的,使得内部类对象可以随意的访问外部类中所有的成员。
4在方法中定义的内部类,如果要访问方法中定义的本地变量或方法的参数,则变量必须被声明final。
5.
内部类可以声明为private或protected;还可以声明为abstract或final。
6.
内部类可以声明为static的,但此时就不能再使用外部类的非static的成员变量和非static的成员方法;
7.非static的内部类中的成员不能声明为static的,只有在顶层类或static的内部类中才可声明static成员。
/*内部类中可以访问外部类中所有成员变量和成员方法 **/ class Outer{ private static int index=100; /*class Inner{ private int index=50; void print(){ int index=30; System.out.println(index);//局部类 System.out.println(this.index);//Inner类成员变量 System.out.println(Outer.this.index);//Outer类成员变量 } }*/ /* void fn(final int a){ //只能在方法内部使用 final int b=3; if(true){//条件语句 class Middle {//语句块 private int index=50; class Inner{ private int index=50; void print(){ int index=30; System.out.println(index);//局部类 System.out.println(Middle.this.index);//Inner类成员变量 System.out.println(Outer.this.index);//Outer类成员变量 //a=5; //b=6; System.out.println(a); System.out.println(b); } } } } }*/ static class Inner{ private int index=50; void print(){ int index=30; System.out.println(index);//局部类 System.out.println(this.index);//Inner类成员变量 System.out.println(Outer.index);//Outer类成员变量 } } void print(){ //Inner inner=new Inner(); //inner.print(); } /*Inner getInner(){ return new Inner(); }*/ /*public static void main(String[] args){ Outer outer=new Outer(); //outer.print(); //Inner inner=outer.getInner(); Inner inner=new Inner();//error inner.print(); }*/ } class Test{ public static void main(String[] args){ Outer outer=new Outer(); //outer.print(); /*Outer.Inner inner=outer.getInner(); inner.print();*/ /*Outer.Inner inner=outer.new Inner(); inner.print();*/ } }
class Car{ class Wheel{ } } class PlaneWheel extends Car.Wheel{ PlaneWheel(Car car){ car.super(); //建立从内部类到外部类的引用关系 } public static void main(String[] args){ Car car=new Car(); PlaneWheel pw=new PlaneWheel(car); } }
内部类实现接口
interface Machine{ void run(); } class Person{ void run(){ System.out.println("run !"); } } class Robot extends Person{ private class MachineHeart implements Machine{ public void run(){ System.out.println("heart run !"); } } Machine getMachine(){ return new MachineHeart(); } } class Test{ public static void main(String[] args){ Robot robot=new Robot(); Machine m=robot.getMachine(); m.run(); robot.run(); } }
interface Animal{ void eat(); void sleep(); } class Zoo{ private class Tiger implements Animal{ public void eat(){ System.out.println("Tiger Eat !"); } public void sleep(){ System.out.println("Tiger Sleep !"); } } //内部类的匿名实现 Animal getAnimal(){ return new Tiger(); /*return new Animal(){ public void eat(){ System.out.println("Animal Eat !"); } public void sleep(){ System.out.println("Animal Sleep !"); } };*/ } } class Test{ public static void main(String[] args){ Zoo z=new Zoo(); Animal an=z.getAnimal(); an.eat(); an.sleep(); } }
用内置类实现C++多继承才能实现的功能
class A{ void fn1(){ } } abstract class B{ abstract void fn2(); } class C extends A{ B getB(){ return new B(){ public void fn2(){ } }; } } class Test{ static void method1(A a){ a.fn1(); } static void method2(B b){ b.fn2(); } public static void main(String [] args){ C c=new C(); method1(c); method2(c.getB()); } }
我们为什么使用内部类
1、在内部类(inner class)中,可以随意的访问外部类的成员,这可以让我们更好地组织管理我们的代码,增强代码的可读性。
2、内部类可以用于创建适配器类,适配器类是用于实现接口的类。使用内部类来实现接口,可以更好地定位与接口关联的方法在代码中的位置。
3、内部类的更多用法。
异常处理
1.打开一个不存在的文件、网络连接中断、数组下标越界、正在加载的类文件丢失等都会引发异常。
2.Java中的异常类定义了程序中遇到的轻微的错误条件。
3.Java中的错误类定义了程序中不能恢复的严重错误条件。如内存溢出、类文件格式错误等。这一类错误由Java运行系统处理,不需要我们去处理。
4.Java程序在执行过程中如出现异常,会自动生成一个异常类对象,该异常对象将被提交给Java运行时系统,这个过程称为抛出(throw)异常。
5.当Java运行时系统接收到异常对象时,会寻找能处理这一异常的代码并把当前异常对象交给其处理,这一过程称为捕获(catch)异常。
6.如果Java运行时系统找不到可以捕获异常的方法,则运行时系统将终止,相应的Java程序也将退出。
7.try/catch/finally语句。
8.对于RuntimeException,通常不需要我们去捕获,这类异常由Java运行系统自动抛出并自动处理。
9.如果父类中的方法抛出多个异常,则子类中的覆盖方法要么抛出相同的异常,要么抛出异常的子类,但不能抛出新的异常(注:构造方法除外)。
10.我们可以在方法声明时,声明一个不会抛出的异常,Java编译器就会强迫方法的使用者对异常进行处理。这种方式通常应用于abstract base class和interface中。
/*catch语句顺序:由特殊到一般 **/ import java.io.*; class Excep{ Excep()throws ArithmeticException{ } public int division(int a,int b) throws ArithmeticException,DivisorIsMinusException/*Exception*/{ //try{ if(b<0) throw new DivisorIsMinusException("Divisor Can't Be Minus !"); return a/b; //} /* catch(Exception e){ e.printStackTrace(); throw new Exception("Can't Divide By Zero !"); //throw e; // return 0; }*/ } public int fn1(int a,int b)throws ArithmeticException,DivisorIsMinusException/*Exception*/{ return division(a,b); } } class ChildExcep extends Excep{ ChildExcep()throws ArithmeticException{ } public int division(int a,int b)throws ArithmeticException/*FileNotFoundException*/{ return a/b; } } class DivisorIsMinusException extends Exception{ DivisorIsMinusException(String str){ super(str); } } class ExcepTest{ public static int method1(Excep excep){ try{ return excep.division(5,0); } catch(ArithmeticException e){ System.out.println(e.toString()); } catch(DivisorIsMinusException ex){ System.out.println(ex.toString()); // return; System.exit(-1);//终止jvm运行 } catch(Exception e){ //System.out.println(e.getMessage()); //System.out.println(e.toString()); e.printStackTrace(); } return 0; } public static void main(String[] args)/*throws Exception*/{ ChildExcep ce=new ChildExcep(); method1(ce); Excep excep=new Excep(); try{ //excep.division(3,0); excep.fn1(3,-3); System.out.println("Exception !"); return; } catch(ArithmeticException e){ System.out.println(e.toString()); } catch(DivisorIsMinusException ex){ System.out.println(ex.toString()); // return; System.exit(-1);//终止jvm运行 } catch(Exception e){ //System.out.println(e.getMessage()); //System.out.println(e.toString()); e.printStackTrace(); } finally{ System.out.println("Finally !"); } //System.out.println("Finish !"); } }
Java编程规范
1.package的命名
package 的名字由全部小写的字母组成,例如:cn.mybole。
2.class和interface的命名
class和interface的名字由大写字母开头而其他字母都小写的单词组成,例如:Person,RuntimeException。
3.class变量的命名
变量的名字用一个小写字母开头,后面的单词用大写字母开头,例如:index,currentImage。
4.class方法的命名
方法的名字用一个小写字母开头,后面的单词用大写字母开头,例如:run(),getBalance()。
5.static final变量的命名
static final变量的名字所有字母都大写,并且能表示完整含义。例如:PI,PASSWORD。
6.参数的命名
参数的名字和变量的命名规范一致。
7.数组的命名
数组应该总是用这样的方式来命名:byte[] buffer。
JVM 规格描述
JVM指令系统
JVM指令系统同其他计算机的指令系统极其相似。Java指令也是由操作码和操作数两部分组成。操作码为8位二进制数,操作数紧随在操作码的后面,其长度根据需要而不同。操作码用于指定一条指令操作的性质(在这里我们采用汇编符号的形式进行说明),如iload表示从存储器中装入一个整数,anewarray表示为一个新数组分配空间,iand表示两个整数的“与”,ret用于流程控制,表示从对某一方法的调用中返回。当长度大于8位时,操作数被分为两个以上字节存放。JVM采用了“big endian”的编码方式来处理这种情况,即高位bits存放在低字节中。这同
Motorola及其他的RISC CPU采用的编码方式是一致的,而与Intel采用的“little endian ”的编码方式即低位bits存放在低位字节的方法不同。 Java指令系统是以Java语言的实现为目的设计的,其中包含了用于调用方法和监视多线程系统的指令。
JVM寄存器
所有的CPU均包含用于保存系统状态和处理器所需信息的寄存器组。如果虚拟机定义较多的寄存器,便可以从中得到更多的信息而不必对栈或内存进行访问,这有利于提高运行速度。然而,如果虚拟机中的寄存器比实际CPU的寄存器多,在实现虚拟机时就会占用处理器大量的时间来用常规存储器模拟寄存器,这反而会降低虚拟机的效率。针对这种情况,JVM只设置了4个最为常用的寄存器。它们是: pc程序计数器 optop操作数栈顶指针 frame当前执行环境指针 vars指向当前执行环境中第一个局部变量的指针 所有寄存器均为32位。pc用于记录程序的执行。optop,frame和vars用于记录指向Java栈区的指针。
JVM栈结构
作为基于栈结构的计算机,Java栈是JVM存储信息的主要方法。当JVM得到一个Java字节码应用程序后,便为该代码中一个类的每一个方法创建一个栈框架,以保存该方法的状态信息。每个栈框架包括以下三类信息: 局部变量 执行环境 操作数栈 局部变量用于存储一个类的方法中所用到的局部变量。vars寄存器指向该变量表中的第一个局部变量。 执行环境用于保存解释器对Java字节码进行解释过程中所需的信息。它们是:上次调用的方法、局部变量指针和操作数栈的栈顶和栈底指针。执行环境是执行一个方法的控制中心。例如:如果解释器要执行iadd(整数加法),首先要从frame寄存器中找到当前执行环境,而后便从执行环境中找到操作数栈,从栈顶弹出两个整数进行加法运算,最后将结果压入栈顶。
操作数栈用于存储运算所需操作数及运算的结果。
JVM碎片回收堆
Java类的实例(对象)所需的存储空间是在堆上分配的。解释器具体承担为类实例分配空间的工作。解释器在为一个实例分配完存储空间后,便开始记录对该实例所占用的内存区域的使用。一旦对象使用完毕,便将其回收到堆中。 在Java语言中,除了new语句外没有其他方法为一对象申请和释放内存。对内存进行释放和回收的工作是由Java运行系统承担的。这允许Java运行系统的设计者自己决定碎片回收的方法。在SUN公司开发的Java解释器和Hot Java环境中,碎片回收用后台线程的方式来执行。这不但为运行系统提供了良好的性能,而且使程序设计人员摆脱了自己控制内存使用的风险。
JVM存储区
JVM有两类存储区:常量缓冲池和方法区。常量缓冲池用于存储类名称、方法和字段名称以及串常量。方法区则用于存储Java方法的字节码。对于这两种存储区域具体实现方式在JVM规格中没有明确规定。这使得Java应用程序的存储布局必须在运行过程中确定,依赖于具体平台的实现方式。
相关文章推荐
- 深入理解java异常处理机制
- 深入理解java异常处理机制
- Java中异常的运用进一步理解
- 深入理解java异常处理机制
- 深入理解java异常处理机制
- 深入理解java异常处理机制
- 深入理解java异常处理机制
- Java 异常处理 理解
- 深入理解java异常处理机制
- 深入理解java异常处理机制(记得看原文评论,1楼评论解决问题或者本文PS说明)
- 深入理解java异常处理机制
- 深入理解java异常处理机制
- 【转】深入理解java异常处理机制
- 深入理解java异常处理机制
- 深入理解java异常处理机制
- 深入理解java异常处理机制
- 详解Java异常处理中finally子句的运用
- 深入理解java异常处理机制
- 深入理解java异常处理机制
- 深入理解java异常处理机制