java 核心技术卷I学习记录(三)
本次记录内容主要包括:java核心技术卷1 第四章的内容
- 面向对象的相关概念简介
-
类
类( class ) 是构造对象的模板或蓝图。由类构造(construct ) 对象的过程称为创建类的实例(instance ) .封装( encapsulation , 有时称为数据隐藏) 是与对象有关的一个重要概念。从形式上看,封装不过是将数据和行为组合在一个包中, 并对对象的使用者隐藏了数据的实现方式。对象
中的数据称为实例域( instance field ), 操纵数据的过程称为方法( method )。 对于每个特定的
类实例(对象)都有一组特定的实例域值。这些值的集合就是这个对象的当前状态( state )。实现封装的关键在于绝对不能让类中的方法直接低访问其他类的实例域,程序只通过对象的方法与对象的数据进行交互,这是提高重用性和可靠性的关键
类的主要特性:
对象的行为:可以对对象施加哪些操作, 或可以对对象施加哪些方法?
对象的状态:当施加那些方法时,对象如何响应?
对象标识:如何辨别具有相同行为与状态的不同对象类之间的关系
依赖(“users-a”):该关系是一种最为明显、最常见的关系,如果一个类的方法操纵另一个类的对象,我们就说一个类依赖于另一个类。
聚合(“has-a”):是指类A 的对象包含类B 的对象,例如,一个Order对象包含一些Item对象,是一种具体且易于理解的关系。
继承(“ is-a”):是一种用于表示特殊与一般关系的。
- 预定义类
对象与对象变量
Date deadLine = new Date();
上面语句是new Date()构造了一个Date类型的对象,并且它的值是对新创建对象的引用。这个引用存储在变量deadline中。
局部变量不会自动化地初始化为null,必须通过调用new或者将他们设置为null来进行初始化。所有的java对象都存储在堆中
- Date类
时间是用距离一个固定的时间点的毫秒数表示,这个点是就是所谓的纪元(epoch),他是UTC时间1970年1月1日00:00,UTC是Coordinated Universal Time (协调世界时)的缩写。
Date类是用来表示时间点的,LocalDate是用来表示大家熟悉的日历表示法的。在使用LocalDate类时应该使用LocalDate.now()来构造一个新对象。 - 更改器和访问器方法
LocalDate newYearsEve = LocalDate.of(1999,12,31);
LocalDate aThousandDaysLater = newYearsEve.plusDays(1000);
int year = aThousandDaysLater.getYear();
int month = aThousandDaysLater.getMonthValue();
int day = aThousandDaysLater.getDayOfMonth();
System.out.println(year);
System.out.println(month);
System.out.println(day);
上面代码中LocalDate aThousandDaysLater = newYearsEve.plusDays(1000)
执行之后newYearsEve并不会改为1000天以后的日期,plusDays方法会生成一个新的LocalDate对象,原来的对象不会做任何改动。只访问对象而不修改对象的方法被称为访问器方法,例如LoacalDate.getYear就是访问器方法(accessor method)。而在访问对象的同时修改了该对象的方法称为更改器方法(mutator method)
LocalDate的相关API的详细使用方法可查阅相关文档。
- 自定义类
当一个文件夹中有两个类,一个为Employee,另一个为EmployeeTest。第二个类是对第一个的测试类。在使用javac命令对这两个类进行编译时,有两种方法:第一是javac Employee*.java
,第二种方法是javac EmployeeTest.java
。第一种是使用通配符对两个类同时进行显式的编译,第二种没有显示的编译Employee.java,然而当Java 编译器发现EmployeeTest.java 使用了Employee 类时会查找名为Employee.class 的文件。如果没有找到这个文件, 就会自动地搜索Employeejava, 然后,对它进行编译。更重要的是: 如果Employee.java 版本较已有的Employee.dass 文件版本新, Java 编译器就会自动地重新编译这个文件。。
在构建类时用public标记实例域,是一种极为不提倡的做法,因为public数据域允许程序中的任何方法对其进行读取和修改,这样做就破坏了类的封装的特性。
class EmployEE{
private Date hireDay;
public Date getHireDay(){
return hireDay;
}
}
EmployEE harry = ...;
Date d = harry.getHireDay();
d.setTime(....)
如果在设计类时按照上面的这种设计方法,在改变变量d的值时,harry中的值也会被改变。因为harry中的hireDay和d引用的是同一个对象。如果需要返回一个可变对象的引用,应该首先对它进行克隆。下面的这种写法就是正确的,在改变返回对象时并不会改变原私有变量的值。
class Employee{
...
public Date getHireDay(){
return (Date)hireDay.clone();
}
...
}
- final关键字
可以将实例域定义为final。构建对象时必须初始化这样的域,在后面的操作中不能对该域进行修改。
- 静态方法与静态域
- 静态变量
如果将某个域定义为static,那么该类的每个对象都共享这一个变量,它是属于类的不是属于任何独立的对象。 - 静态常量
静态常量在定义时就必须对其进行初始化,该类的每个对象都共享这一个常量,并且该常量在后面的操作不能被改变。 - 静态方法
静态方法是不能向对象实施操作的方法,是没有this参数的方法。静态方法不能访问对象的实例域,但是可以访问对象的静态域方法。
通常情况下静态方法的使用情景为:
- 一个方法不需要访问对象状态时,其所需参数都是通过显式参数提供。
- 一个方法只需要访问类的静态域
- main方法
也为静态方法,不对任何对象进行操作,
- 方法参数
c++ 中有传值和传引用之分,而java总是按值传参,接收参数的方法不能改变原变量的值。
- 对象构造:
- 重载
如果多个方法(比如, StringBuilder 构造器方法)有相同的名字、不同的参数列表,便产生了重载。
域与局部变量的主要不同点就是必须明确地初始化方法中的局部变量。但是,如果没有初始化类中的域, 将会被自动初始化为默认值( 0、false 或null )。
- 构造方法
在java中一个构造可以调用同一类的另一个构造器。
public Employee(double s){
this("Employee #" + nextId, s);
nextId++;
}
}
- 初始化块
初始化数据域的方法:
1): 在构造器中设置值。
2): 在声明中赋值。
在java中还有第三种机制,就是初始化块。在一个类的声明中,可以包含多个代码块。只要构造类的对象,这些块就会被执行。利用初始化块对变量域进行初始化的方法不推荐使用。
class Employeee{
private static int nextId = 0;
private int id;
private String name;
private double salary;
{
id = nextId;
nextId ++;
}
public Employeee(String n,double s){
name = n;
salary = s;
}
public Employeee(){
name = "";
salary = 0;
}
public int getNextIdO(){
return Employeee.nextId;
}
}
- 静态初始化块
对类的静态域进行初始化时,可以通过在定义时提供一个初始化值,也可通过静态的初始化块来对静态域进行初始化。
static{
Random generator = new Random();
nextId = generator.nextInt(10000);
}
- 对象析构和finalize方法
由于java中有自动的垃圾回收机制,不需要人工回收内存,所以java就不支持析构器。但是java提供了finalize方法来回收一些使用了内存之外的其他资源的对象。finalize方法在垃圾回收机制清除之前调用。
- 注释
- 类注释
类注释必须放在import语句之后,类定义之前
- 方法注释
每个方法注释必须放在所描述的方法之前。使用@param 进行变量描述,@return标记当前方法的返回部分,@throws 来描述这个方法可能抛出的异常。
- 域注释
只需要对公有域(通常是指静态常量)建立注释
- 通用注释
@author 标记作者名称
@version 标记一个版本条目,对当前版本进行描述。
@since 标记“since”条目。对引入的特性进行版本描述,例如@since version 1.7.1
@deprecated 标记不再使用的类,方法,变量。在文本中会给出取代的建议。
@see 增加一个超链接,链接到javadoc文档的相关部分或外部文档。
- 注释抽取
假设HTML 文件将被存放在目录docDirectory 下。执行以下步骤:
1)切换到包含想要生成文档的源文件目录。如果有嵌套的包要生成文档, 例如com.horstmann.corejava, 就必须切换到包含子目录com 的目录
- 如果是一个包,应该运行命令:
javadoc -d docDirectory nameOfPackage
或对于多个包生成文档, 运行:
javadoc -d docDirectory nameOfPackage1 nameOfPackage . . .
如果文件在默认包中, 就应该运行:
javadoc -d docDirectory *. java
- 类设计技巧
- 一定要保证数据私有
这是最重要的;绝对不要破坏封装性。有时候, 需要编写一个访问器方法或更改器方法,但是最好还是保持实例域的私有性。】
- 一定要对数据初始化
Java 不对局部变量进行初始化, 但是会对对象的实例域进行初始化。最好不要依赖于系统的默认值, 而是应该显式地初始化所有的数据, 具体的初始化方式可以是提供默认值, 也可以是在所有构造器中设置默认值。
- 不要在类中使用过多的基本类型
就是说,用其他的类代替多个相关的基本类型的使用。这样会使类更加易于理解且易于修改。如果基本类型比较多,那么说明该类的抽象程度不高。
- 不是所有的域都需要独立的域访问器和域更改器
需要获得或设置雇员的薪金。而一旦构造了雇员对象, 就应该禁止更改雇用日期,并且在对象中,常常包含一些不希望别人获得或设置的实例域。
- 将职责过多的类进行分解
如果明显地可以将一个复杂的类分解成两个更为简单的类,就应该将其分解。
- 类名和方法名要能够体现它们的职责
命名类名的良好习惯是采用一个名词( Order )、前面有形容词修饰的名词( RushOrder)或动名词(有“ -ing” 后缀)修饰名词(例如, BillingAddress )。
- 优先使用不可变的类
更改对象的问题在于, 如果多个线程试图同时更新一个对象, 就会发生并发更改。其结果是不可预料的。如果类是不可变的,就可以安全地在多个线程间共享其对象。因此, 要尽可能让类是不可变的,当然,并不是所有类都应该是不可变的。
码字不易,如果该文章对你有所帮助,请点开微信扫一扫下面二维码。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Uj4n0RnZ-1618130434610)(https://raw.githubusercontent.com/zhaozhen197/my_markdown_img/master/20180921220654.png)]