2019独角兽企业重金招聘Python工程师标准>>>
第二章:一切都是对象
如果我们说另一种不同的语言,那么我们就会发觉一个有些不同的世界。
——Luduing Wittgerstein(1889-1951)
Java是基于C++的,Java是一种更“纯粹”的面向对象程序设计语言。
Java和C++都是混合/杂合型语言,杂合型语言允许多种编程风格。
C++之所以成为一种杂合型语言主要是因为它支持与C语言的向后兼容。C++是C的一个超集。
Java中(几乎)一切都是对象。
1、用引用操纵对象
每种编程语言都有自己的操纵内存中元素的方式。在Java中一切都被视为对象,因此可采用单一固定的语法。尽管一切都看做对象,但是操纵的标识符实际上是对象的一个“引用”(reference)。
例如:创建一个String的引用:
String s;
但这里所创建的只是引用,并不是对象。如果此时向s发送一个消息,就会返回一个运行时错误。此时s还没有与任何事物相关联。因此安全的做法是:创建一个引用的同时便进行初始化。如下:
String s=”asdf”;
这里用到了Java语言的一个特性:字符串可以用带引号的文本初始化。
2、必须由你创建所有对象
通常用new关键字来创建一个对象,new关键字的意思是“给我一个新对象”。
前面的例子就可以写成如下:
String s = new String(“asdf”);
它不仅表示“给我一个新的字符串”,而且通过提供一个初始化字符串,给出了怎样产生这个String的信息。
除了String类型,Java提供了大量过剩的线程类型。重要的是,你可以自行创建类型,这是Java程序设计中一项基本行为。
1.存储到什么地方
有五个不同的地方可以存储数据:
寄存器:
位于处理器内部,最快的存储区,数量有限,不能直接操作,根据需求进行分配,在程序中感觉不到它的存在。
堆栈:
位于通用RAM(随机访问存储器)中,通过堆栈指针分配和释放内存,速度仅次于寄存器。存放于堆栈中的所有项必须明确其生命周期,便于指针移动,控制内存。对象的引用都存储在堆栈,对象并不存储在堆栈中。
堆:
也位于RAM区,用于存放对象。编译器不需要知道存储的数据在堆里存活多长时间,当需要一个对象时,只需用new来创建即可,当执行这个代码时,会自动在堆里分配空间。用堆进行存储分配和清理可能比用堆栈进行存储分配需要更多的时间。
常量存储:
常量值不会被改变,常量本身会和其他部分隔离开,可以选择将其存放在ROM(只读存储器)中。
非RAM存储:
如果数据完全存活于程序之外,那么它可以不受程序的任何控制,在程序没有运行时也可以存在。
例如:流对象和持久化对象。
在流对象中,对象转化成字节流,通常被发送给另一台机器。
在持久化对象中,对象被存放于磁盘上。
这种存储的特点:把对象转化成可以存放在其他媒介上的事物,在需要时,可恢复成常规的、基于RAM的对象。
2.特例:基本类型
基本类型:不使用new来创建变量,而是创建一个并非是引用的“自动”变量,这个变量直接存储“值”,并保存在堆栈中。
Java要确定每种基本类型所占存储空间的大小,它们的大小不会随着机器硬件架构的变化而变化,这种不变性是Java程序更具可移植性的原因之一。
基本数据类型 | 大小 | 最小值 | 最大值 | 包装器类型 |
---|---|---|---|---|
boolean | - | - | - | Boolean |
cahr | 16bit | Unicode0 | Unicode2^16-1 | Character |
byte | 8bit | -128 | +127 | Byte |
short | 16bits | -2^15 | +2^15-1 | Short |
int | 32bits | -2^31 | +2^15-1 | Interger |
long | 64bits | -2^63 | +2^63-1 | Long |
float | 32bits | IEEE754 | IEEE754 | Double |
double | 64bits | IEEE754 | IEEE754 | Double |
void | - | - | - | Void |
由此可以看出,基本类型有9种,通常只说前8种。
所有数值类型都有正负号,boolean类型所占存储空间的大小没有明确指定,仅能够取true或false两个值。
基本类型具有包装器类,作用是可以在堆中创建一个非基本类型的对象用来表示对应的基本类型。Java SE5提供了自动封箱/拆箱功能。
例如:
char c = ‘x’;
Character ch = new Character(c);
Character ch = new Character(‘x’);
Character ch = ‘x’;
char c = ch;
高精度数字
Java提供了两个用于高精度计算的类:BigInteger和BigDecimal。将所有的运算符使用方法来代替,以速度换取了精度。
BigInteger支持任意精度的整数。
BigDecimal支持任何精度的定点数。
3.Java中的数组
几乎所有的程序设计语言都支持数组。Java也支持,Java确保数组会被初始化,而且不能在他的范围之外被访问。这种范围检查基于每个数组上少量的内存开销以及运行时的下标检查,由此换来的是安全性和高效。
当创建一个数组对象时,实际上就是创建了一个引用数组,并且会赋予默认值null,此时还没有关联对象。在使用任何引用前,必须为其指定一个对象;如果使用一个还是null的引用,在运行时将会报错。
3、永远不需要销毁对象
程序设计中变量的生命周期是非常重要的部分,变量生命周期的混乱往往会导致大量的程序bug。
1.作用域
作用域(scope)决定了在其内定义的变量名的可见性和生命周期。在作用域里定义的变量只可用于作用域结束之前。Java中,作用域由花括号的位置决定。例如:
{
int x = 12;
{
int q = 96;
}
}
Java是一种自由格式(free-form)的语言,空格、制表符、换行都不会影响程序的执行结果。
Java中不允许下面这种方式声明变量:
{
int x = 12;
{
int x = 96;
}
}
编译器会报告变量x已经定义过,Java中认为这样会导致程序混乱。
2.对象的作用域
Java对象的生命周期和基本类型的生命周期是不一样的。
当用new创建一个Java对象后,它的生命周期远大于当前作用域,当前作用域只是限制了此对象的引用的生命周期,超出了当前作用域只是无法再访问此对象,此对象仍然存活于内存中。
Java中靠垃圾回收器,来监视对象,并释放不在被引用的对象的内存空间。
所以对象的生命周期是从new开始,到垃圾回收器释放其内存时结束。对象的生命周期不是随着作用域的结束而结束。
4、创建新的数据类型:类
程序设计语言习惯用关键字class来表示类型,Java中也是使用class这个关键字来创建新类型的。例如:
class ATypeName{/* Class body goes here */}
上面已经创建好了一个类型,可以使用new来创建这个对象。
ATypeName a = new ATypeName();
1.字段和方法
Java的类中设置两种类型的元素:字段(数据成员)、方法(函数)。
字段可以是任何类型的对象,可以通过其引用与其进行通信;也可以是基本类型。
例如:
class DataOnly{
int i;
double d;
boolean b;
String s;
}
此时可以创建这个类型的对象,并可以给这个对象的字段赋值,例如:
DataOnly data = new DataOnly();
data.i =47;
data.d = 1.1;
data.b = false;
data.s = “asdf”;
//修改字段的值
data.i= 50;
基本成员默认值:
若类的某个成员是基本数据类型,及时没有进行初始化,Java也会自动赋予默认值。
boolean的默认值是false;char的默认值是’\u0000’(null);byte、short、int、long都是对应类型的0;float、double都是对应类型的0.0。
上述初始化的默认值不适用于局部变量,只能用于类的成员变量。
5、方法、参数和返回值
Java中习惯用方法这个术语来表示“做某些事情的方式”。
Java的方法决定了一个对象能够接收什么样的消息。方法的基本组成部分包括:名称、参数、返回值和方法体。形式如下:
ReturnType methodName(Argument list){
/* Method body */
}
返回类型描述的是在调用方法之后从方法返回的值。
参数列表给出了要传给方法的信息的类型和名称。
方法名和参数列表合起来称为方法签名,可以唯一的标识出一个方法。
Java中的方法只能作为类的一部分来创建,方法只能通过对象才能被调用(static方法除外),且这个对象必须能执行这个方法调用。对象调用方法时,需要先列出对象名,紧接着是句点,然后是方法名和参数列表。例如:
objectName.methodName(arg1,arg2,arg3);
假设一个方法f(),不带参数,返回类型是int,属于a对象的类,那么调用可以如下这样:
int x = a.f();
接收返回值的变量的类型必须和返回值类型兼容。
调用方法的行为通常被称为发送消息给对象。
1.参数列表
方法的参数列表指定要传递给方法什么样的信息,这些信息采用的都是对象的形式,在参数列表中必须指定每个被传递对象的类型及名字,这里传递的实际上也是引用,并且引用的类型必须正确。
例如:
int storage(String s){
return s.length() * 2;
}
return关键字的用法包括两方面:首先他代表方法的结束。其次传递返回值。
若返回类型时void,return关键字的作用只是用来退出方法。如果返回值类型不是void,那么无论在何处返回,编译器都会强制返回一个正确类型的返回值。
可以这样认为:大体上程序只是一系列带有方法的对象组合,这些方法以其他对象为参数,并发送消息给其他对象。
6、构建一个Java程序
1.名字可见性
名字管理对任何程序设计语言来说,都是一个重要的问题。
为了给一个类库生成不会与其他名字混淆的名字,Java建议反转域名,句点用来代表子目录的划分。
Java1.0和Java1.1中,扩展名com、edu、org、net等约定为大写形式。Java2中包名都是用小写了。
这种机制意味着所有的文件都能够自动存活于他们自己的名字空间内,而且同一个文件内的每个类都有唯一的标识符。
2.运用其他构件
import指示编译器导入一个包,也就是一个类库,或者一个类。
例如:导入一个类。
improt java.util.ArrayList;
导入一个包。
improt java.util.*;
3.static关键字
static关键字可以两个情形的问题:
一种是,只想为某特定域分配单一存储空间,而不去考虑究竟要创建多少对象,甚至根本就不创建对象。
另一种是,希望某个方法不与包含它的类的任何对象关联在一起。
即使从未创建某个类的对象,也可以调用其static方法或访问其static域。
Java中也用到了类数据和类方法两个术语,代表那些数据和方法只是作为整个类,而不是类的某个特定对象而存在的。
只需将static关键字放在定义之前,就可以将字段或方法设定为static。
例如:
class StaticTest{
static int i = 47;
}
引用static变量有两种方法:可以通过一个对象去引用;也可以通过类名直接引用。
例如:
StaticTest.i++;
StaticTest s = new StaticTest();
s.i++;
使用类名是引用static变量的首先方法,某些情况下这种方式可以为编译器进行优化提供了更好的机会。
static作用于字段时,改变了数据创建的方法,static字段对每个类来说都只有一份存储空间,而非static字段则是对每个对象有一个存储空间。
定义静态方法的定义方式与静态变量类似,例如:
class Incrementable{
static void increment(){ StaticTest.i++; }
}
静态方法的调用和静态变量的调用是一样的。
static方法的一个重要用法就是在不创建任何对象的前提下就可以调用它。这一点在main()方法上是标志性的应用。(main()方法是程序的入口)
7、你的第一个Java程序
最后,让我们编写一个完整的程序示例:
import java.util.*;
public class HelloDate {
public static void main(String[] args) {
System.out.println("Hello, it's: ");
System.out.println(new Date());
}
}
java.lang是默认导入到每个Java文件中的,所以它的所有类都可以被直接使用。
java.lang包里没有Date类,可以通过Java JDK文档中选择“Tree”,查询类属于哪个类库,也可是直接使用查询功能搜索Date类,就会看到它属于java.util.Date,所以使用import
java.util.*导入类库才能使用,或者使用import java.util.Date进行导入。
System类有很多属性,out成员变量是此类的一个静态的PrintStream对象,println()方法是PrintStream类的一个方法,此方法的意思是将传入的数据打印到控制台并换行。
类的名字必须和文件名相同。如果你要创建一个独立运行的程序,那么文件中必须存在一个类与文件名相同,且这个类必须包含main()方法,main()的形式是固定的,如下:
public static void main(String[] args) {}
public关键字表此方法的权限,可以被外界调用。
mian()方法的参数是一个String对象的数组。程序中并未使用args,args是用来存储命令行参数。
1.编译和运行
要编译和运行Java程序,首先必须要有一个Java开发环境。
到Java官网下载对应平台对应版本的JDK进行安装,并配置环境变量。
在你存放HelloDate.java文件的目录下打开命令行,输入以下命令:
javac HelloDate.java
如果没有任何提示信息,表明编译通过,如果有报错信息,根据错误信息进行问题解决。
然后再输入以下命令运行程序:
java HelloDate
你就会看到程序输出的消息和当天的日期。
8、注释和嵌入式文档
Java里提供两种注释风格。
第一种风格,注释以“/*”开始,随后是注释内容,并可跨越多行,最后以“*/”结束。
两种表现形式:
/*
* This is a comment
* that continues
* across lines
*/
/* This is a comment that
continues across lines */
每行的开头有没有*号都是一样的。
第二种风格,单行注释,以“//”开头,直到句末。
例如:
//This is a one-line comment
1.注释文档
javadoc是用于提取注释的工具,它是JDK安装的一部分。它采用了Java编译器的某些技术,查找程序内的特殊注释标签。它不仅解析有这些标签呢标记的信息,也将毗邻注释的类名或方法名抽取出来。
javadoc输出的是一个HTML文件,可以用Web浏览器查看。
2.语法
所有的javadoc命令都只能在“/**”注释中出现,注释结束于“*/”。
使用javadoc命令的方式有两种:嵌入HTML,或使用“文档标签”。
独立文档标签是一些以“@”字符开头的命令,且要置于注释行的最前面。
共有三种类型的注释文档,分别对应于注释位置后面的三种元素:类、域和方法。
例如:
/** A class comment */
public class Documentation1 {
/** A field comment */
public int i;
/** A method comment */
public void f() {}
}
javadoc只能为public和protected成员进行文档注释。private和包内可访问成员的注释会被忽略掉。可以使用-private进行标记,可以将private成员的注释也包括在内。
3.嵌入式HTML
javadoc通过生成的HTML文档传送HTML命令对代码进行格式化。
例如:
//:object/Documentation2.java
/**
*
*System.out.println(new Date());
*/
///:~
也可以自定义格式化,例如:
//:object/Documentation3.java
/**
* You can even insert a list:
*
* - Item one
*
- Item two
*
- Item three
*
*/
///:~
以上两种形式就是嵌入式HTML。
嵌入式的HTML中不能使用标题标签,例如:
或者
。
所有类型的注释文档都支持嵌入式HTML。
4.一些标签示例
javadoc标签详细内容可以参考JDK文档。
1>@see:引用其他类
@see标签作用是引用其他类的标签,通过@see标签可以链接到其他文档。
例如:
/**
* @see classname
* @see fully-qualified-classname
* @see fully-qualified-classname#method-name
*/
上述每种格式都会在生成的文档中加入一个具有超链接的“See Also”条目。
javadoc不会检查你所提供的超链接是否有效。
2>{@link package.class#member label}
该标签与@see极其相似,只是它用于行内,并且用“label”作为超链接文本。
/**
* you can see {@link package.class#member label} about this class
*/
3>{@docRoot}
该标签产生到文档根目录的相对路径,用于文档树页面的显式超链接。
4>{@inheritDoc}
该标签从当前这个类的最直接的基类中继承相关文档到当前的文档注释中。
5>@version
该标签用于解释代码版本的相关信息。
格式如下:
@version version-information
使用javadoc -version命令,可以直接提取出version-information。
6>@author
该标签用于标识作者信息。可以使用多个次标签用于标识多个作者的信息,但是必须连续放置。
格式如下:
@author author-information
@author author-information
使用javadoc -author命令,可以直接提取author-information。
7>@since
该标签用于标识程序代码的早期版本。
8>@param
该标签用于方法文档中,标识方法中的参数标识符,以及其释义,可以使用任意个数此标签。
格式如下:
@param parameter-name description
9>@return
该标签用于方法文档,标识返回值的含义。
格式如下:
@return description
10>@throws
该标签用于方法文档,标识方法产生异常的相关信息。
格式如下:
@throws fully-qualified-class-name description
11>@deprecated
该标签用于指出一些特性的改进。
在Java SE5中,此标签已经被@Deprecated注解代替。
5.文档示例
文档注释示例如下:
//:first/HelloDate.java
import java.util.Date;
/**
* The first Thinking in Java example program.
* Displays a string and today's date.
* @author xjd
* @author www.xxx.com.cn
* @version 4.0
*/
public class HelloDate {
/**
* Entry point to class & application
* @param args array of string arguments
* @throws exceptions No exceptions thrown
*/
public static void main(String[] args) {
System.out.println("Hello, it's: ");
System.out.println(new Date());
}/* Output:(55% match)
Hello,it's:
Thu Jun 28 17:56:45 CST 2018
*///:~
}
第一行是作者独特的方法,用一个“:”作为特殊几号说明这是包含原文件名的注释行。
“///:~”标志源代码清单的结束。
/*Output标签表示输出的开始部分将由这个文件生成,通过这种形式,它会自动地测试以验证其准确性。
(55% match)在向测试系统说明程序的当前运行和醒一次运行的输出存在这很大差异,55%是两次输出与其的相关性程度。
9、编码风格
Java编程语言编码约定使用“驼峰风格”,驼峰风格规定:类名的首字母要大写;如果类名由几个单词构成,那么吧他们合并在一起,其中每个内部单词首字母都采用大写形式。方法、字段以及对象引用名称等,将标识符的第一个单词的首字母小写,标识符内的其他单词首字母大写。
例如:
class AllTheColorsOfTheRainbow{
int anIntegerRepresentingColors;
void changeTheHueOfTheColor(int newHue) {}
}
10、总结
通过本章的学习,大家已经接触相当多的关于如何编写一个简单程序的Java编程知识,对Java语言及它的一些基本思想也有了一个总体认识。
个人总结:
本章大体介绍了Java的基础知识,对面向对象编程也做了一些介绍。
上一篇:《Java编程思想》第一章:对象导论
下一篇: