java语言假设我们只进行面向对象的程序设计,也就是说,在开始用java进行设计之前必须将思想转换到面向对象的世界中。
一.用引用操作对象
在java中一切都被视作对象,所以可以采用单一固定的语法操纵内存中的元素,操纵的标识符实际上是对象的一个“引用”。
String s;
这里创建的只是引用,并不是对象,如果此时向s发送一个消息,则会返回运行时错误。是因为此时的s实际上没有与任何事物相关联,因此一种安全的做法是在创建一个引用的同时便进行初始化。
String s = "string";
二.必须由你创建所有对象
一旦创建一个引用就是希望它能与一个新的对象相关联,通常用new操作符实现:
String s = new String("str");
程序运行时,对象的存储以及内存的分配:
1>寄存器 这是最快的存储区,因为它位于不同于其他存储区的地方-处理器内部,但是寄存器的数量及其有限,所以寄存器根据需求进行分配,你不能直接控制,也不能在程序中感觉到寄存器存在的任何痕迹,
2>堆栈 位于通用RAM(随即访问存储器)中,但通过堆栈指针可以从处理器那里获取直接支持,堆栈指针向下移动则分配新的内存,若向上移动则释放那些内存,这是一种快速有效的分配存储方法,仅次于寄存器,创建程序的时候,java系统必须知道存储在堆栈内所有项的确切生命周期,以便上下移动堆栈指针,这一约束限制了程序的灵活性,所以虽然某些java数据存储在堆栈中,特别是对象的引用,但是java对象并不存储在其中。
3>堆 一种通用的内存池(也位于RAM区),用于存放所有的java对象,堆不同于栈的好处是:编译器不需要知道存储的数据在堆里存活多长时间。因此在堆里分配内存有很大的灵活性。不足是在堆中分配和清理可能比用栈进行储存分配需要更多的时间。
4>常量存储 常量值通常直接存放在代码内部,这样做是安全的,因为他们永远不会被改变,有时在嵌入式系统中,常量本身会和其他部分隔离开来,所以在这种情况中, 也可以选择将其存放在ROM(只读存储器)中。
5>非RAM存储 如果数据完全存活于程序之外,那么它可以不受程序的任何控制,在程序运行时也可以存在,其中两个基本的例子是流对象和持久化对象 在流对象中,对象转化成字节流通常被发送给另一台机器,在持久化对象中,对象被存放在磁盘中,因此即使程序被终止,它们仍可以保持自己的状态,java提供了对轻量级持久化的支持,而诸如JDBC和Hibernate这样的机制提供了更复杂的对在数据库中存储和读取对象信息的支持。
特例:基本类型 : 在程序设计中经常用到的一系列类型,他们需要特殊对待,可以把它们想成“基本”类型,之所以特殊对待是因为new将对象存储在“堆”里,所以用new创建一个对象特别是小的简单的变量往往不是很有效,因此对于这些类型,java采用和c++相同的方法,也就是说不用new来创建变量,而是创建一个非引用的“自动”变量,这个变量的值直接存储“值”并置于堆栈中,因此更加高效。
java提供两个用于高精度计算的类:BigInteger和BigDecimal,虽然他们大体上属于包装器类,但是两者都没有对应的基本类型,但是这两个类包含的方法提供的操作与基本类型所能执行的操作相似,也就是说作用到int和float的操作同样能作用在这两个类型上。
BigIngeger支持任意精度的整数,也就是说在运算中,可以准确地表示任何大小的整数值
BigDecimal支持任意精度的定点数
数组: 不同于c/c++ java的主要目标之一是安全性,所以在许多c/c++中困扰程序员的问题在java里不会存在,java确保数组会被初始化。而且不能在它的范围外被访问,这种范围检查是以每个数组上少量内存开销以及运行时的下标检查为代价的。由此换来的安全性和效率提高,因此付出的代价是值得的。
三.永远不要销毁对象
在java中,默认讲一个较大作用域的变量“隐藏”起来的做法是不允许的,因为设计者认为这样做会导致程序混乱。
java对象的作用域: java对象不具备和基本类型一样的生命周期,当用new创建一个对象的时候,它可以存活在作用域之外
{
String s = new String("string");
}
引用s在作用域的终点就消失了,然而s指向的String对象扔继续占用内存空间,在这段代码中无法在这个作用域消失之后访问这个对象,因为它的唯一引用已经超出了作用域的范围。
四.创建新的数据类型:类
class关键字后紧跟着新类型的名称
class ATypeName{}
在java中所做的全部工作就是定义类,产生那些类的对象,以及发送消息给这些对象
一旦定义了一个类就可以在类中设置两种类型的元素:字段(数据成员)和方法(成员函数)字段可以是任何类型的对象,可以通过引用其进行通信。也可以是基本类型的一种,如果字段是对某个对象的引用,那么必须初始化该引用,以便使其与一个实际的对象相关联。
每个对象都有用来存储其字段的空间;普通的字段不能在对象之间共享。下面是一个具有某些字段的类:
class DataOnly{
int i;
double d;
boolean b;
}
可以用DataOnly data = new DataOnly();创建对象并且给字段赋值。
基本成员默认值:
基本类型 | 默认值 |
boolean | false |
char | null |
byte | (byte)0 |
short | (short)0 |
int | 0 |
long | 0L |
float | 0.0f |
double | 0.0d |
若类的某个成员变量是基本类型即使没有初始化java也会确保它获得一个默认值。
当变量作为类的成员变量时才会确保它有默认值
上述方法并不适用于局部变量。
五.方法参数和返回值
方法就是其他程序设计语言中例如c/c++中的函数,表示“做某些事情的方式”
java的方法决定了一个对象能够接收什么样的消息,方法的基本组成部分包括:名称,参数,返回值和方法体
java方法的基本格式如下:
ReturnType methodName(参数列表){
方法体
}
返回值类型描述的是调用方法之后从方法返回的值的类型,参数列表给出了传入方法的信息的类型和名称,方法名和参数列表合起来被称作方法签名 唯一标识某个方法。
java的方法只能作为类的一部分来创建,方法只有通过对象才能被调用,且这个对象必须能执行这个方法调用,如果在某个对象上调用它不具备的方法,那么编译时会得到一条错误信息。
调用方法的方式是:列出对象名,紧接着句点,然后是方法名和参数列表
objectName.methodName(ag1,arg2);
//有参数的方法
int x = a.f();
//如果f()的返回值是int型可以用int变量来接收这个返回值
参数列表:方法的参数列表指定要传递给方法什么样的信息,这些信息采用的是对象形式,因此在参数列表中必须指定每个所传递对象的类型和名字。像java中任何传递对象的场合一样这里传递的实际上也是引用,并且引用的类型必须正确。
返回值类型和return后接着的类型应该是相同的,如果不需要返回值类型则可以将返回值类型定义为void,如果返回值类型不是void,那么无论在何处返回,编译器都会强制返回一个正确类型的返回值。
六.构建一个java程序
这部分介绍了在创建一个java程序之前还必须了解的其他问题
名字可见性:为了避免在某个模块中使用了一个名字,而其他人在另一个模块中使用了相同的名字引起的冲突,java通过返货来使用自己的域名来解决。因为这样可以保证它们是独一无二的。
运用其他构件:如果想在自己的程序中使用预先定义好的类,需要让编译器知道如何定位它们
如果这个类就在发出调用的源文件中,可以直接使用这个类
如果类位于其他文件中,需要用import指示编译器导入一个包,也就是一个类库,例如使用在java绑定的标准类库中的类:
import java.util.ArrayList;
//告诉编译器我想使用java的ArrayList类
import java.util.*;
//使用java.util下的所有类库
static关键字:创建类时就是在描述这个类的外观与行为,在用new创建这个类的对象之前,实际上是未获得任何对象的,执行new之后数据的存储空间才会被分配,其方法才供外部调用。
有两种情况是上述方法无法解决的:1.只想为某特定区域分配单一存储空间,并不去考虑究竟创造多少对象或者不创建任何对象,2.希望某个方法不与包含它的类的任何对象关联在一起,即从未创建某个类的任何对象也可以使用这个方法。
通过static关键字可以满足这两个方面的需求,当声明一个事物是static的时候,就意味这个这个域或方法不会与包含它的那个类的任何对象实例关联在一起,所以不创建某个类的任何对象也可以调用其static方法或者访问其static域。
有些面向对象语言采用类数据和类方法 两个术语,代表那些数据和方法只是作为整个类,而不是类的某个特定对象而存在的,有时一些java文献中会用到这两个术语。
static字段:
ckass StaticTest{
static int i = 1;
}
这个时候即使创建了两个StaticTest对象,StaticTest.i 也只有一份存储空间,这两个对象共同享用一个i
StaticTest st1 = new StaticTest();
StaticTest st2 = new StaticTest();
st1,i和st2.i指向同一存储空间他们的值都是1
引用static变量有两种方法:
第一种是用对象去定位:st1.i;
第二种是通过其类名直接引用:StaticTest.i; -- 这种方式对非静态成员不行
使用类名引用静态变量是首选方式,因为这不仅强调了变量static结构还在某些情况下为编译器进行优化提供了更好的机会
类似的逻辑还引用于静态方法,既可以像其他方法一样通过一个对象来引用某个静态方法,也可以通过类名.静态方法名调用
和其他方法一样,static方法可以创建或使用与其类型相同的被命名对象,因此static方法常常用来做“牧羊人”负责看护与其隶属同一类型的实例群。(个人理解为 类的对象可以创建多个 而static方法是类的方法,且所有对象共用一块静态方法的内存)
七.创建第一个java程序
import java.util.*;
public class HelloDate{
public static void main(String[] args){
System.out.println("hello. it's:");
System.out.println(new Data());
}
}
在每个程序的开头必须声明import用来引入文件代码中所需要用到的额外类。这里说的“额外”是因为有一个特定的类会被自动导入到每一个java文件中:java.lang 由于这个包是默认别导入每个java文件中的所以他的所有类都可以被直接使用
八.注释和嵌入式文档
java有两种注释风格,一种是传统的C语言注释风格 以/*开始 */结束 编译时/**/之间的所有东西都会被忽略
第二种源于C++ 是“单行注释” 以//开头 直到句末 因为容易书写所以更加方便更常用
注释文档:javadoc是便于提取注释的工具,是jdk安装的一部分,采用java编译器的某些技术查找程序内的特殊注释标签,不仅解析由这些标签标记的信息,也毗邻注释的类名或方法名抽取出来。
javadoc输出的是一个html文件,可以用web浏览器查看,这样该工具就使得我们只需要创建和维护单一的源文件并能自动生成有用的文档。
语法:
所有javadoc命令都只能在/**注释中出现,结束于*/使用javadoc的方式主要有两种:嵌入式html 或使用“文档标签”独立文档标签是一些以‘@’字符开头的命令,且要置于注释行最前面,而“行内文档标签”则可以出现在javadoc注释中的任何地方,他们也是以‘@’开头,但要再花括号内
共有三种类型的注释文档,分别对应于注释位置后面的三种元素:类,域或者方法。类注释正好位于类定义之前,域注释正好位于域定义之前方法注释正好位于方法定义前面,
javadoc只能为public和protected成员进行文档注释private和包内可访问成员的注释会自动被忽略掉,
嵌入式html:
javadoc通过生成html文档传送html命令,使得我们可以充分利用html,主要用来对代码进行格式化:
/**
<pre>
System.out.println(Data);
</pre>
*/
一些标签的示例:
@see 允许用户引用其他类的文档
@link package.class 与see相似 用于行内
@docRoot 产生到文档根目录的相对路径
@inheritDoc 该标签从当前这个类的最直接的基类中继承相关文档到当前的文档注释中
@version version-information 可以使任何你认为适合包含在版本说明中的重要信息
@auther auther-information 姓名 电子邮件或其他信息
@since 允许指定程序代码最早使用的版本 可以在html java文档中看到它被用来指定所用的jdk的版本
@param 用于方法文档中,parameter-name description 其中parameter-name是方法参数列表中的标识符 description是可延续数行的文本 终止于新的文档标签出现之前
@return description 用来描述返回值含义
@throws 异常
@deprecated 指出一些旧特性已由新特性取代建议用户不要使用这些旧特性