范围
Java面向对象知识,包括:封装继承多态、构造方法、this、super、final、static、抽象类、接口、内部类、枚举
封装继承多态
封装
把数据封装进类里面,操作核心是控制访问权限(用 private 保护属性,用 public 的 getter/setter 控制访问)
继承
子承父业,使用extends关键字,子类获得父亲的非private的属性和方法。
注意:单继承(一个儿子只有一个父亲)、方法重写@Override、子类构造得先调用父类构造
顺序:
静态>非静态,父类>子类,非构造方法>构造方法
多态
同一行为,不同表现。
前提:子承父业、子类重写父类方法、父类引用指向子类的对象
-
向上转型(生成多态)
Animal animal = new Dog();
父类引用 指向 子类对象,只能调用父类方法,用不了子类特有功能 -
向下转型(还原子类)
Animal obj = new Dog(); // 不安全写法,直接强转容易崩 Dog d = (Dog)obj; // 安全写法 if(obj instanceof Dog){ Dog d = (Dog)obj; d.wang(); // 调用狗狗独有方法 }
示例
//---------------------------基类(封装+为继承设计)-------------------------------
public class OOTest {
//封装
private String name;
private Integer age;
//构造方法
public OOTest(String name, Integer age){
this.name = name;
this.age = age;
}
//构造方法-重载
public OOTest(String name){
this.name = name;
this.age = 18;
}
//公开gett/sett
public String getName() {return name;}
public void setName(String name) {this.name = name;}
public Integer getAge() {return age;}
public void setAge(Integer age) {this.age = age;}
//普通方法
public String makeSound(){return "齁齁齁齁齁齁";}
//静态方法
public static String makeSoundByname(String name){return name + "发出:齁齁齁齁";}
}
//---------------------------子类(继承+重写)-------------------------------
public class OOTestsSon extends OOTest{
// 调用父类构造,完成 name、age 的初始化
public OOTestsSon(String name, Integer age) {
super(name, age);
}
public OOTestsSon(String name) {
super(name);
}
@Override
public String makeSound() {
return "喵喵喵";
}
}
//---------------------------多态----------------------------------------
System.out.println("\n========== 多态调用 ==========");
OOTest o1 = new OOTestsSon("小黑", 6);
OOTest o2 = new OOTestsSon2("小黄", 7);
// 调用同一个方法,实际执行的是子类重写后的版本
System.out.println(o1.makeSound());
System.out.println(o2.makeSound());
//多态在集合中
OOTest[] arr = {new OOTestsSon("小王", 8), new OOTestsSon2("小李", 9)};
for (OOTest o : arr){
System.out.println(o.makeSound());
System.out.println(OOTest.makeSoundByname(o.getName()));
}
调用顺序
========== 多态调用 ==========
【父类】静态代码块执行
【子类】静态代码块执行
【父类】普通代码块执行
【父类】双参构造方法执行
【子类】非静态代码块执行
【子类】双参构造方法执行
【子类】静态代码块执行
【父类】普通代码块执行
【父类】双参构造方法执行
【子类】非静态代码块执行
【子类】双参构造方法执行
喵喵喵
汪汪汪
--------------------------------
//静态方法只会执行一次
【父类】普通代码块执行
【父类】双参构造方法执行
【子类】非静态代码块执行
【子类】双参构造方法执行
【父类】普通代码块执行
【父类】双参构造方法执行
【子类】非静态代码块执行
【子类】双参构造方法执行
喵喵喵
小王发出:齁齁齁齁
汪汪汪
小李发出:齁齁齁齁
构造方法
注意点:
- 类加载时:先父类静态,再子类静态,各执行一次。
- 每次
new时:先父类构造代码块 + 构造方法,再子类构造代码块 + 构造方法。 super(args)必须在子类构造第一行;如果不写,编译器自动插入super()。- 构造代码块(
{}直接写在类里)在构造方法之前执行,每new一个对象就执行一次。 - 若父类没有无参构造,子类必须显式
super(args),否则编译报错。
重载和this()例子
//这里 this()在一个构造里调用了重载的另一个构造,目的是复用初始化逻辑,避免重复代码
class Book {
String title;
double price;
// 无参构造
public Book() {
this("未知书名", 0.0); // 调用本类有参构造,必须第一行
}
// 有参构造
public Book(String title, double price) {
this.title = title;
this.price = price;
}
}
static关键字
static就是把成员从「对象私有」提成「类全局公有」,免实例直接调用,值全局互通可修改
声明方法用static修饰,则该方法叫做静态方法,作用是跳过对象直接访问方法
静态方法只能访问静态变量和调用静态方法
静态代码块
静态代码块通常用来初始化一些静态变量,它会优先于 main() 方法执行
这一内容的作用主要是加载配置文件等等
final关键字
固定常量,final可以修饰变量、对象、方法、类,作用都类似于将其变为“最终状态不可修改状态
final变量
final修饰的变量不可以修改,并且要在声明的时候完成初始化
例如:final修饰的person对象,person不可修改,但是person.age可以修改
final+static一起修饰的叫做常量,即不可修改且唯一
final方法
不可被重写
final类
不可被继承,但是final类的对象是可以改变的
this和super
this指向对象本身,super指向爸爸那部分
this关键字
- 作为引用变量,指向当前对象
举例:在一个类中声明了一个变量,同时定义了一个方法,此方法的内容是将变量赋值为传入的参数,同时传入参数名和成员变量名相同,如果没有使用this指明,java就不知道此变量是不是类的成员变量
结果:null - 调用当前类的方法
在当前类的某一个方法中,使用this.方法名来调用另一个该类中的方法 - 调用当前类的构造方法
在一个构造方法中调用另一个参数不同的构造方法,但是this语句必须写在第一句 - 作为参数传递
把当前对象自己传给另一个方法(可以是外部工具类、其他对象的方法),让它们操作当前对象 - 作为参数在构造方法中传递
this指向的是已经开好内存的半成品对象,不是完整成品,所以构造执行中,拿this传参、调用本类普通方法全都没问题。 - 作为方法返回值
super关键字
- 指向父对象
- 调用父方法
super()可以调用父类的构造方法
instanceof关键字
-
语法
对象 instanceof 类名 -
规则
- 本类对象 → true
- 子类对象 判断父类 → true
- 父类对象 判断子类 → false
null instanceof 任意→ false
-
例子
class Animal{} class Dog extends Animal{} Dog d = new Dog(); Animal a = new Animal(); System.out.println(d instanceof Dog); // true System.out.println(d instanceof Animal); // true System.out.println(a instanceof Dog); // false
抽象类 abstract
抽象类命名要以Abstract或Base开头
特性:不能被实例化,并且子类必须实现它的抽象方法
主要作用:在于继承时的扩展,比如在很多子类中都有但是内容却不一样的方法
接口 interface
可以实现:定义变量、定义抽象方法、定义默认方法default、定义静态方法
限制:
- 不允许直接实例化
- 接口可以为空
- 定义接口不能使用final
- 接口的抽象方法不能为private、protected、final
- 加快的变量为隐式常量,值不能改变
作用:实现多继承
抽象和接口区别:抽象是一个类,接口可以是一个动作或变量
内部类
内部类就是定义在另一个类内部的类,有四种形态:
成员内部类、局部内部类、匿名内部类和静态内部类
成员
最常见、最简单。内部类可以任意调用或访问外部类的成员,而外部类想要访问内部类,需要先声明一个内部类的对象
相当于内部类和外部类完全绑定
局部
定义在一个方法或者一个作用域里面的类,所以生命周期仅限于作用域,不能被权限修饰符修饰,访问权限与成员内部类一样,但访问局部变量时只能访问final
没怎么见过
匿名
最常用,主要作用用来继承其他类或者实现接口,并不需要增加额外的方法,方便对继承的方法进行实现或者重写
lambda大量代替
// 以前:匿名类实现 Runnable
new Thread(new Runnable() {
public void run() { System.out.println("run"); }
}).start();
// 现在:Lambda 表达式
new Thread(() -> System.out.println("run")).start();
// 必须匿名类:抽象类无法用 Lambda
Payment p = new Payment("001", 200) {
public boolean pay() { return true; }
protected String getMethod() { return "自定义"; }
};
静态
成员内部类+static,访问时只能访问静态变量和方法
总结:
内部类是否需要访问外部实例成员?
├─ 不需要 → 静态内部类
└─ 需要
├─ 只在某个方法里用到 → 可考虑局部内部类(很少用)
├─ 被多处使用,且和外部状态强相关 → 成员内部类
└─ 仅需一次性创建 → 匿名内部类(或 Lambda)
枚举 enum
一种特殊的类,是单例的最佳实现
-
命名规范
- 枚举类名使用大驼峰命名法(PascalCase)
- 枚举常量使用全大写,单词间用下划线分隔(UPPER_SNAKE_CASE)
- 枚举类通常应该是公共的(public)
-
使用建议
- 当需要表示一组固定的常量时,应优先使用枚举
- 为枚举添加有意义的方法和属性,而不是仅仅作为常量集合
- 使用枚举的 valueOf() 方法时要注意处理异常
- 在 switch 语句中使用枚举时,建议处理所有可能的枚举值
示例
@Getter
public enum ErrorCode {
SUCCESS(0, "操作成功"),
PARAM_ERROR(400, "参数错误"),
UNAUTHORIZED(401, "未授权"),
FORBIDDEN(403, "禁止访问"),
NOT_FOUND(404, "资源不存在"),
INTERNAL_ERROR(500, "服务器内部错误");
ErrorCode(int code, String message) {
this.code = code; this.message = message;
}
private final int code;
private final String message;
public static ErrorCode fromCode(int code){
for(ErrorCode e : values()){
if(e.code == code )return e;
}
throw new IllegalArgumentException("未知:"+code);
}
}