第五章:初始化与清理
一、构造器
作用:
初始化对象时使用,用于初始化
特点:
1、构造函数无返回值(不是返回void);构造名和类名一致(不遵循驼峰命名规定,首字母大写);
2、每个类不写构造器时,都有默认的无参构造;如果类中含有其他有参构造或无参构造将不会自动添加无参构造(编译时添加)
3、构造调用是编译器的责任
4、new返回的是对象的引用,构造器本身是没有返回值的
public class SimpleConstructor {
private static String str; //静态方法只能调用静态变量;成员变量自动初始化,局部变量需自定义初始化
public static void main(String[] args) {
for(int i = 0; i < 10; i++) {
new Rock();
new Rock(i);
}
System.out.println(str);
}
} /* Output:
Rock Rock 0 Rock Rock 1 Rock Rock 2 Rock Rock 3 Rock Rock 4 Rock Rock 5 Rock Rock 6 Rock Rock 7 Rock Rock 8 Rock Rock 9 null
*///:~
class Rock {
Rock() {
// 无参构造,名字和类名一致,无返回值
System.out.print("Rock ");
}
Rock(int i) {
//有参构造
System.out.print("Rock " + i + " ");
}
}
二、 方法重载
作用:
有很多作用方法的作用很相近但是具体功能却有些差异,在 java 中已重载方式体现。
特点:
1、方法名一样、参数不一致(包括数据类型、参数顺序、参数数量),不使用返回值区分重载
2、方法重载不建议使用参数顺序不一致的用法
3、比较特殊的重载(构造器)
//: initialization/OverloadingOrder.java
// Overloading based on the order of the arguments.
import static net.mindview.util.Print.*;
public class OverloadingOrder {
static void f(String s) {
print("String: " + s );
}
static void f(String s, int i) {
print("String: " + s + ", int: " + i);
}
static void f(int i, String s) {
print("int: " + i + ", String: " + s);
}
public static void uperr(long l){
System.out.println(l);
}
public static void main(String[] args) {
f("String first");
f("String first", 11);
f(99, "Int first");
uperr(5); //进行类型提升
}
} /* Output:
String: String first
String: String first, int: 11
int: 99, String: Int first
5
*///:~
public class OverloadingVarargs {
static void f(Character... args) {
System.out.print("first");
for(Character c : args)
System.out.print(" " + c);
System.out.println();
}
static void f(Integer... args) {
//重载方法,自动包装机制将int提升为Integer,来匹配类型
System.out.print("second");
for(Integer i : args)
System.out.print(" " + i);
System.out.println();
}
static void f(Long... args) {
System.out.println("third");
}
public static void main(String[] args) {
f('a', 'b', 'c');
f(1);
f(2, 1);
f(0);
f(0L);
//! f(); // Won't compile -- ambiguous
}
} /* Output:
first a b c
second 1
second 2 1
second 0
third
*///:~
类型提升:boolean、byte(1个字节)、char(2)、short(2)、int(4)、long(8)、 float(4)、double(8)
byte ==> shrot ==> int == > long ==> float ==> double
char ==> int == > long ==> float ==> double
三、this关键字
作用:
表示当前操作的对象(和对象使用一致);用来明确操作那个引用的成员。
作用范围:
1、只能在方法内使用
2、在不使用static关键字修饰的方法,方法内调用方法(被调用的方法前有个隐士的this关键字,是编译器自动添加的)
3、this关键字在一个非静态方法内不能出现多个this,而且必须放在方法第一行,初始化必须先进行
4、普通方法不能调用构造器
public class Flower {
int petalCount = 0;
String s = "initial value";
Flower(int petals) {
petalCount = petals;
print("Constructor w/ int arg only, petalCount= "
+ petalCount);
}
Flower(String ss) {
print("Constructor w/ String arg only, s = " + ss);
s = ss;
}
Flower(String s, int petals) {
this(petals);
//! this(s); // 一个非静态方法内不能出现多个this,初始化必须先进行
this.s = s; // Another use of "this" 怕产生歧义所有使用this(区别是成员变量)
print("String & int args");
}
Flower() {
this("hi", 47);
print("default constructor (no args)");
}
void printPetalCount() {
//! this(11); // Not inside non-constructor! 普通方法不能调用构造器
print("petalCount = " + petalCount + " s = "+ s);
}
public static void main(String[] args) {
Flower x = new Flower();
x.printPetalCount();
}
} /* Output:
Constructor w/ int arg only, petalCount= 47
String & int args
default constructor (no args)
petalCount = 47 s = hi
*///:~
四、static关键字(静态)
作用位置:
修饰成员(包括成员变量 和 成员函数 以及成员类 static域)
特点及作用:
1、修饰成员表示全局变量,随着类的初始化而初始化,使用类名调用(也可以使用对象调用,建议使用类名调用)
2、使用static修饰的方法是不能使用this,但是反过来就可以。
3、静态数据只占一份存储区域
五、垃圾清理
1、垃圾对象可能不被回收(不是new创建的、对象互相引用)
2、垃圾回收并不等于析构(销毁的意识)
3、垃圾回收只跟内存有关
4、jvm只有在面临内存耗尽的时候,才会调用垃圾回收机制,因为垃圾回收也要耗内存。
5、java在创建对象时,编译器找到对应的class文件,加载到内存,采用的是必要的代码即时编译,不执行的代码不会编译
垃圾工作原理:
①某些java虚拟机中,对象的分配在推中理论是连续的,像传送带;实际这种方式会造成内存频繁调度(可能是两倍空间),也影响性能
②通过垃圾回收将对象排列更紧凑(一边回收空间,一边堆指针移动到传送带开始处,通过重新排列),这样就可以更高速、无限分配的堆空间模型
垃圾工作机制:
引用计数:对象如果被引用就+1操作,失去引用-1操作,当该对象的引用数量为null时,将被释放空间(简单、慢、存在缺陷相互引用的情况)
复制式回收:将获得对象复制到新堆中,然后引用修正(需要多一倍的空间,而且暂停程序)
标记—清扫:从堆栈和静态存储区中遍历所有引用,存活的标记,标记完成才开始清理。(剩下的空间不连续)
停止—复制:暂停程序,复制存活对象到新堆(产生大量碎片时使用)
六、构造器初始化
初始化顺序:
类中成员变量定义的先后顺序进行初始化
构造器初始化
// When the constructor is called to create a
// Window object, you'll see a message:
class Window {
Window(int marker) {
print("Window(" + marker + ")"); }
}
class House {
Window w1 = new Window(1); // 构造器之前
House() {
// Show that we're in the constructor: 构造内
print("House()");
w3 = new Window(33); // Reinitialize w3
}
Window w2 = new Window(2); // After constructor 构造后
void f() {
print("f()"); }
Window w3 = new Window(3); // At end 最后
}
public class OrderOfInitialization {
public static void main(String[] args) {
House h = new House();
h.f(); // Shows that construction is done
}
} /* Output:
Window(1)
Window(2)
Window(3)
House()
Window(33)
f()
*///:~
静态初始化顺序:
class Bowl {
Bowl(int marker) {
// 4,6,11,13,15,21,27
print("Bowl(" + marker + ")");
}
void f1(int marker) {
print("f1(" + marker + ")");
}
}
class Table {
static Bowl bowl1 = new Bowl(1); // 3
Table() {
print("Table()"); // 7
bowl2.f1(1); // 8
}
void f2(int marker) {
print("f2(" + marker + ")");
}
static Bowl bowl2 = new Bowl(2); // 5
}
class Cupboard {
Bowl bowl3 = new Bowl(3); // 14,20,26
static Bowl bowl4 = new Bowl(4); //10
Cupboard() {
print("Cupboard()"); //16,22,28
bowl4.f1(2);//17,23,29
}
void f3(int marker) {
print("f3(" + marker + ")");
}
static Bowl bowl5 = new Bowl(5); //12
}
public class StaticInitialization {
public static void main(String[] args) {
// 1
print("Creating new Cupboard() in main");//18
new Cupboard();//19
print("Creating new Cupboard() in main");//24
new Cupboard();//25
table.f2(1);//30
cupboard.f3(1);//31
}
static Table table = new Table(); //2
static Cupboard cupboard = new Cupboard();// 9
} /* Output:
Bowl(1)
Bowl(2)
Table()
f1(1)
Bowl(4)
Bowl(5)
Bowl(3)
Cupboard()
f1(2)
Creating new Cupboard() in main
Bowl(3)
Cupboard()
f1(2)
Creating new Cupboard() in main
Bowl(3)
Cupboard()
f1(2)
f2(1)
f3(1)
*///:~
对象创建过程
①在允许main方法之前,本类中的静态变量默认初始化(基本类型为0,引用类型为null,boolean为false)、然后显示初始化定义值(顺序至上而下)
②如果静态成员变量是创建对象,将加载该类的class文件到内存,创建字节码对象,静态变量初始化、静态代码块初始化(静态初始化只在class字节码对象首次加载时执行一次,以后不会执行)
③new 对象,在堆中分配足够的内存
⑤非静态成员变量初始化
⑥代码块,多次创建对象多次调用
⑦构造初始化,构造器起始也是静态方法
七、数组初始化
作用:
数组存储相同类型的数据(基本数据类型和引用类型)
定义和创建方式:
int[] a = new int[]{
1,2,3};
int[] b = {
1,2,3};
int[] c = new int[3];
特点及功能:
1、基本类型初始化为0,布尔初始false;引用类型初始为null
2、Arrays的asList、toString方法很好用
public class ArraysOfPrimitives {
public static void main(String[] args) {
int[] a1 = {
1, 2, 3, 4, 5 };
int[] a2;
a2 = a1;
for(int i = 0; i < a2.length; i++)
a2[i] = a2[i] + 1;
for(int i = 0; i < a1.length; i++)
print("a1[" + i + "] = " + a1[i]);
}
} /* Output:
a1[0] = 2
a1[1] = 3
a1[2] = 4
a1[3] = 5
a1[4] = 6
*///:~
八、枚举类型
用来限制常量的范围
public class Test{
public enum Speciful{
A,B,C,C_IN //定义时大写,多个单词下划线分割
}
public static void main(String[] args) {
for (Speciful s : Speciful.values()) {
//遍历枚举类
System.out.println(s + ", ordinal " + s.ordinal()); //常量申明的顺序
}
}
} /*
A, ordinal 0
B, ordinal 1
C_IN, ordinal 2 *///:~