Java超詳細(xì)透徹講解static
1. 引入
當(dāng)我們編寫一個(gè)類時(shí),其實(shí)就是在描述其對象的屬性和行為,而并沒有產(chǎn)生實(shí)質(zhì)上的對象, 只有通過new關(guān)鍵字才會(huì)產(chǎn)生出對象,這時(shí)系統(tǒng)才會(huì)分配內(nèi)存空間給對象,其方法才可以供外部調(diào)用。我們有時(shí)候希望無論是否產(chǎn)生了對象或無論產(chǎn)生了多少對象的情況下,某些特定的數(shù)據(jù)在內(nèi)存空間里只有一份。
例如所有的中國人都有個(gè)國家名稱,每一個(gè)中國人都共享這個(gè)國家名稱,不必在每一個(gè)中國人的實(shí)例對象中都單獨(dú)分配一個(gè)用于代表國家名稱的變量。
2. 理解
static
:靜態(tài)的
3. 使用
3.1 使用范圍
在Java類中,可用static
修飾屬性、方法、代碼塊、內(nèi)部類
3.2 static修飾屬性
3.2.1 設(shè)計(jì)思想
類屬性作為該類各個(gè)對象之間共享的變量。在設(shè)計(jì)類時(shí),分析哪些屬性不因?qū)ο蟮牟煌淖?,將這些屬性設(shè)置為類屬性。相應(yīng)的方法設(shè)置為類方法。
3.2.2 分類
屬性,按是否使用static
修飾,又分為:
靜態(tài)屬性(靜態(tài)變量或類變量)vs 非靜態(tài)屬性(實(shí)例變量)
實(shí)例變量:我們創(chuàng)建了類的多個(gè)對象,每個(gè)對象都獨(dú)立的擁有一套類中的非靜態(tài)屬性。當(dāng)修改其中一個(gè)對象中的非靜態(tài)屬性時(shí),不會(huì)導(dǎo)致其他對象中同樣的屬性值的修改。
靜態(tài)變量:我們創(chuàng)建了類的多個(gè)對象,多個(gè)對象共享同一個(gè)靜態(tài)變量。當(dāng)通過某一個(gè)對象修改靜態(tài)變量時(shí),會(huì)導(dǎo)致其他對象調(diào)用此靜態(tài)變量時(shí),是修改過了的。
3.2.3 注意
靜態(tài)變量隨著類的加載而加載??梢酝ㄟ^"類.靜態(tài)變量"的方式進(jìn)行調(diào)用。
靜態(tài)變量的加載要早于對象的創(chuàng)建。
修飾的成員,被所有對象所共享。
訪問權(quán)限允許時(shí),可不創(chuàng)建對象,直接被類調(diào)用。
由于類只會(huì)加載一次,則靜態(tài)變量在內(nèi)存中也只會(huì)存在一份:存在方法區(qū)的靜態(tài)域中。
無論創(chuàng)建多少個(gè)對象,靜態(tài)數(shù)據(jù)都只占用一份存儲(chǔ)區(qū)域。
static
關(guān)鍵字不能應(yīng)用于局部變量, 因此它只能作用于域。
① 如果一個(gè)域是靜態(tài)的基本類型域,且也沒有對它進(jìn)行初始化,那么它就會(huì)獲得基本類型的標(biāo)準(zhǔn)初值。
② 如果它是一個(gè)對象引用,那么它的默認(rèn)初始化值就是null
。
靜態(tài)變量與實(shí)例變量可修飾的范圍區(qū)別:
靜態(tài)變量 | 實(shí)例變量 | |
---|---|---|
類 | yes | no |
對象 | yes | yes |
3.2.4 舉例
靜態(tài)屬性舉例: ① System.out;
② Math.PI;
應(yīng)用舉例:
應(yīng)用舉例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:這是一個(gè)圓radius:2.0 c2.display();//name:這是一個(gè)圓radius:3.0 } } class Circle { private double radius; public static String name = "這是一個(gè)圓"; 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); } }
應(yīng)用舉例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; // 不用創(chuàng)建對象就可以訪問靜態(tài)成員 } }
應(yīng)用舉例3:
public class StaticDemo { public static void main(String args[]) { Person.total = 100; // 不用創(chuàng)建對象就可以訪問靜態(tài)成員 //訪問方式:類名.類屬性,類名.類方法 System.out.println(Person.total); Person c = new Person(); System.out.println(c.total); //101 } }
3.2.5 類變量內(nèi)存解析
圖解1:
圖解2:
3.3 static修飾方法
3.3.1 設(shè)計(jì)思想
如果方法與調(diào)用者無關(guān),則這樣的方法通常被聲明為類方法,由 于不需要?jiǎng)?chuàng)建對象就可以調(diào)用類方法,從而簡化了方法的調(diào)用。
3.3.2 理解
static
修飾方法為靜態(tài)方法。
3.3.3 使用
沒有對象的實(shí)例時(shí),可以用類名.方法名()
的形式訪問由static
修飾的類方法。
靜態(tài)方法與非靜態(tài)方法可修飾的范圍區(qū)別:
靜態(tài)方法 | 非靜態(tài)方法 | |
---|---|---|
類 | yes | no |
對象 | yes | yes |
3.3.4 注意
因?yàn)椴恍枰獙?shí)例就可以訪問static
方法,因此static
方法內(nèi)部不能有this
。(也不能有super
)
static
修飾的方法不能被重寫。
靜態(tài)方法中,只能調(diào)用靜態(tài)的方法或?qū)傩浴?/p>
非靜態(tài)方法中,既可以調(diào)用非靜態(tài)的方法或?qū)傩?,也可以調(diào)用靜態(tài)的方法或?qū)傩浴?/p>
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("中國人吃中餐"); //調(diào)用非靜態(tài)結(jié)構(gòu) this.info(); System.out.println("name :" +name); //調(diào)用靜態(tài)結(jié)構(gòu) walk(); System.out.println("nation : " + nation); } public static void show(){ System.out.println("我是一個(gè)中國人!"); //不能調(diào)用非靜態(tài)的結(jié)構(gòu) // eat(); // name = "Tom"; //可以調(diào)用靜態(tài)的結(jié)構(gòu) System.out.println(Chinese.nation); walk(); } public void info(){ System.out.println("name :" + name +",age : " + age); } public static void walk(){ } }
4. 注意
關(guān)于靜態(tài)屬性和靜態(tài)方法的使用,可都從生命周期的角度去理解。
開發(fā)中,如何確定一個(gè)屬性是否要聲明為static
的?
屬性是可以被多個(gè)對象所共享的,不會(huì)隨著對象的不同而不同的。
類中的常量也常常聲明為static
。
開發(fā)中,如何確定一個(gè)方法是否要聲明為static
的?
操作靜態(tài)屬性的方法,通常設(shè)置為static
的。
工具類中的方法,習(xí)慣上聲明為static
的。 比如:Math
、Arrays
、Collections
。
5. 單例 (Singleton)設(shè)計(jì)模式
5.1 概述
設(shè)計(jì)模式是在大量的實(shí)踐中總結(jié)和理論化之后優(yōu)選的代碼結(jié)構(gòu)、編程風(fēng)格、 以及解決問題的思考方式。設(shè)計(jì)模免去我們自己再思考和摸索。就像是經(jīng)典的棋譜,不同的棋局,我們用不同的棋譜。”套路”
所謂類的單例設(shè)計(jì)模式,就是采取一定的方法保證在整個(gè)的軟件系統(tǒng)中,對某個(gè)類只能存在一個(gè)對象實(shí)例,并且該類只提供一個(gè)取得其對象實(shí)例的方法。 如果我們要讓類在一個(gè)虛擬機(jī)中只能產(chǎn)生一個(gè)對象,我們應(yīng)該怎么做呢?
① 我們首先必須將類的構(gòu)造器的訪問權(quán)限設(shè)置為private
這樣,就不能用new
操作符在類的外部產(chǎn)生類的對象了,但在類內(nèi)部仍可以產(chǎn)生該類的對象。
② 其次,指向類內(nèi)部產(chǎn)生的該類對象的變量也必須定義成靜態(tài)的
因?yàn)樵陬惖耐獠块_始還無法得到類的對象,只能調(diào)用該類的某個(gè)靜態(tài)方法以返回類內(nèi)部創(chuàng)建的對象, 靜態(tài)方法只能訪問類中的靜態(tài)成員變量,所以,指向類內(nèi)部產(chǎn)生的該類對象的變量也必須定義成靜態(tài)的。
5.2 優(yōu)點(diǎn)
由于單例模式只生成一個(gè)實(shí)例,減少了系統(tǒng)性能開銷,當(dāng)一個(gè)對象的產(chǎn)生需要比較多的資源時(shí),如讀取配置、產(chǎn)生其他依賴對象時(shí),則可以通過在應(yīng)用啟動(dòng)時(shí)直接產(chǎn)生一個(gè)單例對象,然后永久駐留內(nèi)存的方式來解決。
5.3 單例設(shè)計(jì)模式-餓漢式
class Singleton { // 1.私有化構(gòu)造器 private Singleton() { } // 2.內(nèi)部提供一個(gè)當(dāng)前類的實(shí)例 // 4.此實(shí)例也必須靜態(tài)化 private static Singleton single = new Singleton(); // 3.提供公共的靜態(tài)的方法,返回當(dāng)前類的對象 public static Singleton getInstance() { return single; } }
5.4 單例設(shè)計(jì)模式-懶漢式
(1)單例設(shè)計(jì)模式-懶漢式(線程不安全)
class Singleton { // 1.私有化構(gòu)造器 private Singleton() { } // 2.內(nèi)部提供一個(gè)當(dāng)前類的實(shí)例 // 4.此實(shí)例也必須靜態(tài)化 private static Singleton single; // 3.提供公共的靜態(tài)的方法,返回當(dāng)前類的對象 public static Singleton getInstance() { if(single == null) { single = new Singleton(); } return single; } }
(2)單例設(shè)計(jì)模式-懶漢式(線程安全)
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 應(yīng)用場景
網(wǎng)站的計(jì)數(shù)器,一般也是單例模式實(shí)現(xiàn),否則難以同步。
應(yīng)用程序的日志應(yīng)用,一般都使用單例模式實(shí)現(xiàn),這一般是由于共享的日志文件一直處于打開狀態(tài),因?yàn)橹荒苡幸粋€(gè)實(shí)例去操作,否則內(nèi)容不好追加。
數(shù)據(jù)庫連接池的設(shè)計(jì)一般也是采用單例模式,因?yàn)閿?shù)據(jù)庫連接是一種數(shù)據(jù)庫資源。
項(xiàng)目中,讀取配置文件的類,一般也只有一個(gè)對象。沒有必要每次使用配置 文件數(shù)據(jù),都生成一個(gè)對象去讀取。
Application
也是單例的典型應(yīng)用。
Windows
的Task Manager
(任務(wù)管理器)就是很典型的單例模式。
Windows
的RecycleBin
(回收站)也是典型的單例應(yīng)用。在整個(gè)系統(tǒng)運(yùn)行過程中,回收站一直維護(hù)著僅有的一個(gè)實(shí)例。
到此這篇關(guān)于Java超詳細(xì)透徹講解static的文章就介紹到這了,更多相關(guān)Java static內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java連接Sql數(shù)據(jù)庫經(jīng)常用到的操作
這篇文章主要介紹了Java連接Sql數(shù)據(jù)庫經(jīng)常用到的操作的相關(guān)資料,需要的朋友可以參考下2016-02-02Mybatis查詢數(shù)據(jù)的項(xiàng)目實(shí)現(xiàn)
MyBatis通過XML配置文件或注解,把Java對象映射到對應(yīng)的數(shù)據(jù)庫表中,實(shí)現(xiàn)對象關(guān)系和數(shù)據(jù)關(guān)系的互相轉(zhuǎn)換,從而使得Java應(yīng)用程序能夠更簡單的操作和讀取數(shù)據(jù)庫,本文就詳細(xì)的介紹一下如何實(shí)現(xiàn),感興趣的可以了解一下2023-09-09Java發(fā)送https請求并跳過ssl證書驗(yàn)證方法
最近在負(fù)責(zé)一個(gè)對接第三方服務(wù)的事情,在對接期間因?yàn)榈谌椒?wù)為https的請求,這篇文章主要給大家介紹了關(guān)于Java發(fā)送https請求并跳過ssl證書驗(yàn)證的相關(guān)資料,需要的朋友可以參考下2023-11-11Spring根據(jù)URL參數(shù)進(jìn)行路由的方法詳解
這篇文章主要給大家介紹了關(guān)于Spring根據(jù)URL參數(shù)進(jìn)行路由的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起來看看吧。2017-12-12Scala 操作Redis使用連接池工具類RedisUtil
這篇文章主要介紹了Scala 操作Redis使用連接池工具類RedisUtil,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-06-06