Java基础语法09-面向对象下-内部类

九、内部类

将一个类A定义在另一个类B里面,里面的那个类A就称为内部类,B则称为外部类

(1)成员内部类:声明在外部类中方法外

  • 静态成员内部类

  • 非静态成员内部类

(2)局部内部类:声明在外部类的方法体中

  • 有名字的局部内部类

  • 匿名的内部类

静态内部类

1、语法格式:

【修饰符】 class 外部类 【extends 父类】 【implements 接口们】{
  【其他修饰符】 static class 静态内部类 【extends 父类】 【implements 接口们】{
   }
}

外部类的权限修饰符:public或缺省,其他修饰符:abstract或final

静态内部类的权限修饰符:四种,其他修饰符:abstract或final + static

2、静态内部类也是类

(1)可以有自己的父类或父接口

(2)有自己的字节码文件:外部类名$静态内部类名.class

(3)有自己的成员:没有限制

只要在类中可以写的成员它都可以有,只有静态内部类允许有静态成员。

3、静态内部类的使用

(1)静态内部类使用外部类的成员时:

有限制:静态内部类不能使用外部类的非静态成员

(2)在外部类中使用静态内部类

使用静态内部类的静态成员:直接使用“静态内部类名."

使用静态内部类的非静态成员:使用“静态内部类的对象."

(3)在外部类的外面使用静态内部类

前提:这个静态内部类在外面是可见,否则只能通过这个静态内部类的父类或父接口来引用它的对象。

如果可见,使用静态内部类的静态成员:直接使用“外部类名.静态内部类名."

使用静态内部类的非静态成员:使用“静态内部类的对象."

外部类.静态内部类  对象名 = new  外部类.静态内部类(【...】);

非静态内部类

1、语法结构:

【修饰符】 class 外部类 【extends 父类】 【implements 接口们】{
  【其他修饰符】 class 非静态内部类 【extends 父类】 【implements 接口们】{
   }
}

外部类的权限修饰符:public或缺省,其他修饰符:abstract或final

非静态内部类的权限修饰符:四种,其他修饰符:abstract或final

2、非静态内部类也是类

(1)可以有自己的父类或父接口

(2)有自己的字节码文件:外部类名$非静态内部类名.class

(3)有自己的成员:有限制

不能有静态成员,除非静态常量。

3、非静态内部类的使用

(1)非静态内部类使用外部类的成员时:没有限制

(2)在外部类中使用非静态内部类

在外部类的静态成员中使用无法使用非静态内部类的。

在外部类的非静态成员中使用非静态内部类,使用“非静态内部类的对象."

在非静态内部类的方法中有两个this对象,一个是外部类的this对象,一个是内部类的this对象

(3)在外部类的外面使用非静态内部类

前提:这个非静态内部类在外面是可见,否则只能通过这个非静态内部类的父类或父接口来引用它的对象。

如果可见,使用非静态内部类的非静态成员:要求必须有外部类的对象的引用

外部类 out = new 外部类(【...】);
外部类.非静态内部类 对象名 = out.new 非静态内部类(【...】);

//在实际开发中,在外部类中编写一个方法来返回非静态内部类的对象,然后调用这个方法来获取非静态内部类对象

局部内部类

【修饰符】 class 外部类 【extends 父类】 【implements 接口们】{
  【修饰符】 返回值类型 方法名(【形参列表】){
    【abstract或final或没有】 class 局部内部类 【extends 父类】 【implements 接口们】{
     }
   }
}

外部类的权限修饰符:public或缺省,其他修饰符:abstract或final

局部内部类没有权限修饰符,其他修饰符:abstract或final

局部内部类的特点:

  • 和外部类一样,它只是定义在外部类的某个方法中的另一个完整的类结构

    • 可以继承自己的想要继承的父类,实现自己想要实现的父接口们,和外部类的父类和父接口无关

    • 可以在局部内部类中声明属性、方法、构造器等结构,但不包括静态成员,除非是从父类继承的或静态常量

    • 可以使用abstract修饰,因此它也可以被同一个方法的在它后面的其他内部类继承

    • 可以使用final修饰,表示不能被继承

    • 编译后有自己的独立的字节码文件,只不过在内部类名前面冠以外部类名、$符号、编号。

      • 这里有编号是因为同一个外部类中,不同的方法中存在相同名称的局部内部类

  • 和成员内部类不同的是,它前面不能有权限修饰符等

  • 局部内部类如同局部变量一样,有作用域

  • 局部内部类中是否能访问外部类的静态还是非静态的成员,取决于所在的方法

  • 局部内部类中还可以使用所在方法的局部常量,即用final声明的局部变量

    • JDK1.8之后,如果某个局部变量在局部内部类中被使用了,自动加final

