1. 程式人生 > >Java架構-JavaSE(三)之static、final、abstract修飾符

Java架構-JavaSE(三)之static、final、abstract修飾符

閱讀目錄(Content)

一、static修飾符
  1.1、static變數
  1.2、static方法
1.3、程式碼塊和靜態程式碼塊
1.4、建立和初始化物件的過程
二、final修飾符
2.1、修飾類
2.2、修飾方法
2.3、修飾變數
三、abstract修飾符
  3.1、抽象類和抽象方法的關係
  3.2、語法
  3.3、特點及作用
  3.4、思考
一、static修飾符
  1.1、static變數
在類中,使用static修飾的成員變數,就是靜態變數,反之為非靜態變數。

    靜態變數和非靜態變數的區別
        靜態變數屬於類的,"可以"使用類名來訪問,非靜態變數是屬於物件的,"必須"使用物件來訪問.

	 public class Student{
                private static int age;
                private double score;
                public static void main(String[] args) {
                    Student s = new Student();
                    //推薦使用類名訪問靜態成員
                    System.out.println(Student.age);
                    System.out.println(s.age);

                    System.out.println(s.score);
                }
            }

靜態變數對於類而言在記憶體中只有一個,能被類的所有例項所共享。例項變數對於類的每個例項都有一份,它們之間互不影響.
例如:

public class Student{
private static int count;
private int num;
public Student() {
count++;
num++;
}
public static void main(String[] args) {
Student s1 = new Student();
Student s2 = new Student();
Student s3 = new Student();
Student s4 = new Student();
//因為還是在類中,所以可以直接訪問私有屬性
System.out.println(s1.num);
System.out.println(s2.num);
System.out.println(s3.num);
System.out.println(s4.num);

                System.out.println(Student.count);
                System.out.println(s1.count);
                System.out.println(s2.count);
                System.out.println(s3.count);
                System.out.println(s4.count);
            }
        }

在載入類的過程中為靜態變數分配記憶體,例項變數在建立物件時分配記憶體
所以靜態變數可以使用類名來直接訪問,而不需要使用物件來訪問.

1.2、static方法
在類中,使用static修飾的成員方法,就是靜態方法,反之為非靜態方法。

    靜態方法和非靜態方法的區別
        靜態方法數屬於類的,"可以"使用類名來呼叫,非靜態方法是屬於物件的,"必須"使用物件來呼叫.
    
    靜態方法"不可以"直接訪問類中的非靜態變數和非靜態方法,但是"可以"直接訪問類中的靜態變數和靜態方法
        注意:this和super在類中屬於非靜態的變數.(靜態方法中不能使用)
        例如:    
         public class Student{
            private static int count;
            private int num;
            public void run(){}
            public static void go(){}
            

            public static void test(){
                //編譯通過
                System.out.println(count);
                go();
                
                //編譯報錯
                System.out.println(num);
                run();
            }

        }

非靜態方法"可以"直接訪問類中的非靜態變數和非靜態方法,也"可以"直接訪問類中的靜態變數和靜態方法
例如:

         public class Student{
            private static int count;
            private int num;
            public void run(){}
            public static void go(){}

            public void test(){
                //編譯通過
                System.out.println(count);
                go();
                
                //編譯通過
                System.out.println(num);
                run();
            }

        }
    思考:為什麼靜態方法和非靜態方法不能直接相互訪問?
            
    父類的靜態方法可以被子類繼承,但是不能被子類重寫
        例如:
        
        public class Person {
                 public static void method() {}
            }
            
            //編譯報錯
            public class Student extends Person {
                 public void method(){}
            }


        例如:
            public class Person {
                 public static void test() {
                    System.out.println("Person");
                 }
            }
            
            //編譯通過,但不是重寫
            public class Student extends Person {
                 public static void test(){
                    System.out.println("Student");
                 }
            }
            main:
                Perosn p = new Student();
                p.test();//輸出Person
                p = new Person();
                p.test();//輸出Perosn

            和非靜態方法重寫後的效果不一樣
           
    父類的非靜態方法不能被子類重寫為靜態方法    
        例如:

            public class Person {
                 public void test() {
                    System.out.println("Person");
                 }
            }
            
            //編譯報錯
            public class Student extends Person {
                 public static void test(){
                    System.out.println("Student");
                 }
            }

1.3、程式碼塊和靜態程式碼塊
1)類中可以編寫程式碼塊和靜態程式碼塊
例如:
public class Person {
{
//程式碼塊(匿名程式碼塊)
}

            static{
                //靜態程式碼塊
            }
        }
    
    2)匿名程式碼塊和靜態程式碼塊的執行
        因為沒有名字,在程式並不能主動呼叫這些程式碼塊。

        匿名程式碼塊是在建立物件的時候自動執行的,並且在構造器執行之前。同時匿名程式碼塊在每次建立物件的時候都會自動執行.

        靜態程式碼塊是在類載入完成之後就自動執行,並且只執行一次.

        注:每個類在第一次被使用的時候就會被載入,並且一般只會載入一次.

        例如:
   	     public class Person {
              {
                    System.out.println("匿名程式碼塊");
                 }

               static{
                     System.out.println("靜態程式碼塊");
                 }
                 public Person(){
                   System.out.println("構造器");
                 }
            }
             main:
                Student s1 = new Student();
                Student s2 = new Student();
                 Student s3 = new Student();


                //輸出結果:
                靜態程式碼塊
                匿名程式碼塊
                構造器
                匿名程式碼塊
                構造器
                匿名程式碼塊
                構造器

    3)匿名程式碼塊和靜態程式碼塊的作用
        匿名程式碼塊的作用是給物件的成員變數初始化賦值,但是因為構造器也能完成這項工作,所以匿名程式碼塊使用的並不多。

        靜態程式碼塊的作用是給類中的靜態成員變數初始化賦值。
        例如:

