《Java编程思想》学习笔记-第5章

来源:互联网 发布:网络ip冲突是什么意思? 编辑:程序博客网 时间:2024/05/20 23:56

初始化与清理

当我们说要初始化一个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 valueboolean              falsechar                 [ ]byte                  0short                 0int                   0long                  0float                 0.0double                0.0reference             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 = 2Window(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)*///:~ 



如果传入的实际数据类型小于方法中声明的形式参数类型时,实际数据类型将会自动被提升。char类型略有不同,直接被提升至int类型(char的范围是0~65535,byte,short是装不下char类型的);另外一个注意的地方是当一个变量值被指定为整型数字时,默认是int类型,所以上面的5当int值处理,浮点数默认是double类型。


原创粉丝点击