Head First Java 六 七

第六章 构造函数 和GC (实际已是书的第九章了)

堆和栈

本地变量,和函数的调用都存在于Stack上,而对象的申请,都存活于Heap上。

正在运行的函数,处在栈的顶端。

如果一个函数的本地变量是个引用,然后申请了一个对象,让该引用去指向,那么这个引用存活于栈上,而其引用的对象,存活于Heap上。
注意:对象总存在于堆上,不管它的引用在哪里。
注意:成员变量,依附于对象,存活于Heap上。

对于基本类型的成员变量,在堆上创建对象的时候,就根据各种基本类型各自的大小,划分好了空间。比如int是32位,byte 8位等。而对于引用类型,也是划分好引用类型的大小,用于装那个遥控器的大小,当然不需要装下其指向的对象。

构造函数

 Duck myDuck =  new Duck(); 
上面加粗部分,就是在调用构造函数Duck()。

如果自己没有明确写出构造函数,编译器会帮你安一个,形式如下:
public Duck() {

}
注意:上面构造函数的示例里面没写内容,实际的类不一定里面什么都没有。类如果有成员变量,那自动添加的构造函数是会对成员变量进行初始化的。

注意:java是允许一个类里,有一个与类同名的方法的。但是这个方法必然有返回值,这就是它与构造函数的区分之处。

注意:编译器自动添加一个构造函数,是在你完全没有写任何构造函数的时候。如果你自己写了一个,比如public Duck(int size) { duckSize = size;} ,那编译器就不会给你自动添加一个不带参数的构造函数了。所以,比较好的编程方式是, 最好给自己的类添加一个不带参数的构造函数。因为使用这个类的人,不见得就一定知道该给什么参数,有一个默认的会方便很多。
当然这条不是规定啊,还是有很多类,不给参数就无法用,没有指定默认参数的构造函数存在。

注意:重载,仅参数顺序不同也是可以的。比如 public Duck(int size, String name) 和 public Duck(String name , int size) 是可以构成重载的。overload。当然两个参数类型一样时候怎么换顺序都没用了。

注意:构造函数不一定非要是public的,也可以是private  default,我自己亲测protected也行。

注意:虚类也是有构造函数的,他如果有成员变量的话也是要在自己的构造函数中初始化的。虽然没有办法通过 new AClass();的方法来调用这个构造函数。它的调用是在其子类的构造函数调用时,被调用的。

构造函数的调用线

如下图所示,三个类在同一条继承线上。如果我现在调用Hippo的构造函数,实例化一个Hippo,Hippo aHippo = new Hippo();那么首先会调用Hippo的构造函数,但是刚一进去就会先调用Animal的构造函数,然后进入Animal构造函数后,会立即调用Object的构造函数,把 object构造函数执行完毕后,会再继续执行Animal构造函数,最后执行完Hippo的构造函数。

构造函数的调用线,一直持续到调用到Object类的构造函数为止。

注意:一个对象中的父类部分必须完全建立起来后,才能建立子类部分。原因是,子类需要依赖父类存在,可能会用到父类的部分,如果父类没建好就建子类,就可能出问题,所以java规定了这么个调用线。C++也一样。
即,执行过程如下:

父构造函数的调用

在子构造函数中,要主动调用父构造函数,加入super();语句就行了。如:
注意:任何一个构造函数的第一个语句,必须是super()。当然小声说个例外,就是下面那行粗体字。如果一个构造函数调用的是另一个构造函数,那开头就不是super()了,就没有super(),下面会讲。

一般情况下,如果你没显式写出super();,那编译器会自动在你子类的构造函数的开头处,加入这句话,来完成构造函数调用线。

注意:如果你有多个重载的构造函数,编译器会在每个重载的构造函数开头,加入super(), 除非这个构造函数调用的是另外一个同一个类中的构造函数。

注意:因为编译器自动添加的只有super();这句话,所以只会调用父类的没有参数的那个构造函数,如果父类有好几个重载的构造函数,那只会自动调用那个没参数的。

注意:如果父类只有 需要参数的构造函数,那一个子类如果想继承于它,必须手动调用super();并给super();传参数。

构造函数 调用重载的另一个构造函数   this()的使用

这也是为了避免重复,因为几个构造函数中的工作可能差不多,大同小异。那就另一个构造函数为真正的构造函数,其他重载的构造函数只是接收参数,并调用这个真正的构造函数。

方法就是使用 this();

this()调用的是同一个类中的,重载的,另一个构造函数。

注意:this()只能在构造函数中调用,并且如果要被使用,那就必须是第一个语句。

注意:构造函数的第一个语句要么是this() 要么 是 super() ,且两者不能同时存在,且不可能有别的情况出现了。
Every constructor can have a call to super() or this(), but never both!

第七章 数字 和 static

static 方法

static方法,就是不需要对一个类进行实例化就能调用的方法,其内部也不会用到任何成员变量,这样该方法的行为就不会因为不同的对象,而发生变化。

如, 类Math下的所有方法都是static的。
所以可以这样调用,Math.abs(); Math.min();等。

注意:Math类的构造函数被声明为private,目的就是让它无法实例化。Math类也没有任何成员变量。

