Java 一切都是对象

来源:互联网 发布:mac修容偏白用哪个色 编辑:程序博客网 时间:2024/05/22 10:03

Java 一切都是对象

尽管Java是基于C++的,但是相比之下,Java是一种更“纯粹”的面向对象程序设计语言。

C++和Java都是混合、杂合型语言。

C++之所以成为一种杂合型语言主要原因是因为它支持与C语言的向后兼容。

因为C++是C的一个超集,所以势必包括许多C语言不具备的特性,这些特性使C++在某些方面显得过于复杂。

Java语言假设我们只进行面向对象的程序设计。

用引用操作对象

每种编程语言都有自己的操纵内存中元素的方式。

操作在Java中得到了简化。一切都被视为对象,因此可采用单一固定的语法。尽管一切都看作对象,但操纵的标识符实际上是对象的一个“引用”(reference)。可以将这一情形想像成用遥控器(引用)来操纵电视机(对象)。

此外,即使没有电视机,遥控器亦可单独存在。

也就是说,你拥有一个引用,并不一定需要有一个对象与之关联。

必须由你创建所有对象

一旦创建了一个引用,就希望它能与一个新的对象相关联。通常用new操作符来实现这一目的。

new关键字的意思是“给我一个新对象”。

1. 存储到什么地方

程序运行时,对象是怎么进行放置安排的呢?特别是内存是怎么分配的呢?

有5个不同的地方可以存储数据:

  1. 寄存器。这是最快的存储区,因为它位于处理器内部。但寄存器的数量极其有限,所以寄存器根据需求分配。你不能直接控制,也不能在程序中感觉到寄存器存在的任何迹象。
  2. 堆栈。位于通用RAM(随机访问存储器)中,但通过堆栈指针可以从处理器那里获得直接支持。堆栈指针若向下移动,则分配新的内存;若向上移动,则释放内存。这是一种快速有效的分配存储方法,速度仅次于寄存器。

    创建程序时,Java系统必须知道存储在堆栈内所有内容的确切生命周期,以便上下移动堆栈指针。这一约束限制了程序的灵活性,所以虽然某些Java数据存储于堆栈中—-特别是对象引用,但是Java对象并不存储于其中。

  3. 。一种通用的内存池(也位于RAM区),用于存放所有的Java对象。堆不同于堆栈的好处是:编译器不需要知道存储的数据在堆里存活多长时间。因此,在堆里分配存储有很大的灵活性。

    当需要一个对象时,只需要new写一行简单的代码,当执行这行代码时,会自动在堆里进行存储分配。

    当然,为这种灵活性必须要付出相应的代价:用堆进行存储分配和清理可能比用堆栈进行存储分配需要更多的时间。

  4. 常量存储。常量值通常直接存放在程序代码内部,这样做是安全的,因为它们永远不会被改变。有时,在嵌入式系统中,常量本身会和其他部分隔离开,所以在这种情况下,可以选择将其存放在ROM(只读存储器)中。
  5. 非RAM存储。如果数据完全存活于程序之外,那么它可以不受程序和任何控制,在程序没有运行时也可以存在。其中两个基本的例子是流对象和持久化对象。在流对象中,对象转化成字节流,通常被发送给另一台机器。

    在“持久化对象”中,对象被存放于磁盘上,因此,即使程序终止,它们仍可以保持自己的状态。这种存储方式的技巧在于:把对象转化成可以存放在其他媒介上的事物,在需要时,可恢复成常规的,基于RAM的对象。

    Java提供了对轻量级持久化的支持,而诸如JDBC和Hibernate这样的机制提供了更加复杂的对在数据库中存储和读取对象信息的支持。

2. 特例:基本类型

在程序设计中经常用到一系列类型,它们需要特殊对待。可以把它们想像成“基本”类型。

之所以特殊对待,是因为new将对象存储在“堆”里,故用new创建一个对象—特别是小的、简单的变量,往往不是很有效。

因此,对于这些类型,Java采取与C与C++相同的方法。也就是说,不用new来创建变量,而是创建一个并非是引用的“自动”变量。这个变量直接存储“值”,并置于堆栈中,因此更加高效。

Java要确定每种基本类型所占存储空间的大小。它们的大小并不像其他大多数语言那样随机器硬件架构的变化而变化。这种所占存储空间大小的不变性是Java程序比用其他大多数语言编写的程序更具可移植性的原因之一。

所有数据类型都有正负号,所以不要去寻找无符号的数值类型。

基本类型具有的包装器类,使得可以在堆中创建一个非基本对象,用来表示对应的基本类型。

Java SE5的自动包装功能,可以自动地将基本类型转换为包装器类型。

高精度数字

Java提供了两个用于高精度计算的类:

  1. BigInteger 支持任意精度的整数
  2. BigDecimal 支持任意精度的定点数

虽然它们大体上属于“包装器类”的范畴,但二者都没有对应的基本类型。

Java中的数组

几乎所有的程序设计语言都支持数组。在C和C++中使用数组是很危险的,因为C和C++中的数组就是内存块。如果一个程序要访问其自身内存块之外的数组,或在数组初始化前使用内存,都会产生难以预料的后果。

