Java對象初始化通過構造器,清理通過垃圾收集器(Garbage Collector, GC)
構造器
無參構造函器,有參構造器
如果建立一個類,沒有自定義構造器,編譯器會自動建立一個無參構造器
方法重載
函數名相同,參數個數或者參數類型不同,也可參數順序不同(不推薦)
this關鍵字
this可以表示目前對象的引用,不能用于靜态方法(靜态方法與對象無關)
public class Leaf{
int i = 0;
Leaf increment(){
this.i++;
return this;
}
void print(){
System.out.println("i = "+i);
}
public static void main(String [] args){
Leaf x = new Leaf();
x.increment().increment().increment.print();
}
}
this 關鍵字在向其他方法傳遞目前對象時也很有用:
class Person {
public void eat(Apple apple) {
Apple peeled = apple.getPeeled();
System.out.println("Yummy");
}
}
public class Peeler {
static Apple peel(Apple apple) {
// ... remove peel
return apple; // Peeled
}
}
public class Apple {
Apple getPeeled() {
return Peeler.peel(this);
}
}
public class PassingThis {
public static void main(String[] args) {
new Person().eat(new Apple());
}
}
this 在構造器中如果被傳入一個參數清單,則是通過最直接的方式顯示得調用比對參數清單得構造器
public class Flower {
private int preCount = 0;
String s = "initial value";
Flower(int preCount){
this.preCount = preCount;
System.out.println("Constructor w/ int arg only, preCount = " + preCount);
}
Flower(String s){
System.out.println("Constructor w/ string arg only, s = " + s);
this.s = s;
}
Flower(int preCount, String s){
this(preCount);
this.s = s;
System.out.println("String & int args");
}
Flower(){
this(7,"hi");
System.out.println("no-arg constructor");
}
public void print(){
System.out.println("preCount = " + preCount + " s = " + s);
}
public static void main(String []args){
Flower flower1 = new Flower();
flower1.print();
// Tree tree1 = new Tree(1);
// flower1.print();
// flower1.preCount = 2;
// flower1.print();
}
}
class Tree{
private int height;
Tree(int height){
this.height = height;
}
}
成員變量和參數清單中變量同名,用this.s來表明指代得是成員變量,防止混淆
在構造器中調用構造器
在構造器中可以通過this加參數清單的形式調用其他構造器
在一個構造器内隻可以通過this調用一次其他的構造器
必須首先調用構造器
不能在非構造器的方法中調用構造器
static的含義
不能在靜态方法中調用非靜态方法和this,後兩者與對象有關,靜态方法與對象無關
非靜态方法可以調用靜态方法
靜态方法隻能調用靜态變量
垃圾回收器(Garbage Collector)
垃圾回收器一邊回收記憶體,一邊使堆中的對象緊湊排列
引用計數,每個對象有一個引用計數器,每當有引用指向該對象時,引用計數加1,當引用離開作用域或者置null時,引用計數器減1。當引用計數器為0時,釋放其記憶體空間
如果從棧或靜态存儲區出發,周遊所有的引用,你将會發現所有"活"的對象。對于發現的每個引用,必須追蹤它所引用的對象,然後是該對象包含的所有引用,如此反複進行,直到通路完"根源于棧或靜态存儲區的引用"所形成的整個網絡。
Java虛拟機采用一種自适應的垃圾回收技術,停止-複制(stop-and-copy)和标記-清掃(mark-and-sweep)相結合。
"标記-清掃"所依據的思路仍然是從棧和靜态存儲區出發,周遊所有的引用,找出所有存活的對象。但是,每當找到一個存活對象,就給對象設一個标記,并不回收它。隻有當标記過程完成後,清理動作才開始。在清理過程中,沒有标記的對象将被釋放,不會發生任何複制動作。"标記-清掃"後剩下的堆空間是不連續的,垃圾回收器要是希望得到連續空間的話,就需要重新整理剩下的對象
構造器初始化
自動初始化發生在構造器初始化之前
類中變量定義初始化在構造器之前
靜态的基本類型,如果你沒有初始化它,那麼它就會獲得基本類型的标準值,如果是對象引用,就是null。
加載類->如果類是第一次加載則初始化靜态成員變量->初始化非靜态成員變量
導緻類加載的原因: 1、new 一個類的對象,(構造器其實也是靜态方法) ; 2、調用類的靜态方法和靜态成員變量
建立一個類的對象過程:
1、構造器其實也是靜态方法,加載類,Java解釋器在類路徑中查找,定位java.com.util...class;
2、加載類之後,首先初始化靜态成員變量(如果是第一次加載類);
3、當通過new 方法建立對象,在堆上配置設定記憶體空間;
4、配置設定的存儲空間首先會被清零,對象的基本類型資料設定為預設值,引用設定為null;
5、執行所有出現在字段定義處的初始化動作;
6、執行構造器。
靜态塊和其他靜态初始化動作一樣,僅在第一次類加載時執行
隻有new對象的類加載才會初始化非靜态屬性
數組初始化
靜态數組初始化
int [] a = {1,2,3,4,5};
動态數組初始化
int [] a = new int[5];
int [] intA = new int[5];
System.out.println(intA[0]);
System.out.println(Arrays.toString(intA));
System.out.println("*********");
char [] charA = new char[5];
System.out.println(charA[0]);
System.out.println(Arrays.toString(charA));
System.out.println("*********");
Character [] characterA = new Character[5];
System.out.println(characterA[0]);
System.out.println(Arrays.toString(characterA));
System.out.println("*********");
Integer [] IntegerA = new Integer[5];
System.out.println(IntegerA[0]);
System.out.println(Arrays.toString(IntegerA));
結果:
[0, 0, 0, 0, 0]
*********
[ , , , , ]
*********
null
[null, null, null, null, null]
*********
null
[null, null, null, null, null]
可變參數清單
import java.util.Arrays;
public class OverloadingVarargs2 {
static void f(float i, Character... args) {
System.out.println(i);
System.out.println(Arrays.toString(args));
System.out.println("first");
}
static void f(Character... args) {
System.out.println("second");
}
// 修改為下面函數就不會報錯
// static void f(char c, Character... args) {
// System.out.println("second");
// }
public static void main(String[] args) {
// f(1, 'a');
f('a', 'b');
// System.out.println((float) 'r');
}
}
會報錯
Error:(19, 9) java: 對f的引用不明确
OverloadingVarargs2 中的方法 f(float,java.lang.Character...) 和 OverloadingVarargs2 中的方法 f(java.lang.Character...) 都比對
因為char向上轉換(隐式轉換)到float和裝箱為Character優先級相同,如果改為注釋,char能找到對應的參數類型,就不會産生歧義。
枚舉類型 enum
public enum Course {
ENGLISH, CHINESE, MATH, PHYSICAL,
}
public class EnumTest {
Course takeCourse;
EnumTest(Course takeCourse) {
this.takeCourse = takeCourse;
}
public static void main(String[] args) {
Course course1 = Course.CHINESE;
System.out.println(course1);
for (Course c1 : Course.values())
System.out.println(c1.ordinal());
EnumTest test1 = new EnumTest(Course.CHINESE);
EnumTest test2 = new EnumTest(Course.ENGLISH);
EnumTest test3 = new EnumTest(Course.MATH);
test1.printTakeCourse();
test2.printTakeCourse();
test3.printTakeCourse();
}
private void printTakeCourse() {
switch (this.takeCourse) {
case ENGLISH:
System.out.println("take english");
break;
case CHINESE:
System.out.println("take chinese");
break;
default:
System.out.println("take other courses");
break;
}
}
}
enum類型适用于switch;
values() 方法按照 enum 常量的聲明順序,生成這些常量值構成的數組;
ordinal() 方法表示某個特定 enum 常量的聲明順序。