一个类中,既可以有static的方法,也可以有non-static的方法,可以共存。比如main函数就是static的。

注意:因为一个类下,static方法和non-static方法可以共存,所以用一个实例化了的对象去调用static方法是可以的。即, static方法可以由对象调用,虽然它不依赖于对象。但是这么做并不规范,不好。

注意:static的方法,不能使用non-static的成员变量,注意,一定是成员变量,使用本地变量没问题的。因为如果要使用成员变量,必然牵扯到对象,每个对象的成员变量可能不同。

注意:static方法,不能使用non-static的方法(成员函数。理由同上,因为成员函数里可以使用成员变量,即便哪个成员函数现在没使用成员变量,但不定什么时候会使用,所以,禁止static方法,调用non-static方法。

注意:non-static方法,既可以使用static方法,也能访问static的成员变量。

注意:获取一个对象的途径,一个是new,另一个是Java Reflection API,但第二个书上没怎么讲,查查。

类无法实例化的方法

1、类前加上 abstract,即声明该类为虚类。
2、将此类的构造函数前,加上private。

static 变量

批注一下,instance variables就是指成员变量。

初始化static变量

类的static变量的初始化,是在这个类第一次加载的时候就完成的。什么时候加载呢?比较典型的就是用new,实例化一个类的时候,或者使用一个类的static方法或static变量的时候。当然程序员可以自己控制什么时候对类进行加载,但没什么必要,交给JVM就好。

注意:static变量初始化,JVM会保证:
1、static变量初始化,必会在该类的任何一个对象被创造前完成。
2、static变量初始化,必会在该类的任何一个static方法被使用前,完成。

如果没有显式的给static变量初值,那它会自动初始化,和基本类型一样。数字类型初始化为0 或0.0 。布尔是false,引用是null。

使用一个static变量和使用static方法一样,Player.variables = 5;就行了。不用实例化对象。

static final 变量

static final 变量就是常量。

注意:static final 不会自动初始化,你不明确写初值,就报错。

注意:static final的变量,名称必须为大写。这是小规矩。

static final 初始化方法:
               static {
                    BAR_SIGN = 5;
               }
注意:上面的static块,叫做 static initializer,这个类一加载,就会立即运行这个块内的内容。

final 用途

1、在类中, 作为非static变量前时,用于保证这个值不会被更改。

2、 对于一个方法,声明为final,表示这个方法不能被重写 overridden

3、 对于一个类,声明为final,表示这个类不能被继承。



注意:一个类被声明为final后,其下的方法就没必要声明为final了。因为该类无法被继承,其内部方法就不可能被重写了。但是非要写也可以。主要是,如果你觉得一个类下的所有方法,都不想被重写,想保证他们的行为,那就把整个类声明为final。如果只是这个类中的部分方法,不想被重写,其它的允许重写,那就挑出不许重写的方法,标为final。

Math类的方法

有很多,这只写几个。

Math.random()随机产生 0.0 ~ 1.0 不包括两边界的小数。

Math.abs() 返回参数的绝对值,参数可以是int 可以是double。

Math.round() 把小数圆整,返回int或long,根据参数是float还是double。

Math.max()  Math.min() 

基本类型的包装

当你需要将一个基本类型变量,当做一个对象来使用的时候,就需要将它包装一下。

包装的函数有:
Boolean 
Character 
Byte
Short
Integer
Long
Float
Double
包装函数名称,基本就是基本类型的声明类型名,但有两个比较特殊,记忆一下。

java5.0之前,没有自动包装,非常麻烦。每次要使用一个基本类型对象的时候,先要把基本类型包装,然后用完了再解包装,java 5.0之后就没这么麻烦了。

以下示例是 5.0之前,ArrayList的使用方法
有了自动包装后,ArrayList的使用方法就变得简单了,如下:

自动包装(autoboxing)的其他功能:
1、如果一个方法的参数类型是包装类型,有了自动包装后,既可以传基本类型参数,也能传包装类型参数。
2、当然,返回值也可以像上面一样。如果为包装类型的话,实际返回的既可以是基本类型,也能是包装类型。
3、用到布尔表达式的地方,既可以是表达式,也能是布尔的包装类型,也能是布尔的基本类型。
4、最神的是这个,以前只能用在基本变量上的操作符,也能用在包装类型上了,即使用在一个对象上。比如:
这在以前是不可能的,或者如:
这个实际不是改变了语法规则,只是编译器做了手脚,帮你把包装类型变为基本类型后,才做的运算。
5、赋值的时候也能用,被赋值类型可以是基本类型,也可以是包装类型。

包装类型提供的method

包装类型还提供的好处就是静态的函数,方法。

字符串转数字或布尔:
Integer.parseInt("222")      Integer.parseDouble("2.56")
boolean b = new Boolean("true").booleanValue();
注意:布尔的怎么转换的看一下,没有parseBoolean这个函数。

反着也行,数字转字符串:

数字格式控制

书的294开始,到307没怎么看。和printf有点点类似。

Calendar API 可以做跟日历相关的事情。

还有个static import,没看310 311左右
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值