詳解Java中static關(guān)鍵字和內(nèi)部類的使用
一. static 關(guān)鍵字
在Java中,被static修飾的成員,稱之為靜態(tài)成員,也可以稱為類成員,其不屬于某個(gè)具體的對象,是所有對象所共享的。
1. static修飾成員變量
static修飾的成員變量,稱為靜態(tài)成員變量
【靜態(tài)成員變量特性】:
- 不屬于某個(gè)具體的對象,是類的屬性,所有對象共享的,不存儲在某個(gè)對象的空間中
- 既可以通過對象引用訪問(不推薦使用),也可以通過類名訪問,但一般更推薦使用類名訪問
- 類變量存儲在方法區(qū)當(dāng)中
- 生命周期伴隨類的一生(即:隨類的加載而創(chuàng)建,隨類的卸載而銷毀)
public class Student{
public String name;
public String gender;
public int age;
public double score;
public static String classRoom = "rj2104";
public Student(String name, String gender, int age, double score) {
this.name = name;
this.gender = gender;
this.age = age;
this.score = score;
}
// ...
public static void main(String[] args) {
// 靜態(tài)成員變量可以直接通過類名訪問
System.out.println(Student.classRoom);
Student s1 = new Student("Li leilei", "男", 18, 3.8);
Student s2 = new Student("Han MeiMei", "女", 19, 4.0);
Student s3 = new Student("Jim", "男", 18, 2.6);
// 也可以通過對象訪問:但是classRoom是三個(gè)對象共享的
System.out.println(s1.classRoom);
System.out.println(s2.classRoom);
System.out.println(s3.classRoom);
}
}
2. static修飾成員方法
一般類中的數(shù)據(jù)成員都設(shè)置為private,而成員方法設(shè)置為public,
Java中,被static修飾的成員方法稱為靜態(tài)成員方法,是類的方法,不是某個(gè)對象所特有的。
靜態(tài)成員一般是通過靜態(tài)方法來訪問的。
public class Student2{
// ...
private static String classRoom = "rj2104";
// ...
public static String getClassRoom(){
return classRoom;
}
}
class TestStudent {
public static void main(String[] args) {
System.out.println(Student2.getClassRoom());
}
}
【靜態(tài)方法特性】:
- 不屬于某個(gè)具體的對象,是類方法
- 可以通過對象調(diào)用,也可以通過 類名.靜態(tài)方法名(…) 方式調(diào)用,更推薦使用后者
- 不能在靜態(tài)方法中訪問任何非靜態(tài)成員變量和非靜態(tài)成員方法;因?yàn)榉庆o態(tài)方法中默認(rèn)有this參數(shù),但在靜態(tài)方法中調(diào)用時(shí)候無法傳遞this引用;除非在靜態(tài)方法中新new一個(gè)對象,再通過對象引用去訪問此對象
- 靜態(tài)方法無法重寫,不能用來實(shí)現(xiàn)多態(tài)
3. static成員變量的初始化
靜態(tài)成員變量一般不會放在構(gòu)造方法中來初始化,構(gòu)造方法中初始化的是與對象相關(guān)的實(shí)例屬性
靜態(tài)成員變量的初始化分為兩種:就地初始化 和 靜態(tài)代碼塊初始化。
就地初始化:在定義時(shí)直接給出初始值
public class Student2{
// ...
//就地初始化
private static String classRoom = "rj2104";
//...
}
用靜態(tài)代碼塊完成初始化
public class Student2{
// ...
private static String classRoom;
//靜態(tài)代碼塊初始化
static {
classRoom = "rj2104";
}
// ...
}
二. 內(nèi)部類
在 Java 中,可以將一個(gè)類定義在另一個(gè)類或者一個(gè)方法的內(nèi)部, 前者稱為內(nèi)部類,后者稱為外部類。內(nèi)部類也是封裝的一種體現(xiàn)。
內(nèi)部類和外部類共用同一個(gè)java源文件,但是經(jīng)過編譯之后,內(nèi)部類會形成單獨(dú)的字節(jié)碼文件, 一般形成的字節(jié)碼文件文件名為:外部類名字$內(nèi)部類名字.class

