news 2026/6/25 16:05:51

05 JAVA面向对象

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
05 JAVA面向对象

✨博客主页: https://blog.csdn.net/m0_63815035?type=blog

💗《博客内容》:大数据、AI开发、Java、测试开发、Python、Android、Go、Node、Android前端小程序等相关领域知识
📢博客专栏:https://blog.csdn.net/m0_63815035/category_11954877.html
📢欢迎点赞 👍 收藏 ⭐留言 📝
📢本文为学习笔记资料,如有侵权,请联系我删除,疏漏之处还请指正🙉
📢大厦之成,非一木之材也;大海之阔,非一流之归也✨


目录

    • 一、语言发展主线:为什么需要对象?
    • 二、类与对象
      • 1. 类的定义
      • 2. 对象的创建和使用
      • 3. 构造器(Constructor)
      • 4. this 关键字
      • 5. 内存分析(简略)
    • 三、封装
      • 1. 为什么要封装?
      • 2. 访问控制符
      • 3. getter / setter
      • 4. JavaBean 规范
    • 四、继承
      • 1. 继承语法和特点
      • 2. 方法重写(Override)
      • 3. super 关键字
      • 4. 构造器调用顺序
      • 5. Object 类常用方法
    • 五、多态
      • 1. 多态的定义
      • 2. 注意点
      • 3. 向下转型
      • 4. 动态绑定机制
    • 六、抽象类与接口
      • 1. 抽象类
      • 2. 接口
      • 3. 接口 vs 抽象类(Java 8 以前)
      • 4. Java 8 之后的接口变化
      • 5. 面向接口编程
    • 七、内部类
      • 1. 成员内部类
      • 2. 静态内部类
      • 3. 局部内部类
      • 4. 匿名内部类
    • 八、类和类之间的关系
    • 九、设计原则(SOLID 简版)
    • 十、综合练习

本篇是面向对象的完整讲解,从类和对象开始,到封装、继承、多态、接口、内部类,最后涉及设计原则。每个概念都有例子和常见注意事项。


一、语言发展主线:为什么需要对象?

计算机语言发展本质上是为了更自然地表达人的思维,同时管理越来越复杂的数据和操作。

  1. 只有基本变量→ 能存单个数字、字符,但数据一多就乱。
  2. 数组→ 把同一类型的数据连续存放,可以批量处理。但数组要求所有元素类型相同,且只能存数据,没有操作。
  3. 结构体(struct)→ 允许把不同类型的数据(如人的姓名、年龄、身高)组合成一个整体。但数据和方法还是分开的。
  4. 类和对象→ 把数据(属性)和操作(方法)绑在一起。一个对象就像现实中的一个实体,有自己的状态和行为。

面向过程:数据和方法分离,程序 = 数据结构 + 算法,以函数为中心。
面向对象:数据和方法合一,程序 = 对象 + 对象之间的消息传递,以类/对象为中心。

对于复杂系统(比如一个电商平台),宏观上需要用面向对象分析业务,拆成用户、商品、订单等类;但每个方法内部的具体实现(如计算价格、校验库存)仍然是面向过程的。


二、类与对象

1. 类的定义

类是模板,描述了一类事物共有的属性和方法。

