三、this與static 關鍵字
-
this關鍵字
假設一種場景赞辩,現(xiàn)在有一個 類
class A{
void a(int x){}
}
如果有兩個對象a1雌芽、a2都調用a()方法,那么該方法是如何知道被誰調用辨嗽。
為了能用簡便世落、面向對象的語法來編寫代碼,編譯器為我們做了一些幕后操作糟需,它把所操作對象的引用作為第一個參數傳遞給操作方法屉佳,語句"a1.a(5);"在編譯器的內部表現(xiàn)形式是"a1.a(a1, 5)"。
如果你希望在方法內部獲取對當前對象的引用洲押,Java為我們專門定制了一個關鍵字 this武花。this關鍵字只能在方法內部使用,表示調用方法的那個引用诅诱。如果在方法內部調用類的另一個方法髓堪,則this關鍵字可以省略,編譯器會自動添加。只有當需要明確指出當前對象的引用時干旁,才需要使用this關鍵字驶沼。例如
public class Content {
private ArrayList<BrandList> selectedBrandLists;
private ArrayList<DeviceList> selectedDeviceLists;
private ArrayList<ComponentList> selectedComponentLists;
public ArrayList<BrandList> getSelectedBrandLists() {
return selectedBrandLists;
}
public DemandContent setSelectedBrandLists(ArrayList<BrandList> selectedBrandLists) {
this.selectedBrandLists = selectedBrandLists;
return this;
}
public ArrayList<DeviceList> getSelectedDeviceLists() {
return selectedDeviceLists;
}
public DemandContent setSelectedDeviceLists(ArrayList<DeviceList> selectedDeviceLists) {
this.selectedDeviceLists = selectedDeviceLists;
return this;
}
public ArrayList<ComponentList> getSelectedComponentLists() {
return selectedComponentLists;
}
public DemandContent setSelectedComponentLists(ArrayList<ComponentList> selectedComponentLists) {
this.selectedComponentLists = selectedComponentLists;
return this;
}
}
我們使set方法返回當前類對象引用的目的是為了在設置對象內容的時候可以連續(xù)調用set方法
Content content = new Content();
content.setSelectedBrandLists(selectedBrandLists)
.setSelectedDeviceLists(selectedDeviceLists)
.setSelectedComponentLists(selectedComponentLists);
相比于
Content content = new Content();
content.setSelectedBrandLists(selectedBrandLists)
content.setSelectedDeviceLists(selectedDeviceLists)
content.setSelectedComponentLists(selectedComponentLists);
省去了一些不必要的步驟。這種方式在Builder模式中比較常見争群。
當一個類有多個構造器回怜,有時為了避免重復編寫代碼,可以希望在一個構造器內調用另一個構造器换薄,可以用this關鍵字做到這一點玉雾。
在構造器中,如果為this添加參數列表轻要,那么將會是對某個符合參數列表的構造器的直接調用复旬。這樣,調用其他構造器就有了直接的途徑冲泥。
private Context mContext;
private OnLoginDataCheckerListener onLoginDataCheckerListener;
private ILoginModel iLoginModel;
public LoginPresenter(Context mContext, OnLoginDataCheckerListener onLoginDataCheckerListener,
OnGetVCodeListener onGetVCodeListener) {
this(mContext, onLoginDataCheckerListener); //調用其他構造器
this.onGetVCodeListener = onGetVCodeListener; //避免與參數的同名歧義驹碍,使用this.onGetVCodeListener代表數據成員
}
private LoginPresenter(Context mContext, OnLoginDataCheckerListener onLoginDataCheckerListener) {
this.mContext = mContext;
this.onLoginDataCheckerListener = onLoginDataCheckerListener;
this.iLoginModel = new LoginModel();
}
值得注意的是,只能使用this調用一個其他構造器凡恍,并且必須將調用語句置于最起始處志秃,否則編譯無法通過
this關鍵字的作用也不僅限于此,有機會再專門寫一篇記總結一下嚼酝。
-
static關鍵字
static方法就是沒有this的方法浮还。在static方法內部不能調用非靜態(tài)方法,反過來是可以的闽巩。而且可以在沒有創(chuàng)建任何對象的前提下钧舌,僅僅通過類本身來調用static方法。這實際上正是static方法的主要用途又官。
1. static方法
static方法一般稱作靜態(tài)方法延刘,由于靜態(tài)方法不依賴于任何對象就可以進行訪問,因此對于靜態(tài)方法來說六敬,是沒有this的,因為它不依附于任何對象驾荣,既然都沒有對象外构,就談不上this了。并且由于這個特性播掷,在靜態(tài)方法中不能訪問類的非靜態(tài)成員變量和非靜態(tài)成員方法审编,因為非靜態(tài)成員方法/變量都是必須依賴具體的對象才能夠被調用。
但是要注意的是歧匈,雖然在靜態(tài)方法中不能訪問非靜態(tài)成員方法和非靜態(tài)成員變量垒酬,但是在非靜態(tài)成員方法中是可以訪問靜態(tài)成員方法/變量的。
另外記住,關于構造器是否是static方法可參考:http://blog.csdn.net/qq_17864929/article/details/48006835
2. static變量
static變量也稱作靜態(tài)變量勘究,靜態(tài)變量和非靜態(tài)變量的區(qū)別是:靜態(tài)變量被所有的對象所共享矮湘,在內存中只有一個副本,它當且僅當在類初次加載時會被初始化口糕。而非靜態(tài)變量是對象所擁有的缅阳,在創(chuàng)建對象的時候被初始化,存在多個副本景描,各個對象擁有的副本互不影響十办。
static成員變量的初始化順序按照定義的順序進行初始化。
3. static代碼塊
static關鍵字還有一個比較關鍵的作用就是 用來形成靜態(tài)代碼塊以優(yōu)化程序性能超棺。static塊可以置于類中的任何地方向族,類中可以有多個static塊。在類初次被加載的時候棠绘,會按照static塊的順序來執(zhí)行每個static塊炸枣,并且只會執(zhí)行一次。
為什么說static塊可以用來優(yōu)化程序性能弄唧,是因為它的特性:只會在類加載的時候執(zhí)行一次适肠。舉個栗子
class Person{
private Date birthDate;
public Person(Date birthDate) {
this.birthDate = birthDate;
}
boolean isBornBoomer() {
Date startDate = Date.valueOf("1946");
Date endDate = Date.valueOf("1964");
return birthDate.compareTo(startDate)>=0 && birthDate.compareTo(endDate) < 0;
}
}
isBornBoomer是用來這個人是否是1946-1964年出生的,而每次isBornBoomer被調用的時候候引,都會生成startDate和birthDate兩個對象侯养,造成了空間浪費,如果改成這樣效率會更好:
class Person{
private Date birthDate;
private static Date startDate,endDate;
static{
startDate = Date.valueOf("1946");
endDate = Date.valueOf("1964");
}
public Person(Date birthDate) {
this.birthDate = birthDate;
}
boolean isBornBoomer() {
return birthDate.compareTo(startDate)>=0 && birthDate.compareTo(endDate) < 0;
}
}
因此澄干,很多時候會將一些只需要進行一次的初始化操作都放在static代碼塊中進行逛揩。
4. static關鍵字的一些誤區(qū)
(1)static關鍵字會改變類中成員的訪問權限嗎?
有些初學的朋友會將java中的static與C/C++中的static關鍵字的功能混淆了麸俘。在這里只需要記住一點:與C/C++中的static不同辩稽,Java中的static關鍵字不會影響到變量或者方法的作用域。在Java中能夠影響到訪問權限的只有private从媚、public逞泄、protected(包括包訪問權限)這幾個關鍵字“菪В看下面的例子就明白了:
提示錯誤"Person.age 不可視"喷众,這說明static關鍵字并不會改變變量和方法的訪問權限。
(2)能通過this訪問靜態(tài)成員變量嗎紧憾?
雖然對于靜態(tài)方法來說沒有this到千,那么在非靜態(tài)方法中能夠通過this訪問靜態(tài)成員變量嗎?先看下面的一個例子赴穗,這段代碼輸出的結果是什么憔四?
public class Main {
static int value = 33;
public static void main(String[] args) throws Exception{
new Main().printValue();
}
private void printValue(){
int value = 3;
System.out.println(this.value); //輸出33
}
}
這里面主要考察隊this和static的理解膀息。this代表什么?this代表當前對象了赵,那么通過new Main()來調用printValue的話潜支,當前對象就是通過new Main()生成的對象。而static變量是被對象所享有的斟览,因此在printValue中的this.value的值毫無疑問是33毁腿。在printValue方法內部的value是局部變量,根本不可能與this關聯(lián)苛茂,所以輸出結果是33已烤。在這里永遠要記住一點:靜態(tài)成員變量雖然獨立于對象,但是不代表不可以通過對象去訪問妓羊,所有的靜態(tài)方法和靜態(tài)變量都可以通過對象訪問(只要訪問權限足夠)胯究。
(3)static能作用于局部變量么?
在C/C++中static是可以作用域局部變量的躁绸,但是在Java中切記:static是不允許用來修飾局部變量裕循。不要問為什么,這是Java語法的規(guī)定净刮。
具體原因可以參考這篇博文的討論:http://www.debugease.com/j2se/178932.html
參考
《Java編程思想》
https://www.cnblogs.com/dolphin0520/p/3799052.html
http://www.debugease.com/j2se/178932.html
http://blog.csdn.net/qq_17864929/article/details/48006835