1. 程式人生 > >this關鍵字、super關鍵字、final關鍵字、static關鍵字

this關鍵字、super關鍵字、final關鍵字、static關鍵字

1、this關鍵字

(1)功能:

------------------------(一)呼叫本類中的屬性,也就是成員變數。哪個物件呼叫了this所在函式,this就代表哪個物件。

------------------------(二)呼叫本類中的其他方法

------------------------(三)呼叫本類中的其他構造方法,呼叫時要放在構造方法的首行

public class TestThis {
    public static void main(String[] args) {
        Person2 p = new Person2(10,"daming");
        p.show();
        Person2 p1 
= new Person2(20); p1.show(); } } public class Person2{ private int age; private String name; public Person2(){ System.out.println("呼叫了無參建構函式"); } public Person2(int a){ this(); age = a; System.out.println("呼叫了有參建構函式包含年齡"+"age="+age); } public Person2(
int a,String n){ this(a); age = a; name = n; System.out.println("呼叫了有參建構函式包含年齡和名稱"+"age="+age+"--"+"name="+name); } public void show(){ System.out.println("呼叫了有參建構函式void---"+"age="+age+"--"+"name="+name); } } /* p.show(); 呼叫了無參建構函式 呼叫了有參建構函式包含年齡age=10 呼叫了有參建構函式包含年齡和名稱age=10--name=daming 呼叫了有參建構函式void---age=10--name=daming p1.show(); 呼叫了無參建構函式 呼叫了有參建構函式包含年齡age=20 呼叫了有參建構函式void---age=20--name=null
*/

 (2)呼叫構造方法

構造方法之間的呼叫,可以通過this關鍵字來完成。

構造方法呼叫格式:

this(引數列表);

package demo03;

public class Person {
    private String name;
    private int age;
    //空參構造
    public Person(){    
    
    }
    // 給姓名初始化的構造方法
    public Person(String nm){
        name = nm;
    }
    // 給姓名和年齡初始化的構造方法
    public Person(String nm, int a) {
        // 由於已經存在給姓名進行初始化的構造方法 name = nm;
        //因此只需要呼叫即可
        // 呼叫其他構造方法,需要通過this關鍵字來呼叫
        this(nm);
        // 給年齡初始化
        age = a;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    
}
package demo03;

public class Test {

    public static void main(String[] args) {
        Person a = new Person("a",2);
        a.setAge(1);
        
        System.out.println(a.getAge()+a.getName());
        

    }

}

this原理圖解:

Public class Person {
    private int age;
    private String name;

    Person() {
    }
    Person(String nm) {
        name = nm;
    }
    Person(String nm, int a) {
        this(nm);
        age = a;
    }
}

class PersonDemo {
    public static void main(String[] args) {
        Person p = new Person("張三", 23);
    }
}

 

圖例解釋:

(自己的理解)先執行main方法,main方法壓棧,然後執行new person()

看到new一個物件,就在堆中劃出一塊區域,分配記憶體地址,接著成員變數預設值初始化;

構造方法Person(String nm , int a))壓棧,將“張三”傳遞給nm,23傳給age,當賦值結束後,Person(String nm , int a)彈棧。

Person物件在記憶體中建立完成,並將0x33賦值給main方法中的p引用變數。

官方解釋:

1、先執行main方法,main方法壓棧,執行其中的new Person(“張三”,23);

2、堆記憶體中開闢空間,併為其分配記憶體地址0x33,,緊接著成員變數預設初始化(name=null  age = 0);

3、擁有兩個引數的構造方法(PersonString nm , int a))壓棧,在這個構造方法中有一個隱式的this,因為構造方法是給物件初始化的,那個物件呼叫到這個構造方法,this就指向堆中的那個物件。

4、由於PersonString nm , int a)構造方法中使用了this(nm);構造方法Person(String nm)就會壓棧,並將“張三”傳遞給nm。在PersonString nm , int a)構造方法中同樣也有隱式的thisthis的值同樣也為0x33,這時會執行其中name = nm,即把“張三”賦值給成員的name。當賦值結束後PersonString nm , int a)構造方法彈棧。

