3-final、嵌套类、抽象类
1.final:
- 被 final 修饰的类:不能被继承。
- 被 final 修饰的方法:不能被重写。
- 被 final 修饰的变量:变量变为常量,只能进行一次赋值。
这是非常好的一个东西。可以避免我们造出混乱的继承结构。比如Java中的String类就是final的,它是不能被继承的。
final不能修饰抽象类或接口,因为定义抽象类或接口的目的就是为了让其他类继承或实现。
1.1.常量:
1 | public final double PI = 3.14; // 只是不能被再次赋值,也不算是常量 |
如果将基本类型或字符串定义为常量,且在编译时就能确定值。
编译器会使用常量值替代各处常量名(类似 c 语言的宏替换)
上面的例子是编译时能确定值的,下面举例编译时不能确定值的情况。
1 | static final int PI = getPI(); |
小测试:
1 | public static void main(String args[]) { |
解释:
在编译阶段,变量c其实已经是”go die, final”了,所以c和e其实是同一个对象。
但是d却是运行时生成的,并不引用常量池中的”go die, final”这个字符串,所以e和d并不是同一个对象。
究其根本原因,还是在于b 在编译阶段就已经被当作常量“final” 去做下面的编译了。
2.嵌套类:定义在一个类中的类
1 | //最外层的外部类,又称顶级类 |
2.1.内部类:没有被 static 修饰的嵌套类。 (非静态内部类)
一般情况下,类与类之间相互独立。内部类就是打破这种独立,让一个类成为另一个类的内部成员,和成员变量、成员方法同等级别。
1.非静态内部类跟实例变量、实例方法一样,都必须通过外部类的对象才能调用。
1 | public class Persion{ |
2.内部类不能定义除编译时常量以外的任何 static 成员。
1 | public class OuterClass{ |
什么情况下使用嵌套类?
- 如果类 A 只在类 C 内部会被用到,可以考虑将类 A 嵌套到类 C 中。
- 如果类 A 需要经常访问类 C 的非公共成员,可以考虑将类 A 嵌套到类 C 中。
- 如果需要经常访问非公共的实例成员,设计成内部类,否则设计成静态嵌套类。
- 所以设计内部类的时候,能静态就静态。
2.3.局部类:Local Class(局部内部类)
局部类:定义在代码块中的类(可以定义在方法中、for 循环中、if 语句中等)
- 局部类不能定义除编译时常量以外的任何 static 成员。(因为代码块里面的东西作用范围仅在代码块中有效)
- 局部类只能访问 final 或 有效 final 的局部变量。
- 局部类可直接访问外部类中的所有成员(即使被声明为 peivate)
1 | public class Persion{ |
3.抽象类(Abstract Class):被 abstract 修饰的类
在面向对象的概念中,所有的对象都是通过类来描绘的,但是并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。
- 可以定义为抽象方法
- 可自定义构造方法(可通过 new 来创建)
- 子类必须实现抽象父类中的所有抽象方法(除非子类也是抽象类)
- 也可像普通类一样定义成员变量、常量、非抽象方法、嵌套类型、初始化块等
即抽象类中可完全不定义抽象方法。
抽象类意义:
- 用于拓展对象的行为功能:即重用 + 扩展
1 | public abstract class Abs{ |
抽象类使用场景:
- 抽取子类的公共实现到抽象父类中,并且把要求子类必须要单独实现的方法定义成抽象方法。