【core java学习笔记】【第4章】【对象和类】

第4章 对象和类

4.1 面向对象程序设计概述

  • 面向过程 算法第一
  • 面向对象 数据第一

4.1.1 类

类 构造 实例

  • 封装是将数据和行为组合在一个包中,对使用者隐藏了数据的实现方法
  • 实例域是属于对象的域,区别于类域,即静态域
  • 方法是操纵数据的过程
  • 实例域值的集合成为对象的状态
  • 继承即扩展一个类来建立一个新类
  • 不能让类中的方法直接访问其它类的实例域
  • 超类: Java中所有的类都来源于Object

4.1.2 对象

三个主要特性:行为、状态、标识

4.1.3 识别类

看名字,靠自己
名词多为类,动词多为方法

4.1.4 类之间的关系

依赖 use-a
聚合 has-a
继承 is-a

4.2 使用预定义类

不是所有类都有面向对象特征,例如Math类

4.2.1 对象和对象变量

构造器用来构造对象,它是一种特殊的方法,要用new操作符

如new Date()

  • 构造器返回对象的引用
  • 对象和对象变量不是一回事,任何对象变量的值都是对另一对象的引用
  • 在没有引用对象的变量上应用方法会产生编译错误
  • 对象变量可以显式设置成null,表示未引用对象,在值为null的变量上应用方法会产生运行时错误。
  • 局部变量除非调用构造器new或设置为null,否则不会自动初始化

4.2.2 Java类库中的LocalDate类

LocalDate类使用静态工厂方法来代表我调用构造器

LocalDate.now()

4.2.3 更改器方法与访问器方法

LocalDate aThousandDaysLater = newYearsEve.plusDays(1000)

调用plusDays方法会生成一个新对象,原对象不会发生改变

  • 更改器方法

add方法会使调用该方法的对象改变

  • 访问器方法

get方法只访问对象而不修改对象

4.3 用户自定义类

  • 自定义类是自己定义的主力类,通常没有main方法,但有自己的实力域和实例方法
  • 一个完整的程序包括若干个类,但只有一个类有main方法

4.3.1 Employee类

class ClassName
{
instant field1

constructor1

method1

}

  • 文件名域必须与公共类相同,每个文件最多只有一个公共类,可有多个非公共类

4.3.2 多个源文件的使用

  • 也可以按照喜好,为工程中的每一个类都创建一个文件,这样编译时有两种方法:
    一是使用通配符:javac Employee*.java
    二是直接编译有main函数的那个类文件,编译器会自动查找其它类的相应文件。其功能类似于make

4.3.3 剖析Employee类

  • 方法标记为public,使任何类的任何方法都可以调用该方法
  • 实例域用private标记,只有类自身的方法能够访问,对象都不可以
  • 若将实例域用public标记,就破坏了封装,不推荐
  • 其它类类型的对象也可以作为实例域

4.3.4 从构造器开始

  • 构造器与类同名
  • 可以有多个构造器
  • 构造器可以有任意个参数,也可以没有
  • 构造器没有返回值
  • 构造器总是和new操作符一起使用;不能像c++调用构造函数那样调用java构造器;不能对已存在的对象调用构造器来试图重置其实例域,否则产生编译错误。
  • 不能再构造器中定义与类实例域同名的变量

4.3.5 隐式参数与显式参数

  • 隐式参数即调用该方法的类对象,也称为方法调用的目标或接收者,可以用关键字this表示,这样可以区分局部变量和实例域,如

    double raise = this.salary * byPercent / 100;

  • 显式参数就是方法名后括号里的数值

  • Java中方法只可以在类中定义,不可以像C++那样在类外定义,不区分内联方法

4.3.6 封装的优点

做法:为获得或设置实例域的值,提供三个方面的内容

  • 设置为private属性
  • public属性的域访问器方法
  • public属性的域更改器方法

优点

  • 改变内部实现,除了更改该类的方法,不会影响其它代码
  • 更改器方法可以执行错误检查,避免将错误的值直接赋值给实例域

注意:不能编写返回可变对象的访问器方法,所谓可变对象是指存在更改器方法的对象,若将此对象返回,则引用该对象的变量就可以在类外部更改可变对象的值,破坏封装

  • 正确的做法是首先对其克隆