在外部类中使用局部内部类

有作用域,即只能在这个方法体中,并且在声明之后。

在外部类的外面使用局部内部类:不能

在外部类的外面可以得到局部内部类的对象

但是需要通过它的父类或父接口的变量来引用,用方法的返回值返回。

匿名内部类

匿名内部类是没有名字的类,因此在声明类的同时就创建好了唯一的对象。

匿名内部类的对象一般会三种形式使用它

父类/父接口 变量 = new 父类/父接口(【实参列表】){
  //可以写方法....
};

new 父类/父接口(【实参列表】){
  //可以写方法....
}.方法(【实参列表】);

方法名(new 父类/父接口(【实参列表】){
  //可以写方法....
});

所有局部内部类的限制都适用于匿名内部类。例如:

  • 在匿名内部类中是否可以使用外部类的非静态成员变量,看所在方法是否静态

  • 在匿名内部类中如果需要访问当前方法的局部变量,该局部变量需要加final

思考:这个对象能做什么呢?

答:(1)调用某个方法(2)赋值给父类/父接口的变量,通过多态引用使用这个对象(3)作为某个方法调用的实参

注解

和普通注释不同:注解的注释内容是可以被另一段程序读取的

一个完整的注解应该有三个部分:

(1)声明: @interface

(2)使用: @注解名 或 @注解名(....)

(3)读取:

  • SOURCE:只能由编译器读取

  • CLASS:可以由类加载器读取

  • RUNTIME:可以通过反射的代码在运行时读取

系统预定义的三个最基本的注解

1、@Override

用于检测被修饰的方法为有效的重写方法,如果不是,则报编译错误!

只能标记在方法上。

2、@Deprecated

用于表示被标记的数据已经过时,不建议使用。

可以用于修饰 属性、方法、构造、类、包、局部变量、参数。

3、@SuppressWarnings

抑制编译警告。

可以用于修饰类、属性、方法、构造、局部变量、参数

格式:

@SuppressWarnings("all")
@SuppressWarnings("uncheck")
@SuppressWarnings({"unused","uncheck"})

文档注释

  • @author 标明开发该类模块的作者,多个作者之间使用,分割

  • @version 标明该类模块的版本

  • @see 参考转向,也就是相关主题

  • @since 从哪个版本开始增加的

  • @param 对方法中某参数的说明,如果没有参数就不能写

  • @return 对方法返回值的说明,如果方法的返回值类型是void就不能写

  • @throws/@exception 对方法可能抛出的异常进行说明 ,如果方法没有用throws显式抛出的异常就不能写

    • 其中 @param @return 和 @exception 这三个标记都是只用于方法的。

    • @param的格式要求:@param 形参名 形参类型 形参说明

    • @return 的格式要求:@return 返回值类型 返回值说明

    • @exception 的格式要求:@exception 异常类型 异常说明

    • @param和@exception可以并列多个

javadoc.exe就是这些注解的信息处理流程。

如果导出时有乱码问题,可以指定字符编码

-docencoding UTF-8
-encoding UTF-8
-charset UTF-8

JUnit单元测试

  • @Test:标记在非静态的测试方法上。
  • @BeforeClass:标记在静态方法上。因为这个方法只执行一次。在所有方法@Test方法之前执行。

  • @AfterClass:标记在静态方法上。因为这个方法只执行一次。在所有方法@Test方法完成后执行。

  • @Before:标记在非静态方法上。在@Test方法前面执行,而且是在每一个@Test方法前面都执行

  • @After:标记在非静态方法上。在@Test方法后面执行,而且是在每一个@Test方法后面都执行

  • @BeforeClass、@AfterClass、@Before、@After都是配合@Test使用的,单独使用没有意义。

元注解

(1)@Target:用于描述注解的使用范围

  • 可以通过枚举类型ElementType的10个常量对象来指定

(2)@Retention:用于描述注解的生命周期

  • 可以通过枚举类型RetentionPolicy的3个常量对象来指定

  • 唯有RUNTIME阶段才能被反射读取到。

(3)@Documented:表明这个注解应该被 javadoc工具记录。

(4)@Inherited:允许子类继承父类中的注解

自定义注解

