国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計 > 正文

static關(guān)鍵字

2019-11-11 05:55:57
字體:
供稿:網(wǎng)友

你知道么,static的用法至少有五種?

初識static

static是“靜態(tài)”的意思,這個大家應(yīng)該都清楚,靜態(tài)變量,靜態(tài)方法大家也都能隨口道來。但是,你真的理解靜態(tài)變量和靜態(tài)方法么?除了這些static還有什么用處?

事實上,static大體上有五種用法:

靜態(tài)導(dǎo)入。靜態(tài)變量。靜態(tài)方法。靜態(tài)代碼段。靜態(tài)內(nèi)部類。

接下來,我們將逐個看一下這些用法。

靜態(tài)導(dǎo)入

也許有的人是第一次聽說靜態(tài)導(dǎo)入,反正我在寫這篇文章之前是不清楚static還可以這樣用的。什么是靜態(tài)導(dǎo)入呢?我們先來看一段代碼:

public class OldImport { public static void main(String[] args) { double a = Math.cos(Math.PI / 2); double b = Math.pow(2.4,1.2); double r = Math.max(a,b); System.out.PRintln(r); }}1234567891012345678910

看到這段代碼,你有什么想說的么?啥?沒有?你不覺得Math出現(xiàn)的次數(shù)太多了么?

恩,你覺得好像是有點多,怎么辦呢?看下面:

import static java.lang.Math.*;public class StaticImport { public static void main(String[] args) { double a = cos(PI / 2); double b = pow(2.4,1.2); double r = max(a,b); System.out.println(r); }}123456789101112123456789101112

這就是靜態(tài)導(dǎo)入。我們平時使用一個靜態(tài)方法的時候,都是【類名.方法名】,使用靜態(tài)變量的時候都是【類名.變量名】,如果一段代碼中頻繁的用到了這個類的方法或者變量,我們就要寫好多次類名,比如上面的Math,這顯然不是喜歡偷懶的程序員所希望做的,所以出現(xiàn)了靜態(tài)導(dǎo)入的功能。

靜態(tài)導(dǎo)入,就是把一個靜態(tài)變量或者靜態(tài)方法一次性導(dǎo)入,導(dǎo)入后可以直接使用該方法或者變量,而不再需要寫對象名。

怎么樣,是不是覺得很方便?如果你以前不知道這個,你大概在竊喜,以后可以偷懶了。先別高興的太早,看下面的代碼:

