尽管java是基于C++的,但是相比之下 ,java是一种更加“纯粹”的面向对象的语言。
c++与java都是混合/杂合型语言,但是,java中这种杂合性没有c++重要。杂合性语言允许多种编程风格。C++之所以是杂合性语言,因为他要支持C向后兼容,因为C++是C的一个超集,它会包含C不具备的特性,这使得C++显得过于复杂了。
而java是纯粹的面向对象的语言,在java设计之初就把思想转换到面向对象中来了,这使得java学习起来比C++更简单。在java里,一切都是对象。
一:用引用来操纵对象
每种语言都有自己的操纵内存中元素的方式。如C,C++就是通过指针来操纵对象。
所有的一切在java里都简化了,因为在java里一切都视为对象,因此可以用同一个固定的语法。java里一切都是对象,但操纵的标识符实际上是对象的一个“引用”(reference)。可以想象成遥控器(引用)与电视机(对象)的关系。只要有遥控器就可以建立与电视机的联系。当想换台或音量控制时,只要操作遥控器就行,如果你想在房间里走动,依然可以控制电视机,只需要携带遥控器就好了,而不是电视机。此外,如果没有电视机,遥控器依旧可以存在。但是,此时如果要向遥控器发送消息,因为引用没有指定到对象,那么就会报编绎错误。所以,我们在创建一个引用的同时一定要记得初始化。
在 java 里,如果是 null ,那么它的意思是说明引用没有指向对象 。比如程序中我们从前台传到 action 的元素的值,如果前台并没有这个元素,那么在 action 取得到的值就是 null 。
二:必须由你来创建所有对象
创建了一个引用,就希望它与一个对象关联。我们用new一个对象来实现。new的意思是”给我一个对象“。常常,我们new一个已存在现成类,也可以是自行创建的类。
对于对象的存储位置,首先我们要明白有什么存储区域,如下,有五个地方可以存储数据:
1)寄存器
这是最快的存储区,因为它位于处理器内部,这不同于其它的存储区。但它的数量有限,所以寄存器需要根据需求进行分配。
2)堆栈
它位于RAM(随机访问存储器)中,它是通过堆栈指针来移动。栈指针向下移动则分配新的内存,如果向上移动则释放那些内存。引用存储在栈里,而对象是存储在堆里。
3)堆
它是一种通用的内存池,也位于RAM中,它存放所有的java对象。堆不同于堆栈的好处是:编译器不需要知道存储的数据在堆中存活多长时间。因此,在堆里分配存储有很大的灵活性。当需要一个对象时,只要程序里 new 一个对象,当执行这行代码时,会自动在堆里进行存储分配。当然,这也是要付出相应代价的:在堆里进行存储分配和清理可能比在堆栈里进行存储分配需要更多的时间。(这里假设java也可以像c++\c一样可以在堆栈里创建对象)
4)常量存储
常量直接存放在程序代码内部,这样是安全的,因为它永远不会被改变。
5)非RAM存储
数据完全存活于程序之外 ,不受程序的控制,在程序没有运行时也存在。 两个基本的例子就是:流对象和持久化对象。在流对象中,对象转化为字节流,通常被发送给另一台机器 。在”持久化对象“中,对象被存放在磁盘上。国此,即使程序终止,它们仍可以保持自己的状态。这种存储方式 的技巧:把对象转化成可以存储在其它媒价上的事件,在需要时,再恢复成基于RAM的对象。java提供了对国量级持久化的支持:如JDBC和Hibernate这样的机制就提供了复杂的对数据库的存储和读取对象信息的支持。
例外情况:基本类型
因为基本类型大小都固定了,如果对于它们也用new来把对象放在堆里往往不是很有效,基本类型是存在栈内存里的,而不是存储在堆内存里。
java中数组
几乎每种语言都支持数组。在C和C++中使用数组是很危险的,因为在C和C++中,数组就是内存快,如果在数组初始化前使用内存,或是访问了内存之外的数组,那就会产生很糟的后果。
这些问题在java中不会出现,因为java确定数组会被初始化,且必须在它的范围内访问。这种范围检查,是以每个数组上少量的内存开销及运行中的下标检查为代价的。但由此换来的安全性,这些代价是可以付出的。
在java里,当创建一个数组对象时,实质上是创建了一个引用数组,并且每个引用都会自动被初始化为一个特定值,该值拥有自己的关键字null。在java里一旦看到null,就知道这个引用没有指向某个对象。如果试图使用一个还为null的引用,那么就会报错。所以,在java里在使用任何引用时,都必须为引用指定对象。
三:永远不需要销毁对象:
在java里的对象不具备基本类型一样的生命周期。当用new一个对象时,这对象可以存放于作用域之外。
{ String s = new String("sadfasf"); }
在上面的代码中,引用s在作用域外就消失了,但是s指向的String对象却仍继续占据着内存空间。在这个作用域后,我们就没有办法访问这个对象了,因为这个对象的唯一的引用已经超出作用域范围了。当然,我们可以在代码中用传递和复制对象引用来在作用域外再使用这个对象。
在C++中就不是这样了,你必须保证对象的保留时间与使用对象的保留时间一样长,而且要确保在使用完对象后,要把它销毁。
那么java的种方式带来了一个问题,既然对象一直存在内存里,那么怎么才能防止对象存满内存呢?这在C++里会遇到的严重问题,在java里很好的解决了,这就是垃圾回收。
四:创建新的数据类型:类
java里一切都是对象,那么什么决定了某一类对象的外观和与行为的?是什么确定了对象的类型?答案就是类---class。
字段和方法
一旦定义了一个类,接着就可以在类里设置两种类型的元素:字段和方法。字段可以是任意类型的对象,可以通过其引用与其进行通信;也可以是基本类型的一咱。如果字段是对某个对象的引用,那么必须初始化该引用,以使其它与一个对象相关联(通过new来实现)。在java里,你所做的全部工作就是字义类,产生类的对象,以及发送消息给这些对象。
static关键字
通常我们在创建类时,都是在描述这个类的对象的外观与行为。只在没有new对象,这个类的对象就没有创建。只有new了对象,数据存储空间才会分配,其方法才能供外面调用。
有两种情况是上面说的无法解决的:一是只想为某特定域分配单一存储空间,而不去考虑空间要创建多少对象,甚至根本不不创建任何对象。二是希望某个方法不与包含它的类的任何对象关联在一起。也就是即使没有对象,也能够调用这个方法。
通过static可以满足上面要求。当声明一个事物为static时,就意味着这个域或方法不会和包含它的那个类的任何对象实例关联在一起。所以,即使从未创建对象实例,也可以调用static方法和static域。
先说说static字段
class StaticTest{ static int i =10; }
StaticTest st1 = new StaticText(); StaticTest st2 = new StaticText();
上面,就算你创建了两个StaticText对象,StaticText.i也只有一份存储空间,两个对象共享一个同一个i。当其中一个对象操作i使其值变化时,用另一对象去获取i的值也是变化后的值。
一般我们用类名.变量的方式来访问static成员,虽然也可以用对象.变量的方式来访问,但是前者可以让人一看就知道变量是static的。
再说说static方法:
static变量会改变数据的创建方式,因为静态域对每个类都只有一份存储空间,而非static字段则是对每个对象都有一份存储空间。但是对于静态方法来说,差别就没有那么大了,静态方法的一个重要用户就是在不创建任何对象的前提下你也可以调用这个方法。这对于main方法很重要,因为它是运行一个的应用时的入口点。
五:另注意以下两点:
1. 当变量做为类的成员时,如果没有初始化, java 会自动初始化。但是当变量做为方法的局部变量时 , 如果没有初始化编绎器就会报错。
2.以下代码说明需要多少字节才能容纳对特定字符串对象:
int storage(String s){ return s.length() * 2 }
注意:字符串中的每个字符有 2 个字节,有 16 位(一个字节 8 位),以此来对 Unicode 字符集的支持。