5、程式繼續執行構造方法(PersonString nm , int a)中的age = a;這時會將23賦值給成員屬性age。賦值結束構造方法(PersonString nm , int a)彈棧。

6、當構造方法(PersonString nm , int a)彈棧結束後,Person物件在記憶體中建立完成,並將0x33賦值給main方法中的p引用變數。

 this代表什麼:

this代表的是物件,具體代表哪個物件呢?哪個物件呼叫了this所在的方法,this就代表哪個物件。

呼叫其他構造方法的語句必須定義在構造方法的第一行,原因是初始化動作要最先執行。

(3)成員變數與區域性變數同名問題:可以在成員變數名前面加上this.來區別成員變數和區域性變數

public class Person {
    private int age;
    private String name;

    // 給姓名和年齡初始化的構造方法
    public Person(String name, int age) {
        // 當需要訪問成員變數是,只需要在成員變數前面加上this.即可
        this.name = name;
        this.age = age;
    }

    public void speak() {
        System.out.println("name=" + this.name + ",age=" + this.age);
    }
}
public class PersonDemo {
    public static void main(String[] args) {
        Person p = new Person("張三", 23);
        p.speak();
    }
}

 this應用:

package demo05;

public class Person {
    private int age;
    private String name;

    // 給姓名和年齡初始化的構造方法
    public Person(String name, int age) {
        // 當需要訪問成員變數是,只需要在成員變數前面加上this.即可
        this.name = name;
        this.age = age;
    }

    public void speak() {
        System.out.println("name=" + this.name + ",age=" + this.age);
    }

    // 判斷是否為同齡人
    public boolean equalsAge(Person p) {
        // 使用當前呼叫該equalsAge方法物件的age和傳遞進來p的age進行比較
        // 由於無法確定具體是哪一個物件呼叫equalsAge方法,這裡就可以使用this來代替
        /*
         * if(this.age == p.age) { return true; } return false;
         */
        return this.age == p.age;
    }
}
public class Teat {

    public static void main(String[] args) {
        Person a=new Person("張三",18);
        a.speak();
        Person b=new Person("李四",20);
        b.speak();
        boolean bs=a.equalsAge(b);//-----------------------------------------比較
        System.out.println(bs);
    }

}

2、super關鍵字

(1)子父類中構造方法的呼叫

格式:

呼叫本類中的構造方法

this(實參列表);

呼叫父類中的空引數構造方法

super();

呼叫父類中的有引數構造方法

super(實參列表);

例如:

為什麼子類物件建立都要訪問父類中的構造方法?因為子類繼承了父類的內容,所以建立物件時,必須要先看父類是如何對其內容進行初始化的,看如下程式:

public class Fu{
    int num ;
   public Fu(){
        System.out.println("Fu構造方法"+num);//-----------------------------------------------------------------空參構造
        num = 4;
    }
}
public  class Zi extends Fu{
  public  Zi(){
         //super(); 呼叫父類空引數構造方法
        System.out.println("Zi構造方法"+num);//-------------------------------------------------------------------
    }
}
public class Test {
    public static void main(String[] args) {
        new Zi();//-----------------------------------------------------------------------------------------------
    }
    
}

子類構造方法執行時中,呼叫了父類構造方法,這說明,子類構造方法中有一句super()

子類會繼承父類中的內容,所以子類在初始化時,必須先到父類中去執行父類的初始化動作。這樣,才可以使用父類中的內容。

當父類中沒有空引數構造方法時,子類的構造方法必須有顯示的super語句,指定要訪問的父類有引數構造方法。

 子類物件建立中的注意點:

一、如果子類的構造方法第一行寫了this呼叫了本類其他構造方法,那麼super呼叫父類的語句是沒有的。

因為this()或者super(),只能定義在構造方法的第一行,因為初始化動作要先執行。

二、父類構造方法中有隱式的super,只要是構造方法預設第一行都是super();

