Java编程思想学习笔记(四)

第二章 一切都是对象

2.1用引用操纵对象

每种语言都有各自的操纵内存中元素的方式,直接操纵元素或者使用简介表示来操纵(c、c++中的指针)。但是Java中,由于一切事物都被视作对象,所以可以使用固定单一的语法来实现。操纵的标识符实际上是对象的一个引用(reference),就好比使用遥控器来操纵电视机一样,遥控器就是电视机的一个引用,当然,就算没有了电视机,遥控器也可以单独存在,这也就是说,引用并不一定要有一个对象和他相关联

String s;

假设我们想操纵一个词或者句子,那么可以像上述代码创建一个String类型的引用,这里创建的只是引用,并不是实际的对象,这个时候向s传递一个消息,就会抛出一个运行时错误。所以安全的做法是,在创建这个引用的同时就对其初始化:

String s = "abcd";

2.2必须由你创建所有对象

创建一个引用之后,通常使用new关键字来使其与一个对象关联,new关键字的意思是“给我一个新对象”,前面的例子可以写作:

String s = new String("abcd");

(1)存储到什么地方?

  程序运行时,有五个地方可以存放数据:

  a.寄存器:最快的存储区(因为寄存器在处理器的内部),也是因为其位置,寄存器的存储容量非常有限,Java无法在程序中感觉到寄存器存在的任何迹象,他根据需求进行分配(c、c++允许程序员向编译器建议寄存器分配方式);

  b.堆栈:位于RAM(随机访问存储器)中,通过堆栈指针可以从处理器获得直接支持(可以直接根据堆栈指针进行快速的寻址),速度仅次于寄存器。创建程序时,Java系统必须知道存储在堆栈中的所有项的确切生命周期,以便于之后堆栈指针的上下移动,这种方式限制了程序的灵活性,尤其是对象引用的灵活性,所以Java的对象不存储于堆栈中

  c.堆:一种通用的内存池(也位于RAM区),用于存放所有的Java对象,堆中的数据,编译器不需要知道生命周期为何(因为堆相较于堆栈是一种比较灵活的数据结构,所以堆空间的分配具有很大的灵活性),相应的,堆的存储分配和垃圾清理也需要比堆栈更多的时间;

  d.常量存储:直接放在代码的内部,这样做是安全的,永远不会被改变,常用于嵌入式开发中,常量会和其他部分隔开,存放于ROM中;

  e.非RAM存储:若数据完全存在于程序之外,那么他就可以完全不受程序的任何控制,在程序不运行时也可以存在,经典的例子是流对象持久化对象

  流对象,对象转化为字节流,通常被发送给另一台机器;

  持久化对象,被存放于磁盘上(数据库交互中的持久化就是指将程序中的数据转化为数据库中的持久化对象),在程序终止之后,数据还是可以保持自己的状态;

  这两种方式的共同点都是将对象转化成可以存储在其他媒介上的事物,在需要时,还是可以转化回常规的、基于RAM的对象。Java提供了轻量级的持久化支持,JDBC等机制提供了更复杂的与数据库进行交互的支持。

(2)特例:

  基本类型:

  在Java中,基本类型的对象需要被特殊对待,new创建的对象被存储于堆中,但是对于一些小的、简单的、基础的类型的对象,Java采用和C、C++相同的处理方法,也即不用new关键字,而是创建一个并非是引用的“自动”变量,这个变量直接存储值,并且直接存储于堆栈中

  Java确定每种基本类型所占存储空间的大小,并且不随机器硬件架构的变化而变化,这也赋予了Java更强的可移植性。 

 

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

char c = 'x';
Character ch = new Character(c);

上述代码,第一行是创建在堆栈中的基本类型对象,第二行是使用其包装器类在中创建的对象。

Character ch = 'x';//Java SE5自动包装功能可以自动将基本类型转化为包装器类型
char c = ch;//可以实现反向转换

  高精度数字:

  Java提供的用于高精度计算的类:BigInteger(任意精度整数)、BigDecimal(任意精度浮点数),这二者属于包装器类范畴,但是没有对应的基本类型

  作用于int和float的操作,也能实现于这二者,只不过是调用相应的方法,而不是使用符号。

(3)Java中的数组

  大部分程序设计语言都需要数组,但是在c或者c++中使用数组是危险的,因为c、c++的数组就是内存块,在一个程序要访问自身内存块之外的数组,或者数组初始化之前使用内存时,都会产生难以预料的后果。

  安全性是Java的主要目标之一,Java确保数组会被初始化,并且不能在范围之外访问。这种范围检查,是以每个数组上少量内存开销及运行时的下标检查为代价实现的。

  创建一个数组对象时,实际上是创建了一个引用数组,并且每个引用都会自动被初始化为一个特定值,该值有自己的关键字null,Java看到null,就知道这个引用还没有指向某个确切的对象。在使用任何引用前,必须为其指定一个对象,所以使用值为null的引用会在运行时报错。

  创建内容为基本类型的数组时,编译器也会自动进行初始化,具体是将这种数组所占的内存全部置零

2.3永远不需要销毁对象~

(1)作用域

  大多数过程型语言都有作用域(scope)的概念,作用域决定了变量的可见性和生命周期,c和c++中,作用域由花括号决定。

  但是Java是一种自由格式的语言,故缩进只是便于阅读,并不会对执行结果产生影响。

{
  int x = 12;
  {
     int x = 96;   
   }    
}    

  上述代码在c和c++中是合法的,但是在Java中非法,编译器会提示变量x已经定义过,Java设计者认为这种方式是将较大作用域变量隐藏起来的做法,会导致程序的混乱。

(2)对象的作用域

  Java的对象不具备和基本类型一样的生命周期,使用new关键字创建一个对象时,他可以存活于作用域之外:

{
    String s = new String("ababab");
}

  引用s在作用域的终点会消失,但是s指向的String对象仍然占据着内存空间,我们无法在这个作用域结束之后再访问这个对象,因为它唯一的引用已经超出了作用域的范围。

  由new关键字创建的对象,只要你需要,就会一直保留下去,这样就不会涉及到对象的销毁问题。但是这也带来了一个新的问题,如果对象会持续存在,那么怎么防止这些对象占满内存空间,进而阻塞程序的运行呢?Java给出的解决方案是垃圾回收器,垃圾回收器用于监督由new关键字创建的所有对象,并且辨别其中不会再被引用的对象,随后将这些对象的内存空间释放,供其他对象使用。

 

2021.2.1 晚 上传

读到P58

 

posted @ 2021-02-01 20:57  aLieb  阅读(91)  评论(0编辑  收藏  举报