1 static
1.1 static存在的主要意義
static的主要意義是在於創建獨立於具體對象的域變量或者方法。以致於即使沒有創建對象,也能使用屬性和調用方法!
static關鍵字還有一個比較關鍵的作用就是 用來形成靜態代碼塊以優化程序性能。static塊可以置於類中的任何地方,類中可以有多個static塊。在類初次被加載的時候,會按照static塊的順序來執行每個static塊,並且只會執行一次。
static塊可以用來優化程序性能,是因為它的特性:只會在類加載的時候執行一次。因此,很多時候會將一些只需要進行一次的初始化操作都放在static代碼塊中進行。
1.2 static的獨特之處
(1) 被static修飾的變量或者方法是獨立於該類的任何對象,也就是說,這些變量和方法不屬於任何一個實例對象,而是被類的實例對象所共享。
(2) 在該類被第一次加載的時候,就會去加載被static修飾的部分,而且只在類第一次使用時加載並進行初始化,注意這是第一次用就要初始化,后面根據需要是可以再次賦值的。
(3) static變量值在類加載的時候分配空間,以后創建類對象的時候不會重新分配。賦值的話,是可以任意賦值的!
(4) 被static修飾的變量或者方法是優先於對象存在的,也就是說當一個類加載完畢之后,即便沒有創建對象,也可以去訪問。
1.3 static應用場景
因為static是被類的實例對象所共享,因此如果某個成員變量是被所有對象所共享的,那么這個成員變量就應該定義為靜態變量。
因此比較常見的static應用場景有:
- 修飾成員變量
- 修飾成員方法
- 靜態代碼塊
- 修飾類【只能修飾內部類也就是靜態內部類】
- 靜態導包
1.4 靜態變量和實例變量
1.4.1 概念
靜態變量:
static修飾的成員變量叫做靜態變量【也叫做類變量】,靜態變量是屬於這個類,而不是屬於是對象。
實例變量:
沒有被static修飾的成員變量叫做實例變量,實例變量是屬於這個類的實例對象。
還有一點需要注意的是:static是不允許用來修飾局部變量,不要問我問什么,因為java規定的!
1.4.2 靜態變量和實例變量區別
靜態變量:
靜態變量由於不屬於任何實例對象,屬於類的,所以在內存中只會有一份,在類的加載過程中,JVM只為靜態變量分配一次內存空間。
實例變量:
每次創建對象,都會為每個對象分配成員變量內存空間,實例變量是屬於實例對象的,在內存中,創建幾次對象,就有幾份成員變量。
1.4 static靜態方法
static修飾的方法也叫做靜態方法。
靜態方法,類似於靜態變量,靜態方法也屬於類,不屬於實例的。靜態方法只能訪問類的靜態變量,或調用類的靜態方法。通常靜態方法作為工具方法,被其它類使用,而不需要創建類的實例。
還有一點就是:構造方法不是靜態方法!
1.5 靜態內部類
定義:用static修飾的內部類,稱為靜態內部類,完全屬於外部類本身,不屬於外部類某一個對象。
注意:外部類不可以定義為靜態類,Java中靜態類只有一種,那就是靜態內部類,頂級類不能用static 修飾。
靜態內部類與非靜態內部類之間存在一個最大的區別,我們知道非靜態內部類在編譯完成之后會隱含地保存着一個引用,該引用是指向創建它的外圍內,但是靜態內部類卻沒有。沒有這個引用就意味着:
1、它的創建是不需要依賴外圍類的創建。
2、它不能使用任何外圍類的非static成員變量和方法。
靜態內部類使用案例:
package com.ttbank.flep.core.test; /** * @Author lucky * @Date 2022/1/26 9:16 */ public class Outer { //定義一個實例變量和一個靜態變量 private int a=1; private static int b=2; //定義一個靜態方法 public static void say(){ System.out.println("這是Outer.say方法"); } //定義一個非靜態方法 public void test(){ //在外部類中調用內部類的屬性和方法 Outer.Inner.c = 5; //可以通過靜態內部類的全類名來調用靜態內部類的靜態屬性(外部類名.靜態內部類名.屬性) Outer.Inner.go(); //可以通過靜態內部類的全類名來調用靜態內部類的靜態方法(外部類名.靜態內部類名.方法) //Outer.Inner.walk(); //不能通過類靜態內部類的全類名來調用內部類的非靜態屬性和方法 Inner inner = new Inner(); inner.d = 6; inner.sing(); //可以通過創建內部類實例來調用靜態內部類的非靜態屬性和方法 } public void test1(){ System.out.println("這是Outer的非靜態方法test1方法"); }
//靜態內部類 public static class Inner{ //在靜態內部類中定義一個靜態變量和一個實例變量 static int c=3; int d=4; //定義一個匿名代碼塊 {} //定義一個靜態代碼塊 static{} //定義一個靜態方法和一個普通方法 public static void go(){} public void walk(){ //01 在靜態內部類中調用外部類的屬性和方法 int f = b; System.out.println("內部類普通方法可以直接調用外部類的靜態屬性:"+f); say(); //內部類普通方法直接調用外部類的靜態方法 //int e = a; //內部類普通方法直接調用外部類的非靜態屬性出錯編譯出錯 //test(); //內部類普通方法直接調用外部類的非靜態方法時編譯出錯 System.out.println("內部類可以通過創建外部類實例來調用外部類的非靜態屬性和方法"); Outer outer = new Outer(); int e = outer.a; System.out.println("內部類可以通過創建外部類實例來調用外部類的非靜態屬性:"+e); outer.test1(); //可以通過創建外部類實例來調用外部類的非靜態方法 } public void sing(){ System.out.println("這是Inner類的非靜態方法sing"); } } }
測試類代碼:
public class OuterTest { public static void main(String[] args) { /* * 要想訪問靜態內部類的實例成員,需先創建實例對象,才可以調用,因為實例成員是屬於實例的, 創建方法:外部類名.內部類名 name = new * 外部類名.內部類名() * 通過“ 外部類.內部類.屬性(方法)” 的方式直接調用靜態內部類中的靜態屬性和方法 */ System.out.println("------------------------------------------------------"); Outer.Inner inner=new Outer.Inner(); inner.walk(); System.out.println("通過“ 外部類.內部類.屬性(方法)” 的方式直接調用靜態內部類中的靜態屬性:"+inner.d); System.out.println("-------------------------------------------------------"); Outer outer=new Outer(); outer.test(); } }
控制台輸出:
------------------------------------------------------ 內部類普通方法直接調用外部類的靜態屬性:2 這是Outer.say方法 內部類可以通過創建外部類實例來調用外部類的非靜態屬性和方法 內部類可以通過創建外部類實例來調用外部類的非靜態屬性:1 這是Outer的非靜態方法test1方法 通過“ 外部類.內部類.屬性(方法)” 的方式直接調用靜態內部類中的靜態屬性:4 ------------------------------------------------------- 這是Inner類的非靜態方法sing
總結:
1、靜態內部類中可以寫哪些內容
1)匿名代碼塊
2)靜態代碼塊
3)靜態變量和非靜態變量
4)靜態方法和非靜態方法
注意:不能在靜態內部類中寫抽象方法
2、外部類如何調用靜態內部類中的屬性和方法
1)外部類可以通過創建靜態內部類實例的方法來調用靜態內部類的非靜態屬性和方法
2)外部類可以直接通過“ 外部類.內部類.屬性(方法)” 的方式直接調用靜態內部類中的靜態屬性和方法
3、靜態內部類如何調用外部類的屬性和方法
1)靜態內部類可以直接調用外部類的靜態屬性和方法
2)靜態內部類可以通過創建外部類實例的方法調用外部類的非靜態屬性和方法
4、如何創建靜態內部類實例
1)在非外部類中:外部類名.內部類名 name = new 外部類名.內部類名();
2)在外部類中:內部類名 name = new 內部類名();
1.6 總結
加載機制:static在類加載時初始化(加載)完成
含義:static意為靜態的,但凡被static 修飾說明屬於類,不屬於類的對象。
可修飾:static 可以修飾 內部類、方法、成員變量、代碼塊
。
不可修飾:static不可修飾外部類、局部變量
【static 屬於類的,局部變量屬於其方法,並不屬於類】
注意:static
方法不能兼容this
關鍵字【static代表類層次,this代表當前類的對象】
static主要作用:方便調用沒有創建對象的方法/變量。
2 final
2.1 修飾類
final修飾一個類時,表明這個類不能被繼承。
final class Father{ } class Son extends Father{ //編譯報錯,不能繼承final修飾的類 }
2.2 修飾方法
final修飾方法,方法不可以重寫,但是可以被子類訪問 【前提:方法不是 private 類型】。
class Father{ public final void speak(){ System.out.println("father"); } } class Son extends Father{ //編譯報錯,不能繼承final修飾的類 // public void speak(){ // System.out.println("son"); // } }
2.3 修飾變量
final用得最多的時候就是修飾變量
如果被final修飾的是基本數據類型的變量,則其數值一旦在初始化之后便不能更改;如果是引用類型的變量,則在對其初始化之后便不能再讓其指向另一個對象。
加載:final可以在編譯(類加載)時初始化,也可以在運行時初始化,初始化后不能被改變。
class Father{ public final int a=1; public void method(){ // final修飾基本數據類型的變量,其數值一旦在初始化之后便不能更改 a=2; // final修飾引用類型的變量,其初始化之后便不能再讓其指向另一個對象 final String str=new String(); str=new String(); } }
2.3.1 final修飾成員變量
成員變量必須在定義時或者構造器中進行初始化賦值。
class Father{ public int t; //編譯成功 public final int b; //編譯失敗 public final int c = 1; //編譯成功 }
如果在定義成員變量的時候不初始化行不行呢,答案是可以,前提是在構造方法中將成員變量b進行初始化,代碼如下:
class Father{ public int t; public final int b; //編譯成功 public final int c = 1; //編譯成功 public Father() { //構造方法 b=2; //在構造方法中將成員變量b進行初始化 } }
2.4 總結
可修飾:類、內部類、方法、成員變量、局部變量、基本類型、引用類型
。
含義:final“最終的”的意思,在Java中又有意為常量的意思,也就是被final修飾的只能進行一次初始化!
被final修飾各種所蘊含的特殊意義:
1、 final 修飾基本類型:值不能被修改;
2、final 修飾引用類型:引用不可以被修改也就是說不能指向其他對象,但是該引用的對象內容可以被修改;
3、final 修飾 方法,方法不可以重寫,但是可以被子類訪問 【前提:方法不是 private 類型】。
4、final 修飾 類,類不可以被繼承。
3.static final
含義:從字面也可以知道,它代表Static與final二者的共同體。
可修飾:依舊是取二者的共同體,所以只能修飾成員變量、方法、內部類
,被Static final修飾意義分別如下:
(1)成員變量:屬於類的變量且只能賦值一次。
(2)方法:屬於類的方法且不可以被重寫。
(3)內部類:屬於外部類,且不能被繼承
參考文獻:
https://www.cnblogs.com/yichunguo/p/11788640.html
https://blog.csdn.net/qq_44543508/article/details/102736466