第二章:一切都是对象
真的是一切都是对象?
首先得明确java中的对象存储位置:
1) 寄存器:最快的存储区,在处理器内部,暂时忽略。
2) 堆栈:速度仅次于寄存器,但是得明确规定数据的大小和生命周期,对象的引用存储于其中(java对象不存在此)。
3) 堆:java对象的存储区,无需知道数据大小,生命周期。
4) 静态存储:static来标识的对象存储区。
5) 常量存储:常量值通常直接存放在程序代码内部,他们永远不会被改变。
6) 非RAM,忽略。
StringBuffer stringBuffer=newStringBuffer(“hello, world”),见惯不惯的一个代码段。实际java的操作机制:newStringBuffer(“hello, world”)创建了一个对象,该对象被存储到堆中,其实这个对象我们看不见摸不到。为了能够操作该对象,就有了StringBuffer stringBuffer这样一个引用,这个引用存储在堆栈中,”=”将两者联系在了一起。既然stringBuffer是指向new StringBuffer(“hello,world”)这个对象的,再来个StringBuffer stringBuffer1=stringBuffer,这里其实是引用的赋值而非对象本身的赋值,同理若有stringBuffer1==stringBuffer这样一个语句,也是引用的事。以上都好理解,直到看到Bruce Eckel说:java中的任何传递对象的场合,这里的传递实际上是引用,这不是c中的形参实参的关系么。于是立马敲下代码:
packagecom.cedric.thinkingInJava.test;
class Person{
String name;
int age;
}
public class ReferenceAndArgs {
public static void main(String[] args) {
Person person=new Person();
Person personBeforeChangeAge;
setPersonInfo(person);
personBeforeChangeAge=person;
System.out.println("Before thechange:");
printPersonInfo(personBeforeChangeAge);
System.out.println("After thechange:");
changeTheAge(person);
printPersonInfo(person);
printPersonInfo(personBeforeChangeAge);
//这里可以认为所有的引用都指向了最初的new Person()这个对象
}
static void setPersonInfo(Personperson) {
person.name="nerd";
person.age=22;
}
static void printPersonInfo(Personperson) {
System.out.println(person.name+" "+person.age);
}
static void changeTheAge(Personperson) {
person.age++;
printPersonInfo(person);
}
}
运行结果:
Before the change:
nerd 22
After the change:
nerd 23
nerd 23
nerd 23
从结果上看,的确所有的引用都指向了一个对象。再试一次:
packagecom.cedric.thinkingInJava.test;
public class test {
static voidnumberIncreaseByOne(String number){
number=new String("2");
printNumber(number);
}
static void printNumber(Stringnumber) {
System.out.println(number);
}
public static void main(String[] args) {
String integer=new String("1");
numberIncreaseByOne(integer);
printNumber(integer);
}
}
结果是:
2
1
问题出现:String是个对象,那定义的integer和number应该指向同一个对象才对,实际并非如此,它是值传递。这里就回到了最开始的问题:真的是一切都是对象?其实在java里有基本变量,也就是常见的intchar,long ,float,double等,他们不用new来创建,他们的值存储在堆栈中,这样可以更高效的运行,说白了他们不是对象。既然不是对象,他们在函数的参数传递时就是值的传递,和c中的实参传递一样。再来看String,google后知道它是封装类,看看它的源码:
public final class String
implements java.io.Serializable,Comparable<String>, CharSequence
{
/** The value is usedfor character storage. */
private final char value[];
/** The offset is thefirst index of the storage that is used. */
private final int offset;
/** The count is thenumber of characters in the String. */
private final int count;
……
里面的final char value[]就可以说明一切了:首先它其实是对char的一个封装而已,char就是基本类型,此外又是final类型,final类型网上看来是存储在常量存储区的。常量存储区的数据时永远不会变的,没有像其他对象一样的引用,所以就有了虽然是对象,但是还是值传递。那么Integer,Float等就可以解释为什么也是值传递了。至于StringBuffer,它的源代码继承了AbstractStringBuffer:
abstract class AbstractStringBuilder implements Appendable,CharSequence {
/**
* The value isused for character storage.
*/
char value[];
/**
* The count isthe number of characters used.
*/
int count;
/**
* This no-arg constructor isnecessary for serialization of subclasses.
*/
AbstractStringBuilder() {
}
这里的char并非final类型,和String的实现方法并不相同。
虽然知道了类似String这种封装类,但是里面真正的实现机制还是模糊的,下次带着这个问题去看final。
总结:了解了引用,第一次特意去了解StringBuffer stringBuffer=new StringBuffer(“hello, world”)的运行机制,知道了封转类。
第三章:控制程序流程
这章在c里面基本学过,没有太多花时间:
package com.cedric.thinkingInJava.test;
class Person{
Stringname;
}
public classChapter3Test {
public static void main(String[] args) {
//等号的测试
testEquals();
//按位运算的测试(只适用于int)
testBitwiseOperation();
//float转int测试
testFloatToInt();
}
private static void testFloatToInt() {
int i=(int)9.8;
System.out.print(i);//--舍去了小数部分
}
static void testEquals() {
Integern1=newInteger(10);
Integern2=newInteger(10);
Personp1=newPerson();
Personp2=newPerson();
p1.name=p2.name="nerd";
//因为n1和n2是独立的引用,两者不相同
System.out.println(n1==n2);//--false
//java中基本的类库都实现了equals的封装,使得两者比较的是对象的内容
System.out.println(n1.equals(n2));//--true
//自己创建的类对于equals没有进行覆盖
System.out.println(p1.equals(p2));//--false
}
static void testBitwiseOperation(){
int i=-1;
//左移几位相当于乘以几个2
System.out.println(i<<2);//--(-4)
//右移则是除以2
System.out.println(i>>1);//--(-2)
//无符号右移则是在最左边添加0
//-2-->1111111111111110无符号转移后011111111111111
System.out.println(i>>>1);//2147483647
}
}