Java的主要目标之一是安全性,所以许多在C和C++里困扰程序员的问题在Java里不会再出现。

Java确保数组会被初始化,而且不能在它的范围之外被访问。这种范围检查,是以每个数组上少量的内存开销及运行时的下标检查为代价。但由此换来的是安全性和效率的提高,因此付出的代价是值得的。

在创建一个数组对象时,实际上就是创建了一个引用数组,并且每个引用都会自动被初始化为一个特定值,该值拥有自己的关键字null。

一旦Java看到了null,就知道这个引用还没有指向某个对象。在使用任何引用前,必须为其指定一个对象;如果试图使用一个还是null的引用,在运行时将会报错。

还可以创建用来存放基本数据类型的数组。同样,编译器也能确保这种数组的初始化,因为,它会将这种数组所占的内存全部置零。

永远不需要销毁对象

变量需要存活多长时间?如果想要销毁对象,那什么时刻进行呢?

介绍Java是怎样完成清理工作。

作用域

大多数过程型语言都有作用域(scope)的概念。作用域决定了在其内定义的变量名的可见性和生命周期。在C、C++和Java中,作用域由花括号的位置决定。

在作用域里定义的变量只可用于作用域结束之前。

编译器将会报告变量x已经定义过。所以,在C和C++里将一个较大作用域的变量“隐藏”起来的做法(全局变量),在Java里是不允许的。因为Java设计者认为这样作会导致程序混乱。

对象的作用域

Java对象不具备和基本类型一样的生命周期。当用new创建一个Java对象时,它可以存活于作用域之外。

Java有一个垃圾回收器,用来监视用new创建的所有对象,并判别那些不会再被引用的对象。随后,释放这些对象的内存空间,以便供其他新的对象使用。

这样做就消除了这类编程问题(即“内存泄漏”),这是由于程序员忘记释放内存而产生的问题。

创建新的数据类型:类

是什么确定了对象的类型?

你可能期望有一个名为“type”的关键字,当然它必须还要有相应的含义。

然而,从历史发展的角度来看,大多数面向对象的程序设计语言习惯使用关键字class来表示“我准备告诉你一种新类型的对象看起来像什么样子”。

class这个关键字后面紧跟着是新类型的名称。

1. 字段和方法

一旦定义了一个类(在Java中你所做的全部工作就是定义类,产生那些类的对象,以及发送消息给这些对象),就可以在类中设置两种类型的元素:字段(有时被称作数据成员)和方法(有时被称作成员函数)。

字段可以是任何类型的对象,可以通过其引用与其进行通;也可以是基本类型中的一种。如果字段是对某个对象的引用,那么必须初始化该引用,以便使其与一个实际的对象相关联。

每个对象都有用来存储其字段的空间;普通字段不能在对象间共享。

基本成员默认值

若类的某个成员是基本数据类型,即使没有进行初始化,Java也会确保它获得一个默认值。

这样可以防止程序出错。

方法、参数和返回值

许多程序设计语言用函数这个术语来描述子程序;而在java里却常用方法这个术语来表示“做某些事情的方式”。

Java的方法决定了一个对象能够接收什么样的消息。

方法基本组成部分包括:名称、参数、返回值和方法做。

调用方法的行为通常被称为发送消息给对象。

参数列表

方法的参数列表指定要传递给方法什么样的信息。

像Java中任何传递对象的场合一样,这里传递的实际上也是引用,并且引用的类型必须正确。

static关键字

通常来说,当创建一个类时,就是在描述那个类的对象的外观与行为。除非用new创建那个类的对象,否则,实际上并未获得任何对象。

执行new来创建对象时,数据存储空间才被分配,其方法才供外界调用。

有两种情形用上述方法是无法解决的:

  1. 一种情形是:只想为某个特定域分配单一存储空间,而不去考虑究竟要创建多少对象,甚至根本就不创建任何对象。

  2. 另一种情形是:希望某个方法不与包含它的类的任何对象关联在一起。也就是说,即使没有创建对象,也能够调用这个方法。

通过static关键字可以满足这两方面的需要。

当声明一个事物是static时,就意味着这个域或方法不会与包含它的那个类的任何对象实例关联在一起。

所以,即使从未创建某个类的任何对象,也可以调用其static方法或访问其static域。

通常,你必须创建一个对象,并用它来访问数据或方法。因为非static域和方法必须知道它们一起运作的特定对象。

有些面向对象语言采用 类数据 和 类方法 两个术语,代表那些数据和方法只是作为整个类,而不是类的某个特定对象而存在的。

使用类名是引用static变量的首选方式,这不仅是因为它强调了变量的static结构,而且还在某些情况下它还为编译器进行优化提供了更好的机会。

尽管当static作用于某个字段时,肯定会改变数据的创建方式(因为一个static字段对每个类来说都只有一份存储空间,而非static字段则是对每个对象有一个存储空间),但是如果static作用于某个方法,差别却没有那么大。

static方法的一个重要用法就是在不创建任何对象的前提下就可以调用它。

0 0