Java核心技术·卷一·第四章笔记

Java核心技术·卷一

第四章:对象与类

4.1面向对象程序设计概述

对于面向过程:算法+数据结构=程序

而对于面向对象:数据结构+算法=程序

4.1.1类

封装:亦称之为数据隐藏。对象中的数据称为实例字段,操作数据的过程称之为方法。

4.1.2对象

包括:行为,状态,标识

4.1.4类之间的关系
  • 依赖(”uses-a“),一个类的方法使用或者操纵另一个类的对象,也称之为耦合性。如果类A不需要知道类B的存在,那么类B的修改不会对类A造成bug。
  • 聚合(”has-a”)包含关系。
  • 继承(“is-a”)

4.2使用预定义类

再次提醒,声明和创建内存是分开的。也可以两个变量名指向同一个对象内存。本质上也是一个指针

对象变量没有实际包含一个对象,它只是引用了一个对象

在Java中,任何对象变量的值都是对储存在另外一个地方的某个变量的引用

4.2.2Java中的LocalDate类

保存时间与给定时间点命名分开。故Date用于表示时间点,用LoaclDate表示时间命名。

LocalDate a = LocalDate.now();
System.out.println(a.getYear());
LocalDate b = LocalDate.of(2002,05,13);//采用工厂的形式来构造,不要自己new一个对象
System.out.println(a.toString());
//实际上date也有得到年月日的方法,但是已经废弃不用,废弃不用的方法我们应该避免使用,以免以后官方完全删除这些方法造成程序Bug
DayofWeek dayofWeek = a.getDayOfWeek();
dayOfweek.getValue();
//1为周一,7为周日

更改器方法与访问器方法:是否对状态进行修改

4.3自定义类

所有的Java对象都是在堆中构造的,所有的构造函数的都要配合new使用

隐式参数,显式参数

void Employee(int a){
    
}
//显式参数为a,隐式参数为this指针,即当前的变量。

var关键字

可以使用var关键字来声明方法中的局部变量。参数和实体字段的类型必须声明

var harry = new Employee("njq",5000,2021,6,1);

Object类的requirNotNull方法可以实现对null参数的拒绝,然后报错(这样相对于常规报错,更容易定位到错误)

class Demo{
    private int a;

    public Demo(Integer a) {
        Objects.requireNonNull(a);
        this.a = a;
    }
}
//如果传null值,就会报错Exception in thread "main" java.lang.NullPointerException

在c++中通常在类的外部定义方法

void Employee::raiseSalary(doule byPercent){
    ....
}
//如果在类的内部定义方法,这个方法将自动成为内联的
class Employee{
  int getName(){return name}//inline  
};

但是Java所有的方法都要在类的内部定义,是否内联由虚拟机决定。

对getter和setter理解:更好的实现了封装性,还可以实现数据检查,修改字段数据需要调用方法的好处是对破环的溯源。

不要编写返回可变对象引用的访问器方法。这样会破坏封装性,应该返回应该副本

class Employee{
    ...
    public Date getHireDate(){
        return (Date)hireDate.clone();
    }
}

私有的方法由于除了本类不会有其他调用,在确保本类不会出错误的情况下,可以删去private方法。而对于public方法,需要谨慎。

final关键字:不可变的。但是对于可变的类,使用final修饰符可变类,只是说明这个变量不会指向另一个对象。

private final StringBuilder evaluations;
//构造器中:
evaluations = new StringBuilder();
//某一个方法中:
public void giveGoldStar(){
    evaluations.append(LocalDate.now()+GoldStar);
}

4.4静态字段与静态方法

静态字段===>“类字段”。

**仅做了解:System类的out实体变量为static final,但是却有一个setOut的方法,这里是一个原生方法,可以绕过访问控制机制,并不是在Java语言中实现的。

对象是可以调用静态方法的。但是不推荐这样做,因为调用这个静态方法的对象与这个静态方法是没有太大关系的。推荐还是用类名来调用。

工厂方法:

为什么不使用构造器:

  • 无法命名构造器。构造器的名字是确定的,但是有可能希望得到不同类型的实例,使用无法重命名的构造器会造成混乱
  • 无法改变所构造对象的类型。new + 构造器返回的一定是该类,但是有可能需要返回子类这种需求。

4.5方法参数

按值传递与按引用传递:

对对象的传递,本质上是传递了一个指针副本

Test a = new Test();
Test b = new Test();
public void Swap(Test a, Test b){
    Test temp = new Test();
    a = temp;
    a = b;
    b = temp;
}
//但是a,b并没有交换。
public void Change(Test a){
    a.setName("njq");
}
//a对象的名字属性改变了。

C++便可以加入”&“按照引用传递。

4.6对象构造

4.6.1重载

方法的签名:方法名以及参数类型。返回类型不是签名的一部分。也就是说不能有名字相同,形参相同,但是返回类型不同的两个方法。

4.6.2默认字段初始化

实体字段会默认进行初始化(0,null,flase…),而局部变量必须显示的初始化。

public static void main(String[] args) {
    int a;
    System.out.println(a);
}
//报错,java: 可能尚未初始化变量a
public class Application {
    public static void main(String[] args) {
        Test test = new Test();
        System.out.println(test.n);
    }
}
class Test{
    public int n;
}
//ok的,输出为0

仅仅当类没有其他构造器的时候,才会自动生成一个无参构造器。

初始值不一定是常量值,还可以调用方法:

public class Application {
    public static void main(String[] args) {
        Test test1 = new Test();
        Test test2 = new Test();
        System.out.println(test1.getA());
        System.out.println(test2.getA());
    }
}
class Test{
    static private int count = 0;
    private int a = initialize();
    static public int initialize(){
        return count++;
    }
    public int getA(){
        return a;
    }
}
4.6.6调用另一个构造器