import static java.lang.Double.*;import static java.lang.Integer.*;import static java.lang.Math.*;import static java.text.NumberFormat.*;public class ErrorStaticImport { // 輸入半徑和精度要求,計算面積 public static void main(String[] args) { double s = PI * parseDouble(args[0]); NumberFormat nf = getInstance(); nf.setMaximumFractionDigits(parseInt(args[1])); formatMessage(nf.format(s)); } // 格式化消息輸出 public static void formatMessage(String s){ System.out.println(" 圓面積是:"+s); }}1234567891011121314151617181912345678910111213141516171819

就這么一段程序,看著就讓人火大:常量PI,這知道,是圓周率;parseDouble 方法可能是Double 類的一個轉(zhuǎn)換方法,這看名稱也能猜測到。那緊接著的getInstance 方法是哪個類的?是ErrorStaticImport本地類的方法?不對呀,沒有這個方法,哦,原來是NumberFormate 類的方法,這和formateMessage 本地方法沒有任何區(qū)別了。這代碼也太難閱讀了,這才幾行?要是你以后接別人的代碼,看到成千上萬行這種代碼大概你想死的心都有了吧?

所以,不要濫用靜態(tài)導(dǎo)入!!!不要濫用靜態(tài)導(dǎo)入!!!不要濫用靜態(tài)導(dǎo)入!!!

正確使用靜態(tài)導(dǎo)入的姿勢是什么樣子的呢?

import java.text.NumberFormat;import static java.lang.Double.parseDouble;import static java.lang.Integer.parseInt;import static java.lang.Math.PI;import static java.text.NumberFormat.getInstance;public class ErrorStaticImport { // 輸入半徑和精度要求,計算面積 public static void main(String[] args) { double s = PI * parseDouble(args[0]); NumberFormat nf = getInstance(); nf.setMaximumFractionDigits(parseInt(args[1])); formatMessage(nf.format(s)); } // 格式化消息輸出 public static void formatMessage(String s){ System.out.println(" 圓面積是:"+s); }}123456789101112131415161718192021123456789101112131415161718192021

沒錯,這才是正確的姿勢,你使用哪個方法或者哪個變量,就把他導(dǎo)入進(jìn)來,而不要使用通配符(*)!

并且,由于不用寫類名了,所以難免會和本地方法混淆。所以,本地方法在起名字的時候,一定要起得有意義,讓人一看這個方法名大概就能知道你這個方法是干什么的,而不是什么method1(),method2(),鬼知道你寫的是什么。。

總結(jié):

不使用*通配符,除非是導(dǎo)入靜態(tài)常量類(只包含常量的類或接口)。方法名是具有明確、清晰表象意義的工具類。

這里有一個小插曲,就是我在用idea寫示例代碼的時候,想用通配符做靜態(tài)導(dǎo)入,結(jié)果剛寫完,idea自動給我改成非通配符的了,嘿我這暴脾氣,我再改成通配符!特喵的。。又給我改回去了。。。事實證明,用一個好的IDE,是可以提高效率,比呢且優(yōu)化好你的代碼的,有的時候后,想不優(yōu)化都不行。哈哈哈,推薦大家使用idea。

靜態(tài)變量

這個想必大家都已經(jīng)很熟悉了。我就再啰嗦幾句。

java類提供了兩種類型的變量:用static修飾的靜態(tài)變量和不用static修飾的成員變量。

靜態(tài)變量屬于類,在內(nèi)存中只有一個實例。當(dāng)jtbl所在的類被加載的時候,就會為該靜態(tài)變量分配內(nèi)存空間,該變量就可以被使用。jtbl有兩種被使用方式:【類名.變量名】和【對象.變量名】。

實例變量屬于對象,只有對象被創(chuàng)建后,實例對象才會被分配空間,才能被使用。他在內(nèi)存中存在多個實例,只能通過【對象.變量名】來使用。

第一篇文章《萬物皆對象》中講過,java的內(nèi)存大體上有四塊:堆,棧,靜態(tài)區(qū),常量區(qū)。

其中的靜態(tài)區(qū),就是用來放置靜態(tài)變量的。當(dāng)靜態(tài)變量的類被加載時,虛擬機(jī)就會在靜態(tài)區(qū)為該變量開辟一塊空間。所有使用該靜態(tài)變量的對象都訪問這一個空間。

一個例子學(xué)習(xí)靜態(tài)變量與實例變量。

public class StaticAttribute { public static int staticInt = 10; public static int staticIntNo ; public int nonStatic = 5; public static void main(String[] args) { StaticAttribute s = new StaticAttribute(); System.out.println("s.staticInt= " + s.staticInt); System.out.println("StaticAttribute.staticInt= " + StaticAttribute.staticInt); System.out.println("s.staticIntNo= " + s.staticIntNo); System.out.println("StaticAttribute.staticIntNo= " + StaticAttribute.staticIntNo); System.out.println("s.nonStatic= " + s.nonStatic); System.out.println("使用s,讓三個變量都+1"); s.staticInt ++; s.staticIntNo ++; s.nonStatic ++; StaticAttribute s2 = new StaticAttribute(); System.out.println("s2.staticInt= " + s2.staticInt); System.out.println("StaticAttribute.staticInt= " + StaticAttribute.staticInt); System.out.println("s2.staticIntNo= " + s2.staticIntNo); System.out.println("StaticAttribute.staticIntNo= " + StaticAttribute.staticIntNo); System.out.println("s2.nonStatic= " + s2.nonStatic); }}// 結(jié)果:// s.staticInt= 10// StaticAttribute.staticInt= 10// s.staticIntNo= 0// StaticAttribute.staticIntNo= 0// s.nonStatic= 5// 使用s,讓三個變量都+1// s2.staticInt= 11// StaticAttribute.staticInt= 11// s2.staticIntNo= 1// StaticAttribute.staticIntNo= 1// s2.nonStatic= 51234567891011121314151617181920212223242526272829303132333435363738394041424344454612345678910111213141516171819202122232425262728293031323334353637383940414243444546

從上例可以看出,靜態(tài)變量只有一個,被類擁有,所有對象都共享這個靜態(tài)變量,而實例對象是與具體對象相關(guān)的。

與c++不同的是,在java中,不能在方法體中定義static變量,我們之前所說的變量,都是類變量,不包括方法內(nèi)部的變量。

那么,靜態(tài)變量有什么用途呢?

靜態(tài)變量的用法

最開始的代碼中有一個靜態(tài)變量 — PI,也就是圓周率。為什么要把它設(shè)計為靜態(tài)的呢?因為我們可能在程序的任何地方使用到這個變量,如果不是靜態(tài)的,那么我們每次使用這個變量的時候都要創(chuàng)建一個Math對象,不僅代碼臃腫而且浪費了內(nèi)存空間。

所以,當(dāng)你的某一個變量會經(jīng)常被外部代碼訪問的時候,可以考慮設(shè)計為靜態(tài)的。

靜態(tài)方法

同樣,靜態(tài)方法大家應(yīng)該也比較熟悉了。就是在定義類的時候加一個static修飾符。

與靜態(tài)變量一樣,java類也同時提供了static方法和非static方法。

static方法是類的方法,不需要創(chuàng)建對象就可以使用,比如Math類里面的方法。使用方法【對象.方法名】或者【類名.方法名】非static方法是對象的方法,只有對象唄創(chuàng)建出來以后才可以被使用。使用方法【對象.方法名】

static怎么用代碼寫我想大家都知道,這里我就不舉例了,你們看著煩,我寫著也煩。

注意事項

static方法中不能使用this和super關(guān)鍵字,不能調(diào)用非static方法,只能訪問所屬類的靜態(tài)變量和靜態(tài)方法。因為當(dāng)static方法被調(diào)用的時候,這個類的對象可能還沒有創(chuàng)建,即使已經(jīng)被創(chuàng)建了,也無法確認(rèn)調(diào)用那個對象的方法。不能訪問非靜態(tài)方法同理。

用途—單例模式

static的一個很常見的用途是實現(xiàn)單例模式。單例模式的特點是一個類只能有一個實例,為了實現(xiàn)這一功能,必須隱藏該類的構(gòu)造函數(shù),即把構(gòu)造函數(shù)聲明為private,并提供一個創(chuàng)建對象的方法。我們來看一下怎么實現(xiàn):

public class Singleton { private static Singleton singleton; public static Singleton getInstance() { if (singleton == null) { singleton = new Singleton(); } return singleton; } private Singleton() { }}12345678910111213141234567891011121314

這個類,只會有一個對象。

其他

用public修飾的static成員變量和成員方法本質(zhì)是全局變量和全局方法,當(dāng)聲明它類的對象時,不生成static變量的副本,而是類的所有實例共享同一個static變量。

static 變量前可以有private修飾,表示這個變量可以在類的靜態(tài)代碼塊中,或者類的其他靜態(tài)成員方法中使用(當(dāng)然也可以在非靜態(tài)成員方法中使用–廢話),但是不能在其他類中通過類名來直接引用,這一點很重要。

實際上你需要搞明白,private是訪問權(quán)限限定,static表示不要實例化就可以使用,這樣就容易理解多了。static前面加上其它訪問權(quán)限關(guān)鍵字的效果也以此類推。

靜態(tài)方法的用場

靜態(tài)變量可以被非靜態(tài)方法調(diào)用,也可以被靜態(tài)方法調(diào)用。但是靜態(tài)方法只能被靜態(tài)方法調(diào)用。

一般工具方法會設(shè)計為靜態(tài)方法,比如Math類中的所有方法都是驚天的,因為我們不需要Math類的實例,我們只是想要用一下里面的方法。所以,你可以寫一個通用的 工具類,然后里面的方法都寫成靜態(tài)的。

靜態(tài)代碼塊

在講靜態(tài)代碼塊之前,我們先來看一下,什么是代碼塊。

什么是代碼塊

所謂代碼塊就是用大括號將多行代碼封裝在一起,形成一個獨立的數(shù)據(jù)體,用于實現(xiàn)特定的算法。一般來說代碼塊是不能單獨運行的,它必須要有運行主體。在Java中代碼塊主要分為四種:普通代碼塊,靜態(tài)代碼塊,同步代碼塊和構(gòu)造代碼塊。

四種代碼塊

普通代碼塊

普通代碼塊是我們用得最多的也是最普遍的,它就是在方法名后面用{}括起來的代碼段。普通代碼塊是不能夠單獨存在的,它必須要緊跟在方法名后面。同時也必須要使用方法名調(diào)用它。

public void common(){ System.out.println("普通代碼塊執(zhí)行"); } 123123

靜態(tài)代碼塊

靜態(tài)代碼塊就是用static修飾的用{}括起來的代碼段,它的主要目的就是對靜態(tài)屬性進(jìn)行初始化。

靜態(tài)代碼塊可以有多個,位置可以隨便放,它不在任何的方法體內(nèi),JVM加載類時會執(zhí)行這些靜態(tài)的代碼塊,如果static代碼塊有多個,JVM將按照它們在類中出現(xiàn)的先后順序依次執(zhí)行它們,每個代碼塊只會被執(zhí)行一次。

看一段代碼:

public class Person{ private Date birthDate; public Person(Date birthDate) { this.birthDate = birthDate; } boolean isBornBoomer() { Date startDate = Date.valueOf("1990"); Date endDate = Date.valueOf("1999"); return birthDate.compareTo(startDate)>=0 && birthDate.compareTo(endDate) < 0; }} 1234567891011121312345678910111213

 isBornBoomer是用來這個人是否是1990-1999年出生的,而每次isBornBoomer被調(diào)用的時候,都會生成startDate和birthDate兩個對象,造成了空間浪費,如果改成這樣效率會更好:

public class Person{ private Date birthDate; private static Date startDate,endDate; static{ startDate = Date.valueOf("1990"); endDate = Date.valueOf("1999"); } public Person(Date birthDate) { this.birthDate = birthDate; } boolean isBornBoomer() { return birthDate.compareTo(startDate)>=0 && birthDate.compareTo(endDate) < 0; }}1234567891011121314151612345678910111213141516

因此,很多時候會將一些只需要進(jìn)行一次的初始化操作都放在static代碼塊中進(jìn)行。

同步代碼塊

使用 synchronized 關(guān)鍵字修飾,并使用“{}”括起來的代碼片段,它表示同一時間只能有一個線程進(jìn)入到該方法塊中,是一種多線程保護(hù)機(jī)制。

等講多線程的時候,在詳細(xì)講解這種代碼塊~

構(gòu)造代碼塊

在類中直接定義沒有任何修飾符、前綴、后綴的代碼塊即為構(gòu)造代碼塊。我們明白一個類必須至少有一個構(gòu)造函數(shù),構(gòu)造函數(shù)在生成對象時被調(diào)用。構(gòu)造代碼塊和構(gòu)造函數(shù)一樣同樣是在生成一個對象時被調(diào)用,那么構(gòu)造代碼在什么時候被調(diào)用?如何調(diào)用的呢?

看一段代碼:

public class CodeBlock { private int a = 1; private int b ; private int c ; //靜態(tài)代碼塊 static { int a = 4; System.out.println("我是靜態(tài)代碼塊1"); } //構(gòu)造代碼塊 { int a = 0; b = 2; System.out.println("構(gòu)造代碼塊1"); } public CodeBlock(){ this.c = 3; System.out.println("構(gòu)造函數(shù)"); } public int add(){ System.out.println("count a + b + c"); return a + b + c; } //靜態(tài)代碼塊 static { System.out.println("我是靜態(tài)代碼塊2,我什么也不做"); } //構(gòu)造代碼塊 { System.out.println("構(gòu)造代碼塊2"); } public static void main(String[] args) { CodeBlock c = new CodeBlock(); System.out.println(c.add()); System.out.println(); System.out.println("*******再來一次*********"); System.out.println(); CodeBlock c1 = new CodeBlock(); System.out.println(c1.add()); }}//結(jié)果://我是靜態(tài)代碼塊1//我是靜態(tài)代碼塊2,我什么也不做//構(gòu)造代碼塊1//構(gòu)造代碼塊2//構(gòu)造函數(shù)//count a + b + c//6////*******再來一次*********////構(gòu)造代碼塊1//構(gòu)造代碼塊2//構(gòu)造函數(shù)//count a + b + c//612345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061621234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162

這段代碼綜合了構(gòu)造代碼塊,普通代碼塊和靜態(tài)代碼塊。我們來總結(jié)一下:

靜態(tài)代碼塊只會執(zhí)行一次。有多個靜態(tài)代碼塊時按順序依次執(zhí)行。構(gòu)造代碼塊每次創(chuàng)建新對象時都會執(zhí)行。有多個時依次執(zhí)行。執(zhí)行順序:靜態(tài)代碼塊 > 構(gòu)造代碼塊 > 構(gòu)造函數(shù)。構(gòu)造代碼塊和靜態(tài)代碼塊有自己的作用域,作用域內(nèi)部的變量不影響作用域外部。

構(gòu)造代碼塊的應(yīng)用場景:

1、 初始化實例變量 如果一個類中存在若干個構(gòu)造函數(shù),這些構(gòu)造函數(shù)都需要對實例變量進(jìn)行初始化,如果我們直接在構(gòu)造函數(shù)中實例化,必定會產(chǎn)生很多重復(fù)代碼,繁瑣和可讀性差。這里我們可以充分利用構(gòu)造代碼塊來實現(xiàn)。這是利用編譯器會將構(gòu)造代碼塊添加到每個構(gòu)造函數(shù)中的特性。

2、 初始化實例環(huán)境 一個對象必須在適當(dāng)?shù)膱鼍跋虏拍艽嬖冢绻麤]有適當(dāng)?shù)膱鼍埃瑒t就需要在創(chuàng)建對象時創(chuàng)建此場景。我們可以利用構(gòu)造代碼塊來創(chuàng)建此場景,尤其是該場景的創(chuàng)建過程較為復(fù)雜。構(gòu)造代碼會在構(gòu)造函數(shù)之前執(zhí)行。

