-
實例化:
不實例化,就是一個空指針注意,即使只是聲明,也是會分配空間的:
來源:https://zhidao.baidu.com/question/519582801799420045.html?qbl=relate_question_3
我們要看你這句int a處於什么地方,如果是在方法內部中被執行到,也就是說是局部變量,就會在棧內存中分配內存,由於是int型,所以就是4字節,也就是32bit,long類型的才會是64bit。
而你說的表示地址我們稱為堆內存。創建的對象以及對象中的方法和數據是存儲在堆內存中的。JVM會在棧內存中建立對象的引用,然后當執行到new語句時,在堆內存中創建對象,這時就將這個對象的類型以及這塊區域的內存地址值賦給引用,然后進行對象中數據的初始化。也就是說,對象的引用存儲在棧內存中,存放的是類型以及hash值,如Integer@0xff67。而對象里的內容實際上是存儲在堆內存中的。
如果你這句int a只是在某個對象內作為成員變量,那么根本不會涉及到棧內存。a就存儲在它所在的那個對象的堆內存中。明白了么?
所以說,如果是成員變量的話,如果是基本類型,會在聲明時直接在棧上給該類似的大小的內存空間;如果是引用類型,會在棧上給一個指針的大小。
-
對變量的分類實例變量只有實例化之后才能使用,而類變量直接用類名就可以使用
成員變量在堆,局部變量在棧
-
-
匿名對象
new Person().shout();
使用場景:
- 對一個對象只需要一次方法調用
- 作為實參傳遞給方法
-
方法的重載
參數的個數或者參數的數據類型必須不同
-
可變個數的形參
- (String[] args)//定義字符串數組
- (String... args)//JAVA特有的點點點的方式,這種參數在使用時與數組的使用方式相同
兩種方法的區別:
? 第一種如果沒有參數,需要輸入null或者一個空數組;而第二種直接不填就好(...代表可以傳遞0到多個參數)
-
方法的參數傳遞
JAVA只有一種參數傳遞方法:值傳遞。即將實際參數值復制到方法的形參中,而參數本身不受影響(當然這種方法比較慢,但是JAVA嗎23333)
注意,對於引用對象,值還是變化了的,因為傳進去的實際是地址。但是即使修改了函數里的指針指向(例如在函數中new了一個對象並將指針指向了該對象),外部的實際指向也不會受影響,相當於指向了兩個不同的對象而已 -
this關鍵字
使用this的幾個優點:
-
不需要給方法中的形參亂起名字了
如圖,使用this的話,形參的名稱可以和成員變量相同,賦值的時候借助this區分就好,這樣就不需要在函數的形參上亂起名字了 -
增強程序閱讀性
-
this可以作為一個類中,構造器相互調用的特殊格式
用於構造器重載時,可以直接調用已有的構造器然后進行修改即可,使構造器的編寫更加方便注意,這種情況下,this()必須放在構造器的首行(顯然)
-
-
JAVA Bean
也就是說,符合這三條的都可以叫做javaBean
右鍵-》source-》general getters and setters,自動生成get和set方法 -
繼承(extends)和多態
JAVA只支持單繼承
繼承讓類與類之間產生了關系,不要僅僅為了獲取其他類中的某個功能而去繼承-》繼承是要有邏輯關系在其中的
-
方法的重寫(@override)
- 重寫只能重寫方法體,名稱、參數列表和返回值類型均不能改
- 重寫方法不能使用比被重寫方法更加嚴格的訪問權限
- 子類方法拋出的異常不能大於父類被重寫方法的異常
題外話:ctrl+/:eclipse快速注釋代碼
如果子類和父類在同一個包下,那么對於父類的成員修飾符除了private之外,剩下的情況子類都可以使用父類的成員變量;如果不在一個包下,只有protected和public的成員變量可以使用 -
super關鍵字
super和this類似,但是是用於調用父類的成員變量和方法的。
使用super,子類可以調用父類之上的所有父類層級
this和super的區別:
在子類中,通過This或者super調用構造器,只能使用一個,因為都要占據第一行 -
類對象的實例化過程
有繼承時:
在方法區,先加載父類方法,再加載子類方法子類構造方法先入棧,父類再入棧,所以父類先執行
-
instanceof操作符
instance:實例
屬於子類也行 -
Object類
也叫基類
形參定義為object類型,則可以接受任何類型的類(注意,必須是個類!)
-
equal:比較引用對象:是否引用了同一個對象(也就是一個new出來的對象)
Person e=new person(); Person p=new person();//此時e和p指向的是堆中的兩個不同的對象,此時用equal方法檢測是false e=p;//此時e被重定向到p,此時再檢測就是true了
-
-
對象的類型轉換
能進行的是有繼承關系間的類型的轉換從子類到父類:
?
由此可見,object對象可以接收任何類型的對象從父類到子類:
?
示例代碼:
e可以接受父類為Person類的各種類的對象,然后檢查其是否是Student類或Student類的子類,如果是,就執行Student類中獨有的方法,否則執行其他方法。 -
==操作符和equals方法
只有指向同一個對象,==才為true,而比較的不是成員變量的值是否相等equals和==功能相同,除了下面說的幾個特殊情況:
注意String的比較要使用equals而不是==
-
String對象的創建
可以看到,無論是哪一種方法,同樣的字符串也不會保留多個
--所以字面量創建更加省內存,所以其常用而“不重復”只全體現在常量池上,如果使用New的方式,堆中每次都會創建一個新的對象。最特別的是最后一種情況,常量池中添加的是拼接錢的串,而堆中創建的卻是拼接后的串
-
包裝類
將基本數據類型賦予了類的方法-
自動拆箱、裝箱:和基本數據類型寫法可以保持一致(轉換更簡單,使用起來比基本數據類型更方便、功能更強大)
-
包裝類的功能:
借助包裝類的類方法,將字符串轉換為對應類型的數據(注意,只是借助其實現轉換,並沒有直接使用包裝類)
- 字符串轉其他基本數據類型
int i=Integer.parseInt("123");
boolean b=Boolean.parseBoolean("false");
- 其他基本數據類型轉字符串
String istr=String.valueOf(i);
String batr=String.valueOf(b);
->綜上,包裝類主要應用於字符串和其他基本數據類型的應用
-
-
重寫toString()
toString方法是直接用System.out.printIn()打印時調用的方法。默認的toString()是類Object的方法,由於其是所有類的父類,所以其功能比較泛,該方法就是輸出內存地址(大多數情況下這是沒什么用的)。所以各個類可以重寫該方法以打印有意義的內容。
-
static關鍵字
static用來設置類屬性和類方法
static一般只用Public修飾類屬性被所有對象所共用,可以用來計數什么的
-
單例設計模式--設計模式之一
-
什么是設計模式?
設計模式就是實際編程中逐漸總結出來的一些解決問題的套路 -
單例
只有一個實例(實例化對象)
在整個軟件系統運行過程中,這個類只被實例化一次,以后不論在哪都只調用這一個實例
-
應用的場景:
- 該對象的創建要消耗大量的時間和資源
- 重復new對象沒有必要
-
兩種實現方式:
-
先構造后使用構造方法私有化,不能new
實例化也是私有的,引用是私有的類變量
利用公有的方法返回那個類變量
這樣的話,程序中永遠只有一個實例化對象
-
先不構造,用的話再構造,如果從來不用就算了,就這一點區別先判斷(s1==null)來判斷是否需要實例化
-
-
-
理解main方法
?
例如cmd,即可給main傳參 -
初始化代碼塊
作用:對JAVA對象進行初始化類的成員初始化過程:聲明成員變量默認值-》顯示初始化,執行代碼塊-》執行構造方法
-
靜態代碼塊
靜態代碼塊用於初始化靜態屬性非靜態代碼塊每次new都要重新執行,而靜態代碼塊只執行一次。且靜態先於非靜態執行
在實際應用中,靜態代碼塊用的比較多,用於初始化靜態類屬性(尤其對於一些比較復雜的靜態類屬性,例如屬性是一個類的情況下),非靜態的作用不太大 -
-
匿名內部類
對Person類的方法進行了重載,所以其其實是一個Person的子類,故稱為匿名內部類
匿名內部類中成員變量的初始化(如果要和父類的初始化有所不同的話)無法通過構造方法實現(因為沒有類名,無法創建構造方法),只能通過代碼塊的方式完成 -
final關鍵字
概況一下,final修飾的內容初始化之后就不能再修改了,所以變量要均大寫,和常量保持一致(final修飾的變量是常量,常量必須顯式賦值)
final static:全局常量 -
抽象類
含有抽象方法的類必須被聲明為抽象類注意,抽象類中不一定所有方法都是抽象的,如果都是抽象的就是接口了
final和abstract是沖突的
抽象類可以有構造方法 -
模板方法設計模式--設計模式之二
*
-
接口
接口中只有定義,沒有實現interface定義,implements使用
類可以實現多個接口,多個接口之間用,分割
當有一個新的需求時:-
如果父類新增抽象方法,子類就必須實現,否則就需要定義為抽象類。
-
解決方法就是不要在父類中新增抽象方法,而是新增一個接口,由子類去選擇是否實現這一接口
父類需要穩定的抽象,不能總是在改
需要描述一個交叉的關系時:
- 不能使用類的繼承解決這個問題:會污染類的繼承,使繼承關系沒有邏輯性
- 實現接口就好(接口是一類方法(動作)的集合)
對抽象類和接口的總結:
- 抽象類是對於一類事物的高度抽象,其中既有屬性也有方法
- 接口是對方法的抽象,也就是對一系列動作的抽象
- 當需要對一類事物抽象的時候,應該使用抽象類,好形成一個父類;當需要對一系列動作抽象時,就使用接口
匿名內部類在接口中的應用
看到了以下一段代碼:
這里的Runnable是接口,我們知道接口是不能實例化對象的,那這里是什么情況呢?其實這不是聲明了一個接口類型的對象,而是一種多態機制,專業名詞叫“匿名內部類”,實際上是創建了一個遵守了該接口的普通類(Object)對象。
類似的使用還有下面,可以看到,類能聲明的接口幾乎都可以聲明
interface Shape { void draw(); } public class Main { // interface type as instance variable private Shape myShape; // interface type as parameter type for a constructor public Main(Shape s) { this.myShape = s; } // interface type as return type of a method public Shape getShape() { return this.myShape; } // interface type as parameter type for a method public void setShape(Shape s) { this.myShape = s; } public void letItSwim() { // interface type as a local variable Shape locaShape = null; locaShape = this.myShape; // interface variable can invoke methods // declared in the interface and the Object class locaShape.draw(); } }
這其實是一種變相的“用接口作為類型”,也是面向接口的編程的思想之一。
-
-
工廠模式——設計模式之三
在真正的開發工作中,都是合作開發,每個開發人員寫一部分,集合到一起成為一個項目問題:一個開發人員要改代碼,例如改類名,會影響其他人的工作。因此降低了工作效率
解決方法:寫一個產品接口類,一個工廠接口類,其他人用工廠類而不是直接用產品類。通過工廠將new對象隔離,通過產品的接口接受不同實際產品的實現類,實例的類名的改變不影響其他合作開發人員的編程。其他開發人員只需要關注工廠類的使用,而修改代碼只限於產品類的名稱和工廠類的代碼,不會影響工廠類的使用。(這種設計可能是架構師的任務(?ω?))
無論是內部類還是其他,JAVA除了很早期的一些特征外,剩下的特征都是為了解決一些特點問題必不可少的,不是冗余的功能
-
內部類
內部類是外部類的成員注意外部類調用內部類時方法
內部類可以聲明private 或者protected內部類的聲明和外部類互相不影響,可以重名
內部類的作用:
-
內部類的最大作業是實現多重繼承(A想同時獲得類B和類C的方法並重寫)
-
-