4.3.7 基于类的访问权限

方法可以访问所属类的所有对象的私有数据,不仅限于访问隐式参数的私有属性

  • C++也一样哦

4.3.8 私有方法

当一个代码有若干辅助方法组成,这些辅助方法不应该成为公有接口,故应设置为private属性

  • 这样当不需要这些代码时,完全可以将其删掉,因为它们不会被外部的其它类调用;但当方法是公有的,就不能随意删去了,因为其它代码可能依赖它

4.3.9 final实例域

如果实例域在被构造器初始化后不再修改,可以将其声明为final,例如

private final String name;

  • final修饰符应该应用于基本(primitive)类型域,或不可变(immutable)类的域
  • 所谓不可变类是指类的所有方法都不会改变其对象,例如String类
  • final修饰可变类类型的域,例如
    private final StringBuilder evaluations;
    evaluations = new StringBuilder();
    是指evaluations这个变量只能与其第一次引用的对象绑定,不能再引用其它对象,但是被引用的对象还是可以更改的

4.4 静态域与静态方法

static修饰符

4.4.1 静态域

将域设置为static属性,如

private static int nextId = 1;

则nextId将被该类的所有实例(对象)共享,无论定义多少个该类的对象, 都只有一个静态域nextId,即使没有一个对象,静态域nextId仍存在。它属于类,不属于任何独立的对象。

4.4.2 静态常量

静态常量使用的次数更多,例如Math.PI。静态常量比静态域的声明多了final修饰符,而且用public属性修饰,例如

public static final double PI = 3.14159265358979…;

看其属性就知道了,之所以敢用public,是因为final限制了它不能被修改

4.4.3 静态方法

静态方法不能对实例域进行操作,只能访问自身类的静态域,可以认为它没有this参数。可通过类名调用,也可使用该类的对象调用,但即使那样,也不能操作类的实例域,还会给人造成混淆,多以不建议那样做。

4.4.4 工厂方法

静态方法可作为静态工厂方法,用来生成不同风格的格式化对象。它的存在主要有两点原因:
  • 有时无法命名构造器,因为构造器与类同名。
  • 当使用构造器时,无法改变多构造的对象类型,这个不解?为啥要改变类型

4.4.5 main方法

main方法也是静态方法,不需要对象来调用即可执行。

  • 每个类都可以有main方法,无论其是否为public类,这样可以用于单元测试,即测试这个类的代码是否有错误
  • 当一个有main方法的类(姑且叫Sub)是另一个类(姑且叫App)的一部分,使用java App命令则Sub类中的main函数永远也不会被执行。就是这么强势,哈哈

4.5 方法参数

Java中参数传递总是使用值传递
方法参数有两种类型:基本数据类型和对象引用
所以

  • 一个方法不可能修改一个基本数据类型的参数
  • 但可以改变对象参数的状态
    因为方法得到的是参数的拷贝,而对象引用和它的任何拷贝总是引用同一个对象
    但是方法不能让对象参数引用一个新的对象,还是因为值传递

4.6 对象构造

4.6.1 重载

Java允许重载任何方法,自然包括构造器方法
  • 当多个方法有相同的名字,不同的参数,就产生了重载
  • 方法名和参数类型叫做签名,返回类型不是签名的一部分,所以不能有方法名相同、参数类型也相同却返回不同类型值的方法。

4.6.2 默认域初始化

如果没有在构造器中显式地对域进行初始化,那么就会自动初始化为默认值

  • 数值默认为0
  • 布尔值为false
  • 对象引用为null

这不是种好的编程习惯

4.6.3 无参数的构造器

  • 如果编写一个类时没有提供任何构造器,那么系统就会提供一个默认的无参数构造器,将实例域初始化为默认值

  • 如果提供了构造器,但是没有提供无参数的构造器,系统不会提供默认的无参数构造器,那么在调用无参数构造器时就会发生编译错误

4.6.4 显式域初始化

可以在定义实例域时进行赋值操作,显式地初始化,这一点在所有构造器对同一个实例域赋予相同值时特别方便

  • 初始值不一定非得时常量,还可以调用方法对域进行初始化,例如
    class Employee
    {
    private static int nextId;
    private int id = assignId();

    private static int assignId()
    {
    int r = nextId;
    nextId++;
    return r;
    }

    }

