Java學習筆記八(static、final、代碼塊等)

static關鍵字的使用:

static:靜態的
static可以用來修飾屬性、方法、代碼塊、內部類;
使用static修飾屬性:靜態變量(類變量)
按是否使用static修飾,屬性又可以分爲靜態屬性和非靜態屬性(實例變量)。
實例變量:如果創建類的多個對象,每個對象都獨立的擁有一套類中的非靜態屬性,通過改變其中一個對象的屬性,並不會影響到其他對象的同一屬性值。
靜態變量:如果創建類的多個對象,多個對象共享一個靜態變量;當我們通過其中一個對象改變其中的屬性值時,會導致其他對象調用的此靜態變量也是修改過的。

幾點說明
1、靜態變量隨着類的加載而加載,可以通過“類。屬性”的方式進行調用;
2、靜態變量的加載要早於對象的創建;
3、由於類只會加載一次,因此靜態變量在內存中也只存在一份:存在於方法去的靜態域中;
4、

              類變量                  實例變量
      類       yes                      no	
     對象	   yes		               yes

上面標示類和對象出現時類變量和實例變量的情況。
5、靜態變量舉例:System.out;Math.PI;

使用static修飾方法:(靜態方法)
1、隨着類的加載而加載,可以通過“類。靜態方法”
2

              靜態方法               非靜態方法
      類       yes                      no	
     對象	   yes		               yes

3、靜態方法中只能調用靜態的屬性和方法;非靜態方法中可以調用靜態和非靜態的屬性和方法。

static的幾個注意點
1、static修飾的方法中不能使用this和super關鍵字。
2、關於靜態的屬性和方法,我們可以從生命週期的角度去考慮

如何確定一個屬性是否需要使用static:
1、屬性可以被多個對象共享,不會因爲對象的不同而改變;
2、屬性中的常量也常常聲明爲static的;
如何確定一個方法是否需要使用static:
1、操作靜態屬性的方法,通常聲明爲static的;
2、一些工具類中的方法也通常聲明爲static的;比如Arrays、Math、Collections等。

public class StaticTest {
	public static void main(String[] args) {
		
		Chinese.nation = "中國";
		
		
		Chinese c1 = new Chinese();
		c1.name = "姚明";
		c1.age = 40;
		c1.nation = "CHN";
		
		Chinese c2 = new Chinese();
		c2.name = "馬龍";
		c2.age = 30;
		c2.nation = "CHINA";
		
		System.out.println(c1.nation);
		
		//編譯不通過
//		Chinese.name = "張繼科";
		
		
		c1.eat();
		
		Chinese.show();
		//編譯不通過
//		Chinese.eat();
//		Chinese.info();
	}
}
//中國人
class Chinese{
	
	String name;
	int age;
	static String nation;
	
	
	public void eat(){
		System.out.println("中國人喫中餐");
		//調用非靜態結構
		this.info();
		System.out.println("name :" +name);
		//調用靜態結構
		walk();
		System.out.println("nation : " + nation);
	}
	
	public static void show(){
		System.out.println("我是一箇中國人!");
		//不能調用非靜態的結構
//		eat();
//		name = "Tom";
		//可以調用靜態的結構
		System.out.println(Chinese.nation);
		walk();
	}
	
	public void info(){
		System.out.println("name :" + name +",age : " + age);
	}
	
	public static void walk(){
		
	}
}

數組也作爲Object類的子類出現,可以調用Object類中聲明的方法

public void test1(){
		int[] arr = new int[]{1,2,3};
		print(arr);
		
		System.out.println(arr.getClass().getSuperclass());
		
	}

main()的使用說明:

1、main()方法作爲程序的入口;
2、main()方法也是一個普通的靜態方法;
3、main()方法可以作爲我們與控制檯的交互方式;(之前使用的是Scanner)

public class MainTest {
	
	
	public static void main(String[] args) {//入口
		
		Main.main(new String[100]);
		
		MainTest test = new MainTest();
		test.show();
		
	}	
	public void show(){
		
	}
}


class Main{
		
