首页 > 代码库 > 第二章----一切都是对象

第二章----一切都是对象

1、用引用操作对象

  在java中一切都被视为对象,操作对象实际上的操作对象的一个“引用”。两者之间的关系就相当于用遥控器(引用)来操作电视机(对象)。拥有一个引用,并不一定需要有一个对象与它关联,比如Sting a;只是声明了一个引用并没有关联到一个对象。

2、必须由你创建所有对象

  一但创建了一个引用,就希望与一个对象相关联,通常用new来新建一个对象(java中字符串可以用带引号的文本初始化)。

  2.1、存储位置

  (1)寄存器。最快的存储区(位于处理器内部),java中无法人为直接控制(c++/c中允许向编译器建议寄存器分配方式)。

  (2)栈。位于RAM中,栈指针向下移动分配新的内存,向上移动释放内存,速度很快,仅次于寄存器。但是创建系统时java系统必须知道存储在堆栈内所有项的确切声明周期,便于上下移动指针。这一约束限制了程序的灵活性,一些基本类型的变量和对象的引用(java对象并不在其中)被存放在栈中。

  (3)堆。一种通用内存池(位于RAM中),用于存放所有的java对象。堆不同于栈的好处是:编译器不需要知道存储的数据在堆中存活多长事件。当new一个对象时会自动在堆中分配内存进行存储。在不需要该对象时由编译器自动回收无需人为控制。当然,这种灵活性是需要付出代价的:相比于c/c++在栈中创建对象需要更多的时间。

  (4)常量存储。常量值通常直接存放在程序代码内部,因为常量值永远不会改变。

  (5)非RAM存储。数据存活于程序之外,可以不受程序的任何控制。比如流对象和持久化对象。 

  2.2、特例:基本类型

  程序设计中经常用到的一系列类型,比如整数,小数,字符......这些类型被称作基本类型,被特殊对待。

  为什么要特殊对待? new是将对象存储在堆中,之前说到存在堆中的数据需要的时间更长,所以对于这些经常用到的,特别小的,简单的数据,如果存在堆中代价太大。因此java不用new来创建变量,而是创建一个并非是引用的“自动”变量。这个变量直接存值并置于栈中。基本类型所占存储空间大小是固定的。

  为了适应万物皆对象,基本类型都有一个包装器类,使得可以在堆中创建一个非基本对象用来表示对应的基本类型。

  比如:

char c=a;
Character ch=new Character(c);
或者
Character ch=new Character(a);

  java se5中的自动包装功能是的两者之间可以自动转换。

  2.3、作用域

  变量作用域:变量包括直接存值的基本类型和类的引用。只在代码段内存活。

  对象作用域:

{
    String s=new String("string");      
}//end of scope

  引用s存在栈上,在作用域终点生命终结。然而s指向的String对象继续存活在堆中。由java的垃圾回收器来判断何时回收该对象。这样做消除了大部分“内存泄露”的问题。

  2.4、方法参数

  java和c/c++不同,对于java的方法参数到底是传值还是传引用很多人搞不清楚。对于基本数据类型传递的是值,因为基本数据是直接存值在栈区。对象传递的是引用(栈区的对象引用即堆区对象的地址)。以String和StringBuilder来说明。

  下面看两个例子。

public class Test
{
        public static void test(String str)
        {
            str = "world"+str;
        }
        public static void main(String[] args)
        {
            String  str1 = new String("hello");
            test(str1);
            System.out.println(str1);
        }
}

  上面例子的输出结果还是hello,为什么呢?因为在test中对str的修改并不是在原来对象上的修改,这里就涉及到了String对象的特点,String对象创建后无法修改,上面的修改实际上是:新建一个空的StringBuilder然后调用append方法插入“world”,str,然后调用toString方法新建一个新的String对象。所以此时str的引用对象已经是全新的了,所以主函数中str1并未改变。下面再看个StringBuilder的例子。

public class test1 {
    
    static void test(StringBuilder str){
        str.append("1234");
    }
    
    public static void main(String[] args) {
        StringBuilder a=new StringBuilder("abc");
        test(a);
        System.out.println(a.toString());
    }
}

  上面输出结果abc1234,test中对str的修改同时也对a生效,因为str和a的引用都是指向同一个StringBuilder对象,而StringBuilder是可修改的。这里足以说明传递的是引用。

第二章----一切都是对象