重学Java第8天 面向对象

249 阅读11分钟

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
  1. 内部类的可视范围

    内部类的可视范围是它的直接外嵌类,也就是说内部类可以直接引用外嵌类中的任何成员。因为内部类与外嵌类的实例相关,所以内部类拥有两个 this 指针,一个指向内部类实例本身,一个指向外嵌类的实例

  2. 使用内部类的好处

    封装性好:直接通过操作得到内部类内容,甚至连这两个内部类的名字都没有看见!一个内部类对象可以访问创建它的外部类对象的内容,甚至包括私有变量

    Java通过内部类加上接口,可以很好地实现多继承的效果

  3. 内部类的用途

    内部类的一个主要用途是用于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)

  1. Error 与 Exception

    • Error是程序无法处理的异常,这些异常发生时,Java虚拟机(JVM)一般会选择线程终止
    • Exception 是程序本身可以处理的异常,这种异常分为运行时异常和非运行时异常
  2. 运行时异常和非运行时异常

    • 运行时异常都是 RuntimeException 类及其子类异常,这些是不检查的异常,在程序中可以选择捕获处理,也可以不处理。这些异常一般由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生
    • 非运行时异常是 RuntimeException 以外的异常,类型上都属于Exception类及其子类。从程序语法角度讲是必须处理的异常,如果不处理,程序就不能编译通过
  3. Throwable

    Throwable类是Java语言中所有错误或异常的超类。只有当对象是此类的实例时,才能通过Java虚拟机或 Java throw语句抛出。

    • getCause():返回抛出异常的原因
    • getMessage():返回异常的消息信息
    • printStackTrace():对象的堆栈跟踪输出至错误输出流,作为字段System.err的值
  4. Exception

    Exception类及其子类是Throwable的一种形式,它指出了合理的应用程序想要捕获的条件,表示程序本身可以处理的异常

  5. Error

    Error 是 Throwable 的子类,表示依靠程序本身无法恢复的严重错误,用于指示合理的应用程序不应该试图捕获的严重问题。在执行该方法期间,无需在方法中通过 throws 声明可能抛出但没有捕获的Error的任何子类,因为Java编译器不去检查它,也就是说,当程序中可能出现这类异常时,即使没有用 try...catch语句捕获它,也没有 throws 字句声明抛出它,它还是会编译通过

  6. RuntimeException

    RuntimeException 是那些可能在Java虚拟机正常运行期间抛出的异常的超类。Java编译器不去检查它,这种异常可以通过改进代码实现来避免

  7. ThreadDeath

    调用Thread 类中带有零参数的stop方法时,受害线程将抛出一个ThreadDeath实例。仅当应用程序被异步终止后必须清除才应该捕获这个类的实例。如果 ThreadDeath 被一个方法捕获,那么将它重新抛出,因为这样才能让该线程真正终止

    名称异常
    算术异常类ArithmeticException
    空指针异常类NullPointerException
    类型强制转换异常ClassCastException
    数组负下标异常NegativeArrayException
    数组下标越界异常ArrayIndexOutOfBoundsException
    违背安全原则异常SecturityException
    文件已结束异常EOFException
    文件未找到异常FileNotFoundException
    操作数据库异常SQLException
    输入/输出异常IOException
    方法未找到异常NoSuchMethodException
    字符串转换数字异常NumberFormatException
异常的捕捉处理机制
  1. 异常处理的基本语法

    try {
    //程序代码  
    } catch(异常类型 异常的变量名) {
      //异常处理代码
    } finally {
      //异常发生方法返回之前,总要执行的代码
    }
    
    • try 代码块:表示要尝试运行代码,try语句块中代码受异常监控,其中代码发生异常时,会抛出异常对象
    • catch语句块:会捕获try代码块中发生的异常并在其代码快中做异常处理,catch 语句带个 Throwable 类型的参数,表示可捕获异常类型
    • finally语句块:是紧跟catch语句后的语句块,这个语句块总是会在方法返回前执行,而不管try语句块是否发生异常,并且这个语句块总是在方法返回前执行,目的是给程序一个补救的机会
  2. 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 语句顺序是由上到下的
  3. 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"); }

使用异常和自定义异常类
  1. 使用已有的异常类

    try {
      
    }.catch(IOException) {
      
    }.catch(SQLException) {
      
    }
    
  2. 自定义异常类

    public class MyException extends Exception {
      public MyException() {}
      public MyException(String smg) {
        super(smg);
        System.out.println(smg);
      }
    }
    // 在异常类中,可以覆盖或重载父类Exception 中的函数,可以实现自己的代码
    
  3. 使用自定义的异常

    throws声明方法可以抛出自定义的异常,并用 throw 语句在适当的地方抛出自定义的异常

    也可以将异常转型(也叫转译),使异常更易读易于理解。