三、super呼叫的是所有物件的父類Object構造方法(Java體系在設計,定義了一個所有物件的父類Object)

 注意:

類中的構造方法預設第一行都有隱式的super()語句,在訪問父類中的空引數構造方法。所以父類的構造方法既可以給自己的物件初始化,也可以給自己的子類物件初始化。

如果預設的隱式super()語句在父類中沒有對應的構造方法,那麼必須在構造方法中通過this或者super的形式明確要呼叫的構造方法。

 練習:

練習:描述學生和工人這兩個類,將他們的共性nameage抽取出來存放在父類中,並提供相應的getset方法,同時需要在建立學生和工人物件就必須明確姓名和年齡

package lianxi2;

public class Person {
    private String name;
    private int age;
    public Person(String name,int age){
        this.name=name;
        this.age=age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    
}
package lianxi2;

public class Student extends Person{
    //Student類的構造方法
    public Student(String name,int age){
        // 使用super關鍵字呼叫父類構造方法,進行相應的初始化動作
        super(name,age);
    }
    public void study(){
        System.out.println(this.getName()+"同學正在學習");
    }
}
package lianxi2;

public class Worker extends Person{
    public Worker(String name, int age){
        // 使用super關鍵字呼叫父類構造方法,進行相應的初始化動作
        super(name, age);
    }
    public void work(){
        System.out.println(this.getName() + "工人在工作");
    }
}
package lianxi2;

public class Test {

    public static void main(String[] args) {
        Student stu = new Student("小明",23);
        stu.study();        
        Worker w = new Worker("小李",45);
        w.work();
    }

}

 3、final關鍵字

(1)final 關鍵字的概述:

類中的部分方法功能是固定的,不想讓子類重寫。可是當子類繼承了這些特殊類之後,就可以對其中的方法進行重寫,要解決這個問題(讓子類無法對父類中的某一方法進行重寫)

需要使用到一個關鍵字finalfinal的意思為最終,不可變。final是個修飾符,它可以用來修飾類,類的成員,以及區域性變數。不能修飾構造方法。

 (2)final的特點:

---------------------final修飾不可以被繼承,但是可以繼承其他類。

 例如:

public class person {}//定義一個person類
public final class Fu extends person{} //定義一個父類,繼承了person類
public class Zi extends Fu{} //定義子類,因為父類中使用了final所以不能繼承Fu類

 ------------------- final修飾的方法不可以被子類重寫,但父類中沒有被final修飾方法,子類重寫後可以加final。

 例如:

Public class Fu {    //=================================定義父類
    // final修飾的方法,不可以被覆蓋,但可以繼承使用
    public final void method1(){}//====================應用了final修飾的method1
    public void method2(){}//==========================定義一個方法method2
}
Public class Zi extends Fu {//====================定義一個子類,繼承了父類的方法(method1沒有被繼承,無法重寫,因為method1方法應用了final修飾)
    //重寫method2方法
    public final void method2(){}//==================重寫method2
}

 --------------------------------final修飾的變數稱為常量,這些變數只能賦值一次。而且終身不變。

 例如:

final int i = 20;
i = 30; //賦值報錯,final修飾的變數只能賦值一次,一次賦值,終生不變

 ------------------------------ 引用型別的變數值為物件地址值,地址值不能更改,但是地址內的物件屬性值可以修改。(也是一次賦值終生不變)

 例如:

final Person p = new Person();

Person p2 = new Person();

p = p2; //final修飾的變數p,所記錄的地址值不能改變

p.name = "小明";//可以更改p物件中name屬性值

Person p2 = new Person();

p = p2; //final修飾的變數p,所記錄的地址值不能改

p.name = "小明";//可以更改p物件中name屬性值

 ----------------------------------- 修飾成員變數,需要在建立物件前賦值,否則報錯。(當沒有顯式賦值時,多個構造方法的均需要為其賦值。)

 例如:

public class Demo {
    //直接賦值
    final int m = 100;
    
