1. 引入
當我們編寫一個類時,其實就是在描述其對象的屬性和行為,而并沒有產生實質上的對象, 只有通過new關鍵字才會產生出對象,這時系統才會分配內存空間給對象,其方法才可以供外部調用。我們有時候希望無論是否產生了對象或無論產生了多少對象的情況下,某些特定的數據在內存空間里只有一份。
例如所有的中國人都有個國家名稱,每一個中國人都共享這個國家名稱,不必在每一個中國人的實例對象中都單獨分配一個用于代表國家名稱的變量。
2. 理解
static
:靜態的
3. 使用
3.1 使用范圍
在Java類中,可用static
修飾屬性、方法、代碼塊、內部類
3.2 static修飾屬性
3.2.1 設計思想
類屬性作為該類各個對象之間共享的變量。在設計類時,分析哪些屬性不因對象的不同而改變,將這些屬性設置為類屬性。相應的方法設置為類方法。
3.2.2 分類
屬性,按是否使用static
修飾,又分為:
靜態屬性(靜態變量或類變量)vs 非靜態屬性(實例變量)
實例變量:我們創建了類的多個對象,每個對象都獨立的擁有一套類中的非靜態屬性。當修改其中一個對象中的非靜態屬性時,不會導致其他對象中同樣的屬性值的修改。
靜態變量:我們創建了類的多個對象,多個對象共享同一個靜態變量。當通過某一個對象修改靜態變量時,會導致其他對象調用此靜態變量時,是修改過了的。
3.2.3 注意
靜態變量隨著類的加載而加載。可以通過"類.靜態變量"的方式進行調用。
靜態變量的加載要早于對象的創建。
修飾的成員,被所有對象所共享。
訪問權限允許時,可不創建對象,直接被類調用。
由于類只會加載一次,則靜態變量在內存中也只會存在一份:存在方法區的靜態域中。
無論創建多少個對象,靜態數據都只占用一份存儲區域。
static
關鍵字不能應用于局部變量, 因此它只能作用于域。
① 如果一個域是靜態的基本類型域,且也沒有對它進行初始化,那么它就會獲得基本類型的標準初值。
② 如果它是一個對象引用,那么它的默認初始化值就是null
。
靜態變量與實例變量可修飾的范圍區別:
靜態變量 | 實例變量 | |
---|---|---|
類 | yes | no |
對象 | yes | yes |
3.2.4 舉例
靜態屬性舉例: ① System.out;
② Math.PI;
應用舉例:
應用舉例1:
public class Test1 {
public static void main(String args[]) {
Circle c1 = new Circle(2.0);
Circle c2 = new Circle(3.0);
c1.display();//name:這是一個圓radius:2.0
c2.display();//name:這是一個圓radius:3.0
}
}
class Circle {
private double radius;
public static String name = "這是一個圓";
public static String getName() {
return name;
}
public Circle(double radius) {
this.radius = radius;
}
public double findArea() {
return Math.PI * radius * radius;
}
public void display() {
System.out.println("name:" + name + "radius:" + radius);
}
}
應用舉例2:
class Person {
private int id;
public static int total = 0;
public Person() {
total++;
id = total;
}
public static void main(String args[]){
Person Tom=new Person();
Tom.id=0;
total=100; // 不用創建對象就可以訪問靜態成員
}
}
應用舉例3:
public class StaticDemo {
public static void main(String args[]) {
Person.total = 100; // 不用創建對象就可以訪問靜態成員
//訪問方式:類名.類屬性,類名.類方法
System.out.println(Person.total);
Person c = new Person();
System.out.println(c.total); //101
}
}
3.2.5 類變量內存解析
圖解1:
圖解2:
3.3 static修飾方法
3.3.1 設計思想
如果方法與調用者無關,則這樣的方法通常被聲明為類方法,由 于不需要創建對象就可以調用類方法,從而簡化了方法的調用。
3.3.2 理解
static
修飾方法為靜態方法。
3.3.3 使用
沒有對象的實例時,可以用類名.方法名()
的形式訪問由static
修飾的類方法。
靜態方法與非靜態方法可修飾的范圍區別:
靜態方法 | 非靜態方法 | |
---|---|---|
類 | yes | no |
對象 | yes | yes |
3.3.4 注意
因為不需要實例就可以訪問static
方法,因此static
方法內部不能有this
。(也不能有super
)
static
修飾的方法不能被重寫。
靜態方法中,只能調用靜態的方法或屬性。
非靜態方法中,既可以調用非靜態的方法或屬性,也可以調用靜態的方法或屬性。
3.3.5 舉例
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);//CHINA
//編譯不通過
// 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(){
}
}
4. 注意
關于靜態屬性和靜態方法的使用,可都從生命周期的角度去理解。
開發中,如何確定一個屬性是否要聲明為static
的?
屬性是可以被多個對象所共享的,不會隨著對象的不同而不同的。
類中的常量也常常聲明為static
。
開發中,如何確定一個方法是否要聲明為static
的?
操作靜態屬性的方法,通常設置為static
的。
工具類中的方法,習慣上聲明為static
的。 比如:Math
、Arrays
、Collections
。
5. 單例 (Singleton)設計模式
5.1 概述
設計模式是在大量的實踐中總結和理論化之后優選的代碼結構、編程風格、 以及解決問題的思考方式。設計模免去我們自己再思考和摸索。就像是經典的棋譜,不同的棋局,我們用不同的棋譜。”套路”
所謂類的單例設計模式,就是采取一定的方法保證在整個的軟件系統中,對某個類只能存在一個對象實例,并且該類只提供一個取得其對象實例的方法。 如果我們要讓類在一個虛擬機中只能產生一個對象,我們應該怎么做呢?
① 我們首先必須將類的構造器的訪問權限設置為private
這樣,就不能用new
操作符在類的外部產生類的對象了,但在類內部仍可以產生該類的對象。
② 其次,指向類內部產生的該類對象的變量也必須定義成靜態的
因為在類的外部開始還無法得到類的對象,只能調用該類的某個靜態方法以返回類內部創建的對象, 靜態方法只能訪問類中的靜態成員變量,所以,指向類內部產生的該類對象的變量也必須定義成靜態的。
5.2 優點
由于單例模式只生成一個實例,減少了系統性能開銷,當一個對象的產生需要比較多的資源時,如讀取配置、產生其他依賴對象時,則可以通過在應用啟動時直接產生一個單例對象,然后永久駐留內存的方式來解決。
5.3 單例設計模式-餓漢式
class Singleton {
// 1.私有化構造器
private Singleton() {
}
// 2.內部提供一個當前類的實例
// 4.此實例也必須靜態化
private static Singleton single = new Singleton();
// 3.提供公共的靜態的方法,返回當前類的對象
public static Singleton getInstance() {
return single;
}
}
5.4 單例設計模式-懶漢式
(1)單例設計模式-懶漢式(線程不安全)
class Singleton {
// 1.私有化構造器
private Singleton() {
}
// 2.內部提供一個當前類的實例
// 4.此實例也必須靜態化
private static Singleton single;
// 3.提供公共的靜態的方法,返回當前類的對象
public static Singleton getInstance() {
if(single == null) {
single = new Singleton();
}
return single;
}
}
(2)單例設計模式-懶漢式(線程安全)
public class BankTest {
}
class Bank{
private Bank(){}
private static Bank instance = null;
public static Bank getInstance(){
//方式一:效率稍差
// synchronized (Bank.class) {
// if(instance == null){
//
// instance = new Bank();
// }
// return instance;
// }
//方式二:效率更高
if(instance == null){
synchronized (Bank.class) {
if(instance == null){
instance = new Bank();
}
}
}
return instance;
}
}
5.5 應用場景
網站的計數器,一般也是單例模式實現,否則難以同步。
應用程序的日志應用,一般都使用單例模式實現,這一般是由于共享的日志文件一直處于打開狀態,因為只能有一個實例去操作,否則內容不好追加。
數據庫連接池的設計一般也是采用單例模式,因為數據庫連接是一種數據庫資源。
項目中,讀取配置文件的類,一般也只有一個對象。沒有必要每次使用配置 文件數據,都生成一個對象去讀取。
Application
也是單例的典型應用。
Windows
的Task Manager
(任務管理器)就是很典型的單例模式。
Windows
的RecycleBin
(回收站)也是典型的單例應用。在整個系統運行過程中,回收站一直維護著僅有的一個實例。
到此這篇關于Java超詳細透徹講解static的文章就介紹到這了,更多相關Java static內容請搜索html5模板網以前的文章希望大家以后多多支持html5模板網!