1.類與對象的定義與使用
① 類與對象的概念
所謂類,是一個共性的概念,而對象指的是一個具體的、可以使用的事物。
首先産生類(類是生産對象的藍圖),而後才可以産生對象,對象的所有行為一定在類中進行了完整的定義。
類的組成:
1.屬性(變量,描述每個對象的具體特點)
2.方法(操作的行為)
② 類與對象的定義與使用
- 定義一個類
文法如下:
class 類名稱{
屬性1;
屬性2;
...
屬性n;
方法1(){};
方法2(){};
...
方法n(){};
}
注意:此時的方法不再由主類直接調用,而是由該類的執行個體化對象進行調用
類對象執行個體化文法:
類名稱 類對象名稱 = new 類名稱();
示例:定義一個Person類并執行個體化類對象
class Person{
public String name;
public int age;
public Person(String n,int a){
name = n;
age = a;
}
public void getPersonInfo(){
System.out.println("姓名:" + name + ",年齡" + age);
}
}
public class Test{
Person p1 = new Person("李四",19);//直接通過構造函數執行個體化
Person p2 = new Person();
//通過對象修改類屬性、調用類方法
p2.name = "張三";
p2.age = 18;
p1.getPersonInfo();
p2.getPersonInfo();
}
注意:隻要出現了關鍵字new,就開辟了記憶體空間;
Java中,所謂的性能調優,調整的就是記憶體問題。
③ 對象記憶體分析
棧記憶體(虛拟機局部變量表):存放局部變量(包含編譯期可知的各種基本資料類型,對象引用-即堆記憶體位址,可以簡單了解為對象的名稱)。
Java棧是與線程對應起來的,每當建立一個線程,JVM就會為這個線程建立一個對應的Java棧。
堆記憶體:儲存真正的資料。即對象的屬性資訊。
代碼示例:
class Person{
String name;
int age;
}
public class Test{
public static void main(String[] args){
Person per = new Person();
per.name = "張三";
per.age = 30;
}
}
對于主函數中的第一條語句:Person per = new Person();//在堆上配置設定記憶體并産生Person類的對象per引用這部分記憶體。
記憶體分析如下:
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsICM38FdsYkRGZkRG9lcvx2bjxiNx8VZ6l2cs0TW65kMVRUT1kkeONTR6hVMs5mYwh2MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL5QjM4QzNwEDM2IDOwkTMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
接下來兩句:
per.name = "張三";
per.age = 30;
記憶體圖分析如下:
注意:對象必須在執行個體化之後調用,否則會産生NullPointerExecption(運作時錯誤),編譯時不會出錯;
隻有引用類型(數組、類、接口)才會産生此類異常,是以在後續寫代碼過程中如果出現此類異常,就可以根據出錯位置檢視引用資料類型是否初始化。
④ 引用傳遞分析
本質:一塊堆記憶體可以被多個棧記憶體所指向
代碼示例:
Person p1 = new Person();
Person p2 = new Person();
p2 = p1;
記憶體分析圖如下:
垃圾空間:沒有任何棧記憶體指向的堆記憶體空間
所有的垃圾空間會不定期GC,GC不會影響性能,是以在開發中一定要控制好對象的産生數量(無用的對象盡可能少産生)
2.private實作封裝處理&構造方法(匿名對象)
① private實作封裝處理
以上所寫的所有程式都屬于無封裝程式。
在不進行封裝的情況下,在主類中可以任意對Person類的對象屬性進行修改。此時,要回避此類問題,讓類内部操作堆外部不可見(對象不能直接操作屬性),可以使用private進行封裝。
示例:在Person類中使用private封裝屬性
private String name;
private int age;
此時使用private堆屬性進行了封裝,要通路私有屬性,按照Java的設計原則必須在類中提供以下兩種方法:
1.getter方法:主要用于進行屬性内容的設定和修改
2.getter方法:主要用于屬性内容的取得
示例:擴充Person類中的方法,實作對Person類屬性的封裝
class Person{
private String name;
private int age;
public void setName(String a){
name = n;
}
public String getName(){
return name;
}
public void setAge(int i){
if(i > 0 && i <= 100){
age = i;
}else{
age = 0;
}
}
public int getAge(){
return age;
}
public void getPersonInfo(){
return "姓名:"+name+",年齡:"+age;
}
}
public class Test{
public static void main(String[] args){
Person p = new Person();
p.setName("張三");
p.setAge(18);
p.getPersonInfo();
}
}
通過以上代碼我麼可以發現,private實作封裝的最大特征在于:隻允許本類通路,而不允許外部類通路。
- 類的設計原則:
1)在編寫類時,類中的所有屬性必須使用private封裝
2)屬性若要被外部通路,必須定義setter、getter方法。
②構造方法與匿名對象
回顧産生對象的方法:
①類名稱 ②對象名稱 = ③new ④類名稱();
- ① 任何對象都有對應的類,類時對象的藍圖 ;
- ② 對象名稱是一個唯一的标記,引用一塊堆記憶體;
- ③ new表示開辟新的堆記憶體空間;
- ④ 構造方法
通過上述分析可知,所謂的構造方法就是使用關鍵字new執行個體化新對象來進行調用的操作方法。對于構造方法的定義,也需要遵循以下原則:
1.方法名必須與類名稱相同;
2.構造方法沒有傳回值類型聲明;
3.每一個類中一定至少存在一個構造方法(沒有明确定義,則系統自動生成一個無參構造)
問題:構造方法無傳回值,為什麼沒有void聲明?
首先我們先來看一下類的組成:屬性、構造方法、普通方法
1.屬性是在對象開辟堆記憶體時開辟的空間;
2.構造方法是在使用new後調用的;
3.普通方法是在空間開辟了,構造方法執行之後可以多次調用的。
部分代碼示例:
public void Person(){} //命名不标準的普通方法
public Person(){} //無參構造方法
從以上描述我們可以看出,編譯器是根據程式結構來區分普通方法和構造方法的,是以在構造方法前沒有傳回值類型聲明。
若類中定義了構造方法,則預設的無參構造将不再生成。
示例:使用構造方法設定對象屬性
class Person{
private String name;
private int age;
public Person(String n,int a){
name = n;
age = a;
}
public void setName(String n){
name = n ;
}
public String getName(){
return name;
}
public void setAge(int i){
if (i>0&&i<=200) {
age = i ;
}else {
age = 0 ;
}
}
public int getAge(){
return age;
}
public void getPersonInfo(){
System.out.println("姓名:"+name+",年齡:"+age);
}
}
public class Test{
public static void main(String[] args) {
Person person = new Person("張三",-200);//使用構造函數對對象屬性進行指派
person.getPersonInfo();
}
}
構造方法的調用和對象記憶體配置設定幾乎是同步完成的,是以我們可以利用構造方法來為類中的屬性進行初始化操作(可以避免多次的setter調用)
構造方法重載:參數類型或個數不同
示例:
public Person(){
System.out.println("---無參構造---");
}
public Person(String n){
name = n;
System.out.println("---有參構造---");
}
建議:若幹構造方法,最好按照參數個數升序或降序編寫;
在進行類定義時:①定義屬性-->②定義構造方法-->③定義普通方法
範例:匿名對象
new Person("張三",20).getPersonInfo();
注意:由于匿名對象不會有任何的棧空間指向,是以使用一次後就成為垃圾空間。
3.this關鍵字
① 用途
ⅰthis調用本類屬性
ⅱ this調用本類方法
ⅲ this表示目前對象
② this調用本類屬性
代碼示例:不用this關鍵字時
class Person{
private String name;
private int age;
public Person(String name,int age){
name = name ;
age = age ;
}
public String getPersonInfo(){
return "姓名:" + name + ",年齡:"+age;
}
}
public class Test{
public static void main(String[] args) {
Person per = new Person("張三",20);
System.out.println(per.getPersonInfo());
}
}
通過上述代碼我們可以發現:當參數與類中屬性同名時,類中屬性無法被正确指派。此時若加上this關鍵字就可以解決這個問題。
示例:使用this關鍵字修改上述代碼
public Person(String name,int age){
this.name = name;
this.age = age;
}
為了避免類似問題,隻要在類中方法通路類中屬性,一定要加this關鍵字。
②this調用本類方法
this調用本類方法有兩種情況:
ⅰ調用普通方法:this.方法名稱(參數);
ⅱ 調用構造方法:this(參數);
示例:this調用普通方法
class Person{
private String name;
private int age;
public Person(String name,int age){
this.name = name;
this,age = age;
this.print(); //this調用普通方法
}
public String getPersonInfo(){
return "姓名:" + name + ",年齡:"+age;
}
public void print(){
System.out.println("*****************");
}
}
public class Test{
public static void main(String[] args) {
Person per = new Person("張三",20);
System.out.println(per.getPersonInfo());
}
}
示例:多個構造函數同時存在
class Person{
private String name;
private int age;
public Person(){
System.out.println("********産生一個新的Person對象********");
}
public Person(String name){
System.out.println("********産生一個新的Person對象********");
this.name = name ;
}
public Person(String name,int age){
System.out.println("********産生一個新的Person對象********");
this.name = name ;
this.age = age ;
}
public String getPersonInfo(){
return "姓名:" + name + ",年齡:"+age;
}
}
public class Test{
public static void main(String[] args) {
Person per1 = new Person();
Person per2 = new Person("張三");
Person per3 = new Person("李四",20);
System.out.println(per1.getPersonInfo());
System.out.println(per2.getPersonInfo());
System.out.println(per3.getPersonInfo());
}
}
Java中支援構造函數的互相調用
示例:this調用構造函數(上述代碼的修改)
public Person(){
System.out.println("---産生一個新的Person對象---");
}
public Person(String name){
this();//調用本類無參構造
this.name = name;
}
public Person(String name,int age){
this(name);//調用本類有參構造
this.age = age;
}
- 使用this調用構造方法時應注意:
1.this調用構造方法的語句必須放在構造方法首行;
2.使用this調用構造方法時,必須留有出口(即不能成環)
④ 使用this表示目前對象
示例:
class Person{
public void print(){
System.out.println("[PRINT]方法:"+this);
}
}
public class Test{
public static void main(String[] args) {
Person p1 = new Person();
System.out.println("[MAIN]方法:"+p1);
p1.print();
System.out.println("=================");
Person p2 = new Person();
System.out.println("[MAIN]方法:"+p2);
p2.print();
}
}
隻要對象調用了本類中的方法,這個this就表示目前執行的對象。
5.static關鍵字
static可以修飾屬性和方法
① static屬性(類屬性)
示例:執行個體屬性的記憶體分析
class Person{
String Country = "中國";
String name;
int age;
public void getPersonInfo(){
System.out.println("姓名:"+this.name+",年齡:"+this.age+",國家:"+this.Country);
}
}
public class Test{
public static void main(String[] args){
Person p1 = new Person();
p1.name = "張三";
p1.age = 19;
Person p2 = newPerson();
p2.name = "李四";
p2.age = 20;
p1.getPersonInfo();
p2.getPersonInfo();
}
}
記憶體圖解:
傳統屬性所具備的特征:儲存在堆記憶體中,且每個對象獨享屬性。
描述共享屬性,隻需要再屬性前添加static關鍵字即可。
static屬性又稱為類屬性,儲存在全局資料區的記憶體之中,所有對象都可以進行該資料區的通路。
若修改上述代碼堆country的定義為:
static String Country = "中國";
此時記憶體分析圖如下:
結論:
1.通路static屬性(類屬性)應使用類名稱.屬性名
2.所有非static屬性(執行個體變量)必須在對象執行個體化後使用,而static屬性(類屬性)不受對象執行個體化控制。
此時,如果我們修改country屬性,所有對象都同步此值
定義類時,如何選擇執行個體變量和類屬性變量?
1.定義類時,一般情況下不會考慮static屬性,以非static屬性為主
2.如果需要描述共享屬性的概念,或者不受對象執行個體化的控制,使用static
② static方法(類方法)
使用static定義的方法,直接通過類名通路
示例:
class Person{
private static String country;
private String name;
private int age;
public Person(String name,int age){
this.name = name;
this.age = age;
}
public static void setCountry(String c){
country = c;
}
public void getPersonInfo(){
System.out.println("姓名:"+this.name+",年齡:"+this.age+",國家:"+this.country);
}
}
public class Test{
public static void main(){
Person.setCountry("中國");
Person person = new Person("張三",18);
person.getPersonInfo();
}
}
注意:
(1)所有static方法不允許調用非static定義的屬性或方法;
(2)所有的非static方法允許通路static方法或屬性。
使用static定義方法的目的:某些方法不希望受類的控制,即可以在沒有執行個體化對象的時候執行(廣泛存在于工具類中)