this指示一个方法的隐式参数。不过,当形如this(…)为构造器的第一个语句时,它会调用同一个类的另一个构造器。

public Employee(double s){
    this("Employee #"+nextId,s);//调用Employee(String,double)构造器
    nextId++;
}
4.6.7初始化块

除了:

  • 构造器初始化
  • 声明中初始化(public int a = 0;)

还可以用初始化块。可以包含多个代码块,只要构造这个类的对象,这些块就会被调用。

构造处理步骤:

  1. 如果构造器的第一行用this(…)调用了另一个构造器,则转到另一个构造器

  2. 否则:

    1. 所有字段初始化为默认值
    2. 按照在类声明中出现的顺序,执行所有的字段初始化方法和初始化块

    3.执行构造器主体代码

public class Application {
    public static void main(String[] args) {
        Test test1 = new Test();
        Test test2 = new Test();
        System.out.println(test1.getA());
        System.out.println(test2.getA());
    }
}
class Test{
    static private int count;
    private int a = initialize();
    static public int initialize(){
        return count++;
    }
    public int getA(){
        return a;
    }
    static {
        count = 10;
        System.out.println("static Construct block");
    }
    {
        System.out.println("simple Construct block of "+count);
    }
}
/* result:
static Construct block
simple Construct block of 11
simple Construct block of 12
10
11
*/
//注意这里的simple为11和12,这也印证了上面提到的构造顺序
Java.UtilRandomRandom r = new Random();
System.out.println(r.nextInt(1000));
//返回一个0到999的整数

Java中没有析构函数…

4.7包

4.7.1包名

从编译器的角度来讲,嵌套的包没有任何的关系。例如:java.lang与java.util毫无关系

4.7.2类的导入

一个类可以使用所属包中的所有类,以及导入包的公共类

实际上import更多的是相当于C++中的命名空间

4.7.3静态导入

可以直接使用静态方法和字段

但是感觉没什么卵用

import static java.lang.System.*;
public class Application {
    public static void main(String[] args) {
        out.println("static import");
    }
}
//在某种程度上可以使代码清晰
sqrt(pow(x,2) + pow(y,2))
//比下面清晰
Math.sqrt( Math.pow(x,2) + Math.pow(y,2) )
4.7.4在包中增加类

将包的名字放在源文件的开头

package com.werun.njq;

如果没有package语句,就属于无名包

源文件应该放在与包名对应的文件夹下。上面那个包就应该放在com/werun/njq目录下。如果包与路径不匹配,JVM就找不到类。

用“-classpath”来表示类路径

4.8 JAR文件

用 Jar -cvf 打包的文件名(带后缀jar) 打包的文件 打jar包

更普遍的形式是 jar options file1 file2…

c创建一个新的或者空的存档文件并加人文件。如果指定的文件名是目录,jar 程序将会对它们进行递归处理
Cjar cvf jarFileName.jar -C classes *.class切换到classes子目录以便增加类文件
e在清单文件中创建一一个人口点
f指定JAR文件名作为第二个命令行参数。如果没有这个参数,jar 命令会将结果写至标准输出(在创建 JAR文件时)或者从标准输人读取(在解压或者列出 JAR文件内容时)
i建立索引文件(用于加快大型归档中的查找)
m将一个清单文件添加到JAR文件中。清单是对归档内容和来源的一个说明。 每个归档有一个默认的清单文件。但是,如果想验证归档文件的内容,可以提供自己的清单文件
M不为条目创建清单文件
t显示内容表
u更新一个已有的JAR文件
v生成详细的输出结果
x解压文件。如果提供个或多个文件名, 只解压这些文件:否则,解压所有文件
o存储,但不进行ZIP压缩

4.9文档注释

javadoc生成HTML文档

4.9.1注释的导入

标记+自由格式文本

可以使用HTML修饰符,例如用于强调的em,着重强调的strong,用于项目符号列表的ul,li;用于图像的img,用于等宽代码用{@code},这样可以避免<>的转意

链接文件需要放到doc-files目录,javadoc会自动提取这个目录的内容到文档目录中,例如:

<img src="doc-files/uml.png" alt=UML diagram>
4.9.2类注释

类注释必须放在import语句之后,类定义以前。

4.9.3方法注释

必须放在所描述的方法值之前

/**
 * 返回两个数的最大值
 * @param a   给参数部分添加一个条目,可以占据多行,可以使用html标记。所有@param标记必须放在一起
 * @param b
 * @return 返回部分,可以占据多行,可以使用html标记
 * @throws 表示这个方法有可能抛出异常
 */
public int max(int a ,int b){
    return a>b?a:b;
}
4.9.4字段注释

只需要对公共字段(通常指的是静态变量)建立文档

/**
 * The Count of id
 */
public static final int COUNT = 1;
4.9.5通用注释

@since,@author @version

@see reference ,reference有以下选择:

  • package.class#feature label
  • <“a href=”…">label</"a> (那两个引号是为了避免转义)
  • ”text"
@see com.werun.njq.AdminController#login(...)
//注意要使用#来分割类名与方法名,或者类名与常量名
@see <a href="182.92.225.218:8080">MyWeb</a>
@see "MyWeb"可以有多个@see标记,但是必须放在一起。
    可以用{@link 在任何地方增加一个链接,用法与@see类似}
@author 作者是{@link com.werun.njq....#...}
4.9.6包注释
  • 提供一个名为package-info.java的文件,文件里面全为文档注释,不能有其他内容
  • 提供一个package.html的html文件。javadoc会收取<'body></'body>之间的内容
4.9.7注释抽取

基本方法:

javadoc -d docDirectory nameOfPackage

javadoc -d MyDoc com.njq.werun

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值