学习目的
- 掌握什么是面向对象
- 精通java为什么是面向对象的
- 掌握类和对象的概念及关系
- 掌握面向对象的三大特性
- 掌握一个"完整"类的组成
- 掌握常用关键字
一.面向对象
- 概念
世间万物,一切事物皆对象。所有的现实物质都可以成为对象,现实中的所有行为都由对象来执行完成。 - 定义
面向对象全称Object Oriented,是一种以对象为中心的编程思想。一切事情由对象去创建、执行和处理。 - Java与面向对象
Java 是一门简单的、面向对象、分布式、解释性、健壮、安全、结构中立、便捷、高性能、多线程、动态的语言。
如果可以将问题从事物表象中抽取出来,那么什么样的对象可以解决问题呢?这个对象用java代码怎么表示呢? - 作用
面向对象可以有效提高编程效率,通过封装技术,将对象作为程序的基本单元,将程序和数据封装其中,提高软件的重用性、灵活性和扩展性。 - 过程分类
- OOA:面向对象分析(Object-Oriented Analysis),按照面向对象的思想来分析业务,如何将问题从事物表象中抽取出来。
- OOD:面向对象设计(Object-Oriented Design),什么样的对象可以解决问题,对象之间的联系以及如何解决问题的。
- OOP:面向对象编程(Object-Oriented Programming),解决问题的对象用java代码怎么表示和实现。
1.1 面向对象与面向过程
- 定义
- 面向过程:考虑的是实际的具体实现,一般是从上往下步步求精,注重完成一件事情的每一个细节。
- 面向对象:主要是把事物抽象化对象化,对象包括属性与行为。
- 区别
- 面向过程:当程序规模不是很大时,程序流程清楚,模块与函数的方法很好组织,面向过程因此有优势。<蛋炒饭>
- 面向对象:对于复杂而庞大的系统,将程序规模分为对象和方法即可,每一段程序都由对象执行具体的方法实现。<蛋盖饭>
- 不足
- 面向过程:一步依赖另一步,注重于细节的每一步实现,关联性过于紧密。
- 面向对象:将事物抽象成对象的过程难以充分体现现实事物,对象的类别很难满足需求,对象间的关系建立也较难。
二.类与对象
2.1 类
- 定义
类是现实世界当中具有共同特征的事物。将事物在现实中的共同状态和共同行为,进行抽象形成的模板就叫做类。如:水果、蔬菜、汽车等。 - 组成
- 现实组成:类 = 事物状态 + 事物行为
- 代码组成:类 = 共有属性 + 公共方法
2.2 对象
- 定义
对象是现实世界实际存在的个体事物,对象是类的实例化。对象包括属性与行为。如:苹果、榴莲、西红柿、奔驰等 - 代码实现
引用类型 变量 = new 引用类型();
对于new 引用类型()这一整块就是一个对象。 - 类与对象关系
类是对象的抽象,对象是类的实例;由类到对象的过程叫对象的实例化,由对象到类的过程叫抽象。 -
对象与jvm堆内存
三.面向对象三大特性
3.1 封装(Encapsulation)
- 概念
现实生活中有很多现实的例子都是封装的。例如手机,电视机,笔记本电脑,照相机,都是外部由一个外壳封装起来,保护内部部件,保证部件是安全的。封装以后,对于使用者来说看不见内部的复杂结构的,也不需要关心内部有多么复杂,只需要操作外壳的按键按钮就可以完成使用。 - 特点
为了保证内部安全,对属性进行私有化;同时为了方便用户使用,再对外提供一个方法作为公开的访问入口。 - 好处
外部程序通过公开入口去访问数据时,可以在入口处设立关卡,一般在set()方法中设置安全访问,进行安全控制,保证对象内部的数据安全。
3.2 继承(Inheritance)
- 概念
封装好的个体类之间,或者接口之间存在的一种关系。继承时,子类继承父类的特征和行为,使得子类对象具有父类的属性,子类从父类继承父类方法,使得子类具有与父类相同的行为。常称遗传特性,是一种is-a关系。 - 关键字
extends关键字表示继承,但类与类之间只支持单继承,不支持多继承。 - 作用
- 实现代码复用:子类可以继承父类的属性和方法,还能拥有属于子类自己特有的属性和方法;
- 多态的基础:无论是面向接口编程的多态,还是面向抽象(类)编程的多态,基础都是继承。
- 范围
除了父类的构造方法外<构造方法名必须和类名相同>,所有的父类属性和方法都可以被子类继承,包括私有的(私有的属性可以继承,但不能在子类中直接访问,需通过父类的get方法间接访问)。 - 特殊点
- 构造方法不能继承:构造方法是每个类都特有的,构造方法名必须和类名相同,因而不能被继承;
- 所有的类没有显示的继承任何类时,默认继承 Object 类;
- 子类没有显示继承父类方法时,默认在子类的类体当中第一行使用super()继承父类方法。
- 缺点
- 子类继承了父类之后的耦合度非常高时,会影响扩展性,父类的修改会影响子类的继承使用
- 能使用组合关系(组合是多个旧类作为一个新类的属性),尽量不使用继承;组合关系中的旧类代码改变时,不影响新类。
- 继承的执行顺序
父类静态代码块 --> 子类静态代码块 --> 父类代码块 --> 父类构造方法 --> 子类代码块 --> 子类构造方法
3.3 多态(Polymorphism)
- 前提
实现多态的前提是,类完成封装形成了独立体,并且类之间或类和接口之间实现了继承关系,满足向上转型(子转父--自动类型转换)和向下转型(父转子,需加instanceof符) - 概念
多态就是父类型引用 指向 子类型对象,通过父类或者父接口,创建子类型的对象; - 多态实质
多态的实际上就是一个引用对象在不同阶段,可以指示多种实际类型的现象,从而产生多种形态、多种状态。java程序在执行之前都分为 编译和运行 两个阶段,多态也因此分为编译期的静态绑定和运行期的动态绑定。
3.3.1 多态的分类
-
编译时多态
编译时多态属于静态绑定的多态。在编译期,编译器只看源代码的语法问题,因此编译期只看到父类型引用,从而找到父类型字节码文件,进行父类方法绑定。(常见错误:f.父类型引用调用子类型方法,找不到该方法) -
运行时多态
运行时多态属于动态绑定的多态。在运行期,会在堆内存中创建一个真实的子类型对象,来执行绑定子类型对象的方法;而不是使用编译时的父类型对象执行父类型方法。 -
instanceof()运算符
一个父类可以被多个子类同时继承,当父类想要向下调用某一个子类的特定方法时,需要先向下转型判断该父类型引用指向的是具体哪一个子类型。先匹配,再去调用对应的子类特定方法。instanceof()运算符就是用于测试一个对象是否为一个类的实例。
//使用格式:**obj instanceof class**
//其中 obj为一个对象,Class 表示一个类或者一个接口
if ( 父类型引用 instanceof 子类 ) {
子类 变量 = (子类)父类型引用;//向下转型
}
- 特别注意
- 在进行任何向下转型之前,都要使用 instanceof 进行判断
- 编译阶段和具体 new的对象无关
-
运行阶段看的是底层具体 new的是哪个类型的子对象,运行期new的是"真实对象",调用的是真实对象的相关方法
四.类的组成
- 组成
每一个类都是从现实世界中抽象出来的,因此类具有现实事物的共同状态和行为,在Java中表示分别表示为属性和方法。
4.1 属性
- 概念
属性是现实事物具有共性状态抽取出来的、用代码表示的"抽象共性"。如物体的颜色、形状、大小,人的年龄、性别、身高等。 - 分类
- 静态属性:使用static关键字修饰的属性,属于类级别,和类一样加载时直接加载到方法区内存。
- 成员属性:又称为对象属性,非static修饰的属性,需要创建类的实例对象后才能调用。
- 常量:使用final修饰的属性,不可修改,必须初始化。
4.2 构造器
- 概念
构造器就是类中用于 构造的一个器具,直白的讲就是类用于 构造/创造对象的"工具"。构造器的实质是在堆内存创建出一个对象,并且每调用一次构造器,创建出的对象地址都不一样。 - 作用
- 创建对象:构造方法调用可以创建出一个类的实例对象;
- 初始化对象属性:调用带参构造器完成属性初始化操作;
- 实例变量赋值:不是在类加载器加载时赋值,实例变量属于对象的范畴,因而是对象创建(调用构造方法过程中)才会进行赋值。
- 特点
- 一个类中可以定义多个构造方法,多个构造方法形成方法重载;
- 构造方法的返回值类型实际上是当前类,返回一个当前类的类型的对象。
- 编写要求
- 无返回值
- 构造方法名必须和类名相同
- 固定格式:public 类名(参数列表){ };
-
构造器使用格式
- 构造器分类
- 无参构造:不带参数的构造器,若不重写无参构造,创建出来的对象所有属性为空。
- 带参构造:带参数的构造器,参数一般为类的属性,创建出来的对象会给所有属性赋值。
4.2.1 无参构造<缺省构造器>
- 定义
没有参数的构造器,只能创建对象,并不能初始化对象属性。 - 调用实质
调用无参构造时,会在堆内存开辟一块空间创建一个新的对象,并给实例变量进行赋默认值。 - 特点
系统默认提供,但建议必须手动写上。
4.2.2 带参构造
- 定义
带有参数的构造器,参数列表一般为该类的属性列表,创建对象时并初始化对象的属性。 - 调用实质
调用带参构造器时,会在堆内存中开辟一块空间存储创建出的一个新的对象,并将栈内存中的局部变量<实际参数> 传递给 堆内存中的对象属性,完成对实例变量的初始化赋值。 - 特点
支持重载,可以编写多个不同参数的带参构造器
4.2.3 this关键字
- 含义
this指向的是当前对象。当某个对象需要使用类的实例变量或者实例方法时,由于某个对象后续才创建的,具有不确定性,因而使用this代替当前对象去使用。 - 设计原则
- this遵循"开闭原则",面向扩展开放,对修改关闭;
- this表示当前对象,用于指向每一个刚刚创建出来的对象;
- this用于set()方法中或实例方法中,区分实例变量和方法传进的形式参数(局部变量);
- this()用在构造方法中(一般是无参构造),只能出现在构造方法第一行,表示调用另一个带参构造方法,如:this(构参1,构参2,构参3)。
- 特点
- this本身存在于虚拟机栈的方法栈帧中,每一个方法栈帧可能有多个局部变量,因此栈帧使用数组保存多个局部变量,而下标0就是this变量;
- this 不能使用在 static方法中,可以使用在实例方法中;
- 在实例方法中可以直接访问 this当前对象的实例变量以及实例方法,在 static 方法中无法直接访问 this的实例变量和实例方法。
4.2.4 super关键字
- super实质
super关键字类似于this关键字,this指向的是当前调用的对象,而super指向的是当前子类 所继承的父类对象的部分特征。super代表的只是"this当前对象"父类的一部分特征。并不指向独立的对象,也不保存某个对象的内存地址。 - 作用
super是在子类需要调用父类的构造方法 或者 子类需要对父类的属性和方法进行初始化时使用。 - 使用格式
- super()特指子类调用父类的构造方法,表示 继承父类和子类共同一部分的属性(子类特有的属性可以用this.区分),提高代码复用性;
- super.属性/方法 特指在子类中调用了父类同名的属性或方法,以便区分 子类和父类的属性或方法;
- super和this一样无法使用在静态方法当中。
- 特点
- super() 必须是子类构造器中的第一个语句;
- super()调用父类构造方法 和 this()调用本类构造方法时,在子类构造方法中都只能放在第一行,但是两者不能同时共存,只能写其一;
- 没有手动写上super()时,系统默认在子类构造方法第一行调用super();
- super()的默认构造器中没有使用this进行属性赋值,系统会赋默认值。
-
native关键字
用native关键字修饰,且以分号;结束的方法,表明该方法底层调用的是c++编写的dll程序(dll是动态链接库文件),可以直接在计算机底层运行,不需要重写。
4.3 get()与set()方法
- 概念
get() 与 set()方法是基于类的封装上提供的方法,由于封装性,类的消费者不能对创建类进行直接访问,更不能修改。因此提供get()和set()方法供类的消费者来使用该类。
4.3.1 get()方法
- 定义
用于获取对象属性值的方法,属性private封装私有化后,get()方法提供给外界可以获取该对象的实例变量值。构建类时必须对属性封装和提供get()方法。 - 使用格式
//返回值是获取的属性 对应的数据类型值
public 数据类型 get属性名(){ };
4.3.2 set()方法
- 定义
属性使用private封装私有化后,set()方法提供给外界可以修改该对象的实例变量值,专门用于提供给调用者 可以设置、修改、赋值对象属性的方法。 - 使用格式
//设置对象的属性值
public void set属性名(){ };
4.4 重写Object类的方法
- 概念
Object类是所有类的父类,系统默认所有类继承于Object,因此也继承了它的所有方法。但是由于Object只是个模板,并未根据现实中具体的需求对具体行为做出响应,因此需要将继承过来的方法进行重写,满足现实需求。
- toString()方法:重写toString()方法,返回的是以"易读性字符串"来表示该对象;未重写时返回的是 该对象的类型@哈希码经过转换的16进制码值
- hashCode()方法:未重写时返回的是该对象在内存中的哈希码值,重写后返回的是哈希码值经过哈希算法--转换得到的--对象在内存的下标。
- equals()方法:未重写时,底层采用==号比较数值;重写后可以比较对象的每一个属性是否相等,从而判断两个对象是否相等。