4.6.5 参数名

  • 构造器参数如果用简单的字母命名则不够直观
  • 构造器参数可以在实例域名前加前缀a来区分,很直观
  • 构造器参数可以与实例域同名,屏蔽实例域,同时使用关键字this指示隐式参数,具有技巧性

4.6.6 调用另一个构造器

public Employee(double s)
{
this(“Employee #” + nextId, s);
nextId++;
}

  • 在构造器的第一行调用this(…)
  • 通过调用new Employee(60000)将调用Employee(String, double)构造器,这样对公共的构造器代码只编写一次即可
  • C++不可以这么做

4.6.7 初始化块

初始化数据域有三种方法,前面已经有两种方法:

  • 在构造器中设置值
  • 在声明中赋值

第三种是初始化块

一个类的声明中可以包括多个块,这些块会在构造类的对象时,在构造器执行前执行。块类似于方法,但是没有参数和返回值,可以执行复杂的操作

总结调用构造器初始化数据域的步骤

  • 所有数据域初始化为默认值
  • 按在类中出现的顺序依次执行域初始化语句和初始化块
  • 如果构造器第一行调用另一个构造器,则先执行另一个构造器
  • 执行构造器主体

静态域初始化也有两种方法

  • 直接赋值
  • 静态初始化块,即在块前加关键字static修饰,那么只执行一次?
  • 否则就是默认值

4.6.8 对象析构与finalize方法

java没有析构器,有自动的垃圾回收器回收内存

如果有其它资源需要回收,在类中添加finalize方法,它会在垃圾回收器前调用,但不要用它回收紧缺的资源,因为不知道具体什么时候调用

可以手动close

4.7 包

  • 利用包可以组织代码
  • 可以使用嵌套层次组织包
  • 所有标准的Java包都处于java和javax包层次中
  • 使用包可以保证类名唯一性,类似于C++的namespace
  • 建议使用因特网名的逆序作为包名
  • 包和划分为子包,嵌套的包间没有任何关系,都拥有独立的类集合

4.7.1 类的导入

一个类可以使用所属包的所有类,以及其他包的公共类

对应其他包中的公共类,有两种方式

  • 在类名前添加完整的包名,麻烦
  • 使用import语句

    import语句必须位于文件的顶部,package语句的后面

  • 可以import java.util.*;也可以导入特定类improt java.util.time.LocalDate;

  • *号只能用于导入一个包下的所有类,不能一个导入相同前缀的多个包
  • 当导入的多个包中有同名类时,可以导入要使用的特定类,也可是使用包含包名的类全称

4.7.2 静态导入

可以使用import方法导入一个类的静态方法和静态域,这样就可以直接使用而不用加类名,不推荐。方法是:

导入一个类的所有静态域和静态方法
improt static java.lang.System.*;
也可以导入特定静态方法或域
improt static java.lang.System.out;

4.7.3 将类放入包中

使用package语句,必须放在源文件的开头

  • 如果不添加package,那么源文件中的类就属于默认包default package
  • 包中的文件必须放到与完整包名匹配的子目录中,例如com.horstmann.corejava包的所有源文件应放到com/horstmann/corejava子目录下,否则包和目录不匹配,虚拟机找不到类

4.7.4 包作用域

最好不要忘了添加public或private关键字,如不添加,类、方法或变量将可以被同一个包的所有方法访问,破坏封装

4.8 类路径

看了,不太懂,暂时不太需要

4.9 文档注释

/* /的用法

4.9.1 注释的插入

4.9.2 类注释

4.9.3 方法注释

4.9.4 域注释

4.9.5 通用注释

4.9.6 包和概述注释

4.9.7 注释的抽取

4.10 类设计技巧

  • 数据私有,不要破坏封装
  • 数据初始化
  • 不要在类中使用过多的基本数据类型
  • 不是所有的域都需要独立的域访问器和域更改器
  • 将职责过多的类进行分解
  • 类名和方法名要能体现它们的职责
  • 优先使用不可变的类,但不是必须,不可变的类可以放心地在多线程程序中共享

未完待续

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值