Java第四章对象与类学习笔记
Java是面向对象编程的语言,只有熟悉OOP才能编写好Java程序
- 什么是面向对象程序编程?
- 比如编写的程序要提到人,那么人就是其中的一个对象,人能做的所有事都在人这个类中
- 用人来举例,如何分辨对象与方法?
- 人是对象
- 人能执行的功能就是方法
- 面向对象编程的优点
- 更加适用于解决规模较大的问题
- 将数据放于第一位,而如何操做数据次之。
- 更容易找出bug,便于后期维护
一、类
-
由类构造对象的过程称为创建类的实例
-
封装(数据隐藏)是类的一个重要概念
-
对象中的数据称为实例域
-
操纵数据的过程称为方法
-
对于每个特定的类实例(对象)都有一组特定的实例域值,这些值的集合就是这个对象的当前状态(state)
-
无论何时,只要对象发送一个消息,它的状态就有可能发生改变
-
如何实现封装?
-
绝不能让类中的方法直接访问其他类的实例域,即某一类的方法只能对该类数据进行操做。
-
程序仅能通过对象的方法对对象的数据进行交互
-
将对象的数据设为私有类private
-
注意,封装就意味着一个类可以全面的改变储存数据的方式,而其它类就不会知道或是受到影响
-
-
OOP可以通过拓展一个类来建立一个新的类,拓展后的类拥有父类的全部属性和方法,我们将这个过程称之为继承。
二、对象
- 对象的三个主要特征
- 行为:可以对对象实行的操做,具体为对象的方法实现
- 状态:调用方法后,对象做出的响应
- 标识:如何便被具有相同行为与状态的不同对象?
- 对象行为是用可调用的方法来定义的,比如说人要说话,那么建立一个
speak()
方法,再调用该方法就相当于该类产生了“说”这种行为。 - 对象状态:每个对象都保存着描述当前特征的信息。对象状态的改变必须通过调用方法来实现。
- 每个对象都有唯一一个身份,每个对象永远是不同的,抓鬼太也往往存在差异。
- 对象的关键特性再彼此间相互影响,比如货物在“未签收”就不能申请“已到货”。
三、识别类
1. OOP打破C自顶向下编程,要编写JAVA程序,首先的从设计类开始,再丰富类的方法。
2. 如何设计类
- 找到“名词”名词往往就对应着类,例如:订单、货物、书、人等就相当于类
- 找到“动词”,动词往往对应着方法,例如:添加、删除、说等就相当于方法。
3. 如何设计类往往还要根据编写者的编程开发经验来设计
四、类之间的关系
1. 最常见的关系
- 依赖(users-a):最明显、最常见的关系
- 聚合(has-a)
- 继承(is-a)
2. 依赖:**如果一个类的方法操纵另一个类的对象**,那么我们就说一个类依赖于另一个类。比如说订单类要访问账户类查询账户金额,此时我们就说订单类依赖于账户类。
3. **尽可能地减少类之间的依赖关系**
4. 聚合:例如“订单”会包含部分“商品”类,**聚合就意味着类A的对象包含类B的对象**。
5. 继承:一种用于表示特殊与一般关系的,如果类B继承自类A,那么B往往还会拥有相较于A的独特功能。例如`student`类继承`people`类,那么`student`不仅仅具有`people`类的所用属性,还有`people`没有的属性/功能。
五、使用预定义类
虽然Java是面向对象编程性语言,并不然而是所有的类都具有面向对象的特征。例如
Math
类
-
对象与对象变量
-
要使用对象,首先要构造对象,并指定其初始状态,然后对对象应用方法。
-
构造器:java中用来构造新实例,一种特殊的方法,用来构造并开始初始化对象。
-
构造公式如下:
/*假定要构造一个Student类*/ Stuent xiaoming = new Student(); //其中,Student是类名 //xiaoming 是构造的一个学生,我们将其称为对象变量 //new Student() 用于构造一个Student类型的变量,它的值是对新创建对象的引用,这个引用储存在xiaomin中
-
对象变量并没有实际包含一个对象,而是仅仅引用一个对象
-
Java中,任何对象变量的值都是对储存在另外一个地方的一个对象的引用。
-
可以将对象变量设置为null表示该对象变量没有引用任何对象
-
如果将一个方法应用于一个值为
null
的对象上,就会出现运行时错误/*将一个方法应用于一个值为null的对象上 */ birthday = null; String s = birthday.toString();//运行时错误。
对象变量类似于C的指针,这样,相关的操做就很好理解了。
-
五、用户自定义类
如何设计复杂应用程序的各种主力类:
- 通常这些类没有
main
方法,却有自己的实例域何实例方法- 一个完整的程序是由一个包含
main
方法的主类加其他若干个类组和而来的
-
在一个源文件中,只能有一个公有类,但可以有任意数目的非公有类。
-
多个源文件的使用
- 最好将一个类单独存放到另外的源文件中,即一个类一个源文件。
-
用关键词
- 有
public
标记方法,则意味着,任何类的任何方法都可以调用这个方法。 - 用
private
(私有)标记类的实例域,则表明只有该类的方法能够修改和访问实例域的数值
- 有
-
类的构造器
/*类的实例域*/ class Employee{ private String name; private double salary; private LocalDate hireDay;//hireDay为LocalDate的对象变量 /*Employee类的构造器*/ public Employ(String n,double s,int year,int month,int day){ this.name = n; this.salary = s; LocalDate hireDay = LocalDate.of(year,month,day); } }
- 构造器与类同名,构造器总是伴随着
new
操作符的执行被调用,而不能对一个已经存在的对象调用构造器来达到重新设置实例域的目的。 - 每个类可以有一个以上的构造器。
- 构造器可以实0个、1个或多个参数。
- 构造器没有返回值。
- 构造器总是伴随着
new
操做一起调用 - 注意:不要再构造器中定义与实例域重名的局部变量
- 构造器与类同名,构造器总是伴随着
-
隐式参数与显示参数
-
出现在方法名字括号后面的称为显示参数
public SetSalary(double s)
,其中的s
便被称为显示参数。 -
隐式参数:
public void Setsalary(double s){ this.salary = s;//this 后面接的salary就表示隐式参数,他是方法调用的目标/接收者 }
-
为了更好的区分显隐参数,我们常用
this
关键字来表示,如上面的代码。这样做能很好地将实例域与局部变量区分开。 -
在java中,所有的方法都必须在类的内部进行定义。
-
-
封装的特点
-
public String GetName(){ return name; }//我们将这种只返回实例域值的方法称为域访问器 public void Setsalary(double s){ this.salary = s; }//我们将这种能够修改实例域值的方法称之为域更改器
-
获得/设置实例域的值,要做到一下三项:
- 一个私有的数据域
- 一个公有的域访问器方法
- 一个公有的域更改器方法
-
如果需要返回一个可变的数据域的拷贝就应该使用
clone
对象。
-
-
final
实例域- 可以将实例域定义为final,构建对象的时候必须初始化这样的域
- 用
final
构建实例域值后将表示该实例不能被修改,或者说,只能被初始化一次。其后不能在进行修改。 - 用法:
private final String name;
六、静态域与静态方法
main方法被static标记,那么到底,static修饰符代表了什么含义?
-
静态域
- 如果将域定义为
static
,那么,每个类中就只能有一个这样的域。
- 如果将域定义为
-
静态常量
-
相较于静态变量,静态常量使用更多。
-
public class Math{ ... public static final double PI = 3.14159265358979323846; ... }
-
调用静态变量:
Math.PI
即可。
-
-
静态方法(参见P114)
-
工厂方法(参见P115)
-
main
方法-
不需要使用对象调用静态方法,例如不需要构造Math类的对象就可以调用
Math.pow
. -
main方法不对任何对象进行操作,启动程序时没有任何对象,而静态的main方法将执行并创建程序所需要的对象。
-
每一个类可以有一个main方法,这是一个常用于对类进行单元测试的技巧
public Employee{ public Employee(String n,double s,int year,int month,int day){ this.name = n; this.salary = s; LocalDate hireDay = LocalDay.of(year,month,day); } public static void main(String []arts){ Employee e = new Employee("xiaoming",5000,2012,10,9); System.out.println(e.getName()+" " +getSarlary()); } }
-
如果要单独测试Employee类只需要执行
java Employee
指令 -
如果Employee是一个更大型程序的一个部分,那么就可以使用
java Application
指令进行测试。 -
Employee中的main方法永远不会被执行。
-
七、方法参数
程序设计中有关参数传递给方法的方式
- 按值调用(call by value):表示方法接受的是调用者的值
- 按引用调用(call by reference):表示方法接受的时调用者的地址。
-
java语言总是采用按值调用的方式,即方法得到的始终是所有参数值的一个拷贝值。
-
特别的:方法不能修改传递给它的任何参数变量的内容
-
方法参数总共有两种类型
- 基本数据类型:数字、布尔值
- 对象引用
-
一个方法不可能修改一个基本数据类型的参数,而对象引用作为参数就可以实现该功能了。
//实现该操做 //只从Employee类中摘取了加薪方法 public void raiseSalary(double byPercent){ double raise = salary * byPercent/100; salary += raise; } //在这里,要注意传入的值时Employee x public staic void tripleSalary(Employee x){ x.raiiseSalary(200); }
当我们调用
harry = new Employee(...); tripleSalary(harry);//使得x为harry值的拷贝
就可以实现将harry的工资提升至原来的三倍,具体过程
- x被初始化为harry值得拷贝,注意,这里是一个对象的引用
raiseSalary
方法应用于对这个对象的引用- 方法结束后,参数变量x将不再使用,而harry则继续引用修改后的工资。
-
一定要记住,对象引用也是按值传递的。
-
java中方法参数的使用情况总结
- 一个方法不能修改一个基本数据类型的参数(即数值型和布尔型)
- 一个方法可以修改一个对象参数的状态
- 一个方法不能让对象参数引用一个新的对象
八、对象构造
-
重载
- 有些类有多个构造器,这种特征就被叫做重载。
- 有相同的名字,不同的参数*,便产生了重载。
- 编译器通过用各种方法给出的参数类型域特定方法调用所使用的值类型进行匹配来挑选出相应的方法。该过程也被称为重载解析。
- java允许重载任何方法
-
默认域初始化
- 如果构造器没有显示的给域赋予初值,那么就会自动的赋上相应的默认值:0、null、false。
- 如果不明确的对域进行初始化就会影响程序代码的可读性。
-
无参数的构造器
- 对象由无参数函数构造器创建时,其状态会设置为相应的默认值。
- 如果编写一个类没有提供构造器,那么系统就会提供一个无参数构造器,并未所有的实例域赋相应的默认值。
- 如果一个类提供了至少一个构造器,但是没有提供无参数的构造器,则在构造对象时如果没有提供参数就会被视为不合法。
-
显示域初始化
- 可以采用多种形式设置实例域的初始状态,以确保不管怎样调用构造器,每个实例域都可以被设置为一个有意义的值。
- 在执行构造器之前,先执行赋值操作。
- 初始值不一定是常量值。
-
参数名
-
通常,参数用单个字符命名(但是只有阅读源码才知道所代表的意义)
public Employee(String n,double s){ name = n; sarlary = s; }
-
相对来说比前一种较好的做法是在参数名前面加一个前缀a
public Employee(String aName,double aSalary){ name = aName; sarlary = aSalary; }
这样的代码可读性更强
-
个人比较喜欢第三种方法,利用this
public Employee(String name,double salary){ this.name = name; this.salary = salary; }
这样既可以防止隐式参数被显示参数屏蔽,也可以让读者清除显示参数做代表的意义。
-
-
调用另一个构造器
-
this关键字可以用于引用方法的隐式参数
-
this也可以用于调用同一个类的另一个构造器
public Employee(double s){ this("Employee #" + nextId,s);//调用Employee(String ,double)构造器 nextId++; }
当我们调用
Employee(6000)
时,Employee(double )
就会调用Employee(string ,double )
构造器 -
采用这样的方式使得对公共的构造器代码部分只编写一次即可。
-
java中的
this
等价于C++中的this
指针
-
-
初始化块(p127)
-
方法
- 在构造器中设置值
- 在声名中赋值
- 初始化块
-
使用方式,前面
class Employee{ private static int nextId; private int id; private String name; private double salary; { id = nextId; nextId++; } public Employee(String n,double s){ naem = n; salary = s; } public Employee(){ name = " "; salary = 0; } ... }
无论使用那种构造器对象,id域都是在对象初始化中被初始化的
-
调用构造器具体处理步骤
- 将所有数据初始化为默认值
- 按类在声名中出现的次序,一次执行所有域初始化语句和初始化块。
- 如果构造器第一行调用了第二个构造器,则执行第二个构造器主题。
- 执行构造器主体。
-
九、包
包可以更好的组织代码,能够很好的将自己的代码与别人提供的代码分开管理。
使用包的主要原因时为了确保类名的唯一性,如果都有Employee,只需要将两个类放入不同的包里,就不会出现冲突。
常将公司域名以逆序的形式作为包名,因为独一无二性。
-
类的导入
- 一个类可以使用所属包中的所有类,以及其他包中的公有类。
- 访问另一个包中的类
- 在每个类名前面添加完整的包名,例如
java.time.LocalDate tody = java.time.LocalDate.now()
- 使用
import
语句,(在源文件的顶部,package语句的后面)添加例如:import java.util.*;
,就表示导入了java.until
这个包。这样调用的时候就不用再前面加前缀了。
- 在每个类名前面添加完整的包名,例如
- 只能使用
*
号导入一个包,而不能使用import java.*
导入以jiava为前缀的所有包,即要做到精确导入,用哪个包,就导入哪一个。 - 在包中定位是编译器的工作
- C++中命名空间与包类似
-
静态导入
-
import不仅仅可以导入类,还能导入静态方法和静态域
import static java.lang.System.*; //引入System类的静态域和静态方法后,就可以不用再加类名前缀 out.println("Hello!");
-
import还可以导入特定的方法/域,
impotr static java.lang.System.out;
-
-
将类放入包中
-
要想将类放入包中,则必须要将包的名字放在源文件的开头,包中定义类的代码之前即
package com.Miubai; public Employee{ ... }
-
如果没有package语句,则源文件就会被放到一个没有名字的默认的包 (defaulf package) 中
-
如果包与类所存放的目录不一致,那么Java虚拟机将找不到类。
-
-
包作用域
- 包也有作用域
-
类路径
- 设置类路径
-
文档注释
在源代码中使用/**注释,则很容易生成一个看上去很有专业水准(逼格)的文档,”而这样做能将代码与注释保存到一个地方”,那么到底能写出多有逼格的注释呢??
- 注释插入
- 插入到一下位置的前面
- 包
- 公有类与接口
- 公有的和受保护的构造器和方法
- 公有的和受保护的域
- 注释以
/**
开始*/
结束,文档注释在标记后紧跟自由格式文本, - 在自由格式文本中,可以使用HTML修饰符,但要注意不能使用
<h1>...</h1>
这样的标签,这样会打乱排版,但是<em>..</em>
这样的还是可以用的,甚至可以插入图片。 - 键人等宽代码,必须使用
{@code...}
而不是<code>...</code>
,这样就可以避免代码对<
的转义。
- 插入到一下位置的前面
- 类注释
- 类注释必须放到import语句之前
- 方法注释
- 方法注释必须放到所描述方法之前
- 除开使用的通用标签例如
@auther
外还可以使用的标签有@param
+变量描述@return
+描述@throws
+类的描述
- 域注释
- 通用注释
@auther
(作者)+姓名@version
(版本)+文本@since
(始于,例如始于上一个版本) +文本@deprecated
+ 文本。可以用于给其一个不再使用的原因注释,可以给一个能优化此代码的建议。@see
+引用,可以增加一个超链接
- 包的概述与注释
- 注释的抽取
- 注释插入
十、类的设计技巧
- 一定要保证数据私有
- 一定要对数据初始化
- 不要在类中使用过多的基本类型
- 不是所有的域都需要独立的域访问器和域更换器
- 将职责过多的类进行分解
- 类名和方法名要能够体现他们的职责
- 优化不可变的类
所读书目《java核心技术卷 卷I》第四章 对象与类
整体感悟:相对教材介绍的很详细,借助这本书能将更深层次的原理大致吃透,理解更加深刻。
笔记记得比较详细,主要是为了日后复习好用,也是为了加深记忆。