    //final修飾的成員變數,需要在建立物件前賦值,否則報錯。
    final int n; 
    public Demo(){
        //可以在建立物件時所呼叫的構造方法中,為變數n賦值
        n = 2016;
    }
}

final應用舉例:

//final修飾類(太監類)
//不能被繼承,但可以繼承其他類
public final class Fu {

}
public class Fu2 {
public final void xiuche(){
    System.out.println("失傳的修車手藝");
}
public void maiche(){
    System.out.println("這是祖傳的買車手藝");
}
}
public class Zi extends Fu2{
    public final void maiche(){
        System.out.println("失傳的mai車手藝");
    }
}
public class Zi2 {
    public void eat(){
        final int i;
        i=3;
        //final Fu2 f=new Fu2();
        Fu2 f=new Fu2();
        f=null;
    }
}
//被final修飾的成員變數沒有預設賦值
public class Zi3 {
    final String name="小明";//必須賦值
}

 4、static關鍵字

(1)static關鍵字概述:

-----------------------------不建立物件,就可以呼叫方法,可以通過static關鍵字來實現。static它是靜態修飾符,一般用來修飾類中的成員。

 (2)static的特點:

-------------static修飾的成員變數屬於類,不屬於這個類的某個物件。

 (也就是說,多個物件在訪問或修改static修飾的成員變數時,其中一個物件將static成員變數值進行了修改,其他物件中的static成員變數值跟著改變,即多個物件共享同一個static成員變數)

 舉例說明:

public class Demo {
    public static int num = 100;//==========================被static修飾過
}
public class Test {
    public static void main(String[] args) {
        Demo d1 = new Demo();
        Demo d2 = new Demo();
        d1.num = 200;
        System.out.println(d1.num); //結果為200
        System.out.println(d2.num); //結果為200
    }//============================================其中一個更改了結果,所有的就都改過來了所以結果為200
}

-------------------------------------static修飾的成員可以並且建議通過類名直接訪問。

 例如:

public class Student {
    String name;
    int age;
    static String schoolname;
}
public class Test {
    public static void main(String[] args) {
        Student s=new Student();
        s.name="小紅";
        s.age=18;
        Student.schoolname="背景大學";//本來按照平時習慣應該是s.schoolname="背景大學",但被static修飾過所以建議改成直接用類名訪問
        Student s2=new Student();
        s2.name="小明";
        s2.age=18;
        Student.schoolname="清華大學";
                
        System.out.println(Student.schoolname+"..."+Student.schoolname);
    }

}

 注意:

--------------------------------- 靜態內容是優先於物件存在,只能訪問靜態,不能使用this/super。靜態修飾的內容存於靜態區。

- -------------------------------同一個類中,靜態成員只能訪問靜態成員

---- ---------------------------- main方法為靜態方法僅僅為程式執行入口,它不屬於任何一個物件,可以定義在任意類中。

---------------------------------多型呼叫方法中,編譯看=左邊,父類有,編譯成功,父類沒有,編譯失敗

            執行,靜態方法,執行父類中的靜態方法,

            執行,非靜態方法,執行子類的重寫方法

            成員變數,編譯執行全是父類

 定義靜態常量時:

在類中定義一個靜態常量,通常使用public static final修飾的變數來完成定義。此時變數名用全部大寫,多個單詞使用下劃線連線。

定義格式:

public static final 資料型別 變數 = ;

 例如:

class School {
    public static final String SCHOOL_NAME = "北京大學";
    public static void method(){
        System.out.println("一個靜態方法");
    }
}

當我們想使用類的靜態成員時,不需要建立物件,直接使用類名來訪問即可

System.out.println(School.SCHOOL_NAME); 
School.method(); // 呼叫一個靜態方法

介面中的每個成員變數都預設使用public static final修飾。

所有介面中的成員變數已是靜態常量,由於介面沒有構造方法,所以必須顯示賦值。可以直接用介面名訪問。

interface Inter {
    public static final int COUNT = 100;
}

訪問介面中的靜態變數

Inter.COUNT