1. final关键字
final关键字是最终的意思,可以修饰(类、方法、变量)
- 修饰类:该类被称为最终类,特点是不能被继承
- 修饰方法:该方法被称为最终方法,特点是不能被重写
- 修饰变量:该变量只能被赋值一次
final修饰变量的注意事项
final修饰基本数据的变量,变量存储的数据不能被改变
final修饰引用类型的变量,变量存储的地址不能被改变,但地址所指向对象的内容是可以被改变的
补充知识
使用了static final 修饰的成员变量被称为常量;
作用:通常用于记录系统的配置信息
Public class Constant {
public Static final SCHOOL_NAME = "wuhan"
}
注意:
常量的命名规范:建议使用大写英文字母,多个单词,使用下划线连接起来,使用常量记录系统配置信息的优势,执行原理
- 代码可读性更好,可维护性也更好
- 程序编译后,常量会被“宏替换”,出现常量的地方全部会被替换成其记住的字面量,这样可以保证使用常量和直接使用字面量的性能一样
认识抽象类
在java中又一个关键字叫:abstract,它就是抽象的意思,可以用它修饰类、成员方法
修饰符 abstract class 类名 {
修饰符 abstract 返回值类型 方法名称(形参列表);
}
// 示例
Public abstract class A {
// 抽象方法:必须abstract修饰,只有方法前面,不能有方法体
public abstract void test();
}
抽象类的注意事项
- 抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类
- 类该有的成员(成员变量、方法、构造器),抽象类都可以有
- 抽象类最主要的特点:抽象类不能创建对象,仅作用一种特殊的父类,让子类继承并实现
一个类继承抽象类,必须重写完抽象类的全部方法,否则这个类也必须定义成抽象类
抽象类的场景和好处
父类知道每个子类都要做某个行为,但每个子类要做的情况不一样,父类就定义抽象方法,
交给子类去重写实现,设计这样的抽象类,就是为了更好的支持多态
抽象类的常见应用场景:模板方法设计模式
模板方法设计模式解决了什么问题?
- 解决方法中重复代码的问题
方法名一样,这两个方法中存在大量重复代码,只有中间部分代码不同,可以把这个方法抽成所谓的模板方法设计模式出来,以便减少重复代码
模板方法设计模式的写法
-
定义一个抽象类
-
在里面定义2个方法
-
一个模板方法:把相同的代码放里面去
-
一个是抽象方法:具体实现交给子类去完成
-
多学一招:
建议使用final关键字修饰模板方法,为什么?
模板方法是给对象直接使用的,不能被子类重写,一旦子类重写了模板方法,模板方法就失效了
认识接口
java提供了一个关键字interface,用这个关键字可以定义出一个特殊的结构:接口
Public interface 接口名 {
// 成员变量(常量)默认加 public static final
// 成员方法(抽象方法)默认加 public abstract
}
注意:接口不能创建对象,接口是用来被类实现的(implements),实现接口的类称为实现类
修饰符 class 实现类 implements 接口1,接口2,接口3,...{
}
一个类可以实现多个接口(接口可以理解成干爹),实现类实现多个接口,必须重写完全部接口的全部抽象方法,否则实现类需要定义成抽象类
接口的好处(重点)
弥补了类单继承的不足,一个类同时可以实现多个接口
让程序可以面向接口编程,这样程序员就可以灵活方便的切换各种业务实现
JDK8开始,接口新增了三种形式的方法
Public interface A {
// 1. 默认方法:使用default修饰,默认会被加上public修饰
// 注意:只能使用接口的实现类对象调用
default void test1 {
}
// 2.私有方法:必须使用private修饰(JDK9才开始支持)
private void test2() {
...
//注意:只能在接口内部被调用
}
// 3. 类方法(静态方法):使用static修饰,默认会被加上public修饰
// 注意:只能用接口名来调用
Static void test3() {
...
}
}
JDK8开始,接口中为什么要新增这些方法?
增强了接口的能力,更便于项目的扩展和维护
接口中的方法为什么默认是用public修饰的?
接口定义出来都是供别人实现或者供别人面向接口编程,所以要暴露出去
接口的其他细节:
接口的多继承,使用接口的注意事项(了解)
接口的多继承:一个接口可以同时继承多个接口
Public interface C extends B,A {
}
接口多继承的作用,便于实现类去实现
接口的其他注意事项
- 一个接口继承多个接口,如果多个接口中存在方法签名冲突,则此时不支持多继承
- 一个类实现多个接口,如果多个接口中存在方法签名冲突,则此时不支持多实现
- 一个类继承了父类,又同时实现了接口,父类中和接口中又存在同名的默认方法,实现类会优先使用父类的方法
- 一个类实现了多个接口,多个接口中存在同名的默认方法,可以不冲突,这个类重写该方法即可
内部类
是类中的五大成分之一(成员变量、方法、构造器、内部类、代码块),如果一个类定义在另一个类的内部,这个类就是内部类
场景:当一个类的内部,包含了一个完整的事物,且这个事物没有必要单独设计时,就可以把这个事物设计成内部类
内部类有四种形式
- 成员内部类
- 静态内部类
- 局部内部类
- 匿名内部类
1. 成员内部类
就是类中的一个普通成员,类似前面我们学过的成员变量,成员方法
Public class outer {
// 成员内部类
public class Inner {
}
}
成员内部类创建对象的格式:
outer.Inner in = new outer().new Inner();
成员内部类中访问其他成员的特点:
- 和实例方法一样,成员内部类的实例方法中,同样可以直接访问外部类的实例成员、静态成员
- 可以在成员内部类中的实例方法中,拿到当前外部类对象,格式:外部类名.this
2. 静态内部类
有static修饰的内部类,属于外部类自己持有
Public class Outer() {
// 静态内部类
public static class Inner {
}
}
静态内部类创建对象的格式
外部类名.内部类名 对象名 = new 外部类.内部类(…);
outer.Inner in = new Outer.Inner(...);
静态内部类中访问外部类成员的特点
可以直接访问外部类的静态成员,不可以直接访问外部类的实例成员
3. 局部内部类
局部内部类是定义在方法中,代码块中,构造器等执行体中
Public class Test {
public static void main(String[] args) {
public static void go() {
class A {
}
abstract class B {
}
interface C {
}
}
}
4. 匿名内部类(重点)
就是一种特殊的局部内部类;所谓匿名:指的是程序员不需要为这个类声明名字
new 类或接口(参数值...){
类体(一般是方法重写);
}
new Animal() { // 把这个匿名内部类编译成一个子类,然后会立即创建一个子类对象出来
@override
public void cry() {
}
}
特点:匿名内部类本质就是一个子类,立即创建出一个子类对象
作用:用于更方便的创建一个子类对象
匿名内部类在开发中的使用场景
通常作为一个参数传输给方法
需求:猫和狗参加跑步比赛
Public interface Run() {
void run();
}
Public class Test {
public static void main(String[] args) {
// 认识匿名内部类,并掌握其作用
Run s1 = new Run() { 创建一个Run的子类对象出来给s1
@override
Public void run() { // 重写父类的run方法
System.out.println("狗跑的飞快");
}
go(s1);
}
go(new Run(){ // 直接把创建出来的子类对象传给go方法,执行子类重写的run方法
@override
Public void run() {
System.out.println("猫也跑的还行");
}
})
Public static void go(Run s) {
System.out.println("开始");
s.run; // 执行子类重写的run方法
}
}
}