Java核心技术 读书笔记:

第四章 对象与类

对象的理解:

每个对象包含对用户公开的特定功能部分和隐藏的实现部分。从根本上来说,只要对象能够满足要求,就不必关心其功能到底如何实现!

此外,每个对象都保存着描述当前状况的信息——对象的状态。对象状态的改变必须通过调用方法实现(如果不经过调用就可以改变对象状态,只能说明破坏了封装性!

对象引用:

对象的创建通过对象提前写好的构造函数(无参 有参),new+构造才能够创建出一个新的对象

1
2
Date s = new Date()
Date s = k

实际上,k和s引用的是同一对象(new的Date的对象),指向相同!

所有的Java对象都存储在中,当一个对象包含另一个对象变量时,它只是包含着另一个堆对象的指针!

类:

三种关系:

  • 依赖(uses-a)如Order类使用Account类,是因为Order对象需要访问Account对象查看信用状态!——我们应该尽可能减少相互依赖:减少类之间的耦合!
  • 聚合(has-a)包含关系
  • 继承(is-a)

公共类和非公共类(是否带public)

  • 源文件名必须与public类的名字相匹配,在一个源文件中,只能有一个公共类,但可以有任意数目的非公共类。
  • 一般习惯将类单独命名为xxx.java

类中的public方法:

public意味着任何类的任何方法都可以调用这些方法(一共有4个级别,后面介绍)

构造器:

  • 与类同名
  • 可以有一个以上的构造器
  • 构造器可以有任意数目的参数
  • 构造器没有返回值
  • 总是伴随new一起调用!

var声明局部变量:

Java10中,如果可以从变量的初始值推导出它们的类型,可用var关键字声明局部变量,无须指定类型。

1
2
Employee harry = new Employee("Harry",5000,1989,10,1);
var harry = new Employee("Harry",5000,1989,10,1);

两者等效

隐式参数和显式参数:

如:

1
2
3
4
5
public viod raiseSalary(double byPercent) {
double raise = salary * byPercent / 100;
salary += raise;
}
number007.raiseSalary(5)

其结果是将number007.salary字段新增5%(设置为了一个新值)

raiseSalary有两个参数,其一是前面的Employee类的对象,第二则是括号中的参数

关键词this指示隐式参数,可以改写:(强烈推荐)

1
2
3
4
public viod raiseSalary(double byPercent) {
double raise = this.salary * byPercent / 100;
this.salary += raise;
}

可以将实例字段和局部变量明显区分出来

警告!(初探对象封装性)

不要编写返回可变对象引用的访问器方法。

例如:

1
2
3
4
5
6
7
8
9
class Employee
{
private Date hireDay;
...
public Date getHireDay()
{
return hireDay //Bad
}
}

其中的Date类有更改器方法setTime,也就是说Date对象是可变的,这就破坏了封装性!

1
2
3
4
Employee harry = ...;
Date d = harry.getHireDay();
double tenYearsInNilliseconds = 10 * 365.25 * 24 * 60 * 60 * 1000;
d.setTime(d.getTime() - (long)tenYearMilliseconds);

d和harry.hareDay引用的是同一个对象,对d调用更改器方法就可以自动地改变这个Employee对象的私有状态!

如果要返回一个可变对象的引用,首先应该对它进行克隆!对象克隆指放在另一个新位置上的对象副本。

1
2
3
4
5
6
7
8
9
class Employee
{
private Date hireDay;
...
public Date getHireDay()
{
return (Date)hireDay.clone(0) //Bad
}
}

谈谈私有方法和公共方法

由于公共数据非常危险,应该将数据字段设置为私有的字段(很好理解),对于方法来说,尽管大部分都是公共的,但有些情况下用私有会更好:如,数据的表示发生了变化,这个方法可能会变得难以实现,或者不再需要,这并不重要,重要的是,只要它是私有方法,类的设计者就可以确信它不会在别处使用没所以可以将其删去,如果一个方法是公共的,就不能简单的删除,因为有可能在别处依赖!

final实例字段

  • 一旦设置,以后就不再修改这个字段,如Employee类中的name字段设置为final,因为在对象构造后,值不会改变,即没有setName方法。

  • 对于基本类型或者不可变类的字段尤其有用:

    对于可变的类,可能混乱:

    1
    private final StringBuilder evaluations;

    它在Employee中初始化为:

    1
    evaluations = new StringBuilder();

    final关键字只是表示存储在evaluations变量中的对象引用不会再指向另一个不同的StringBuilder对象。不过这个对象依旧是可以更改的!!也就是地址不变而已

静态字段与静态方法

静态字段:属于类,不属于对象!例如,要给每个员工一个唯一的标识码,这里给Employee类添加一个实例字段id和一个静态字段nextId;

1
2
3
4
5
6
7
8
9
10
11
class Employee
{
private static int nextId = 1;
private int id;
...
}
public void setId()
{
id = nextId;
nextId++;
}

当新增员工时,其id是在整个员工nextId基础之上的!也就是说,这个nextId是公共调用的!

静态常量用的更多,比如Math类下的PI值

以下两种情况下可以使用静态方法:

  • 方法不需要访问对象的状态,因为它需要的所有参数都通过显式参数提供,如Math.pow
  • 方法只需要访问类的静态字,如Employee.getNextId