面向对象编程的三大特性
OOP三大特性
封装
程序设计追求高内聚,低耦合。
- 高内聚就是类的内部数据操作细节自己完成,不允许外部干涉
- 低耦合:仅暴露少量的方法给外部使用。
封装(即为数据的隐藏)
通常应禁止直接访问一个对象中数据的实际表示,而应通过操作接口来访问,这称为信息隐藏。
进行封装的操作:将属性设为私有private,设立get/set方法
set方法里面还可以做一些安全性的验证和判断
快捷键alt+insert快速生成get/set方法
public class Student{
//属性私有
private String name;
private int id;
private char sex;
//提供一些可以操作这个属性的方法,如提供public的get/set方法
//get 获得这个数据
public String getName(){
return this.name;
}
//set给这个数据设置值
public void setName(String name){
//要有形式参数 会被调用
this.name = name;
}
}
public class Demo{
public static void main(String[] args){
Student student = new Student();
//属性私有的情况下, student.name;是错误的,不可以这样使用,会爆红
String name = student.getName();//这样就可以得到name了
//通过set方法设置一个名字,这个值会传到setName()方法中,name就会被赋到值
student.setName ("fafa");
//输出name
System.out.println(student.getName());
}
}
使用封装可以规避一下不合法的输入,例如有一个int age
s1.setAge(999);//不合法的,又不是太上老君谁能活这么长
public String getAge(){
returnage;
}
public void setName(int age){
if(age>120 || age<0){
//不合法情况直接给他们赋一个正常的值,避免破坏程序
this.age = 18;
}
else{
this.age = age;
}
}
小插曲:方法中this.xx=xxx this. 代表当前类 ,而后面=的那个就是参数传进来的值
封装的意义
- 提高程序的安全性,保护数据
- 隐藏代码的实现细节
- 统一接口 都是get/set
- 系统的可维护性增加的,便于修改内部代码
继承
继承的本质是对某一批类的抽象,从而实现对现实世界更好的建模。
继承是类和类之间的一种关系。除此之外,类和类之间的关系还有依赖、组合、聚合等。
继承关系的俩个类,一个为子类(派生类),一个为父类(基类);一般成为父子关系。子类继承父类,使用关键字extends来表示。子类和父类之间,从意义上讲应该具有"is a"的关系,就如 旺财 is a dog
extends的意思是“扩展” 其中子类是父类的扩展。
子类继承了父类,就会拥有父类中的全部方法,前提是该方法修饰符是public,不过一般属性才是私有的
修饰符优先级 public protected default(默认的,不写修饰符时就默认是这个) private
JAVA中类只有单继承,没有多继承!一个儿子只能有一个爸爸,但一个爸爸可以有多个儿子。直接的继承只有一个,但间接的继承可以有多个
在Java中,所有的类都默认直接或间接继承object类
super
public class Application{
public static void main(String[] args){
Student student = new Student();
student.test("花花")
}
}
public class Person{
protected String name = "fafa";
}
public class Student extends Person{
private String name = "huahua";
public void test(String name){
//形参
System.out.println(name);//当前这个string name 传递过来的参数 输出花花
System.out.println(this.name);//指代当前Student类中的这个name 输出huahua
System.out.println(super.name);//调用到父类中的name 输出fafa
}
}
super同样适配继承方法的调用
public class Student extends Person{
public void print(){
System.out.println("student");
}
public void test1(){
print();//调用当前类中的print方法,输出student
this.print();//当前类中的print方法 输出student
super.print();//调用了父类中的print方法 输出person
}
}
public class Person{
//注意是public修饰 私有的东西是无法被继承的!!
public void print(){
System.out.println("person");
}
super中的构造器
public class Person{
public Person(){
System.out.println("Person的无参构造执行了");
}
}
public class Student extends Person{
public Studenr(){
//这里有一个隐藏代码 调用了父类的无参构造
//即隐藏了 super();
//而且调用父类的构造器,必须要在子类构造器的第一行,即这个super()一定要在这个sout上面
//this同理,调用自己的构造器(有参)也要放第一个,所以调用构造器,要么调用父类 要么调用子类的
//如果父类中没有无参构造,那么就必须写出来是super("...")
System.out.println("Student的无参构造执行了");
}
}
public class Application{
public static void main(String[] args){
Student student = new Student();
//会执行
//1 Person的无参构造执行了
//2 Student的无参构造执行了
}
}
super注意点
- super调用父类的构造方法,必须要出现在构造方法的第一个
- super必须只能出现在子类的方法或构造方法中
- super和this不能同时调用构造方法
super和this的区别
- 代表的对象不同
- this: 谁调用它就是谁,代表本身调用者这个对象
- super: 代表父类对象的应用
- 使用前提不同
- this:没有继承也可以使用
- super: 只能在继承条件下才可以使用
- 调用构造方法不同
- this: 调用本类的构造
- super: 调用父类的构造
方法的重写
重写都是方法的重写,与属性无关
重写的关键词只能是public 不能是private
静态方法下(与重写无关)
public class A extends B{
public static void test(){
System.out.println("aaaaa");
}
}
public class B{
public static void test(){
System.out.println("bbbbb");
}
}
public class Application{
public static void main(String[] args){
A a = new A();
a.test();//输出aaaaa
//在静态方法下 方法的调用只和左边有关即定义的数据类型有关
//父类的引用指向子类
B b = new A();
b.test();//输出bbbbb
}
非静态方法下
public class A extends B{
@Override
public void test(){
System.out.println("aaaaa");
}
}
public class B{
publicc void test(){
System.out.println("bbbbb");
}
}
public class Application{
public static void main(String[] args){
A a = new A();
a.test();//输出aaaaa
//重写只和非静态方法有关
//父类的引用指向了子类
B b = new A();//子类重写了父类的方法 就会执行子类的方法
b.test();//输出aaaaa
//子类跟父类都有的情况下,只要子类没有重写父类就调用父类的 子类要是重写了就调用子类的
}
重写的小结
- 需要有继承关系,子类重写父类的方法
- 方法名必须相同
- 参数列表必须相同
- 修饰符:范围可以扩大,但不能缩小。 就像父类是public,子类想变成private是不可能的
- 抛出的异常:范围可以被缩小但不能扩大
重写,子类的方法和父类必须要一致,方法体不同
tips: 快捷键 alt+insert 选择override
多态
多态即同一方法可以根据发送对象的不同而采用多种不同的行为方式。
一个对象的实际类型是确定的,但可以指向对象的引用的类型有很多
多态存在的条件
- 有继承关系
- 子类重写父类方法
- 父类引用指向子类对象
注意:多态是方法的多态,属性没有多态性
//一个对象的实际类型是确定的
//new Student();
//new Person();
//but 可以指向这个对象的引用类型是不确定的
//即父类的引用指向子类
Student s1 = new Student();
Person s2 = new Student();
Object s3 = new Student();
//Student能调用的方法都是自己的或者继承父类的
//Person是父类型,虽然可以指向子类,但是不能调用子类独有的方法
对象能执行哪些方法,主要看对象左边的类型,和右边的关系不大
多态小结 (注意事项)
- 多态是方法的多态,属性没有多态
- 父类和子类之间要有联系,不然会有类型转换异常(ClassCastExcepetion),就像String类型不能转为Person类型,狗不能转换为猫
- 多态存在的必要条件:
- 继承关系
- 方法需要重写
- 父类引用指向子类对象 father f1 = new Son();
but !有些方法不能被重写
- static方法,静态方法是属于类的,不属于实例
- final是常量的,被final修饰的在常量池中也不能被重写
- private方法是私有的,也不能被重写
instanceof
instanceof关键字判断两个类之间是否存在父子关系
instanceof关键字是在比较对象是否为后面类的实例
Object object = new Student();
//Object > Person > Student
//Object > Person > Teacher
//Object > String
//只有在同一个线上才能比出true or FALSE
//非同一线上比较就会出现编译错误
System.out.println(object instanceof Student);//True
System.out.println(object instanceof Person);//T
System.out.println(object instanceof Object);//T
System.out.println(object instanceof Teacher);//False
System.out.println(object instanceof String);//F

A(对象) instcnaceof B(类)结果为boolean型
A和B比较之前会先判断A能不能转换成B类型,能则通过,不能则编译报错
Person person = new Student();
Object object = new Student();
person instanceof String之所以编译会报错是因为person是Person类型,而String是final类型,两者不能转换
而object instanceof String中object是Object类型,String是Object的子类也继承了Object类型,所有能类型转换,编译通过
编译通过后会把A和B比较,如果A是B本类或者子类的对象,结果就是true,反之就是flase
因此object instanceof String,object这个对象不是String的本类或子类,所以出false
小结:
引用类型 变量名 = new 类名1();
变量名 instanceof 类名2;
Step1: 引用类型是否可以强制转换为类名2
可以:Step2;
不可以:编译报错,结束
Step2:类名1 是否为 类名2 的子类或类(本身)
是:true
不是:false
类型转换
高转低要强制转换
//例如Person类中有run方法 , Student类中有go方法
//父类转子类
//高 低
Person pp = new Student();
//pp.go();这是错误的 需要强制转换
//pp目前是Person类型的 需要将pp这个对象转换为Student类型,这样就可以使用Student类型的方法了
Student student = (Student)pp;
student.go();
//如果整合就是 ((Student)pp).go();
低转高不需要操作
//子类转换为父类,可能会丢失自己本来的一些方法
//低转高是自然发生的 student转person直接写就可以了
Person person = student;
//但这时要用go方法 不可以person.go() 需要强制转换成
((Student)pp).go();
多态小结
- 父类引用指向子类的对象
- 把子类转换为父类,向上转型,不需强制转型
- 父类转换为子类,向下转型,需强制转换
- 方便方法的调用,减少重复的代码
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?