面向過程與面向對象的區別:
面向對象,將跟對象有關的功能都封裝在其內
面向對象三大特征:封裝,繼承,多態
找對象,創建對象,使用對象,並維護對象之間的關系
類:對現實中事物的描述
對象:就是實實在在 存在的事物
映射到java中,描述就是class定義的類
具體對象就是對應java在堆內存中new建立的實體
類與對象:
設計圖紙就是類,里面包含對象的描述:比如說車的顏色,輪胎數,發動機....
Note:對象建立的時候,屬性值都會先置為null,顯式初始化后才會變成具體的值
成員變量VS局部變量:
作用范圍:
成員變量作用於整個類中;
局部變量作用於函數或者語句中;
在內存中的位置:
成員變量在堆內存中,由於對象的存在,才在內存中存在;
局部變量在棧內存中;
局部變量必須初始化,否則不能運行;
成員變量有默認初始化值,因此可以不初始化;
當成員變量和局部變量名稱一致時,默認使用局部變量
本類中可以創建本類對象(一般不用);
匿名對象:沒有定義名稱的對象
如下圖,左邊是有名稱的對象,右邊是匿名對象
匿名對象的傳值調用:調用結束后,在堆內存新生成的對象成為垃圾(無指向),因此過一段時間就會被垃圾回收機制回收.
封裝:隱藏對象的屬性和實現細節,僅僅提供公共訪問方式;
關鍵字:private 權限修飾符,只在本類中有效
私有只是封裝的一種表現形式
一般情況下,把屬性都隱藏,提供公共訪問方式訪問;
對外提供訪問屬性的方式(set&get方法),是因為在訪問方式中可以加入邏輯判斷等語句;
對訪問的數據進行操作,提高代碼的健壯性
class Person
{
int age;
public void setAge(int a)//一個屬性一般由兩個方法來訪問(設置和獲取)
{
if(a >0 && a <130)
age =a;
else
System.out.println("Illegal age!");
}
public int getAge()
{
return age;
}
}
構造函數:函數名和類名一致,不能用return
對象一建立就會調用構造函數,可以用於對特定對象進行初始化;
若類中沒有定義構造函數,系統會默認加入一個空參數的構造函數;
構造函數也可以私有化,私有化后不能使用該函數創建對象
如果所有構造函數都私有化,那么就不能創建對象
一般方法是對象調用才運行,可以被調用多次;
構造代碼塊:給所有對象的共性進行初始化,對象一建立就運行,優先於構造函數執行
{
System.out.println();//沒有函數名
}
this:代表當前調用對象(當變量前面加了this,該變量可以認為是成員變量)
當本類功能內部需要使用本類對象時,都用this來表示
class Person
{
private String name;
//同名變量區分
Person(String name)
{
this.name(成員變量) = name(局部變量);
}
//構造函數調用;注意,構造函數不能互相調用,否則將進入死循環
Person(String name,int age)
{
this(name);//只能放在第一行,因為初始化要先執行;再次初始化
this.age = age;
}
}
static:靜態,修飾成員(包括變量和方法,不能修飾局部),表示共性數據
可以被類名調用:類名.靜態成員
被所有對象共享,只占一塊內存(方法區,共享區,數據區)
隨着類的加載而加載,隨着類的消失而消失,生命周期最長
優先於對象存在
被所有對象所共享
可以直接被類名調用(可以不創建對象)
String name;//成員變量,實例變量,隨着對象的建立而存在
static String country = "CN";//靜態變量,類變量
靜態變量和成員變量的區別:
存放位置:
實例變量隨着對象的建立存在於堆內存中,
類變量隨着類的加載存在於方法區中
生命周期:
實例變量隨着對象消失而消失
類變量隨着類消失而消失
使用注意事項:
靜態方法只能訪問靜態成員
靜態方法中不可以定義this,super關鍵字(因為靜態有限於對象存在)
主函數是靜態的,作為程序入口,可以被jvm調用
利: 對共享數據進行單獨空間存儲,節省空間.
可以直接被類名調用
弊: 生命周期過長,訪問出現局限性(只能訪問靜態)
public static void main(String[] args)解析:
/*
public:代表這該函數訪問權限最大
static:代表主函數隨着類的加載就已經存在
void:沒有返回值
main:特殊單詞,可以被jvm識別
String[] args:參數是一個數組,該數組中的元素是字符串
*/
主函數可以重載,但是jvm只識別main(String[] args);
javac 命令 啟動編譯器
java 命令 啟動jvm,所以可以在運行命令java *.class后面添加args參數
class MainDemo
{
public static void main(String[] args)
{
}
}
靜態變量:當對象中出現共享數據時
靜態函數: 當功能內部沒有訪問到非靜態數據時
若編譯時,當前調用的class不存在時,會先去當前目錄下找相應的java文件,如果有,則會直接編譯,生成class文件
靜態代碼塊:隨着類的加載而執行,只執行一次,優先於主函數
用於給類進行初始化
構造代碼塊會執行多次;
運行順序:靜態代碼塊,構造代碼塊,構造函數
class StaticDemo
{
static
{
執行語句
}
void show(){}
}
StaticDemo.show();//加載
StaticDemo s1 = new StaticDemo;//加載
StaticDemo s1 = null;//未加載
一個對象的建立過程:
Person p= new Person("zhangsan",20);
1.找到Person.class文件並加載到內存中
2.執行static代碼塊
3.在堆內存中開辟空間,分配內存地址(main函數開始)
4.在堆內存中建立對象的特有屬性,並進行默認初始化
5.對屬性進行顯示初始化
6.對對象進行構造代碼塊初始化
7.對對象進行對應的構造函數初始化
8.將內存地址賦值給棧內存中的p變量
初始化過程:默認初始化,顯式初始化,構造初始化
繼承:
將類的共有屬性提取出來,將之變為超類,父類
提高了代碼復用性
讓類與類之間產生了關系,因此有了多態的特性
只支持單繼承,不支持多繼承
(容易帶來安全隱患:當多個父類中定義了相同功能,但內容不同時,子類不確定執行哪個功能)
但是java保留了這種機制,並用另一種體現形式來完成表示(接口的多實現);
java支持多層繼承,爺爺類-父親類-孫子類,也叫做繼承體系;
在具體調用時,只需創建最子類的對象;
父類可能不能創建對象;
創建子類對象可以使用更多功能,包括共有的和特有的;
查閱父類功能,創建子類對象使用功能;
聚集,聚合,組合
若子類和父類有同名變量:
子類訪問本類中的變量,前面加this;
子類要訪問父類的變量,前面加super;
若變量不同名,則this和super(如果父類中有該變量)指向同一個變量
若子類和父類中函數同名,則會使用子類的函數;父類的函數被覆蓋(重寫,overide)
沿襲父類功能,但是重寫功能內容.
子類方法覆蓋父類方法條件:
靜態只能覆蓋靜態
必須保證子類權限大於父類,(父類的權限不能為(private))
public >默認權限>private
重載:只看參數列表
重寫:兩個方法需要一模一樣(包括返回值,參數類型)
子類和父類的構造函數:絕對不能重寫!
父類先於子類加載,因為在子類的所有構造函數之前都有一句隱世的super()(空參數的父類構造函數);
父類中若有空參數的父類構造函數,子類中的構造函數可以不寫super();
父類中若沒有空參數的構造函數,則子類的每個構造函數第一句需要顯式的寫明super(XXX);
父類中的數據子類可以直接獲取,子類對象在建立時,需要先查看父類是如何對這些數據進行初始化的;
因此子類在對象初始化時,要先訪問父類中的構造函數。
this();或者super();都只能寫在第一行,只能存在一個.
子類中至少有一個構造函數會訪問父類中的構造函數;
extends Object(所有類的上帝,默認父類)
final:
修飾類,函數,變量
被修飾的類不可以被繼承
被修飾的方法不可以被復寫
被修飾的變量是一個常量,只能賦值一次,可以修飾成員變量和局部變量
所有字母都大寫
修飾類:public final
抽象類和抽象方法:
abstract class Student//抽象方法必須存在於抽象類中,不能用該類創建對象,因為沒有意義
{
abstract void study();//抽象方法,內容待定,要被使用,必須有子類復寫該方法
}
子類如果不覆蓋所有的抽象方法,則子類還是一個抽象類
父類可以強制子類執行抽象方法;
抽象類和一般類:抽象類多了一些不確定的功能(抽象方法),需要子類具體執行
接口:Interface,不能創建對象
特點:
1.所以變量都是public static final
2.所有方法都是public abstract
class interfaceTest implements Interface1
接口可以被類多實現,一個類中可以實現多個interface:因為多個接口的方法都沒有主體;
一個類在繼承一個父類的同時,可以實現多個接口;
接口之間可以繼承,並且一個接口可以繼承多個接口
接口的特點:降低了耦合性
多態:
函數的多態體現:重載和覆蓋
多態的體現:
父類的引用指向了自己的子類對象
父類的引用也可以接受自己的子類對象
多態的前提:
類與類有關系,要么是繼承,要么是實現;
存在覆蓋;
多態的好處:
提高了程序的擴展性,但是只能使用父類的引用訪問父類中的成員
多態的應用:
多態中(非靜態)成員函數的特點:
編譯時期:參閱引用型變量所屬的類中是否有調用的方法,如果有,則編譯可以通過
運行時期:參閱對象所屬類中是否有調用方法
Fu z = new zi();
編譯時,看左邊的Fu類
運行時,看右邊的zi類
面試注意點:
多態中成員變量和(靜態)成員函數的特點:
無論編譯或運行,都參考左邊
靜態綁定,只看引用,只參考左邊;
動態綁定,
如果每個子類每次都要調用父類中的共性方法,可以在主函數中或者一個類中創建一個共性方法,
參數以父類對象為准,調用的時候只需要將子類對象傳入即可.
object類:所有類的直接或間接父類
內部類:
內部類不用建立對象就可以訪問外部類的成員變量和函數,包括私有
外部類要訪問內部類,必須建立內部類對象
建立在非所屬類中時,需先建立外部類,Outer.Inner in = new Outer().new Inner();
內部類可以私有
內部類訪問外部類成員變量 Outer.this.x
注意:當內部類中定義了靜態成員,則該內部類必須也是靜態的
當外部類中的靜態方法訪問內部類時,內部類也必須是靜態的
局部內部類不能靜態
內部類定義在局部時,不可以被成員修飾符修飾
可以直接訪問外部類中的成員
但是不可以訪問所在局部中的變量,只能訪問被final修飾的局部變量
成員修飾符(Static,private…)只能修飾成員變量
下面這個例子不會報錯!
Out.method(7);執行完后就會釋放內存!
因此out.method(8);會重新加載
匿名內部類:
前提,內部類必須是繼承一個類或者實現接口
abstract class Absdemo
{ abstract void show();}
class Outer
{
...
public void function()
{
new Absdemo()//這是一個Absdemo的一個匿名子類對象
{
void show()
{
System.out.println("匿名內部類!");
}
}.show();
}
...
}
格式:new 父類或者接口(){定義子類內容};
其實匿名內部類是一個匿名子類對象,而且這個對象是帶有內容的
匿名內部類中定義的方法最好不要超過3個(方法比較多的話就直接創建一個有名字的子類)
上圖中d.abc();會編譯失敗,因為Absdemo中未定義abc();
AbsDemo d = new AbsDemo(){};//多態