Java 编程思想第 4 版学习笔记(一)
第二章 一切都是对象(Hello World)
这个笔记本主要记录了我在学习 Java 编程思想(第 4 版,中文版)的过
程中遇到的重难点及其分析。主要参考了 C++11 版本的 C++语言,对比了它
们不同的部分。
知识点 0:第一章概括
在探讨第二章的内容之前,先简要地概括一下第一章说了什么,第一章的
标题叫做“对象导论”,第二章叫做“一切都是对象”,这种令人混淆的说法
或许让人乍一看很难区分第一二章讲的内容有什么区别。
不过显然,这两章主要讲述的内容是不同的——第一章主要讲了面向对象
编程中一些重要的概念,这些概念在任何一门适合配合面向对象编程的思想进
行开发的语言上我们都能看到——就是 对象的概念、接口(类方法)的概念、
用对象组合程序的概念、访问控制的概念、继承和派生的概念、多态的概念、
容器的概念 和 泛型的概念。
第一章里提到了一些 Java 和这些概念的关联和几个细节,比如设计类的内
聚性和耦合性、派生类对基类方法的覆盖、编译时的前期绑定和后期绑定、
Java 的一切基于 Object 的单根继承结构、内存分配、并发 和 网络编程等概
念。第一章涵盖了这些也许要把整本书阅读完再回过头看才能明白一些的基础
和复杂的概念,它们并不完整,有很多点都需要在实践中不断的补充完善。因
此也许初学者不需要一开始纠结于弄明白第一章,而是要在学会 C/C++之类的
语言的一些基础后,起码编过程序,再来学习这本书,粗读第一章,然后从第
二章开始。
第二章主要讲了 Java 中对象的表现形式——引用、基本类型和其包装器
类型、简单的对象生命周期/作用域、创建类类型、类字段(数据成员)和方法、
初始化、类内函数、包、静态成员、HelloWorld、编译运行、注释和 Javadoc。
(这里面提到的概念比第一章少多了而且更具体),总之,第二章就是一个
HelloWorld 式的章节,浅显的讲了一下为了你能够不那么迷惑的写出 Java
语言的 HelloWorld 而需要知道的 Java 最重要的一些知识,虽然这些概念也
仍然没有得到充分的讲解,不过第二章使你对 Java 中对象是怎么存在的有了一
个基本的认识。
下面就梳理一下第二章中比较重要和难懂的知识
点。
知识点 1:P21,2.1,创建和操纵对象
创建一个可以操控的对象
Java 创建对象的语句形如这样:new 类型(构建对象的参数-可选);,其中
new 为创建对象的关键字,类型可以是基本类型,包装器类型以及各种类类型,
()里是参数列表,代表调用了构造函数,分号代表语句的结尾。这个语句创
建了指定类型的对象。要想使用这个对象,必须要声明一个对象类型的引用,
引用就是一个别名,Java 里引用的概念和 C++中引用的概念类似。比如
String s = new String("1234");或者是 String s = "1234";
初始化
第一句话定义并初始化了一个 String 类型的引用 s,s 被赋值为一个
String 类型的对象,这个对象被初始化为字符串字面值“1234”。
这里发生了两次初始化,引用 s 的初始化,以及一个不具名的 String 类型
对象的初始化。
一个引用必须在使用(除了赋值操作的其他操作)之前初始化,一个对象
创建的时候就一定被构造函数初始化过了,一个未经初始化的引用,其初值为
null,使用值为 null 的引用会导致报错。
内存布局
引用和基本类型的对象都被存储到堆栈中。
其他对象被存储到堆中。
常量储存在代码内部。
作用域和生命周期
基本类型 和 对象引用 的作用域在它所在的语句块内,生命周期从它被定
义到它所在的语句块结束。
Java 对象的作用域在它所在的语句块内,生命周期从它被定义到它被 Java
的自动垃圾回收机制回收。
知识点 2:P23,2.2.2,基本类型及其包装器类型
基本类型有哪些
boolean(布尔值),char(字符),byte(很小的整数),short(比
较小的整数),int(整形),long(长整形),float(浮点数),double
(高精度浮点数),void(空类型)。
什么是包装器
基本类型没有一个函数,不方便按照面向对象的思想向其传递信息,因此
Java 给每一个基本类型都对应了一个包装器类型,它们是一些类类型,在堆中
被创建,可以执行各种方法,更方便使用。
以上类型对应的包装器类型有哪些
Boolean(布尔值),Character(字符),Byte(很小的整数),Short
(比较小的整数),Integer(整形),Long(长整形),Float(浮点数),
Double(高精度浮点数),Void(空类型)。
基本类型的特点
大小固定,存在堆栈中,过作用域就被释放,不是对象,不需要用引用操控,
没有可以调用的函数,按值传递。
包装器类型的特点
大小固定,存在堆中,由 GC 释放,本身是对象,需要依赖引用操控,有函
数可以调用,按引用传递。
初始化基本类型的方法
可以一开始就用字面值初始化,比如 char c = 'c';
也可以用另一个基本类型的值初始化,比如 char ch = c;
还可以用这个基本类型的包装器类型初始化基本类型的值,比如 char
ch2 = new Character('c');
如果不在创建之初就初始化一个作为类成员的基本类型,则这个基本类型
的变量会得到一个默认值,比如 0。
初始化 基本类型的包装器类型的引用 的方法
可以一开始就用字面值初始化,比如 Character c = 'c';
也可以 先用字面值初始化这个包装器类型的对象,再用这个对象初始化这
个包装器类型的引用,比如 Character ch = new Character('c');
还可以 先用基本类型的值初始化这个包装器类型的对象,再用这个对象初
始化这个包装器类型的引用,比如 Character ch = new Character(c);
知识点 3:P25,2.4,类类型
什么是类类型
类类型是一种区别于基本类型的类型分类,它允许 Java 使用者自己创造一
些新的类型和这些类型的细节。
创建和使用类类型
创建类类型的代码看起来如下:class 类型名{ 类体 },其中,class 是创建
新类型的关键字,类型名是一个大写字母开头的名字,类体包括数据成员(属
性)和函数成员(方法)。
要想创建这个自定义类型的对象,需要使用下述语句:类型名 对象的引用
名 = new 类型名(构造对象的参数-可选);
可见自定义的类类型和 Java 已经存在的类类型的用法基本一致。
什么是类属性/字段/数据成员/域(在特定语境下)
字段(或者属性,数据成员,域)基本都是一个意思,是组成类的两个元素
之一,它可以由一个或几个,可以是基本类型或引用类型,是用来存储类实例
数据的类成员(或称“实例域”)。
什么是类方法/类函数/函数成员
类方法(method)是组成类的两个元素之一,可以有一个或多个,是用来
操控修改数据成员的子程序(可复用程序片段),在 Java 中,没有全局的函数,
一个函数(方法)必定属于某个类。
知识点 4:P27,2.5,类方法
定义和使用类方法
类定义一个类方法的语句形如 返回值类型 类方法名(参数列表){ 方法
体 },必须定义在 class 后面的大括号里,其中,参数列表形如(类型 1 参数 1,
类型 2 参数 2,etc)。如果返回类型不为 void/Void,方法体中需显式地写出
return 语句来结束这个函数,形如 return 返回值; 其中返回值可以为对象的引
用或者基本类型的变量,也可以是一个字面值,一个常量。这个值的类型需和
方法定义中的返回值类型一致或能非窄化地转换为返回值类型。比如 double
func(){return 1;},其中返回的 1 是 int 类型字面值,它转换到定义的 double
类型精度无损失(非窄化转换)。因此这样做可行。
使用一个类方法,需要用点运算符。形如 对象引用.类方法名(想传入的参
数);
静态方法有特殊的调用方式,本章稍后就能看到。
知识点 5:P28,2.6.1,import 是什么,怎么用
包(Java 类库)和名字冲突
包就是一个 Java 类库,是程序员写好、打包好的一些类、方法的集合。
我们在写 Java 程序中往往要根据一些已经实现好的功能做我们的新功能,
而不是什么都自己开发。所以可以在你的 Java 编程 IDE 中进行设置来导入一个
别人打包好的功能,通过在代码中使用 import 这个包的名.具体的类; 来使用你
导入的包中一个具体的类,或者使用 import 这个包的名.*; 把这个语句放在一
个 Java 文件的开头,来导入这个包中所有的类。大部分编译器都有编译优化,
会只编译你用到的,不过仍然要说明这么一句,让编译器知道你可能会用到的
内容。
Java 自己就提供了丰富的类库,其中 java.lang 类库是基础类库,每次都
会被自动导入,而 java.uitl 非常常用,类似于 C++中的 SL,常用的写法是
import java.util.*; 来导入 java.util 中的所有类。
我们可能导入了多个包,不同的包中可能声明了同名的类,不过同一个文
件中不能用同名的类,甚至在同一个方法下的不同作用域里,变量名都不能相
同,所以显然无论你导入了几个包,它们中有几个你想用的同名的类,你都只
能使用其中的一个。
用 import 这个包的名.具体的类; 就可以明确的告诉编译器,你想要使用哪
个包里的这个名字的类。
很多包名好像一个网站的网址倒过来写,比如 com.google.xxxx(我随便
举的例子)。这是因为网址是不重复的,不同的类库的开发者很难拥有同一个
网址,所以 Java 希望你给包起名时用自己的网站倒过来的网址。试想你和另一
个人都使用了 com.baidu.useless 作为包名,里面都有一个叫做 Date 的类,
这两个类其实是不同的(但导入都要写成 import com.baidu.useless.Date;),
别的开发者拿到你们两个人的包想使用 Date 类时就会头疼了。
知识点 6:P29,2.6.3,static 关键字
静态成员的定义、性质和使用
static 关键字用于放在定义语句的类型前面,说明正在定义的字段/方法是
静态的,被 static 修饰的类方法和类字段统称为静态成员。
比起同一个类型的其他成员,所有这个类型的实例中的静态成员都是同一
个对象,占用一个存储空间,它不依赖某个具体实例化的对象而存在,即使没
有这种类型的对象,这种类型的静态成员也能被访问。
举个例子,class StaticTest{ static int i = 47; } 在这个类中,i 就是静态成
员,而且被预初始化为 47,直接在类体中写类似赋值的形式就行了,即使创建
了两个 StaticTest 类的实例,比如 StaticTest st1 = new
StaticTest();StaticTest st2 = new StaticTest();,st1 和 st2 中的 i 仍是同一个
变量。
你可以试着把 st2 中的 i 赋值成 88,写下这个语句 st2.i = 88; ,之后你再
检查 st1.i 的值,就会发现它也变成了 88。
访问 StaticTest 的静态数据成员有两种方法,一种是上述例子中的 st1.i,
通过点运算符,链接对象引用和对象内成员,这个常见的访问成员的方式对静
态成员同样适用。还有一种访问方法是静态成员独有的,就是 类名.静态成员
名 ,通过这种简单的方法你也可以访问到它。在 StaticTest 例子中想访问静态
成员 i 还可以这么写:StaticTest.i,效果和 st1.i 或者 st2.i 是没有区别的。
静态方法也可以这么访问,比如 class StaticTest{ static void Func(){} },
这个新的 StaticTest 类里定义了什么都不做的静态方法(静态函数成员)Func,
可以使用 StaticTest.Func();,在不创建 StaticTest 对象的情况下访问这个类内
静态的函数。
知识点 7:P30,2.6.3,主函数
主函数和 HelloWorld
在目前的很多 IDE 下,Java 可以有多个主函数,不过你要选择其中的一个
进行执行。主函数的写法很简单,不过因为 Java 的所有函数必须以类方法的形
式存在,因此你需要先随便创建一个单独的类:
public class MainTest{}
class 前面的 public 代表一种公开状态的访问权限,具体使用方法不在这
章讲,总之要写成这样。MainTest 可以起成任何别的你喜欢的名字,不过一
个 Java 文件里只能有一个 public 修饰的类,而且这个 Java 文件的文件名必须
和 public 修饰的类名保持一致。
然后,在类中写一个特殊的方法:
public class MainTest{
public static void main(String[] s){
//主函数第一行,程序执行从这里开始
}
}
就像这样,类必须是 publc 的,方法必须是 public static 的(如你所见,
它们并列修饰一个函数时,public 关键字要在 static 前面),返回值为 void,
参数类型是一个 String 数组 s,用来存储命令行参数,就和其他的语言差不多。
这样,一个主函数就写好了,书上给出了一个很简单的 HelloWorld:
import java.util.*;
public class MainTest{
public static void main(String[] s){
System.out.println("Hello World!");
System.out.println(new Date());
}
}
让我们稍微分析一下这个 HelloWorld,首先是 import java.util.*;,导入
java.util 包中的所有类,我们下面用到了 Date 类,因此需要引入这个包。
主函数里,System 是一个类,out 是 System 类的静态对象,println 是
out 对象的静态方法,因此即使不创建 System 类,也能用点运算符访问它的
对象,再用点运算符访问其对象的方法。
println 是一种很常见的方法,println 可以向控制台输出它接收到的信息,
比如一个字符串字面值"HelloWorld!"或者 new Date(); 创建出的一个对象。
知识点 8:P32,2.8,三种注释
C 风格注释
你可以把注释内容写在/* */里,可跨多行,一旦标记了/*,它遇到下一个*/
就会结束注释。
单行注释
你可以把注释内容写在//标记之后,知道本行结束,不可跨多行。
用于提取文档的注释(注释文档)
Java 提供了 Javadoc 机制从源码的注释中提取和生成 html 文档,不过这
个注释要符合特定格式,
用于提取文档的注释以/**开头,以*/结束。这样的注释也可跨多行,注释
间每行开始如果有一个*或任意空白都可被忽略,为了更方便的提取文档,可以
在这种注释里直接加入 html 代码,比如:
/**
*具体类信息可以到这里查找
*
*/
把这段注释文档放在某个你想注释的类,字段 或者 方法前面一行,再用
javadoc 提取文档你就能看到你对这个类/字段或者方法的注释,后面我们会提
到,只能对标记为 public 或 protect 的类/域/方法做注释。
也可以通过@符号加一些标记让 javadoc 快速自动帮你生成符合情境的
html 文档,比如:
/**
*@author TiriSane
*/
提取文档后,这个注释对应的类/域/方法介绍上会有作者这一项。除了
author 还有很多标记可以用:
@see 类名
@see 类名#类成员名
@see 可以在你介绍一个类成员时,链接到其他类/类成员的文档。
{@link 类名#类成员名 你想要显示的标签名}
@link 作用类似域@see,不过文档中超链接处会显示标签名而不是类名。
@version
用于说明版本信息。
@since
用于说明代码使用 JDK 的最早版本,比如@since JDK 1.8
@author
用于说明作者信息。
@param 参数名 描述
带@param 的注释需放在一个类方法之前,用于说明这个方法的其中一个
参数的意义。
@return 描述