第五章 初始化与清理
方法重载:相同方法名称 + 不同参数列表
构造器重载 成员函数重载
为什么方法签名不包含 方法返回值?
void f() {} 与 int f(){ return 1; } 编译器很容易区分。
但是在调用 有返回值的f()方法时,如下都行。 第二行的调用编译器就无法确分这两个方法了
int aInt = f(); f();
- 涉及基本类型的重载
代码
// boolean can't be automatically converted static void prt(String s) { System.out.println(s); } void f1(char x) { prt("f1(char)"); } void f1(byte x) { prt("f1(byte)"); } void f1(short x) { prt("f1(short)"); } void f1(int x) { prt("f1(int)"); } void f1(long x) { prt("f1(long)"); } void f1(float x) { prt("f1(float)"); } void f1(double x) { prt("f1(double)"); } void f2(byte x) { prt("f2(byte)"); } void f2(short x) { prt("f2(short)"); } void f2(int x) { prt("f2(int)"); } void f2(long x) { prt("f2(long)"); } void f2(float x) { prt("f2(float)"); } void f2(double x) { prt("f2(double)"); } void f3(short x) { prt("f3(short)"); } void f3(int x) { prt("f3(int)"); } void f3(long x) { prt("f3(long)"); } void f3(float x) { prt("f3(float)"); } void f3(double x) { prt("f3(double)"); } void f4(int x) { prt("f4(int)"); } void f4(long x) { prt("f4(long)"); } void f4(float x) { prt("f4(float)"); } void f4(double x) { prt("f4(double)"); } void f5(long x) { prt("f5(long)"); } void f5(float x) { prt("f5(float)"); } void f5(double x) { prt("f5(double)"); } void f6(float x) { prt("f6(float)"); } void f6(double x) { prt("f6(double)"); } void f7(double x) { prt("f7(double)"); }
入参 - 整型常量时,如f5,f6,f7 int型会自动向上转型(没有精度丢失)
void testConstVal() { prt("Testing with 5"); f1(5);f2(5);f3(5);f4(5);f5(5);f6(5);f7(5); } //Output f1(int) f2(int) f3(int) f4(int) f5(long) f6(float) f7(double)
入参 - char型时,先被转换成int 然后同int型入参结果
void testChar() { char x = 'x'; prt("char argument:"); f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x); } //Output f1(char) f2(int) f3(int) f4(int) f5(long) f6(float) f7(double)
入参 - byte型时,自动向上转型
void testByte() { byte x = 0; prt("byte argument:"); f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x); } //Output f1(byte) f2(byte) f3(short) f4(int) f5(long) f6(float) f7(double)
入参 - short型时,自动向上转型
void testShort() { short x = 0; prt("short argument:"); f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x); } //Output f1(short) f2(short) f3(short) f4(int) f5(long) f6(float) f7(double)
如果入参类型表数范围 > 方法入参类型 编译报错
默认构造器 = 空参构造器
- 当class中构造器为0个时,系统默认提供空参构造
- 当class中构造器 != 0个时,系统不提供空参构造
this关键字 = 调用方法的那个对象(一个对象的引用)
在方法内部调用同一个class的other 方法不必用this(不要滥用this)
用途1 ex:
class Person { public void eat() { Apple peeled = apple.getPeeled(); System.out.println("Yummy); } } class Peeler { Static Apple peel(Apple apple) { // 剥皮... retrun apple; //削好皮的苹果 } } class Apple { Apple getPeeled() { retrun Peeler.peel(this); } } public class PassingThis { public static void main(String[] args) { new Person().eat(new Apple()); } }
用途2 this() 指代 构造器
public class Flower { private int petalCount = 0; private String s = new String("null"); Flower(int petals) { petalCount = petals; System.out.println("Constructor w/ int arg only, petalCount= " + petalCount); } Flower(String ss) { System.out.println( "Constructor w/ String arg only, s=" + ss); s = ss; } Flower(String s, int petals) { this(petals); //! this(s); // Can't call two! this.s = s; // Another use of "this" System.out.println("String & int args"); } Flower() { this("hi", 47); System.out.println( "default constructor (no args)"); } void print() { //! this(11); // Not inside non-constructor! System.out.println( "petalCount = " + petalCount + " s = "+ s); } public static void main(String[] args) { Flower x = new Flower(); x.print(); } }
static
- static 方法内部没this关键字
- 不创建任何class的实例,能够用 className调用static的filed 和 method
java中的finalize()方法 与 C++中的析构函数不同
- 对象可能不被垃圾回收
- 垃圾回收 != 析构
- 垃圾回收只与内存有关
- 本地方法 支持C和C++ 在内存中可能会存下 与java创建对象方式不同的内存区域
- 肤浅的认为,垃圾回收机制存在 导致 java 没有析构函数
- 垃圾回收 和 finalize() 都不保证一定发生,JVM没有面临内存耗尽的情形,不一定会浪费时间和资源去执行垃圾回收
- 暂时不看
感受垃圾回收器如何工作
- 引用计数 - 为每个对象统计被引用的次数,次数为0 置为null, 不停遍历所有对象,删除。(弊端:两个对象相互引用,数量都=1 但是都需要被删除)
- 另一种思路,对于任何“活”对象,一定能最终追溯到其存活在heap 或者 静态存储区之中的引用。从 heap 和 静态存储区开始,遍历所有引用,找到“活”的对象。
成员初始化
Data type Inital value boolean false char '' (value = 0) byte 0 short 0 int 0 long 0 float 0.0 double 0.0 引用类型 初始值 为 null
构造器初始化
无法阻止自动初始化的进行,它将在构造器被调用之前发生
class Flower { int i; Flower() { System.out.println(i); i = 7; } public static void main(String[] args) { Flower flower = new Flower(); System.out.println(flower.i); } } //Output 0 7
类内部 变量定义的先后顺序决定了 初始化的顺续
- 先初始化成员变量 然后执行构造器
static不能作用于局部变量
static域是基本类型 有默认标准初值 如果是 引用类型 则 null
静态资源只有class的第一个对象被创建or这个静态域第一次被引用时才会被创建
- 其实在类加载器加载这个类时就初始化了静态对象
类初始化顺序
1. 初始化静态对象(若其从未被创建) 2. 执行static 代码块 3. 然后非静态 - 开辟空间给所有成员赋默认值,然后赋值类定义时的给值 4. 执行构造代码块 5. 执行构造器
数组初始化 类型相同,统一标识访问,序列
定义
int [] arr; int arr[];
初始化
int[] arr = {1,2,3,4};
标识符拿到的是数组的引用,每次访问数组,java都要做边界检查
数组初始化时,会给变量 赋予。对于数值,空值就是零;对于 char,它是null;而对于boolean,它却是 false
利用数组 - 不定参数列表
public class VarArgs { static void f(Object[] x) { for (int i = 0; i < x.length; i++) System.out.println(x[i]); } //JDK5 加入可变参数列表 static void ff(int count, Object... args) { for (Object arg : args) { System.out.println(arg); } } static void ff(int abc, Object... args) { for (Object arg : args) { System.out.println(arg); } } public static void main(String[] args) { f(new Object[]{ new Integer(47), new VarArgs(), new Float(3.14), new Double(11.11)}); f(new Object[]{"one", "two", "three"}); f(new Object[]{new AA(), new AA(), new AA()}); //调用方式 ff(new Object[]{new AA(), new AA(), new AA()}); ff(new AA(), new AA(), new AA()); ff(); ff(10); } } class AA { int i; }
数组的getClass() 可以看出 可变参数列表实际使用的是基本类型 不是包装类
int[] arr = new int[10]; char[] arr1 = new char[10]; byte[] arr2 = new byte[10]; boolean[] arr3 = new boolean[10]; String[] arr4 = new String[10]; short[] arr5 = new short[10]; Short[] arr6 = new Short[10]; Boolean[] arr7 = new Boolean[10]; System.out.println(arr.getClass()); System.out.println(arr1.getClass()); System.out.println(arr2.getClass()); System.out.println(arr3.getClass()); System.out.println(arr4.getClass()); System.out.println(arr5.getClass()); System.out.println(arr6.getClass()); System.out.println(arr7.getClass()); Integer[] arr8 = {new Integer(10), 10}; //Output class [I class [C class [B class [Z class [Ljava.lang.String; class [S class [Ljava.lang.Short; class [Ljava.lang.Boolean; class java.lang.Integer class java.lang.Integer
Enum关键字 Java1.5 可以在switch语句中使用
语法
enum Spiciness { NOT, MILD, MEDIUM, HOT, FLAMING; public static void main(String[] args) { System.out.println(Spiciness.FLAMING); System.out.println(Spiciness.FLAMING.getClass()); System.out.println(Spiciness.valueOf("MEDIUM")); System.out.println(Spiciness.FLAMING.ordinal()); } } //Output FLAMING class Spiciness MEDIUM 4
由上可以看出,创建类时,编译器提供了toString()方法。还有ordinal()方法,static values()方法
看似新数据类型,生产这个类时,会发生一些编译器的行为。事实上,enum确实是类