Java 面向对象编程扩展
Java 静态类(Static Class)
静态类,即定义了静态方法、静态变量、静态代码块的类,或静态内部类
静态类不能实例化,类的成员都要是静态成员和静态方法 非静态类一般需要实例化后才可以操作,不过接口和抽象类不能直接实例化
静态的类都是在运行时静态地加载到内存中的(一开始运行首先从静态的类开始),所以也不需要对它们进行初始化,也没有实例,因此在类的内部也不能用this
静态方法
通常,在一个类中定义一个方法为static,那就是说,无需本类的对象即可调用此方法。调用一个静态方法就是 类名.方法名
静态变量
静态变量与静态方法类似,所有此类实例共享次静态变量,也就是说在类装载时,只分配一块存储空间,所有此类的对象都可以操控此块存储空间
静态代码块
在 static {} 后面跟着一段代码,这是用来显式地初始化静态变量,这段代码只会初始化一次,且在类被第一次装载时
静态内部类
通常普通类不允许声明为静态的,只有内部类才可以。这时这个声明为静态的内部类可以直接作为一个普通类来使用,而不需实例化一个外部类
Java 匿名类(Anonymous[əˈnänəməs] Class)
匿名内部类通常用在GUI编程添加事件监听器中,目的是简化代码编写
匿名类的定义
new <类或接口><类的主体>
从技术上说,匿名类可被视为非静态的内部类,所以它们具有和方法内部声明的非静态内部类一样的权限和限制
匿名类的声明是在编译时进行的,实例化在运行时运行的。这就意味着 for 循环中的一个 new 语句会创建相同匿名类的几个实例,而不是创建几个不同匿名类的一个实例
interface ITest { void print() }
public class MyClass {
public ITest getTest() {
return new ITest() {
public void print1() {
System.out.println("Hello World");
}
}
}
public static voif main(String args[]) {
MyClass c = new MyClass();
ITest test = c.getTest();
test.print();
}
}
Java 内部类(Inner[ˈinər] Class)
内部类 是在另一个类的内部声明的类
包装了内部类声明的类就称为 外部类
Java语言规范允许定义一下几种内部类
- 在另一个类或者一个接口中声明一个类
- 在另一个接口或者一个类中声明一个接口
- 在一个方法中声明一个类
内部类是在一个类的内部嵌套定义的类它可以是其他类的成员,也可以在一个语句块的内部定义,还可以在表达式内部匿名定义
特性
- 一般用在定义它的类或语句块之内, 在外部引用它时必须给出完整的名称,名字不能与包含它的类名相同
- 可以使用包含它的类的静态和实例成员变量,也可以使用它所在方法的局部变量
- 可以定义为 abstract
- 可以声明为private 或 protected
- 若被声明为 static,就变成了顶层类,不能再使用局部变量
- 若想在 Inner Class中声明任何static 成员,则该 Inner Class 必须声明为 static
-
内部类的可视范围
内部类的可视范围是它的直接外嵌类,也就是说内部类可以直接引用外嵌类中的任何成员。因为内部类与外嵌类的实例相关,所以内部类拥有两个 this 指针,一个指向内部类实例本身,一个指向外嵌类的实例
-
使用内部类的好处
封装性好:直接通过操作得到内部类内容,甚至连这两个内部类的名字都没有看见!一个内部类对象可以访问创建它的外部类对象的内容,甚至包括私有变量
Java通过内部类加上接口,可以很好地实现多继承的效果
-
内部类的用途
内部类的一个主要用途是用于GUI的事件处理程序
局部内部类
当内部类定义放在函数内部时,class前不能够使用 private、protected和public 修饰符,因为此时的类仅仅在该代码块作用可见,不需要对外部开放可视权限
不能在 if 之外创建这个内部类的对象,因为这个已经超出了它的作用域。
内部类引用外部类对象
在创建非静态内部对象时,一定要先创建相应的外部类对象,因为非静态内部类对象有着指向其外部类对象的引用
在任何非静态类中,都不能有静态数据、静态方法或者另外一个静态内部类
Java 异常类(Exception[ikˈsepSH(ə)n] Class)
Java对异常的处理是按异常分类处理的,不同异常有不同的分类,每种异常都对应一个类型(class),每个异常都对应一个异常(类的)对象
- 异常类有两个来源:一个是Java 语言本身定义的一些基本异常类型;二是用户通过继承Exception 类或者其子类自己定义的异常
- 异常的对象有两个来源:一是Java运行时环境自动抛出系统生成的异常,而不管你是否愿意捕获和处理,它总要抛出;二是程序员自己抛出的异常,这个异常可以是程序员自己定义的,用 throw 关键字抛出异常,这种异常常用来调用者汇报异常的一些信息。异常是针对方法来说的,抛出、声明抛出、捕获和处理异常都是在方法中进行的。
Java的异常层次结构
Throwable 类是所有异常和错误的超类,它有两个子类 Error[ˈerər] 和 Exception,分别表示错误和异常。其中异常类Exception 又分为运行时异常(Runtime Exception)和非运行时异常,这两种异常有很大的区别,也称为不检查异常(Unchecked[ˌʌnˈtʃekt] Exception)
-
Error 与 Exception
- Error是程序无法处理的异常,这些异常发生时,Java虚拟机(JVM)一般会选择线程终止
- Exception 是程序本身可以处理的异常,这种异常分为运行时异常和非运行时异常
-
运行时异常和非运行时异常
- 运行时异常都是 RuntimeException 类及其子类异常,这些是不检查的异常,在程序中可以选择捕获处理,也可以不处理。这些异常一般由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生
- 非运行时异常是 RuntimeException 以外的异常,类型上都属于Exception类及其子类。从程序语法角度讲是必须处理的异常,如果不处理,程序就不能编译通过
-
Throwable
Throwable类是Java语言中所有错误或异常的超类。只有当对象是此类的实例时,才能通过Java虚拟机或 Java throw语句抛出。
- getCause():返回抛出异常的原因
- getMessage():返回异常的消息信息
- printStackTrace():对象的堆栈跟踪输出至错误输出流,作为字段System.err的值
-
Exception
Exception类及其子类是Throwable的一种形式,它指出了合理的应用程序想要捕获的条件,表示程序本身可以处理的异常
-
Error
Error 是 Throwable 的子类,表示依靠程序本身无法恢复的严重错误,用于指示合理的应用程序不应该试图捕获的严重问题。在执行该方法期间,无需在方法中通过 throws 声明可能抛出但没有捕获的Error的任何子类,因为Java编译器不去检查它,也就是说,当程序中可能出现这类异常时,即使没有用 try...catch语句捕获它,也没有 throws 字句声明抛出它,它还是会编译通过
-
RuntimeException
RuntimeException 是那些可能在Java虚拟机正常运行期间抛出的异常的超类。Java编译器不去检查它,这种异常可以通过改进代码实现来避免
-
ThreadDeath
调用Thread 类中带有零参数的stop方法时,受害线程将抛出一个ThreadDeath实例。仅当应用程序被异步终止后必须清除才应该捕获这个类的实例。如果 ThreadDeath 被一个方法捕获,那么将它重新抛出,因为这样才能让该线程真正终止
名称 异常 算术异常类 ArithmeticException 空指针异常类 NullPointerException 类型强制转换异常 ClassCastException 数组负下标异常 NegativeArrayException 数组下标越界异常 ArrayIndexOutOfBoundsException 违背安全原则异常 SecturityException 文件已结束异常 EOFException 文件未找到异常 FileNotFoundException 操作数据库异常 SQLException 输入/输出异常 IOException 方法未找到异常 NoSuchMethodException 字符串转换数字异常 NumberFormatException
异常的捕捉处理机制
-
异常处理的基本语法
try { //程序代码 } catch(异常类型 异常的变量名) { //异常处理代码 } finally { //异常发生方法返回之前,总要执行的代码 }- try 代码块:表示要尝试运行代码,try语句块中代码受异常监控,其中代码发生异常时,会抛出异常对象
- catch语句块:会捕获try代码块中发生的异常并在其代码快中做异常处理,catch 语句带个 Throwable 类型的参数,表示可捕获异常类型
- finally语句块:是紧跟catch语句后的语句块,这个语句块总是会在方法返回前执行,而不管try语句块是否发生异常,并且这个语句块总是在方法返回前执行,目的是给程序一个补救的机会
-
try、catch、finally语句块应注意的问题
- try、catch、finally 3个语句块均不能单独使用,3者都可以组成 try···catch···finally、try···catch、try···finally 3种结构,catch 语句可以有一个或多个,finally语句最多一个
- try、catch、finally 3个代码块中变量的作用域为代码块内部,分别独立而不能相互访问。如果要在3个块中都可以访问,则需要将变量定义到这些块的外面
- 使用多个catch块时,只会匹配其中一个异常类并执行catch块代码,而不会再执行别的catch块,并且匹配catch 语句顺序是由上到下的
-
throw、throws 关键字
throw关键字是用于方法体内部,用来抛出一个Throwable 类型的异常。如果抛出了检查异常,则还应该在方法头部声明方法可能抛出的异常类型。该方法的调用者也必须检查处理抛出的异常。如果所有方法都层层上抛获取的异常,最终JVM会进行处理,处理也很简单,就是打印异常消息和堆栈信息。
throws 关键字用于方法体外部的方法声明部分,用来声明方法可能会抛出某些异常。仅当抛出了检查异常,该方法的调用者才必须处理或重新抛出该异常。当方法的调用者无力处理该异常的时候应该继续抛出
throw 与 throws的区别与联系
throw 语法: throw <异常对象> throws 语法 : [<修饰符>]<返回值类型><方法名>([<参数列表>]) [throws <异常类>]异常类可以声明多个,用逗号分隔
-
throws 可以单独使用,但 throw 不能
-
throw 要么和 try···catch···finally语句配套使用,要么与throws配套使用。但 throws 可以单独使用,然后再由处理异常的方法捕获
public static void test() throws Exception { throw new Exception("方法 test 中的 Exception"); }
-
使用异常和自定义异常类
-
使用已有的异常类
try { }.catch(IOException) { }.catch(SQLException) { } -
自定义异常类
public class MyException extends Exception { public MyException() {} public MyException(String smg) { super(smg); System.out.println(smg); } } // 在异常类中,可以覆盖或重载父类Exception 中的函数,可以实现自己的代码 -
使用自定义的异常
throws声明方法可以抛出自定义的异常,并用 throw 语句在适当的地方抛出自定义的异常
也可以将异常转型(也叫转译),使异常更易读易于理解。