初始化与清理
当我们说要初始化一个java对象时通常指的是成员变量初始化和构造器(类构造函数)初始化
1.成员变量初始化
- 基本类型初始化
- 引用对象初始化
2.构造器初始化
构造器是访问一个java对象的入口,如果类中没有构造器,则编译器会帮你自动创建一个无参构造器(java文档中称为无参构造器,但程序员更习惯叫默认构造器,这个称呼在java语言出来之前就已经有了)。
知识关注点:
一、成员变量初始值问题
public class InitialValues {
boolean t;
char c;
byte b;
short s;
int i;
long l;
float f;
double d;
InitialValues reference;
void printInitialValues() {
System.out.println("Data type Initial value");
System.out.println("boolean " + t);
System.out.println("char [" + c + "]");
System.out.println("byte " + b);
System.out.println("short " + s);
System.out.println("int " + i);
System.out.println("long " + l);
System.out.println("float " + f);
System.out.println("double " + d);
System.out.println("reference " + reference);
}
public static void main(String[] args) {
InitialValues iv = new InitialValues();
iv.printInitialValues();
}
}/* Output:
Data type Initial value
boolean false
char [ ]
byte 0
short 0
int 0
long 0
float 0.0
double 0.0
reference null
*///:~
结论:从例子中可以看出, 类的每个成员变量虽然没有指定初始值,但他们确实有初值(char值为0,所以显示空白,Unicode码用0表示空字符);引用对象不指定初始值话,被赋予了一个特殊的值null。
对于
方法局部变量(包括构造函数里面定义的变量),使用前必须指定初始值,如果未指定的话,编译器将报错,像下面的代码
void f() {
int value;
value++; //编译器直接报错, The local variable value may not have been initialized
}
二、初始化顺序(代码执行顺序)
class Window {
Window(int marker) {
System.out.println("Window("+marker+")");
}
}
class House {
int value1;
static int value2;
int value3 = 2;
static int value4;
{
System.out.println("初始化非静态成员变量:value1 = " + value1 + ", value3 = " + value3);
}
static {
value4 = 1;
System.out.println("初始化静态成员变量:value2 = " + value2 + ", value4 = " + value4);
}
Window w1 = new Window(1);
House() {
System.out.println("House()");
w3 = new Window(33);
}
Window w2 = new Window(2);
void f() {
System.out.println("f()");
}
Window w3 = new Window(3);
}
public class OrderOfInitialization {
public static void main(String[] args) {
House h = new House();
h.f();
}
}/* Output:
初始化静态成员变量:value2 = 0, value4 = 1
初始化非静态成员变量:value1 = 0, value3 = 2
Window(1)
Window(2)
Window(3)
House()
Window(33)
f()
*///:~
new一个类对象时,数据块初始化顺序如下图所示,需要注意的是 静态域只初始化一次(static属于类级别的,该类产生的所有对象共享),随着第一个对象的产生而触发;而 非静态域属于对象级别的,所有每次创建新对象时都会触发一次。 注:如果引入类继承关系,执行顺序会发生变化,不过我们暂时不考虑,在以后的章节中再继续讨论它。
三、方法重载
说方法重载前,我们首先需要区分重载方法,典型案例
void f() {}
int f() { return 1; }
很多人误认为上面的方法是不同的方法,因为它俩看上去确实不太一样,但是编译器却不会让你这样干,为什么呢?
假如使用者这样使用 int value = f(),我们确实可以明确的知道他想调用哪个方法,但是假如他不关心返回值,还想使用第二个方法的逻辑呢,代码是不是就成了这样f(),所以这样编译器就无法区分你想调用哪个方法了。
所以区分方法唯一的途径就是首先看看方法的名字,然后是方法的参数类型,参数类型一样,但是所处的位置不一样的话,编译器也视为不同的方法。例如:
void f(int i, String s) {
System.out.println("int: " + i + ", String: " + s);
}
void f(String s, int i) {
System.out.println("String: " + s + ", int: " + i);
}
涉及基本类型重载的问题(基本类型向上转型问题)
import static com.thinking.java.support.Print.*;
public class PrimitiveOverloading {
void f1(char x) { printnb("f1(char)"); }
void f1(byte x) { printnb("f1(byte)"); }
void f1(short x) { printnb("f1(short)"); }
void f1(int x) { printnb("f1(int)"); }
void f1(long x) { printnb("f1(long)"); }
void f1(float x) { printnb("f1(float)"); }
void f1(double x) { printnb("f1(double)"); }
void f2(byte x) { printnb("f2(byte)"); }
void f2(short x) { printnb("f2(short)"); }
void f2(int x) { printnb("f2(int)"); }
void f2(long x) { printnb("f2(long)"); }
void f2(float x) { printnb("f2(float)"); }
void f2(double x) { printnb("f2(double)"); }
void f3(short x) { printnb("f3(short)"); }
void f3(int x) { printnb("f3(int)"); }
void f3(long x) { printnb("f3(long)"); }
void f3(float x) { printnb("f3(float)"); }
void f3(double x) { printnb("f3(double)"); }
void f4(int x) { printnb("f4(int)"); }
void f4(long x) { printnb("f4(long)"); }
void f4(float x) { printnb("f4(float)"); }
void f4(double x) { printnb("f4(double)"); }
void f5(long x) { printnb("f5(long)"); }
void f5(float x) { printnb("f5(float)"); }
void f5(double x) { printnb("f5(double)"); }
void f6(float x) { printnb("f6(float)"); }
void f6(double x) { printnb("f6(double)"); }
void f7(double x) { printnb("f7(double)"); }
void testConstVal() {
printnb("5: ");
f1(5);f2(5);f3(5);f4(5);f5(5);f6(5);f7(5);print();
}
void testChar() {
char x = 'x';
printnb("char: ");
f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);print();
}
void testByte() {
byte x = 0;
printnb("byte: ");
f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);print();
}
void testShort() {
short x = 0;
printnb("short: ");
f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);print();
}
void testInt() {
int x = 0;
printnb("int: ");
f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);print();
}
void testLong() {
long x = 0;
printnb("long: ");
f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);print();
}
void testFloat() {
float x = 0;
printnb("float: ");
f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);print();
}
void testDouble() {
double x = 0;
printnb("double: ");
f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);print();
}
public static void main(String[] args) {
PrimitiveOverloading p = new PrimitiveOverloading();
p.testConstVal();
p.testChar();
p.testByte();
p.testShort();
p.testInt();
p.testLong();
p.testFloat();
p.testDouble();
}
}/* Output:
5: f1(int)f2(int)f3(int)f4(int)f5(long)f6(float)f7(double)
char: f1(char)f2(int)f3(int)f4(int)f5(long)f6(float)f7(double)
byte: f1(byte)f2(byte)f3(short)f4(int)f5(long)f6(float)f7(double)
short: f1(short)f2(short)f3(short)f4(int)f5(long)f6(float)f7(double)
int: f1(int)f2(int)f3(int)f4(int)f5(long)f6(float)f7(double)
long: f1(long)f2(long)f3(long)f4(long)f5(long)f6(float)f7(double)
float: f1(float)f2(float)f3(float)f4(float)f5(float)f6(float)f7(double)
double: f1(double)f2(double)f3(double)f4(double)f5(double)f6(double)f7(double)
*///:~