靜態(tài)內(nèi)部類

被static修飾的內(nèi)部類,它可以不依賴于外部類實例對象而被實例化,而通常的內(nèi)部類需要在外部類實例化后才能實例化。靜態(tài)內(nèi)部類不能與外部類有相同的名字,不能訪問外部類的普通成員變量,只能訪問內(nèi)部類中的靜態(tài)成員和靜態(tài)方法(包括私有類型)。

由于還沒有詳細(xì)講解過內(nèi)部類,這里先一筆帶過,在講解內(nèi)部類的時候會詳細(xì)分析靜態(tài)內(nèi)部類。

只有內(nèi)部類才能被static修飾,普通的類不可以。

總結(jié)

本文內(nèi)容就先到這里,我們再來回顧一下學(xué)了什么:

static關(guān)鍵字的五種用法:

靜態(tài)導(dǎo)入靜態(tài)變量靜態(tài)方法靜態(tài)代碼塊

代碼塊

普通代碼塊靜態(tài)代碼塊構(gòu)造代碼塊同步代碼塊

回憶一下這些知識點的內(nèi)容,如果想不起來,記得翻上去再看一遍~

彩蛋 —— 繼承+代碼塊的執(zhí)行順序

如果既有繼承,又有代碼塊,執(zhí)行的順序是怎樣呢?