	public static void main(String[] args) {
	
		for(int i = 0;i < args.length;i++){
			args[i] = "args_" + i;
			System.out.println(args[i]);
		}
		
	}
	
}

單例設計模式:

所謂類的單例設計模式,就是採取一定的辦法保證在整個軟件系統中,某個類只能存在一個對象實例。
單例模式有餓漢式和懶漢式兩種形式;
區分餓漢式和懶漢式:
餓漢式:

  • 壞處:對象加載時間過長;
  • 好處:餓漢式是線程安全的;

懶漢式:

  • 好處:對象是延遲創建的;
  • 壞處:目前的寫法,線程不安全;(多線程處在進行修改)
public class SingletonTest1 {
	public static void main(String[] args) {
//		Bank bank1 = new Bank();
//		Bank bank2 = new Bank();
		
		Bank bank1 = Bank.getInstance();
		Bank bank2 = Bank.getInstance();
		
		System.out.println(bank1 == bank2);
	}
}

//餓漢式
class Bank{
	
//1.私有化類的構造器
	private Bank(){
		
	}
	
//2.內部創建類的對象
	//4.要求此對象也必須聲明爲靜態的
	private static Bank instance = new Bank();
	
//3.提供公共的靜態的方法,返回類的對象
	public static Bank getInstance(){
		return instance;
	}
}
public class SingletonTest2 {
	public static void main(String[] args) {
		
		Order order1 = Order.getInstance();
		Order order2 = Order.getInstance();
		
		System.out.println(order1 == order2);
		
	}
}
class Order{
//1.私有化類的構造器
	private Order() {
		
	}
	//2.聲明當前類對象,沒有初始化
	//4.此對象也必須聲明爲static的
	private static Order instance = null;
	//3.聲明public、static的返回當前類對象的方法
	public static Order getInstance() {
		if(instance == null) {
			instance = new Order();
		}
		return instance;
	}
}

final關鍵字的使用:

final:最終的;
final可以用來修飾: 類,方法、變量(包括屬性和局部變量);

final修飾類則此類不能被其他的類所繼承;比如:String類、System類、StringBuffer類;
final修飾方法:
final修飾方法則此方法不可以被重寫;比如:Object中的getClass();
final修飾變量:
final修飾變量:此時的變量稱之爲常量;

  • final修飾屬性:則此屬性必須進行賦值,可以考慮的賦值方式有:顯示初始化,代碼塊初始化,構造器初始化;
  • final修飾局部變量:尤其是使用final修飾形參時,表明此形參是一個常量;當我們調用此方法時,給常量形參賦一個實參,一旦賦值之後就只能在方法體內使用此形參,不能夠再進行賦值。

static final修飾屬性: 全局常量;

public class FinalTest {
	// 一定要進行賦值,且只能賦值一次
	final int WIDTH = 0;
	final int LEFT;
	final int RIGHT;
//  final int DOWN;
	
	{
		LEFT = 1;
	}
	
	public FinalTest(){
		RIGHT = 2;
	}
	
	public FinalTest(int n){
		RIGHT = n;
	}
	
//	public void setDown(int down){
//		this.DOWN = down;
//	}
	
	
	public void doWidth(){
//		width = 20;
	}
	
	
	public void show(){
		final int NUM = 10;//常量
//		NUM += 20;
	}
	
	public void show(final int num){
//		num = 20;//編譯不通過
		System.out.println(num);
	}
	
	
	public static void main(String[] args) {
		
		int num = 10;
		
		num = num + 5;
		
		FinalTest test = new FinalTest();
//		test.setDown(3);
		
		test.show(10);
	}
}


final class FinalA{
	
}

//class B extends FinalA{
//	
//}

//class C extends String{
//	
//}

class AA{
	public final void show(){
		
	}
}

class BB extends AA{
	
//	public void show(){
//		
//	}
}

類的成員之代碼塊:

代碼塊的作用:用來初始化類、對象;
代碼塊只能使用statuc進行修飾;分爲靜態代碼塊和非靜態代碼塊;
靜態代碼塊
1、靜態代碼塊隨着類的加載而執行,且只能執行一次,內部可以有輸出語句;
2、作用是初始化類的信息;
3、如果一個類中定義了多個靜態代碼塊,則按照先後順序執行,靜態代碼塊的執行要早於非靜態的代碼塊;
4、靜態代碼塊只能夠調用靜態的屬性和方法;

