什麼時候該用類方法(靜態方法)?什麼時候該用實例化方法?

一個新來的同事,寫Java方法時,通篇都是static修飾,原因只是因爲不需要new對象就可直接調用。一個類中抽象出來的方法,用static修飾無可厚非,但是一般而言,抽象出來的公共方法,大多都應該放在util工具類中,而不是直接寫在該類中。static修飾的靜態方法,雖然調用簡單而且也快,但是實際編程中,不建議這麼做。

這並非是因爲靜態方法佔用內存更高,而是因爲我們只有理解其原理,才能更好地應用到實際編程中。比如爲什麼有時候需要用單例模式,而不是靜態方法?比如加載某些配置和屬性,需要在整個生命週期存在,但僅僅只需要維護一份,但此時這些配置和屬性又是通過面向對象的方式得到的,這個時候就要用單例模式,雖然用靜態方法也能解決,但最好的方式還是採用單例模式。

所以,什麼時候用靜態方法呢?

1)工具類中的常用方法,不需要依賴具體實例,而且使用頻率高。

2)不需要對象的“輕”方法,因爲靜態方法是無法直接使用任何非靜態成員的,除非將實例作爲參數傳入。

那麼,什麼時候應該使用實例化方法呢?
方法依賴於類對象的時候,就應該使用實例化方法,因爲在多線程場景下對靜態方法中的靜態變量進行更改操作易造成線程安全問題,這個時候,就一定要用實例化方法。

public class TestStatic {

	static class test {
		//靜態成員變量
		static String a = "H";

		//修改該靜態成員變量
		static void modify(String v) {
			a = v;
		}
	}

	public static void main(String[] args) {
		for (int i = 0; i < 10; i++) {
			new Thread(() -> {
				test.modify(Thread.currentThread().getName());
				System.out.println(Thread.currentThread().getName() + ":" + test.a);
			}).start();
		}
	}

}

爲什麼會出現上述結果呢?

Java內存模型中,堆中存放對象示例、靜態成員變量、數組元素等,這每個對象示例都有一把對應的鎖監視器,而類的靜態成員變量歸類.class所有,所以上述的靜態方法,相當於直接把共享變量a指向了v的引用,在多線程的情況下,如果一個線程修改了一個類的靜態變量,再獲取獲該類的變量時,就有可能獲取到的是被其他線程修改後的變量,所以說這種情況線程不安全。

那麼如何解決這個問題呢?答案就是加鎖。

public class TestStatic {

	static class test {
		// 靜態成員變量
		static String a = "H";

		// 修改該靜態成員變量
		static void modify(String v) {
			a = v;
		}
	}

	public static void main(String[] args) {
		for (int i = 0; i < 10; i++) {
			new Thread(() -> {
				synchronized (test.class) {
					test.modify(Thread.currentThread().getName());
					System.out.println(Thread.currentThread().getName() + ":" + test.a);
				}
			}).start();
		}
	}

}


輸出:
Thread-4:Thread-4
Thread-7:Thread-7
Thread-6:Thread-6
Thread-5:Thread-5
Thread-1:Thread-1
Thread-2:Thread-2
Thread-0:Thread-0
Thread-3:Thread-3
Thread-9:Thread-9
Thread-8:Thread-8

另外一種方法,就是不要用靜態方法,改成實例化方法,比如:

public class TestStatic {

	public static void main(String[] args) {
		test te = new test();
		for (int i = 0; i < 10; i++) {
			new Thread(() -> {
				te.modify(Thread.currentThread().getName());
				System.out.println(Thread.currentThread().getName() + ":" + te.a);

			}).start();
		}
	}

}

class test {
	// 靜態成員變量
	String a = "H";

	public String getA() {
		return a;
	}

	public void setA(String a) {
		this.a = a;
	}

	public test(String a) {
		super();
		this.a = a;
	}

	public test() {

	}

	// 修改變量
	void modify(String v) {
		a = v;
	}
}

 

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