public class OutClass {
class InnerClass{
}
}
// OutClass是外部類
// InnerClass是內(nèi)部類
根據(jù)內(nèi)部類定義的位置不同,一般可以分為以下幾種形式:
1.成員內(nèi)部類(普通內(nèi)部類)
實(shí)例內(nèi)部類:未被static修飾的成員內(nèi)部類
靜態(tài)內(nèi)部類:被static修飾的成員內(nèi)部類
2.局部內(nèi)部類
3.匿名內(nèi)部類
1. 實(shí)例內(nèi)部類
即未被static修飾的成員內(nèi)部類。
【注意事項(xiàng)】:
- 外部類中的任何成員都可以在實(shí)例內(nèi)部類方法中直接訪問
- 實(shí)例內(nèi)部類當(dāng)中不能有靜態(tài)的成員變量;非要定義,那么只能是被static final修飾的靜態(tài)常量,常量是在程序編譯的時(shí)候就確定的
- 實(shí)例內(nèi)部類所處的位置與外部類成員位置相同,因此也受public、private等訪問限定符的約束
- 實(shí)例內(nèi)部類對象必須在先有外部類對象前提下才能創(chuàng)建
- 實(shí)例內(nèi)部類的非靜態(tài)方法中默認(rèn)包含了一個(gè)指向外部類對象的引用和一個(gè)指向自身實(shí)例內(nèi)部類對象的引用
- 在實(shí)例內(nèi)部類方法中訪問同名的成員時(shí),優(yōu)先訪問自己的,如果要訪問外部類同名的成員,必須:外部類名稱.this.同名成員 來訪問
- 外部類中,不能直接訪問實(shí)例內(nèi)部類中的成員,如果要訪問必須先要創(chuàng)建內(nèi)部類的對象。
public class OutClass {
private int a;
static int b;
int c;
public void methodA() {
a = 10;
System.out.println(a);
}
public static void methodB() {
System.out.println(b);
}
// 實(shí)例內(nèi)部類:未被static修飾
class InnerClass {
int c;
//實(shí)例內(nèi)部類當(dāng)中 不能有靜態(tài)的成員變量. 非要定義,那么只能是被static final修飾的
public static final int d = 6;
public void methodInner() {
// 在實(shí)例內(nèi)部類中可以直接訪問外部類中:任意訪問限定符修飾的成員
a = 100;
b = 200;
methodA();
methodB();
System.out.println(d);
// 如果外部類和實(shí)例內(nèi)部類中具有相同名稱成員時(shí),優(yōu)先訪問的是內(nèi)部類自己的
c = 300;
System.out.println(c);
// 如果要訪問外部類同名成員時(shí)候,必須:外部類名稱.this.同名成員名字
OutClass.this.c = 400;
System.out.println(OutClass.this.c);
}
}
public static void main(String[] args) {
// 外部類:對象創(chuàng)建 以及 成員訪問
OutClass outClass = new OutClass();
System.out.println(outClass.a);
System.out.println(outClass.b);
System.out.println(outClass.c);
outClass.methodA();
outClass.methodB();
System.out.println("=============實(shí)例內(nèi)部類的訪問=============");
// 要訪問實(shí)例內(nèi)部類中成員,必須要創(chuàng)建實(shí)例內(nèi)部類的對象
// 而普通內(nèi)部類定義與外部類成員定義位置相同,因此創(chuàng)建實(shí)例內(nèi)部類對象時(shí)必須借助外部類
// 創(chuàng)建實(shí)例內(nèi)部類對象
OutClass.InnerClass innerClass1 = new OutClass().new InnerClass();
innerClass1.methodInner();
// 上述語法比較怪異,也可以先將外部類對象先創(chuàng)建出來,然后再創(chuàng)建實(shí)例內(nèi)部類對象
OutClass.InnerClass innerClass2 = outClass.new InnerClass();
innerClass2.methodInner();
}
}
2. 靜態(tài)內(nèi)部類
被static修飾的內(nèi)部成員類稱為靜態(tài)內(nèi)部類。、
【注意事項(xiàng)】:
在靜態(tài)內(nèi)部類中只能訪問外部類中的靜態(tài)成員,除非在內(nèi)部類當(dāng)中new一個(gè)外部類的對象,通過外部類對象的引用去訪問其中的非靜態(tài)成員。
創(chuàng)建靜態(tài)內(nèi)部類對象時(shí),不需要先創(chuàng)建外部類對象
public class OuterClass2 {
public int data1 = 1;
int data2 = 2;
public static int data3 = 3;
public void test() {
System.out.println("out::test()");
}
// 靜態(tài)內(nèi)部類:被static修飾的成員內(nèi)部類
static class InnerClass2 {
public int data4 = 4;
int data5 = 5;
public static int data6 = 6;
public void func() {
System.out.println("out::func()");
//test();
// 編譯失敗,在靜態(tài)內(nèi)部類中不能直接訪問外部類中的非靜態(tài)成員
//System.out.println(data1);
//System.out.println(data2);
//外部類的非靜態(tài)成員,需要通過外部類的對象的引用才能訪問。
OuterClass2 outerClass = new OuterClass2();
System.out.println(outerClass.data1);
System.out.println(outerClass.data2);
outerClass.test();
// 在靜態(tài)內(nèi)部類中只能訪問外部類的靜態(tài)成員
System.out.println(data3);
System.out.println(data4);
System.out.println(data5);
System.out.println(data5);
System.out.println(data6);
}
}
public static void main(String[] args) {
// 靜態(tài)內(nèi)部類對象創(chuàng)建 和 成員訪問
OuterClass2.InnerClass2 innerClass2 = new OuterClass2.InnerClass2();
innerClass2.func();
}
}
3. 局部內(nèi)部類
定義在外部類的方法體或者{ }中,一般使用的非常少。
【注意事項(xiàng)】
局部內(nèi)部類只能在所定義的方法體內(nèi)部使用
不能被public、static等修飾符修飾
局部內(nèi)部類生成的字節(jié)碼文件稍有區(qū)別:外部類名字$數(shù)字內(nèi)部類名字.class

