面向对象的三大特性
封装
高内聚低耦合:
- 高内聚:类内部的操作细节自己完成,不需要外部干涉
- 低耦合:仅提供少量方法供外部使用
封装的意义:
- 提高安全性,保护数据
- 隐藏代码实现细节
- 统一接口
- 提高系统的可维护性
属性私有,get/set:
- 属性私有:通过 private关键字实现,使的属性无法访问,修改
- get/set:提供一些可以操作私有属性的方法(有public修饰的get、set方法),set方法可以用于做一些安全性判断
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
继承
继承的本质是对有共同特点的类的抽象
关键字extends
,在定义类时,在类名后加extends 父类名
表示继承,子类是父类的扩展
继承特点:
- 继承是类跟类之间的关系,类之间的关系还有依赖、组合、聚合等
- 继承关系的两个类包括:父类(基类)和子类(派生类)
- 子类和父类之间有
is a
的关系 - 子类可以继承父类中所有
public
修饰的方法和属性 - Java中,所有的类都默认直接或间接继承Object类
- Java中只有单继承,没有多继承;一个类只能直接继承一个类,可以间接继承多个类
final
修饰的类无法被继承
IDEA中可以通过control + H
查看类的层次结构
super
super
表示父类对象的引用,可以通过super
关键字调用父类的属性和方法,但只能在继承条件下使用.
private
修饰的属性和方法无法继承,super
也无法调用
构造器中的super
特点:
- 子类构造器的第一行必须调用默认构造器(
super()
或this()
) - 子类构造器,会隐式的调用父类的无参构造器
- 若父类只有有参构造器,则子类构造器必须显式的调用父类有参构造器
- 不能同时调用
super()
和this()
构造方法
方法重写
方向重写的前提是类之间要有继承关系,子类可以重写父类的方法
重写注意点:
- 方法名必须相同
- 参数列表必须相同
- 修饰符:范围可以扩大,但不能缩小,例:public重写为private
- 抛出异常:范围可以缩小,但不能扩大
重写知识点:
- 重写是针对方法的,与属性无关
- 重写是基于非静态方法的
- 静态方法是类的方法,非静态方法是对象的方法;静态方法的调用取决于引用变量的类,非静态方法的调用取决于new的对象的类
重写的意义:父类方法可能不满足子类要实现的功能
IDEA可以通过快捷键快速生成重写:Win:alt + Insert
;Mac:Command + N
多态
多态:同一方法会根据引用类型的不同而采用不同的调用方式。
多态是针对方法的,属性没有多态。
一个对象的实际类型是确定的,但其引用类型可能有多个,父类的引用可以指向子类
多态存在的条件:
- 类之间为继承关系
- 子类重写了父类的方法
- 不能被重写的方法:
static
修饰的方法:静态方法,属于类,不属于任何实例private
修饰的方法:常量,无法被修改final
修饰的方法:私有方法,无法被访问
- 父类的引用指向子类的对象
- 引用类型指向的对象必须存在继承关系,否则会触发类型转换异常
ClassCastException
多态注意事项:
- 父类的引用可以指向子类,但是不能调用子类的方法(所以对象能调用的方法主要取决于其引用类型)
- 父类可以通过强制类型转换来调用子类的方法
- 子类可以使用自己的方法以及继承自父类的方法
- 父类的引用指向子类时,若调用的方法被子类重写,则执行子类的方法
- 父类引用指向自身对象时,不属于多态,调用自己的方法
instanceof
instanceof
关键字用于判断两个类之间是否存在联系,是一个二元运算符。
X instanceof Y
注意事项:
- 语句能否编译通过取决于X与Y之间是否存在继承关系
- 返回值取决于X实例的实际类型是否为Y的实例对象或直接、间接子类
类型转换(引用类型)
类型转换:
- 基本类型转换:高 > 低 (数据范围大小)
- 引用类型转换:父 > 子 (继承关系父子)
类型转换注意事项:
- 父类 -> 子类,需要强制类型转换,父类转换为子类才能使用子类的方法
- 子类 -> 父类,无需强制类型转换,子类转换为父类可能会丢失自己的部分方法
- 类型转换是为了方便调用方法(父类使用子类的方法),减少重复代码
static
static修饰符可以修饰变量、方法、代码块:
- static修饰变量:
- 表示静态变量,一般用于多线程中,方便多个实例共享
- 静态变量一般通过类名调用
- 非静态变量通过实例化对象来调用
- static修饰方法:
- 表示静态方法,随类一起加载,通过类名调用
- 非静态方法要通过实例化对象来调用
- static修饰代码块:
- 表示静态代码块,会随类一起加载,且只在类加载的时候执行一次
- 没有static修饰的代码块为匿名代码块,一般用于赋初始值,在实例化对象时被调用,可以执行多次
- 调用顺序:静态代码块 > 匿名代码块 > 构造器
抽象类和接口
抽象类
abstract
可以修饰方法或类,表示抽象方法或抽象类
抽象类仍是类,只能通过extends
进行单继承,接口可以多继承
抽象类特点:
- 不能通过
new
进行实例化,抽象类是一种约束,要靠子类进行实现 - 抽象类中可以写普通的方法,但抽象方法只能写在抽象类中
- 非抽象子类继承抽象类时,必须实现抽象类中的抽象方法,非抽象方法可以不实现
抽象类是用于抽象出类的模板,用于给子类继承,提高开发效率
接口
接口就是规范,定义一组规则,接口的本质是契约,声明接口的关键字interface
- 普通类:每个方法都有具体的实现
- 抽象类:可以有具体实现的方法,也可以有规范(抽象方法)
- 接口:只有规范,无法书写方法;专业的约束,用于实现约束和分离、
接口的特点:
- 接口是用来做约束的,用于定义一些方法,通过后续的类进行实现
- 接口中所有定义的方法都是抽象的(相当于默认带了
public abstract
修饰符) - 接口中定义的变量都是常量(相当于默认带了
public static final
修饰符) - 接口不能被实例化,因为接口中没有实现方法
- 类可以通过
implements
关键字实现多个接口,伪多继承 - 类实现接口必须重写接口的所有方法
内部类
内部类就是在类的内部再定义一个类,A类中定义B类,则B类是A类的内部类,A类是B类的外部类
- 成员内部类:写在类内部的类,需要通过外部类实例来实例化内部类。内部类可以使用外部类的私有属性和方法
Outer outer = new Outer();
// 通过外部类来实例化内部类
Outer.Inner inner = outer.new Inner();
- 静态内部类:写在类内部,且被static修饰的类。静态内部类不能访问外部类的非静态属性
- 局部内部类:写在方法中的类,局部内部类中也可以写方法
- 匿名内部类:没有名字的内部类,需要借助接口或父类
new ILike(){
@Override
public void lambda() {
System.out.println("lambda4");
}
}.lambda();
内部类相关知识点:
- 内部类不能直接调用外部类的方法,只能在内部类中写方法实现
- 静态内部类不能访问外部类的非静态属性
- 一个java文件中可以有多个class,但只能有一个public class