Java基础-内部类与异常处理
(创作不易,感谢有你,你的支持,就是我前行的最大动力,如果看完对你有帮助,请留下您的足迹)
目录
一、Java 内部类
什么是内部类?
使用内部类的优点
访问局部变量的限制
内部类和继承
内部类中没有静态成员
生成的内部类的类文件
静态上下文中的内类
二、Java 内部类类型
成员内部类
局部内部类
匿名内部类
三、Java 异常处理
try-catch块
Java 异常类
异常类层次结构
使用多个catch块
一、Java 内部类
什么是内部类?
作为包的成员的类被称为顶级类。
一个类可以在另一个类中声明。这种类型的类称为内部类。
如果在另一个类中声明的类被显式或隐式声明为static,它被称为嵌套类,而不是内部类。
包含内部类的类称为封闭类或外部类。
下面的代码声明一个内部类。
class Outer { public class Inner { // Members of the Inner class go here } // Other members of the Outer class go here }
Outer类是一个顶级类。
Inner类是一个内部类。它是外类的成员。
外层类是Inner类的封闭(外部)类。
内部类可以是另一个内部类的封闭类。内部类的嵌套层次没有限制。
内部类的实例只能存在于其封闭类的实例中。
使用内部类的优点
以下是内部类的一些优点。
在将使用它们的其他类附近定义类。
提供了一个额外的命名空间来管理类结构。
一些设计模式使用内部类更容易实现。
实现回调机制使用内部类是优雅和方便的。它有助于在Java中实现闭包。
访问局部变量的限制
下面的代码演示了访问局部内部类中的局部变量的规则。
main()方法声明两个局部变量x和y。这两个变量都是最终的。
变量x在被初始化之后从不改变,变量y不能被改变,因为它被声明为final。
public class Main { public static void main(String... args) { int x = 1; final int y = 2; class LocalInner { void print() { System.out.println("x = " + x); System.out.println("y = " + y); } } /* * Uncomment the following statement will make the variable x no longer * an effectively final variable and the LocalIneer class will not compile. */ // x = 100; LocalInner li = new LocalInner(); li.print(); } }
上面的代码生成以下结果
内部类和继承
内部类可以继承另一个内部类,顶级类或其封闭类。
class A { public class B { } public class C extends B { } public class D extends A { } } class E extends A { public class F extends B { } }
内部类中没有静态成员
Java中的关键字static使一个构造成为一个顶层结构。
因此,我们不能为内部类声明任何静态成员(字段,方法或初始化器)。
允许在内部类中有作为编译时常量的静态字段。
class A { public class B { public final static int DAYS_IN_A_WEEK = 7; // OK public final String str = new String("Hello"); } }
生成的内部类的类文件
每个内部类都被编译成一个单独的类文件。
成员内部类和静态内部类的类文件名格式如下:
<outer-class-name>$<member-or-static-inner-class-name>
局部内部类的类文件名的格式如下:
<outer-class-name>$<a-number><local-inner-class-name>
匿名类的类文件名的格式如下:
<outer-class-name>$<a-number>
类文件名中的<a-number>是从1开始顺序生成的数字,以避免任何名称冲突。
静态上下文中的内类
class Outer {
static int k = 1;
int m = 2;
public static void staticMethod() {
// Class Inner is defined in a static context
class Inner {
int j = k; // OK. Referencing static field k
// int n = m; // An error. Referencing non-static field m
}
}
}
二、Java 内部类类型
您可以在类中的任何位置定义内部类,您可以在其中编写Java语句。
有三种类型的内部类。内部类的类型取决于位置和声明的方式。
成员内部类
局部内部类
匿名内部类
成员内部类
成员内部类在类中声明的方式与声明成员字段或成员方法相同。
它可以声明为public,private,protected或package-level。
成员内部类的实例可以仅存在于其封闭类的实例内。
以下代码创建了一个成员内部类。
class Car { private int year; // A member inner class named Tire public class Tire { private double radius; public Tire(double radius) { this.radius = radius; } public double getRadius() { return radius; } } // Member inner class declaration ends here // A constructor for the Car class public Car(int year) { this.year = year; } public int getYear() { return year; } }
局部内部类
局部内部类是定义在一个方法或者一个作用域里面的类,它和成员内部类的区别在于局部内部类的访问仅限于方法内或者该作用域内。
class People{ public People() { } } class Man{ public Man(){ } public People getWoman(){ class Woman extends People{ //局部内部类 int age =0; } return new Woman(); } }
匿名内部类
匿名内部类没有名称。因为它没有名称,它不能有一个构造函数。
匿名类是一次性类。您定义一个匿名类并同时创建它的对象。
创建匿名类及其对象的一般语法如下:
new Superclass(<argument-list-for-a-superclass-constructor>) { // Anonymous class body goes here }
new Interface() { // Anonymous class body goes here }
它后面是现有的接口名称或现有的类名称。
接口名称或类名称不是新创建的匿名类的名称。
如果使用接口名称,则匿名类实现接口。
如果使用类名,则匿名类继承自类。
仅当新运算符后面跟有类名时,才使用<argument-list>。如果新运算符后跟接口名称,则它为空。
如果<argument-list>存在,它包含要调用的现有类的构造函数的实际参数列表。
匿名类主体像往常一样在大括号中。
匿名类主体应该简短,以便更好的可读性。
下面的代码包含一个简单的匿名类,它在标准输出上打印一条消息。
public class Main { public static void main(String[] args) { new Object() { // An instance initializer { System.out.println("Hello from an anonymous class."); } }; // A semi-colon is necessary to end the statement } }
上面的代码生成以下结果
三、Java 异常处理
异常是在没有定义正常执行路径时在Java程序的执行期间可能出现的条件。
Java通过将执行操作的代码与处理错误的代码分离来处理错误。
当发生异常时,Java会创建一个包含有关异常的所有信息的对象,并将其传递给相应的异常处理代码。
有关异常的信息包括异常的类型,发生异常的代码中的行号等。
try-catch块
要处理异常,请将代码放在try块中。try块如下所示:
try { // Code for the try block }
try块以关键字try开头,后面是开括号和结束括号。
try块的代码放在开口和关闭大括号内。
try块本身不能使用。
它必须后跟一个或多个catch块,或一个finally块,或两者的组合。
要处理可能在try块中抛出的异常,请使用catch块。
一个catch块可用于处理多种类型的异常。
catch块的语法与方法的语法相似。
catch (ExceptionClassName parameterName) { // Exception handling code }
catch块的声明就像一个方法声明。
它从关键字catch开始,后面跟一对括号。
在括号中,它声明了一个参数。
参数类型是应该捕获的异常类的名称。
parameterName是用户给定的名称。括号后面是开口括号和结束括号。异常处理代码放在大括号中。
当抛出异常时,异常对象的引用将复制到parameterName。
我们可以使用parameterName从异常对象中获取信息。
我们可以将一个或多个catch块与try块关联。
try-catch块的一般语法如下。
try { // Your code that may throw an exception } catch (ExceptionClass1 e1){ // Handle exception of ExceptionClass1 type } catch (ExceptionClass2 e2){ // Handle exception of ExceptionClass2 type } catch (ExceptionClass3 e3){ // Handle exception of ExceptionClass3 type }
例子
下面的代码显示了如何处理除零异常。
public class Main { public static void main(String[] args) { int x = 10, y = 0, z; try { z = x / y; System.out.println("z = " + z); } catch (ArithmeticException e) { String msg = e.getMessage(); System.out.println("The error is: " + msg); } System.out.println("The end."); } }
上面的代码生成以下结果
Java 异常类
异常类层次结构
异常类层次结构从java.lang.Throwable类开始。
当抛出异常时,它必须是Throwable类的对象或其任何子类。
catch块的参数必须是Throwable类型,或其子类之一,例如Exception,ArithmeticException,IOException等。
我们可以通过从一个异常类继承我们的类来创建我们自己的异常类。
使用多个catch块
Java运行时选择适当的catch块,并从第一个catch块开始顺序寻找合适的catch时钟。
try块的多个catch块必须从最具体的异常类型排列为最通用的异常类型。
以下代码使用多个catch块的有效序列。
ArithmeticException类是RuntimeException类的子类。
如果这两个异常都在同一个try块的catch块中处理,那么最具体的类型,即ArithmeticException,必须出现在最通用的类型之前,即RuntimeException。
try { // Do something, which might throw Exception } catch(ArithmeticException e1) { // Handle ArithmeticException first } catch(RuntimeException e2) { // Handle RuntimeException after ArithmeticException }