![public class Person {
public static String name;
static{
name = “tom”;
}
public Person(){
name = “zs”;
}
}
main:
System.out.println(Person.name);//tom]

            注:在構造器中給靜態變數賦值,並不能保證能賦值成功,因為構造器是在建立物件的時候才指向,但是靜態變數可以不建立物件而直接使用類名來訪問.          

1.4、建立和初始化物件的過程

     Student s = new Student();
        4.1)Student類之前沒有進行類載入
            1、類載入,同時初始化類中靜態的屬性
            2、執行靜態程式碼塊
            3、分配記憶體空間,同時初始化非靜態的屬性(賦預設值,0/false/null)
            4、呼叫Student的父類構造器
            5、對Student中的屬性進行顯示賦值(如果有的話)
            6、執行匿名程式碼塊
            7、執行構造器
            8、返回記憶體地址

            注:子類中非靜態屬性的顯示賦值是在父類構造器執行完之後和子類中的匿名程式碼塊執行之前的時候

例如:
在這裡插入圖片描述

            //輸出結果:
            Student靜態程式碼塊
            Person構造器
            student print方法: name = null
            Student匿名程式碼塊
            Student構造器


        Student s = new Student();
       4. 2)Student類之前已經進行了類載入
            1.分配記憶體空間,同時初始化非靜態的屬性(賦預設值,0/false/null)
            2.呼叫Student的父類構造器
            3.對Student中的屬性進行顯示賦值(如果有的話)
            4.執行匿名程式碼塊
            5.執行構造器
            6.返回記憶體地址

5)靜態匯入
    靜態匯入是JDK5.0引入的新特性。

例如:
在這裡插入圖片描述

二、final修飾符
2.1、修飾類
用final修飾的類不能被繼承,沒有子類。
例如:我們是無法寫一個類去繼承String類,然後對String型別擴充套件的,因為API中已經被String類定義為final的了.
我們也可以定義final修飾的類:
在這裡插入圖片描述
2.2、修飾方法
用final修飾的方法可以被繼承,但是不能被子類的重寫。
例如:每個類都是Object類的子類,繼承了Object中的眾多方法,在子類中可以重寫toString方法、equals方法等,但是不能重寫getClass方法 wait方法等,因為這些方法都是使用fianl修飾的。

    我們也可以定義final修飾的方法:     

在這裡插入圖片描述
2.3、修飾變數
用final修飾的變量表示常量,只能被賦一次值.其實使用final修飾的變數也就成了常量了,因為值不會再變了。

    1)修飾區域性變數:
    例如:

在這裡插入圖片描述

2)修飾成員變數:
        非靜態成員變數:
            public class Person{
                private final int a;
            }
            只有一次機會,可以給此變數a賦值的位置:
                宣告的同時賦值
                匿名程式碼塊中賦值
                構造器中賦值(類中出現的所有構造器都要寫)
            
        靜態成員變數:
            public class Person{
                private static final int a;
            }
            只有一次機會,可以給此變數a賦值的位置:
                宣告的同時賦值
                靜態程式碼塊中賦值
        
3)修飾引用變數 

在這裡插入圖片描述

三、abstract修飾符
abstract修飾符可以用來修飾方法也可以修飾類,如果修飾方法,那麼該方法就是抽象方法;如果修飾類,那麼該類就是抽象類。

3.1、抽象類和抽象方法的關係
   抽象類中可以沒有抽象方法,但是有抽象方法的類一定要宣告為抽象類。

3.2、語法
    public abstract class Action{
   public abstract void doSomething();
   }

      public void doSomething(){...}
      對於這個普通方法來講:
      "public void doSomething()"這部分是方法的宣告
      "{...}"這部分是方法的實現,如果大括號中什麼都沒寫,就叫方法的空實現

      宣告類的同時,加上abstract修飾符就是抽象類
      宣告方法的時候,加上abstract修飾符,並且去掉方法的大口號,同時結尾加上分號,該方法就是抽象方法。

3.3、特點及作用
     抽象類,不能使用new關鍵在來建立物件,它是用來讓子類繼承的。
  抽象方法,只有方法的宣告,沒有方法的實現,它是用來讓子類實現的。

      注:子類繼承抽象類後,需要實現抽象類中沒有實現的抽象方法,否則這個子類也要宣告為抽象類。
      例如:
          public abstract class Action{
              public abstract void doSomething();
          }
          main:
              //編譯報錯,抽象類不能new物件
              Action a = new Action();
        
          //子類繼承抽象類
          public class Eat extends Action{
              //實現父類中沒有實現的抽象方法
              public void doSomething(){
                  //code
              }
          }

          main:
              Action a = new Eat();
              a.doSomething();
           
          注:子類繼承抽象類,那麼就必須要實現抽象類沒有實現的抽象方法,否則該子類也要宣告為抽象類。

3.4、思考
    思考1:抽象類不能new物件,那麼抽象類中有沒有構造器?
    思考2:抽象類和抽象方法意義(為什麼要編寫抽象類、抽象方法)
     有抽象方法的抽象類
     無抽象方法的抽象類
為什麼某些人會一直比你優秀,是因為他本身就很優秀還一直在持續努力變得更優秀,而你是不是還在滿足於現狀內心在竊喜!
合理利用自己每一分每一秒的時間來學習提升自己,不要再用"沒有時間“來掩飾自己思想上的懶惰!趁年輕,使勁拼,給未來的自己一個交代!

還是那句話,希望此文能幫到大家的同時,也聽聽大家的觀點。歡迎留言討論,加關注,分享你的高見!持續更新!

To-陌霖Java架構

分享網際網路最新文章 關注網際網路最新發展