C++ 引入了构造器的概念,这是一个在创建对象时被自动调用的特殊方法。Java也采用了构造器,并且额外提供了垃圾回收器。
1 用构造器确保初始化
构造器是与对象同名的方法,在使用 new 创建对象时,默认执行对象的无参构造方法执行初始化。
2 方法重载
以构造方法为例,有参构造方法即为重载的构造方法,即同名的方法是方法重载的必要条件。
2.1 区分重载方法
重载方法名称相同,参数列表不同,定义时参数顺序最好有规律性,比如
void fun(int i);
void fun(int i, String s);
void fun(int i, String s, long l);
复制代码
2.2 涉及基本类型的重载
void fun(short i)
void fun(int i)
复制代码
如果执行 fun(5)实际被调用的方法是void fun(int i)也就是没有指定基本类型的参数类型时,会被默认地提高精度,char 类型如果没有 void fun(char c) 方法,会默认提高精度到int
如果参数精度大于方法参数定义,则需要强转窄化。
2.3 以返回值区分重载方法
不以返回值区分方法的原因是,有时候业务不关注方法的返回值,程序无法识别方法,如
int fun();
String fun();
复制代码
假设上面方法是可用的,在程序中调用fun();程序并不知道要调用哪一个,所以不用返回值区分方法。
3 默认构造器
如果没有显示定义构造器,则默认构造器为无参构造器。
4 this 关键字
this 只能在方法内部使用,表示调用方法的那个对象的引用。
public class PassingThis {
public static void main(String[] args) {
new Person().eat(new Apple());
}
}
class Person{
public void eat(Apple apple){
Apple peeled = apple.getPeeled();
System.out.println("Yummry");
}
}
class Peeler{
static Apple peel(Apple apple){
return apple;
}
}
class Apple{
Apple getPeeled(){
return Peeler.peel(this);
复制代码
this 用于值传递
4.1 在构造器中调用构造器
public class Flower {
int petalCount = 0;
String s = "inital value";
Flower(int petals){
petalCount = petals;
}
Flower(String ss){
s = ss;
}
Flower(int petalCount, String ss){
this(ss);
}
Flower(int petalCount, String ss, long y){
this.petalCount = petalCount;
}
复制代码
在构造器中,this()表示调用无参构造器(有参传参数即可)
4.2 static的含义
static 修饰的方法就是没有this 的方法,可以看作是全局方法。
5 清理:终结处理和垃圾回收
垃圾回收器只知道释放那些经由new分配的内存,所以它不知道该如何释放该对象的这块特殊内存。一旦垃圾回收器准备好释放对象占用的存储内空间,将首先调用其finalize方法 ,并且在下一次垃圾回收动作发生时才会真正回收对象占用的内存。
对象可能不被垃圾回收
垃圾回收并不等于析构
5.1 finalize()的用途何在
看不太明白,大致和内存有关,不可过多的使用finalize()
5.2 你必须实施清理
c++中通过析构函数实现对象内存释放,java中由垃圾回收器自动调用,但是也有可能回收不了对象,迷糊。
5.3 终结条件
可以这样理解,垃圾回收时,会调用对象的finalize()方法,可以把一些对该对象的检测逻辑放到finalize()里。
public class TerminationCondition {
public static void main(String[] args) {
Book novel = new Book(true);
novel.checkIn();
new Book(true);
System.gc();
}
}
class Book{
boolean checkOut = false;
public Book(boolean checkOut){
this.checkOut = checkOut;
}
void checkIn(){
checkOut = false;
}
protected void finalize(){
if(checkOut){
System.out.println("Error : checked out");
}
复制代码
5.5 垃圾回收器如何工作
1、引用计数法
2、标记-清除法
3、复制算法
等等
6 成员初始化
类的数据类型是基本类型时会被初始化成对应的类型的初始值。引用类型会声明成null。
6.1 指定初始化
即初始化赋值。
7 构造器初始化
类的成员变量在构造器调用之前就会被初始化。
class Counter{
int i;
public Counter(){
i = 5;
}
}
复制代码
i在调用构造方法之前就被初始化成0,调用构造方法后被赋值为5
7.1 初始化顺序
即时变量定义散布于方法定义之间,它们仍旧会在任何方法被调用前被初始化。
7.2 静态数据的初始化
静态初始化只有在必要时刻才会进行。
假设有一个Dog类。
1、当首次使用构造方法创建对象时,或许Dog类地静态方法静态域首次被访问时,Java解释器必须查找类路径,以定位Dog.class
2、载入Dog.class,有关静态初始化的所有动作都会执行,因此,所有静态初始化旨在Class对象中首次加载的时候进行1次。
3、当用new Dog()创建对象时,首先在堆上为对象分配足够的存储空间。
4、这块存储空间会被清0,所有地成员变量被初始化成0 或null
5、执行所有成员变量初始化动作。
6、执行构造器。
public class StaticInitialization {
public static void main(String[] args) {
print("Creating new Cupboard() in main");
new Cupboard();
print("Creating new Cupboard() in main");
new Cupboard();
table.f2(1);
cupboard.f3(1);
}
static Table table = new Table();
static Cupboard cupboard = new Cupboard();
}
class Bowl{
Bowl(int marker){
print("Bowl(" + marker + ")");
}
void f1(int marker){
print("f1("+marker+")");
}
}
class Table{
static Bowl bowl = new Bowl(1);
Table(){
print("Table()");
bowl2.f1(2);
}
void f2(int marker) {
print("f2(" + marker + ")");
}
static Bowl bowl2 = new Bowl(2);
}
class Cupboard{
Bowl bowl3 = new Bowl(3);
static Bowl bowl4 = new Bowl(4);
Cupboard(){
print("Cupboard()");
bowl4.f1(2);
}
void f3(int marker){
print("f3("+ marker +")");
}
static Bowl bowl5 = new Bowl(
复制代码
7.3 显示的静态初始化
静态初始化动作只进行一次。
7.4 非静态示例初始化
{}的语句会在对象初始化之前执行。
8 数组初始化
所有数组都有一个固定成员,可以通过它获取数组内包含了多少个元素,这个成员时length。
数组初始化方式:
Type[] list = new Type[5];
8.1 可变参数列表
可变参数列表本质上就是Object 数组。
9 枚举类型
枚举类型为常量,定义时应该用大写,enum是为了编译器有更好的优化,实际上还是java类,有默认的toString()方法,输出变量名,ordinal()方法,用于枚举定位。
10 总结
初始化和资源回收是面向对象的语言很重要的特性,还需要深入研究,垃圾回收机制虽然占用一部分资源,但慢慢地java的性能提升后也可以慢慢接受。