public class Parent { static { System.out.println("父類靜態(tài)代碼塊"); } { System.out.println("父類構(gòu)造代碼塊"); } public Parent(){ System.out.println("父類構(gòu)造函數(shù)"); }}class Children extends Parent { static { System.out.println("子類靜態(tài)代碼塊"); } { System.out.println("子類構(gòu)造代碼塊"); } public Children(){ System.out.println("子類構(gòu)造函數(shù)"); } public static void main(String[] args) { new Children(); }}//結(jié)果://父類靜態(tài)代碼塊//子類靜態(tài)代碼塊//父類構(gòu)造代碼塊//父類構(gòu)造函數(shù)//子類構(gòu)造代碼塊//子類構(gòu)造函數(shù)1234567891011121314151617181920212223242526272829303132333435363712345678910111213141516171819202122232425262728293031323334353637

結(jié)果你也知道了:

先執(zhí)行靜態(tài)內(nèi)容(先父類后子類),然后執(zhí)行父類非靜態(tài),最后執(zhí)行子類非靜態(tài)。(非靜態(tài)包括構(gòu)造代碼塊和構(gòu)造函數(shù),構(gòu)造代碼塊先執(zhí)行)


如果文中有錯誤或者你有其他見解,請及時與我聯(lián)系。不保證文章內(nèi)容的完全正確性。

原文地址:http://blog.csdn.net/QQ_31655965/article/details/54767522

轉(zhuǎn)載請注明出處。

看完文章,如果你學(xué)到了你以前不知道的知識,點個贊支持一下喲~


上一篇:Tickets HDU - 1260

下一篇:jQuery版本的演變

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 酉阳| 阜宁县| 霍城县| 闽清县| 迭部县| 泽普县| 洛浦县| 达孜县| 隆尧县| 乌恰县| 长治市| 增城市| 五家渠市| 清丰县| 鹤山市| 萨迦县| 时尚| 商洛市| 青冈县| 忻州市| 普陀区| 湘潭市| 福贡县| 调兵山市| 临清市| 新宾| 镶黄旗| 乡宁县| 台安县| 镇康县| 岐山县| 永修县| 连平县| 息烽县| 西畴县| 来宾市| 伊川县| 偏关县| 文水县| 镇雄县| 卢龙县|