ppublic class OutClass {
int a = 10;
public void method(){
int b = 10;
// 局部內(nèi)部類:定義在方法體內(nèi)部
// 不能被public、static等訪問限定符修飾
class InnerClass{
public void methodInnerClass(){
System.out.println(a);
System.out.println(b);
}
}
// 只能在該方法體內(nèi)部使用,其他位置都不能用
InnerClass innerClass = new InnerClass();
innerClass.methodInnerClass();
}
public static void main(String[] args) {
// OutClass.InnerClass innerClass = null; 編譯失敗
}
}4. 匿名內(nèi)部類
匿名內(nèi)部類,就是沒有名字的一種嵌套類
匿名內(nèi)部類形成的字節(jié)碼文件文件名為:外部類名字$數(shù)字.class

4.1 使用匿名內(nèi)部的好處與演示
在實(shí)際開發(fā)中,我們會遇到下面的情況:
一個(gè)接口/類的方法的某個(gè)執(zhí)行過程在程序中只會執(zhí)行一次,但為了使用它,我們需要創(chuàng)建它的實(shí)現(xiàn)類/子類去實(shí)現(xiàn)/重寫方法。
代碼中為了這一次的使用去創(chuàng)建一個(gè)類,未免太過麻煩,此時(shí)就可以使用匿名內(nèi)部類來解決這個(gè)問題
首先來看我們正常的實(shí)現(xiàn)邏輯,假設(shè)有一個(gè)接口,接口當(dāng)中只有一個(gè)方法
public interface Interface {
void show();
}
為了使用該接口的show方法,我們需要去創(chuàng)建一個(gè)實(shí)現(xiàn)類,重寫show方法的具體實(shí)現(xiàn)
public class Test implements Interface{
@Override
public void show() {
System.out.println("只執(zhí)行一次show()");
}
}
public class Main {
public static void main(String[] args) {
Test test = new Test();
test.show();
}
}
如果實(shí)現(xiàn)類Test在程序中只使用一次,那么為了這一次的使用去創(chuàng)建一個(gè)類太過繁瑣,這種情況下就可以用匿名內(nèi)部類來實(shí)現(xiàn),無需創(chuàng)建新的類,減少代碼冗余,
看下面代碼:
class Main {
public static void main(String[] args) {
//寫法一
Interface in = new Interface() {
@Override
public void show() {
System.out.println("匿名內(nèi)部類中重寫show()");
}
};
//調(diào)用接口方法
in.show();
//寫法二
new Interface() {
@Override
public void show() {
System.out.println("匿名內(nèi)部類中重寫show()");
}
}.show();//調(diào)用接口方法
}
}4.2 匿名內(nèi)部類的定義格式和使用
定義格式1:
接口名稱 引用名 = new 接口名稱() {
// 覆蓋重寫所有抽象方法
};
引用名.方法調(diào)用
定義格式2:
new 接口名稱() {
// 覆蓋重寫所有抽象方法
}.方法調(diào)用;
對格式“new 接口名稱() {…}”的理解:
new代表創(chuàng)建一個(gè)新的對象對象
接口名稱就是匿名內(nèi)部類需要實(shí)現(xiàn)哪個(gè)接口
{…}中是匿名內(nèi)部類的內(nèi)容
【注意事項(xiàng)】:
- 匿名內(nèi)部類,在【創(chuàng)建對象】的時(shí)候,只能使用唯一 一次。
- 匿名對象,在【調(diào)用方法】的時(shí)候,只能調(diào)用唯一 一次。
- 匿名內(nèi)部類是省略了【實(shí)現(xiàn)類/子類名稱】,但是匿名對象是省略了【對象名稱】
- 匿名內(nèi)部類可以用在具體類、抽象類、接口上,且對方法個(gè)數(shù)沒有要求。
public class Class {
public void show(String s){
System.out.println("Class::show()");
}
}
public abstract class AbstractClass {
abstract void show(String s);
}
public interface Interface {
void show(String s);
}
public class TestDome {
public static void main(String[] args) {
//重寫普通類的方法
new Class(){
@Override
public void show(String s) {
System.out.println(s);
}
}.show("普通類");
//重寫抽象類的抽象方法
new AbstractClass(){
@Override
void show(String s) {
System.out.println(s);
}
}.show("抽象類");
//實(shí)現(xiàn)接口的抽象方法
new Interface(){
@Override
public void show(String s) {
System.out.println(s);
}
}.show("接口");
}
}
執(zhí)行結(jié)果:

以上就是詳解Java中static關(guān)鍵字和內(nèi)部類的使用的詳細(xì)內(nèi)容,更多關(guān)于Java static關(guān)鍵字 內(nèi)部類的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java中Runnable與Callable接口的區(qū)別詳解
這篇文章主要為大家詳細(xì)介紹了Java中Runnable與Callable接口的區(qū)別,文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)Java有一定的幫助,需要的可以參考一下2023-03-03
Spring Boot項(xiàng)目打包指定包名實(shí)現(xiàn)示例
這篇文章主要為大家介紹了Spring Boot項(xiàng)目打包指定包名實(shí)現(xiàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-11-11
Mybatis動態(tài)調(diào)用表名和字段名的解決方法
今天在項(xiàng)目開發(fā)中有個(gè)業(yè)務(wù)是需要限制各個(gè)用戶對某些表里的字段查詢以及某些字段是否顯示,這種情況下,就需要構(gòu)建sql來動態(tài)傳入表名、字段名了,下面給大家介紹mybatis動態(tài)調(diào)用表名和字段名的解決方法,一起看看吧2016-10-10
SpringBoot入口類和@SpringBootApplication講解
這篇文章主要介紹了SpringBoot入口類和@SpringBootApplication講解,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03