@元注解
【修饰符】 @interface 注解名{
  数据类型 参数名1();
  数据类型 参数名2() default 默认值;
}

(1)声明时,类型有要求:

8种基本数据类型、String、枚举、Class、注解,以及他们的数组

(2)使用时

可以在定义 Annotation 的成员变量时为其指定初始值, 指定成员变量的初始值可使用 default 关键字

如果定义的注解含有配置参数,那么使用时必须指定参数值,除非它有默认值。格式是“参数名 = 参数值”,如果只有一个参数成员需要赋值,且名称为value,可以省略“value=”

自定义注解必须配上注解的信息处理流程才有意义。

异常

对于异常,一般有两种解决方法:一是遇到错误就终止程序的运行。另一种方法是由程序员在编写程序时,就考虑到错误的检测、错误消息的提示,以及错误的处理。

异常的根类是java.lang.Throwable,其下有两个子类:java.lang.Errorjava.lang.Exception,平常所说的异常指java.lang.Exception

Java基础语法09-面向对象下-内部类_第1张图片

如果要自定义异常,必须继承Throwable或它的子类

Error:严重错误Error,无法通过处理的错误,只能事先避免

Exception:表示异常,其它因编程错误或偶然的外在因素导致的一般性问题,程序员可以通过代码的方式纠正,使程序继续运行,是必须要处理的。

Exception的两大类:编译时异常和运行时异常

运行时异常:RuntimeException或它的子类

编译时异常:除了运行时异常都是编译时异常

Java异常处理的五个关键字:try、catch、finally、throw、throws

1、try:尝试执行可能会发生异常的代码

2、catch:尝试捕获try中发生的异常

3、finally:无论try中是否发生异常,也无论catch是否可以捕获异常,也不管try和catch中是否有return语句,都要执行。除非在try或catch中执行了System.exit(0)语句。

4、throw:用于手动抛出异常

5、throws:表示某个方法内部没有处理xx异常,抛给调用者处理,在方法的签名中显式声明抛出哪些异常

try{
  可能发生异常的代码
}catch(异常类型 e){
  处理异常的代码
  //打印,或什么都不写,或者其他处理代码
}catch(异常类型 e){
  处理异常的代码
  //打印,或什么都不写,或者其他处理代码
}finally{
  ...
}

throw用在方法内,用来抛出一个异常对象,将这个异常对象传递到调用者处,并结束当前方法的执行。

throw new 异常类名(参数);

关键字throws运用于方法声明之上,用于表示当前方法不处理异常,而是提醒该方法的调用者来处理异常(抛出异常).

修饰符 返回值类型 方法名(参数) throws 异常类名1,异常类名2…{   }

在方法中使用try-catch的语句块来处理异常。

try:该代码块中编写可能产生异常的代码。

catch:用来进行某种异常的捕获,实现对捕获到的异常进行处理。

  • 可以有多个catch块,按顺序匹配。

  • 如果多个异常类型有包含关系,那么小上大下

finally:有一些特定的代码无论异常是否发生,都需要执行。另外,因为异常会引发程序跳转,导致有些语句执行不到。而finally就是解决这个问题的,在finally代码块中存放的代码都是一定会被执行的。

 

注意:finally不能单独使用。当只有在try或者catch中调用退出JVM的相关方法,例如System.exit(0),此时finally才不会执行,否则finally永远会执行。

一般我们是使用一次捕获多次处理方式

注意:这种异常处理方式,要求多个catch中的异常不能相同,并且若catch中的多个异常之间有子父类异常的关系,那么子类异常要求在上面的catch处理,父类异常在下面的catch处理。

  • 运行时异常被抛出可以不处理。即不捕获也不声明抛出。

  • 如果finally有return语句,永远返回finally中的结果,避免该情况.

  • 如果父类抛出了多个异常,子类重写父类方法时,抛出和父类相同的异常或者是父类异常的子类或者不抛出异常。

  • 父类方法没有抛出异常,子类重写父类该方法时也不可抛出异常。此时子类方法中产生了编译时异常,只能捕获处理,不能声明抛出

自定义异常

要求

1、必须继承Throwable或它的子类,一般继承Exception或RuntimeException

2、尽量保留两个构造器:无参和有参(message)

3、加序列化版本ID

4、自定义异常类型的对象只能使用throw语句抛出

自定义异常最重要的是异常类的名字,当异常出现时,可以根据名字判断异常类型。

 常见异常列表

你可能感兴趣的:(Java基础语法09-面向对象下-内部类)