面向对象
面向过程(POP)与面向对象(OOP)
二者都是一种思想,面向对象是相对于面向过程而言的。面向过程强调的是功能行为,以函数为最小单位,考虑怎么做。面向对象,将功能封装进对象,强调具备了功能的对象,以类/对象为最小单位,考虑谁来做。
面向对象更加强调运用人类在日常的思维逻辑中采用的思想方法与原则,如抽象、分类、继承、聚合、多态等。
面向对象编程:Object Oriented Programming
面向过程编程:Procedure Oriented Programming
面向对象的思想概述
程序员从面向过程的执行者转化成了面向对象的指挥者。
面向对象分析方法分析问题的思路和步骤:
- 根据问题需要,选择问题所针对的现实世界中的实体。
- 从实体中寻找解决问题相关的属性和功能,这些属性和功能就形成了概念世界中的类。
- 把抽象的实体用计算机语言进行描述,形成计算机世界中类的定义。即借助某种程序语言,把类构造成计算机能够识别和处理的数据结构。
- 将类实例化成计算机世界中的对象。对象是计算机世界中解决问题的最终工具。
类(Class)和对象(Object)是面向对象的核心概念。
- 类是对一类事物的描述,是抽象的、概念上的定义
- 对象是实际存在的该类事物的每个个体,因此也称为实例(instance)。
- “万事万物皆对象”
- 可以理解为:类=抽象概念的人;对象=实实在在的某个人
- 面向对象程序设计的重点是类的设计
- 类的设计,其实就是类的成员的设计
理解“万事万物皆对象”
1.在Java语言范畴中,我们都将功能、结构等封装到类中, 通过类的实例化来调用具体的功能结构
>Scanner,String等
>文件:File
>网络资源: URL
2.涉及到Java语言与前端Html、CSS、JavaScript、 后端的数据库交互时,前后端的结构在Java层面交互时, 都体现为对象。
Java类及类的成员
1.属性:对应类中的成员变量
2.行为(方法):对应类中的成员方法
Field=属性=成员变量,Method=(成员)方法=函数
java类的实例化,即创建类的对象
3.构造器(构造方法constructor)的使用
构造器的作用:
1.创建对象
2.初始化对象的信息
说明:
1.如果没有显式的定义类的构造器的话,则系统默认提供一个空参的构造器
2.定义构造器的格式:权限修饰符 类名(形参列表){}
3.一个类中定义的多个构造器,彼此构成重载
4.一旦我们显示的定义了类的构造器之后,系统就不再提供默认的空参构造器
5.一个类中,至少会有一个构造器。
4.代码块(或初始化块)
1.代码块的作用:用来初始化类、对象
2.代码块如果有修饰的话,只能使用static。
3.分类:静态代码块和非静态代码块
4.静态代码块
>内部可以有输出语句
>随着类的加载而执行,而且只执行一次
>作用:初始化类的信息
>如果一个类中定义了多个静态代码块,则按照声明的先后顺序执行
>静态代码块的执行要优先于非静态代码块的执行
>静态代码块内只能调用静态的属性、静态的方法,不能调用非静态的结构
5.非静态代码块
>内部可以有输出语句
>随着对象的创建而执行
>每创建一个对象,就执行一次非静态代码块
>作用:可以在创建对象时,对对象的属性等进行初始化
>如果一个类中定义了多个非静态代码块,则按照声明的先后顺序执行
>非静态代码块内可以调用静态的属性、静态的方法,或非静态的属性、非静态的方法
5.内部类
1. Java中允许将一个类A声明在另一个类B中,则类A就是内部类,类B称为外部类
2.内部类的分类:成员内部类(静态、非静态)和局部内部类(方法内、代码块内、构造器内)
3.成员内部类:
一方面,作为外部类的成员:
>调用外部类的结构
>可以被static修饰
>可以被4种不同的权限修饰
另一方面,作为一个类:
>类内可以定义属性、方法、构造器等
>可以被final修饰,表示此类不能被继承。言外之意,不使用final,就可以被继承
>可以被abstract修饰
4.成员内部类:
4.1如何创建成员内部类的对象(静态的,非静态的)
//创建静态的Dog内部类的实例(静态的成员内部类) Person.Dog dog = new Person.Dog(); //创建非静态的Bird内部类的实例(非静态的成员内部类) //Person.Bird bird = new Person.Bird();//错误的 Person p = new Person(); Person.Bird bird = p.new()Bird();
4.2如何在成员内部类中调用外部类的结构
1 class Person{ 2 String name = "小明"; 3 4 //非静态成员内部类 5 class Bird{ 6 String name = "杜鹃"; 7 public void display(String name){ 8 System.out.println(name);//方法的形参 9 System.out.println(this.name);//内部类的属性 10 System.out.println(Person.this.name);//外部类的属性 11 } 12 13 } 14 }
总结:
成员内部类和局部内部类,在编译以后,都会生成字节码文件。
格式:成员内部类:外部类$内部类名.class
局部内部类:外部类$数字 内部类名.class
对属性可以赋值的位置:
①默认初始化
②显式初始化/⑤在代码块中赋值
③构造器中初始化
④有了对象以后,可以通过"对象.属性"或"对象.方法"的方式,进行赋值
执行的先后顺序:① - ② / ⑤ - ③ - ④
类和对象的使用(面向对象思想落地的实现)
1.创建类,设计类的成员
2.创建类的对象
3.通过“对象.属性”或“对象.方法”调用对象的结构
如果创建了一个类的多个对象,则每个对象都独立拥有一套类的属性。(非static的)意味着,如果我们修改一个对象的属性值a,则不影响另外一个对象的属性a的值。
匿名对象的使用
理解:我们创建的对象,没有显式的赋给一个变量名,即为匿名对象。
特征:匿名对象只能调用一次。
对象的内存解析
内存解析的说明
引用类型的变量,只可能存储两类值: null或 地址值(含变量的类型)
类中属性的使用
属性(成员变量)和局部变量
1.相同点:
1.1定义变量的格式:数据类型 变量名 = 变量值
1.2先声明,后使用
1.3变量都有其对应的作用域
2.不同点:
2.1在类中声明的位置不同
属性(成员变量):直接定义在类的一对{}内
局部变量:声明在方法内、方法形参、代码块内、构造器形参、构造器内部的变量
2.2关于权限修饰符的不同
属性:可以在声明属性时,指明其权限,使用权限修饰符。
常用的权限修饰符,private、public、缺省、protected - - ->封装性
局部变量:不可以使用权限修饰符。
2.3默认初始化值的情况:
属性(成员变量):类的属性,根据其类型,都有默认初始化值。
整形(byte、short、int、long),0
浮点型(float、double),0,0
字符型(char),0(或‘\u0000’)
布尔型(boolean):false
引用数据类型(类、数组、接口),null
局部变量:没有默认初始化值。
意味着,我们在调用局部变量之前,一定要显式赋值。
特别地:形参在调用时,我们赋值即可。
2.4在内存中加载的位置:
属性:加载到堆空间中(非static)
局部变量:加载到栈空间
类中方法的声明和使用
方法的声明:权限修饰符 返回值类型 方法名(形参列表){
方法体
}
说明:
关于权限修饰符:默认方法的权限修饰符先都使用public
返回值类型:有返回值、没有返回值
如果方法有返回值,则必须在方法声明时,指定返回值的类型。同时,方法中,需要使用return关键字来返回指定类型的变量或常量,“return 数据”。
如果方法没有返回值,则方法声明时,使用void来表示。通常,没有返回值的方法中,就不使用return,但是,如果使用的话,只能“return;”表示结束此方法的意思。
方法名:属于标识符,遵循标识符的规则和规范,“见名知意”
形参列表:方法可以声明0个,1个,或多个形参。
格式:数据类型1 形参1,数据类型2 形参2,...
方法体:方法功能的体现。
方法的重载(overload)
1.定义:在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型不同即可。
“两同一不同”:同一个类、相同方法名
参数列表不同,参数个数不同,参数类型不同
2.判断是否是重载:
跟方法的权限修饰符、返回值类型、形参变量名、方法体都没有关系!
3.在通过对象调用方法时,如何确定某一个指定的方法:
方法名--->参数列表
方法参数的值传递机制
1.形参: 方法定义时,声明的小括号内的参数
实参:方法调用时,实际传递给形参的数据
2.值传递机制:
如果参数是基本数据类型,此时实参赋给形参的是实参真实存储的数据值。
如果参数是引用数据类型,此时实参赋给形参的是实参存储数据的地址值。
递归(recursion)方法
递归方法:一个方法体内调用它自身。
方法递归包含了一种隐式的循环,它会重复执行某段代码,但这种重复执行无须循环控制。
递归一定要向已知方向递归,否则这种递归就变成了无穷递归,类似于死循环。
面向对象的三大特征
程序设计追求“高内聚”,“低耦合”。
高内聚:类的内部数据操作细节自己完成,不允许外部干涉;
低耦合:仅对外暴露少量的方法用于使用。
封装(Encapsulation)
隐藏对象内部的复杂性,只对外公开简单的接口,便于外界调用,从而提高系统的可扩展性、可维护性。通俗的说,把该隐藏的隐藏起来,该暴露的暴露出来。这就是封装性的设计思想。
封装性的体现
1.将类的属性私有化(private),同时,提供公共的(public)方法来获取(get)和设置(set)此属性的值。
2.不对外暴露的私有的方法
3.单例模式...
封装性的体现:需要权限修饰符来配合。
1.Java规定的4种权限修饰符(从小到大排列):private、缺省、protected、public
2.4种权限修饰符可以用来修饰类及类的内部结构:属性、方法、构造器、内部类
3.具体的,4种权限修饰符可以用来修饰类及类的内部结构:属性、方法、构造器、内部类
修饰类的话,只能使用:缺省、public
封装性总结:Java提供了4种权限修饰符来修饰类及类的内部结构,体现类及类的内部结构在被调用时的可见性的大小。
继承(Inheritance)
—、继承性的好处
① 减少了代码的冗余,提高了代码的复用性
② 便于功能的扩展
③ 为之后多态性的使用,提供了前提
二、继承性的格式: class A extends B{ }
A:子类、派生类、subclass
B:父类、超类、基类、superclass
2.1 体现:一旦子类A继承父类B以后,子类A中就获了父类B中声明的结构。属性、方法
特别的,父类中声明为private的属性或方法,子类继承父类以后,仍然认为获取了父类中私有的结构。
只是因为封装性的影响,使得子类不能直接调用父类的结构而已。
2.2 子类继承父类以后,还可以声明自己特有的属性或方法:实现功能的拓展。
子类和父类的关系,不同于子集和集合的关系。
extends:延展、扩展
三、Java中关于继承性的规定:
1.一个类可以被多个子类继承。
2.Java中类的单继承性:一个类只能有一个父类
3.子父类是相对的概念。
4.子类直接继承的父类,称为:直接父类。间接继承的父类称为:间接父类
5.子类继承父类以后,就获取了直接父类以及所有间接父类中声明的属性和方法
四、继承说明
1.如果我们没有显式的声明一个类的父类的话,则此类继承于java.lang.Object类
2.所有的java类(除java.lang.Object类之外)都直接或间接的继承于java.lang.Object类
3.意味着,所有的java类具有java. lang.Object类声明的功能。
方法的重写(override / overwrite)
1.重写:子类继承父类以后,可以对父类中同名同参数的方法,进行覆盖操作
2.应用:重写以后,当创建子类对象以后,通过子类对象调用子父类中的同名同参数的方法时,实际执行的是子类重写父类的方法
3.重写的规定:
方法的声明: 权限修饰符 返回值类型 方法名(形参列表) throws 异常的类型{
//方法体
}
约定俗成:子类中的叫重写的方法,父类中的叫被重写的方法
① 子类重写的方法的方法名和形参列表与父类被重写的方法的方法名和形参列表相同
② 子类重写的方法的权限修饰符不小于父类被重写的方法的权限修饰符
>特殊情况:子类不能重写父类中声明为private权限的方法
③ 返回值类型:
>父类被重写的方法的返回值类型是void,则子类重写的方法的返回值类型只能是void
>父类被重写的方法的返回值类型是A类型,则子类重写的方法的返回值类型可以是A类或A类的子类
>父类被重写的方法的返回值类型是基本数据类型(比如: double),则子类重写的方法的返回值类型必须是相同的基本数据类型(必须也是double)
④ 子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常类型
子类和父类中的同名同参数的方法要么都声明为非static的(考虑重写),要么都声明为static的(不是重写)。
注意:
1.若子类重写了父类方法,就意味着子类里定义的方法彻底覆盖了父类里的同名方法,系统将不可能把父类里的方法转移到子类中:编译看左边,运行看右边
2.对于实例变量则不存在这样的现象,即使子类里定义了与父类完全相同的实例变量,这个实例变量依然不可能覆盖父类中定义的实例变量:编译运行都看左边
子类对象实例化的全过程
1. 从结果上来看:(继承性)
子类继承父类以后,就获取了父类中声明的属性或方法。
创建子类的对象,在堆空间中,就会加载所有父类中声明的属性。
2. 从过程上来看:
当我们通过子类的构造器创建子类对象时,我们一定会直接或间接的调用其父类的构造器,进而调用父类的父类的构造器直到调用了java. lang.Object类中空参的构造器为止。正因为加载过所有的父类的结构,所以才可以看到内存中有父类中的结构,子类对象才可以考虑进行调用。
明确: 虽然创建子类对象时,调用了父类的构造器,但是自始至终就创建过一个对象,即为new的子类对象。
多态(Polymorphism)
1. 理解多态性:可以理解为一个事物的多种形态。
2. 何为多态性:
对象的多态性:父类的引用指向子类的对象(或子类的对象赋给父类的引用)
3. 多态的使用:虚拟方法调用
有了对象的多态性以后,我们在编译期,只能调用父类中声明的方法,但在运行期,我们实际执行的是子类重写父类的方法。
总结:编译,看左边;运行,看右边。
4. 多态性的使用前提:① 类的继承关系 ② 方法的重写
5. 对象的多态性,只适用于方法,不适用于属性(编译和运行都看左边)
注意:有了对象的多态性以后,内存中实际上是加载了子类特有的属性和方法的,但是由于变量声明为父类类型导致编译时,只能调用父类中声明的属性和方法。子类特有的属性和方法不能调用。如何才能调用子类特有的属性和方法?使用强制类型转换符向下转型。
重写和重载
从编译和运行的角度看:
重载,是指允许存在多个同名方法,而这些方法的参数不同。编译器根据方法不同的参数表,对同名方法的名称做修饰。对于编译器而言,这些同名方法就成了不同的方法。它们的调用地址在编译期就绑定了。Java的重载是可以包括父类和子类的,即子类可以重载父类的同名不同参数的方法。
所以:对于重载而言,在方法调用之前,编译器就已经确定了所要调用的方法,这称为“早绑定”或“静态绑定”;
而对于多态,只有等到方法调用的那一刻,解释运行器才会确定所要调用的具体方法,这成为“晚绑定”或“动态绑定”。
JavaBean
JavaBean是一种Java语言写成的可重用组件。
所谓JavaBean,是指符合如下标准的Java类:
1.类是公共的
2.有一个无参的公共的构造器
3.有属性,且有对应的get、set方法
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· 使用C#创建一个MCP客户端
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· Windows编程----内核对象竟然如此简单?