对象与类
一、面向对象思想的概述
1>面向对象与面向过程:
- 二者都是一种思想,面向对象是相对于面向过程而言的。面向过程强调的是功能行为。面向对象,将功能封装进对象,强调具备了功能的对象。
- 面向对象更加强调运用人类在日常的逻辑中采用的思想方法与原则,如抽象,分类,继承,聚合,多态等。
- 面向对象的三大特征:封装,继承,多态。
/*
2>面向对象(OOP)程序设计概述
1、 面向对象的程序是由对象组成的,每个对象包含对用户公开的特定功能部分和隐藏的实现部分。
传统的面向过程程序设计(结构化程序设计)通过设计一系列的过程(算法)来求解问题。一旦确定了这些过程,就要开始考虑存储数据的适当方式。(这就是常说的:算法+数据结构=程序)。明确的来说,编程,首先要确定如何操作数据,然后决定如何组织数据的结构,以便于操作数据。 但是,OOP却调换了这个次序,将数据放在第一位,然后再考虑操作数据的算法
2、总结
- 程序员从执行者转化成指挥者
- 完成需求时
➡先去找具有所需功能的对象来用。
➡如果该对象不存在,那么创建一个更具有所需功能的对象
➡这样简化开发并提高复用。
- class类和object对象时面向对象的核心概念
➡类是对一类事物的描述,是抽象的、概念上的定义。
➡对象是实际存在的该类事物的每个个体,因而也称实例
- 万事万物皆对象
- 面向对象设计程序的重点是类的设计
- 定义类其实是定义类中的成员(成员变量和成员方法)
3、面向对象思想的落地法则一:
- 设计类并设计类的成员(成员变量以及成员方法)。
- 通过类,来创建类的对象(类的实例化)。
- 通过"对象.属性 对象.方法"来调用,完成相应的功能。
二、对象与类
1>类
1.1 java类及类的成员
1.1.1 描述类的两种方法:属性、行为。
- 属性对应类中的成员变量
属性=成员变量
- 行为对应类中的成员方法
成员方法=函数
例一:
//类是抽象的
例二:
public
1.2 类的内存解析
1.3 java类的属性(成员变量)与局部变量
1.3.1 相同点:
- 遵循变量声明的格式
- 都有作用域
1.3.2 不同点:
- 声明位置的不同。
成员变量:声明在类里,方法外
局部变量:声明在方法内,方法的形参部分,代码块内。
- 成员变量的修饰符有四个:public private protected 缺省
局部变量没有修饰符:与所在方法的修饰符相同。
- 初始化值:一定会有初始化值
成员变量:如果在声明的时候,不显示的赋值,不同的数据类型会有不同的默认初始化值
局部变量: 一定要显示的赋值。(局部变量没有默认初始化值)
- 二者内存中存放的位置不同:成员变量存在于堆空间中;局部变量:栈空间中
1.4 类的方法:提供某种功能的实现
- 例:
public
格式: 权限修饰符 返回值类型(void : 无返回值/具体的返回值类型)
返回值将会返回给当前的对象
类中的方法可以访问类中的成员变量
1.4.1 重载
public
以上的代码就是一个方法的重载
- 重载的定义:有着相同的方法名,相同的返回类型,不同的参数(个数不同,类型不同),就构成了重载。
再往深了说,Java中,重载可以用于一切方法,包括构造方法(构造器)。
注释:要完整的描述一个方法,需要指定方法名以及参数类型。叫做这个方法的签名。然而返回类型不是签名的一部分,也就是说,不能有两个名字相同、参数类型也相同但却有不同返回类型的方法。
1.4.2 方法参数
1.4.2.1 形参与实参
- 形参:方法声明时的括号里的参数
- 实参:调用方法时实际传入的参数
1.4.2.2 java中的传递机制------值传递
- 值传递和地址传递:
值传递:表示方法接收的是调用者提供的值。
地址传递:表示方法接收的是调用者提供的变量地址(典型的就是C语言中的指针)
- 参数为基本数据类型的值传递:
假如要写一个方法,这个方法的功能是交换 a b 的值
public
内存解析如下:
那我们考虑一个有效的写法:
//我们可以把要交换的一对值写进一个类里,并且把这个类实例化
内存解析如下:
那直接交换的内存解析是什么呢?不妨动手画一画吧!
1.5 类的构造器:
类的第三个成员:构造器(构造方法)。
1.5.1构造器的作用:
- 创建对象
- 给创建的对象的属性赋值
- 初始化属性
person
1.5.2 空构造器
设计类时,若不显示声明类的构造器的话,程序会默认提供一个空的构造器
构造器写法如下
//构造器函数名与类名一样
1.5.3 一旦显示的定义类的构造器,那么默认的构造器就不再提供。
1.5.4 格式
声明类的构造器,
格式: 权限修饰符 类名(形参){}
1.5.5 构造器的重载
类的构造器之间也可以构成重载
1.5.6 属性的赋值的先后顺序:
属性的默认初始化值,属性的显示赋值(要在构造器赋值的前面),构造器的初始化值,通过对象的.方法的方式给属性赋值。
1.6 this关键字
- 可以用来修饰属性、方法、构造器
- this理解为当前对象或当前正在创建的对象:this.name,this.show();
- this(形参):可以用来显示的调用当前类的重载的构造器,必须放在首行。
- tihs()使用次数有限制
class
1.7 static------静态字段与静态方法
static 静态的 可以用来修饰属性 方法 代码块(初始化块) 内部类
1.7.1 修饰属性(类变量):
- 由类创建的所有的对象,都共用这一个属性,也可以这样说,静态变量属于类,而不属于任何单个的对象。
- 当其中一个对象对此属性进行修改,会导致其他对象对此属性的一个调用。
- 类变量随着类的加载而加载(不依据实体对象的存在)
- 静态的变量可以直接通过“类.类变量”的形式来调用
- 类变量的加载是要早于对象的,所有当有对象以后,可以“对象.类变量” 但是“类.实例变量”是不行的
- 类变量存在于静态域中
2、修饰方法(类方法):
- 随着类的加载而加载,在内存中也是独一份
- 可以直接通过“类.方法”的方式来调用
- 内部可以调用静态的属性或者静态的方法,而不能调用非静态的属性或者方法。反之,非静态的方法是可以调用静态的属性或者方法
1.8 关键字final
最终的,可以用来修饰类,属性,方法
1.8.1 修饰类,这个类不可以被继承。
1.8.2 修饰方法,这个方法不可以被重写
1.8.3 final修饰属性,此属性就是一个常量,用大写字符去表示
此常量在那里赋值:a.不能使用默认初始化 b.可以显示的赋值,代码块,构造器
1.8.4 static final 修饰的是 全常量
1.9 初始化块(类的第四个成员)的应用
代码块是什么呢?如下:
class
1.9.1 关于属性赋值的几种操作方法:
- 通过默认的初始化
- 通过显示的初始化或代码块初始化(按照顺序结构执行)
- 通过构造器
- 通过方法
- 通过代码块:如果有修饰符,修饰符只能是static
1.9.2 分类:
- 非静态代码块:
a.可以对类的属性(静态,非静态)进行赋值,同时也可以调用本类声明的方法
b.可以有输出语句
c.一个类可以有多个非静态的代码块,多个代码块之间按照顺序结构执行
d.每创建一个类,非静态的代码块就加载一次
e.非静态的代码块的执行要早于构造器
f.代码块与实例字段按照顺序执行
- 静态代码块(修饰符为static):
a.与静态的属性和方法一样,只加载一次。
b.加载早于非静态的
c.多个静态代码块之间按照顺序执行
d.静态的代码块中只能执行静态的结构(类属性,类方法)
e.随着类的加载而加载
1.9.3 代码内含构造器与代码块的处理步骤:
- [x] 如果构造器的第一行调用了另一个构造器,则基于所提供的参数执行第二个构造器
- [x] 否则
- 所有数据字段初始化为其默认值(0、false或null)
- 按照在类声明中出现的顺序,执行所有字段初始化方法和初始化块
- [x] 执行构造器主体代码
2>对象与实例化
2.1 对象与对象变量
2.1.1 对象与对象变量
- 先看如下代码:
public
- 对象变量: 代码中的 Person person Person person1 的 person person1 都是对象变量
- 对象:代码中的new出来的就是对象,这个对象就是由构造器创建的。
- 我们来看看 他的内存解析:
2.1.2 类的实例化
在Java程序设计语言中,要用构造器构造新实例。构造器是一种特殊的方法,用来构造并初始化对象。创造对象的这个过程就称为类的实例化的过程。
2.2 用var声明局部变量
在java10中如果可以从变量的初始值推导出他们的类型,那么可以用var关键字声明这个卡局部变量。
例如:
Person
从现在开始倘若无需了解任何Java API 就能从等号右边明显看出类型,在这种情况下我们都将使用var表示法。
但是,我们不会对数值类型使用var,如 int long double。
3>类之间的三大关系
3.1 依赖
依赖是一种最明显的、最常见的关系。简单来说,如果一个类的方法使用或操作另一个类的对象,我们可以说一个类依赖于另一个类。我们编写了一个账户类和订单类,而我们要考虑到在账户下订单的时候,订单类会访问账户类的对象来查看信用状态,由此,构成了订单类使用或操作了账户类,所以订单类依赖账户类。
应该注意的是,应该尽可能的减少相互依赖的类减至最少。智利的关键是,如果类A不知道B的存在,它就不会关心B的任何改变(这意味着B的改变不会导致A产生任何bug)。用软件工程的术语来讲,就是尽可能减少类之间的“耦合”。
3.2 聚合
简单来说就是 一个类包含着另一个类
3.3 继承
继承是面向对象中很重要的一个概念,我们会在后面深入讨论。
所以我们在这里留一个悬念,到后面我们深入交流~~~
4>类要具有封装性
4.1 什么是封装性?
封装性,就是指,一个类的成员变量是被封装起来的,不可以在类的外部直接访问,而是要通过方法来访问,操作它。
4.2 为什么要有封装性
如果一个字段没有被封装起来,那么外部操作修改他的“捣蛋者”可能出现在任何地方,这样不利于调试。但是,如果封装起来,只有这个成员的变量的访问器和修改器可以访问与操作他,我们只需要调试两个方法就可以。
4.3 如何做到封装性
- 看如下代码
public
以上为一个具有封装性的类
我们来分析它
4.3.1 需要私有的数据字段
什么是”私有的“? 就是用private关键字修饰的
我们下来介绍几个权限修饰符的关键字(按照权限从大到小排序):
- public 权限最大,被修饰的成员变量和成员方法可以在任意地方被访问
- protect 被修饰的成员变量和成员方法只能在本包中被访问以及被子类(继承的内容,后面会谈到)访问。
- default 默认修饰符,比如 我们在 int a; 看起来是没有加任何权限修饰符,实际上它是default的,即只能在本包中被访问
- private 权限最小,只能在本类中被访问
4.3.2 一个公共的字段访问器方法
就是上面代码中的get方法
4.3.3 一个公共的字段修改器方法
就是上面代码的set方法
5>类设计技巧
5.1 一定要保证数据私有
5.2 一定要对数据进行初始化
5.3 不要在类中使用过多的基本类型
这个想法是要用其他的类替换使用多个相关的基本类型。这样会使得类更易于理解,也更易于修改。例如,用一个名为Address的新类替换一个Customer类中一下的实例字段:
private
5.4 不是所有的字段都需要单独的字段访问器和字段更改器
例如你要设计一个Employee类,要设置员工的雇佣日期,一旦实例化以后就不会再更改,所以雇佣日期字段不需要访问器和更改器