classStudent{// 属性(成员变量,实例变量)intid;Stringname;intage;// 方法voidstudy(){System.out.println(name+"正在学习");}}
  • 属性可以设默认值,不设则系统给默认值:00.0false\u0000null
  • 方法定义和之前的函数一样,只不过它属于类。

2. 对象的创建和使用

Students1=newStudent();s1.id=1001;s1.name="张三";s1.study();
  • new Student()在堆内存中开辟空间,并返回地址给栈中的变量s1
  • 每个对象有自己的属性副本,互相独立。
  • 方法代码只存一份,所有对象共享。

3. 构造器(Constructor)

构造器是创建对象时自动调用的特殊方法,用来初始化对象。

特点:

  • 名字和类名完全相同
  • 没有返回值(也不能写void
  • 不能被staticfinalabstract修饰
  • 可以重载
classStudent{intid;Stringname;// 无参构造Student(){System.out.println("调用无参构造");}// 有参构造Student(intid,Stringname){this.id=id;// this 区分成员变量和局部变量this.name=name;}}

重要

  • 如果你不写任何构造器,编译器会自动生成一个无参构造(空实现)。
  • 只要你写了任何带参构造,编译器就不再自动生成无参构造。为了避免子类继承时出错,建议手动把无参构造也写上

构造器之间可以用this(...)互相调用,但必须放在第一行。

Student(){this(0,"无名");// 调用有参构造}

4. this 关键字

  • 在构造器中,表示正在初始化的对象。
  • 在实例方法中,表示调用该方法的对象。
  • 不能出现在静态方法中(因为静态方法不属于任何对象)。

常用场景:

  1. 区分成员变量和参数。
  2. 调用另一个构造器(必须第一行)。
  3. 返回当前对象(链式调用)。
classCalculator{Calculatoradd(intx){// ... 运算returnthis;// 返回自身}}Calculatorc=newCalculator().add(5).add(3);

5. 内存分析(简略)

  • :存放局部变量(包括基本类型和对象引用),方法调用时会压栈。线程私有,速度较快。
  • :存放所有new出来的对象(包括数组)。线程共享,速度稍慢。
  • 方法区:存放类信息(字节码)、静态变量、字符串常量等。线程共享。
Students=newStudent();
  1. 加载Student.class到方法区。
  2. 栈中创建s变量(引用)。
  3. 堆中开辟一块空间存 Student 对象,成员变量取默认值。
  4. 执行构造器代码(如果存在)。
  5. 将堆中对象的地址赋给s

三、封装

1. 为什么要封装?

  • 防止外部代码随意修改内部状态(例如年龄不能为负数)。
  • 隐藏实现细节,外部只需知道调用什么方法,不必关心内部如何实现。
  • 提高代码的可维护性:修改内部逻辑不影响调用方。

2. 访问控制符

修饰符同类同包子类(不同包)任何地方
private
(default)
protected
public
  • 属性通常用private隐藏。
  • 方法一般用public向外提供服务。
  • 仅本类内部调用的辅助方法可以用private

3. getter / setter

publicclassPerson{privateStringname;privateintage;privatebooleanmarried;publicStringgetName(){returnname;}publicvoidsetName(Stringname){this.name=name;}publicintgetAge(){returnage;}publicvoidsetAge(intage){if(age>=0&&age<=150){this.age=age;}else{thrownewIllegalArgumentException("年龄非法");}}// 注意:boolean 的 getter 习惯用 isXxxpublicbooleanisMarried(){returnmarried;}}

4. JavaBean 规范

一个标准的 JavaBean 需要:

  • 类公开,有无参构造
  • 属性私有
  • 提供 getter/setter
  • 实现Serializable(可序列化,后面再学)

封装不是简单的私有化,而是提供合理的访问接口。


四、继承

1. 继承语法和特点

classAnimal{Stringname;voideat(){System.out.println("吃东西");}}classDogextendsAnimal{voidbark(){System.out.println("汪汪");}}
  • Java 只支持单继承(一个类只能有一个直接父类),但可以实现多接口。
  • 所有类(除了Object)都直接或间接继承Object
  • 子类拥有父类所有的成员,但private成员不能直接访问(可以通过publicprotected方法间接访问)。

2. 方法重写(Override)

子类重新实现父类的方法。

规则:

  • 方法名、参数列表必须完全相同。
  • 返回值类型:子类返回值类型可以是父类返回值类型的子类(协变返回类型,了解即可)。
  • 访问权限不能更严格(可以扩大,不能缩小)。
  • private方法不能被重写,static方法不能被重写(但是可以重新声明)。
  • 可以用@Override注解,让编译器帮你检查。
classAnimal{protectedvoidshout(){System.out.println("动物叫");}}classCatextendsAnimal{@Overridepublicvoidshout(){// protected -> public 允许System.out.println("喵喵");}}

3. super 关键字

  • 访问父类的属性(当子类隐藏了父类同名属性时):super.name
  • 调用父类的方法:super.shout()
  • 调用父类的构造器:super(...),必须出现在子类构造器的第一行。

4. 构造器调用顺序

创建子类对象时,会先创建父类部分(递归直到Object),然后再执行子类构造器体的代码。

  • 子类构造器默认第一行有super()(调用父类无参构造)。
  • 如果父类没有无参构造,子类构造器必须显式调用父类的有参构造。
classFather{Father(intx){System.out.println("Father "+x);}}classSonextendsFather{Son(){super(100);// 必须写,否则编译错误System.out.println("Son");}}

5. Object 类常用方法

  • toString():返回对象的字符串表示,通常重写。
  • equals(Object obj):判断对象是否相等,默认比较地址,通常需要重写。
  • hashCode():返回对象的哈希码,重写equals时必须重写hashCode
  • getClass():返回运行时类信息。
@OverridepublicStringtoString(){return"Person{name="+name+", age="+age+"}";}

五、多态

1. 多态的定义

同一个类型的变量,调用同一个方法,实际执行的行为取决于运行时具体的对象类型。

必要条件:

  • 继承
  • 方法重写
  • 父类引用指向子类对象
Animala=newDog();// 向上转型(自动)a.shout();// 调用的是 Dog 的 shout()

2. 注意点

  • 属性没有多态:访问属性看编译时类型,不是运行时类型。
Animala=newDog();System.out.println(a.age);// 还是 Animal 的 age
  • 静态方法没有多态:静态方法属于类,调用时看编译时类型。
Animala=newDog();a.staticMethod();// 调用的是 Animal 的静态方法

3. 向下转型

当你想调用子类特有的方法时,需要把父类引用转回子类类型。

Animala=newDog();if(ainstanceofDog){// 安全检查,避免 ClassCastExceptionDogd=(Dog)a;d.bark();// Dog 独有的方法}

instanceof关键字:判断对象是否是某个类(或其子类)的实例。

4. 动态绑定机制

  • 编译时,编译器只检查引用变量的类型中是否有该方法。
  • 运行时,JVM 会找到对象实际类型的方法表,执行真正的方法。
  • 这就是多态的核心原理。

六、抽象类与接口

1. 抽象类

当某个方法无法在父类中给出合理实现时,可以声明为抽象方法,要求子类必须实现。

abstractclassShape{abstractdoublearea();// 抽象方法,无方法体voidshow(){System.out.println("这是一个形状");}}
  • 有抽象方法的类必须声明为abstract
  • 抽象类不能实例化(不能new)。
  • 抽象类可以有构造器(供子类调用)、普通属性、普通方法。
  • 子类必须实现所有抽象方法,除非子类也是抽象类。

2. 接口

接口是完全抽象的规范,强调“能做什么”。

interfaceFlyable{intMAX_HEIGHT=1000;// public static finalvoidfly();// public abstract}
  • 接口中的变量默认是public static final,方法默认是public abstract
  • 接口不能有构造器,不能有实例属性(但可以有静态常量)。
  • 一个类可以实现多个接口(多实现)。
  • 实现类必须重写所有接口中的抽象方法,且方法必须是public
classBirdimplementsFlyable{@Overridepublicvoidfly(){System.out.println("鸟飞");}}

3. 接口 vs 抽象类(Java 8 以前)

特性抽象类接口
多继承不支持支持(类可多实现)
实例属性可以有只能有静态常量
构造器可以有不能有
访问权限可以任意方法默认 public
使用场景表示“是什么”(is-a)表示“能做什么”(can-do)

4. Java 8 之后的接口变化

  • 默认方法:用default修饰,可以有方法体,实现类可以继承或重写。
  • 静态方法:用static修饰,属于接口,通过接口名调用。
interfaceVehicle{defaultvoidrun(){System.out.println("交通工具在跑");}staticvoidhonk(){System.out.println("嘀嘀");}}

这些变化允许接口在不破坏已有实现类的情况下增加方法。

5. 面向接口编程

优先使用接口类型声明变量,而不是具体类。这样更换实现不影响调用代码。

List<String>list=newArrayList<>();// 好// ArrayList<String> list = new ArrayList<>(); // 不好,耦合太强

七、内部类

内部类定义在另一个类内部,可以更好地封装,也能访问外部类的所有成员(包括私有)。

1. 成员内部类

classOuter{privateintx=10;classInner{voidprint(){System.out.println(x);// 可以访问外部类私有成员}}}// 创建方法Outerout=newOuter();Outer.Innerin=out.newInner();
  • 成员内部类不能有静态成员(除了静态常量)。
  • 内部类中可以使用Outer.this访问外部类当前对象。

2. 静态内部类

classOuter{staticclassInner{}}// 创建Outer.Innerin=newOuter.Inner();
  • 不持有外部类对象的引用,只能访问外部类的静态成员。
  • 可以像普通类一样有静态成员。

3. 局部内部类

定义在方法内部,作用域仅限该方法。

voidmethod(){classLocal{voidwork(){}}Locall=newLocal();}
  • 局部内部类可以访问外部类的成员,也可以访问方法中的局部变量,但局部变量必须是final或“实际上 final”(JDK 8 后不需要显式写 final,但不能修改)。

4. 匿名内部类

最常用,一次性使用,无需命名。

Runnabler=newRunnable(){@Overridepublicvoidrun(){System.out.println("run");}};
  • 匿名内部类继承某个类或实现某个接口,不能同时做两件事。
  • 不能定义构造器。
  • 常用于事件监听、线程、回调等场景。
button.addActionListener(newActionListener(){publicvoidactionPerformed(ActionEvente){// 处理点击}});

八、类和类之间的关系

关系描述UML 表示代码示例
依赖一个类临时使用另一个类(方法参数)虚线箭头方法参数、局部变量
关联一个类长期持有另一个类的引用实线箭头成员变量
聚合整体与部分,部分可独立存在空心菱形+实线箭头成员变量(弱)
组合整体与部分,同生共死实心菱形+实线箭头成员变量(强)
继承is-a空心三角+实线(子类→父类)extends
实现类实现接口空心三角+虚线(类→接口)implements
  • 聚合:汽车和轮胎,轮胎可以拆下来装在另一辆车上。
  • 组合:人和心脏,人没了心脏也就没了意义。

九、设计原则(SOLID 简版)

  1. 单一职责:一个类只负责一项职责。
  2. 开闭原则:对扩展开放,对修改关闭。增加功能尽量新增代码,而不是改原有代码。
  3. 里氏替换:子类必须能替换父类并且程序行为正确。
  4. 接口隔离:接口应该小而专,不要做“胖接口”。
  5. 依赖倒置:依赖抽象(接口/抽象类),不依赖具体实现。
  6. 迪米特法则:一个对象应尽可能少地了解其他对象。

这些原则不是死的,但遵循它们能让代码更容易维护和扩展。


十、综合练习

  1. 定义一个Point3D:三个坐标x,y,z,提供构造器,计算到原点的距离平方,计算到另一个Point3D对象的距离平方。
  2. 定义一个Circle:包含圆心(Point)和半径,提供面积方法,以及判断一个Point是否在圆内的方法。
  3. 动物多态Animal抽象类,shout()抽象方法。DogCat继承并重写。用Animal引用调用shout()
  4. 接口练习:定义USB接口,含work()方法。实现MouseKeyboard类,模拟将 USB 设备插入计算机。

学习面向对象时,多思考现实中的事物如何抽象成类,类之间有哪些关系。代码写多了,自然就会明白为什么需要封装、继承和多态。遇到不确定的就多翻 API 或写个小例子验证。

今天这篇文章就到这里了,大厦之成,非一木之材也;大海之阔,非一流之归也。感谢大家观看本文

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/8 14:22:48

StarCore DSP上判决反馈均衡器(DFE)的定点实现与优化

1. 项目概述&#xff1a;在StarCore DSP上实现高效判决反馈均衡器在数字通信接收机的设计里&#xff0c;信道均衡是个绕不开的坎。信号在传输过程中&#xff0c;会因为多径效应、带宽限制等因素产生码间干扰&#xff0c;导致接收端判断符号时出错。对于高阶调制&#xff0c;比如…

作者头像 李华
网站建设 2026/6/8 14:21:51

3步搞定B站视频永久保存:m4s-converter让你告别收藏失效的烦恼

3步搞定B站视频永久保存&#xff1a;m4s-converter让你告别收藏失效的烦恼 【免费下载链接】m4s-converter 一个跨平台小工具&#xff0c;将bilibili缓存的m4s格式音视频文件合并成mp4 项目地址: https://gitcode.com/gh_mirrors/m4/m4s-converter 你是否曾经遇到过这样…

作者头像 李华
网站建设 2026/6/8 14:21:25

终极macOS歌词同步神器:LyricsX让你的音乐体验瞬间升级

终极macOS歌词同步神器&#xff1a;LyricsX让你的音乐体验瞬间升级 【免费下载链接】LyricsX &#x1f3b6; Ultimate lyrics app for macOS. 项目地址: https://gitcode.com/gh_mirrors/ly/LyricsX 还在为macOS上找不到完美的歌词同步工具而烦恼吗&#xff1f;LyricsX就…

作者头像 李华
网站建设 2026/6/8 14:19:50

3分钟学会永久备份QQ空间所有历史记忆:高效数据导出终极指南

3分钟学会永久备份QQ空间所有历史记忆&#xff1a;高效数据导出终极指南 【免费下载链接】GetQzonehistory 获取QQ空间发布的历史说说 项目地址: https://gitcode.com/GitHub_Trending/ge/GetQzonehistory 还在为QQ空间里那些珍贵的青春记忆逐渐消失而担忧吗&#xff1f…

作者头像 李华
网站建设 2026/6/8 14:19:42

论企业集成架构设计及应用

在数字化转型深度推进的当下&#xff0c;多数企业逐步搭建了ERP、CRM、WMS、OA等各类业务信息系统&#xff0c;但各系统独立建设、技术标准不统一、数据互不互通&#xff0c;形成了严重的信息孤岛、业务断层问题&#xff0c;极大制约了企业业务协同效率与数字化运营能力。企业集…

作者头像 李华
网站建设 2026/6/8 14:17:57

Serverless 2.0冷启动终结:AWS Lambda已悄悄跑赢传统容器

Serverless 2.0冷启动终结&#xff1a;AWS Lambda已悄悄跑赢传统容器 很多人还在为 Serverless 的“冷启动”焦虑&#xff0c;觉得它不够稳定&#xff0c;不如传统容器架构可靠。但如果你仔细看一眼 AWS Lambda 最近的性能基准测试&#xff0c;会发现一个被忽略的事实&#xff…

作者头像 李华