非靜態代碼塊
1、非靜態代碼塊睡着對象的創建而執行,且對象創建一次就執行一次,內部可以有輸出語句;
2、作用是初始化對象的信息(屬性等);
3、如果一個類中定義了多個非靜態代碼塊,則按照先後順序執行;
4、非靜態的代碼塊可以調用非靜態的屬性和方法也可以調用靜態的屬性和方法。

public class BlockTest {
	public static void main(String[] args) {
		
		String desc = Person.desc;
		System.out.println(desc);
		
		Person p1 = new Person();
		Person p2 = new Person();
		System.out.println(p1.age);
		
		Person.info();
	}
}


class Person{
	//屬性
	String name;
	
	int age;

	static String desc = "我是一個人";
	
	//構造器
	public Person(){
		
	}
	public Person(String name,int age){
		this.name = name;
		this.age = age;
	}
	
	//非static的代碼塊
	{
		System.out.println("hello, block - 2");
	}
	{
		System.out.println("hello, block - 1");
		//調用非靜態結構
		age = 1;
		eat();
		//調用靜態結構
		desc = "我是一個愛學習的人1";
		info();
	}
	//static的代碼塊
	static{
		System.out.println("hello,static block-2");
	}
	static{
		System.out.println("hello,static block-1");
		//調用靜態結構
		desc = "我是一個愛學習的人";
		info();
		//不可以調用非靜態結構
//		eat();
//		name = "Tom";
	}
	
	//方法
	public void eat(){
		System.out.println("喫飯");
	}
	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + "]";
	}
	public static void info(){
		System.out.println("我是一個快樂的人!");
	}
	
}

對屬性進行賦值的先後順序:
①默認初始化
②顯示初始化/③代碼塊中初始化
④構造器中初始化
⑤有了對象以後,可以通過"對象.屬性"或"對象.方法"的方式,進行賦值
其中②和③不分先後;

關於靜態代碼塊、非靜態代碼塊以及構造器在子父類中的執行順序:
總結就是:由父及子,靜態先行;(非靜態代碼塊要在對象創建時對對象進行初始化,因此在構造器之前。)
注意:如果main函數中有輸出語句,也要在靜態之後,因爲要先加載完類的信息後纔開始執行程序。

class Root{
	static{
		System.out.println("Root的靜態初始化塊");
	}
	{
		System.out.println("Root的普通初始化塊");
	}
	public Root(){
		super();
		System.out.println("Root的無參數的構造器");
	}
}
class Mid extends Root{
	static{
		System.out.println("Mid的靜態初始化塊");
	}
	{
		System.out.println("Mid的普通初始化塊");
	}
	public Mid(){
		super();
		System.out.println("Mid的無參數的構造器");
	}
	public Mid(String msg){
		//通過this調用同一類中重載的構造器
		this();
		System.out.println("Mid的帶參數構造器,其參數值:"
			+ msg);
	}
}
class Leaf extends Mid{
	static{
		System.out.println("Leaf的靜態初始化塊");
	}
	{
		System.out.println("Leaf的普通初始化塊");
	}	
	public Leaf(){
		//通過super調用父類中有一個字符串參數的構造器
		super("尚硅谷");
		System.out.println("Leaf的構造器");
	}
}
public class LeafTest{
	public static void main(String[] args){
		new Leaf(); 
		System.out.println();
		new Leaf();
	}
}

執行結果:
Root的靜態初始化塊
Mid的靜態初始化塊
Leaf的靜態初始化塊
Root的普通初始化塊
Root的無參數的構造器
Mid的普通初始化塊
Mid的無參數的構造器
Mid的帶參數構造器,其參數值:尚硅谷
Leaf的普通初始化塊
Leaf的構造器

Root的普通初始化塊
Root的無參數的構造器
Mid的普通初始化塊
Mid的無參數的構造器
Mid的帶參數構造器,其參數值:尚硅谷
Leaf的普通初始化塊

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章