static
概述
靜態的意思
可以修飾的內容
(1) 成員變量
(2) 成員方法
(3) 代碼塊
修飾成員變量
概述: static 修飾的成員變量稱為 靜態變量 類變量 靜態屬性
成員變量: 定義在類的成員位置的變量
實例變量: 就是現在說的成員變量 ---> 非靜態變量
靜態變量: 被static 修飾的實例變量 ----> 靜態變量
在實際的開發中不會特意的區分 實例變量 和 靜態變量,經常使用成員變量來默認表示實例變量
語法:
訪問修飾符 static 數據類型 變量名 = 變量值;
static 訪問修飾符 數據類型 變量名 = 變量值;
特點:
- 被所有對象共享
- 可以使用 類名.屬性名訪問
- 也可以通過對象的引用進行訪問 (不推薦)
案例:
//案例1: 關於特點1
public class Demo2 {
public static void main(String[] args) {
//創建兩個對象 ---> test1 test2 是兩個獨立的對象 每個對象中都有自己的 a b
Test1 test1 = new Test1();
Test1 test2 = new Test1();
test1.a++;
test1.b++;
test1.c++;
System.out.println(test1.a);//11
System.out.println(test1.b);//21
System.out.println(test1.c);//31
System.out.println(test2.a);//10
System.out.println(test2.b);//2
System.out.println(test2.c);
Test1 test3 = new Test1();
System.out.println(test3.c);
}
}
class Test1{
// 定義一個成員變量
int a = 10;
int b = 20;
// 定義一個靜態變量
static int c = 30;
}
//案例2: 關於特點2
public class Demo2 {
public static void main(String[] args) {
//創建兩個對象 ---> test1 test2 是兩個獨立的對象 每個對象中都有自己的 a b
// Test1 test1 = new Test1();
// Test1 test2 = new Test1();
//
// //對於成員變量來說 成員變量隨着對象的創建而存在 對象沒有 成員變量也就沒有
// System.out.println(test1.a);
// System.out.println(test1.b);
//靜態變量 : 是隨着 類的加載 而存在 隨着類的消失而消失
// 類的加載: 當第一次使用一個類的時候 jvm 會從硬盤中讀取字節碼文件中的信息 將信息保存到 Java虛擬機的方法區
// 1 類先加載 2 才能創建對象
// 靜態變量的存在 先於 對象的存在 ----> 類變量
//直接通過類名訪問靜態變量
System.out.println(Test1.c);
}
}
class Test1{
// 定義一個成員變量
int a = 10;
int b = 20;
// 定義一個靜態變量
static int c = 30;
}
//案例3: 關於特點3
public class Demo2 {
public static void main(String[] args) {
//創建兩個對象 ---> test1 test2 是兩個獨立的對象 每個對象中都有自己的 a b
// Test1 test1 = new Test1();
// Test1 test2 = new Test1();
//
// //對於成員變量來說 成員變量隨着對象的創建而存在 對象沒有 成員變量也就沒有
// System.out.println(test1.a);
// System.out.println(test1.b);
//靜態變量 : 是隨着 類的加載 而存在 隨着類的消失而消失
// 類的加載: 當第一次使用一個類的時候 jvm 會從硬盤中讀取字節碼文件中的信息 將信息保存到 Java虛擬機的方法區
// 1 類先加載 2 才能創建對象
// 靜態變量的存在 先於 對象的存在 ----> 類變量
//直接通過類名訪問靜態變量
//System.out.println(Test1.c);
//創建對象訪問
Test1 test1 = new Test1();// 浪費空間
System.out.println(test1.c);
}
}
class Test1{
// 定義一個成員變量
int a = 10;
int b = 20;
// 定義一個靜態變量
static int c = 30;
}
修飾成員方法
概述:
static 修飾成員⽅法: 靜態⽅法
語法:
訪問修飾符 static 返回值類型 ⽅法名(形參列表){
⽅法的實現;
}
static 訪問修飾符 返回值類型 ⽅法名(形參列表){
⽅法的實現;
}
特點:
1.靜態的⽅法中 不可以直接訪問⾮靜態的成員(成員變量 和 成員⽅法)
2.如果要訪問⾮靜態的成員 必須創建對象 通過引⽤去訪問
3.靜態⽅法可以通過 類名.⽅法名() 直接訪問 也可以通過引⽤去訪問(不建議)
4.靜態的⽅法可以被繼承 靜態的⽅法不能被⾮靜態的⽅法所覆蓋 當子類的靜態方法和父類中的靜態方法語法上能形成重寫的語法但是也不能構成重寫,重寫注解@Override 不能通過 靜態方法的調用不符合多態的特點 (引⽤是什么類型 調⽤的⽅法就是這個類型中的⽅法
5.在靜態⽅法中是不可以使⽤ this 和 super 關鍵字 因為 this 和 super都是和對象有關的⽽靜態的成員和對象⽆關 先於對象存在
特點-案例
案例1: 關於特點1
public class Demo2 {
public static void main(String[] args) {
}
}
class Test1 {
// 成員變量
int a = 10;
//靜態變量
static int b = 20;
//定義一個成員方法 ---> 可以訪問 成員變量 靜態變量
public void m1() {
System.out.println(a);
System.out.println(b);
System.out.println("我是成員方法");
}
//定義一個靜態方法
public static void m2() {
//System.out.println(a);//訪問不了 成員變量 因為成員變量隨着對象的創建而存在 靜態方法先於 成員變量存在
//m1();
System.out.println(b);
System.out.println("我是靜態方法");
}
}
// 問題: 在講方法的時候,為什么要求 方法的修飾符固定寫為 public static ?
// 解答: 就是因為主方法是靜態的
//案例2: 關於特點2
public class Demo2 {
public static void main(String[] args) {
}
}
class Test1 {
// 成員變量
int a = 10;
//靜態變量
static int b = 20;
//定義一個成員方法 ---> 可以訪問 成員變量 靜態變量
public void m1() {
System.out.println(a);
System.out.println(b);
System.out.println("我是成員方法");
}
//定義一個靜態方法
public static void m2() {
//System.out.println(a);//訪問不了 成員變量 因為成員變量隨着對象的創建而存在 靜態方法先於 成員變量存在
//m1();
//非要訪問成員變量 必須創建對象
Test1 test1 = new Test1();
System.out.println(test1.a);
test1.m1();
System.out.println(b);
System.out.println("我是靜態方法");
}
}
案例3: 關於特點3
public class Demo2 {
public static void main(String[] args) {
// Test1 test1 = new Test1(); //不建議
//
// test1.m1();//成員方法
// test1.m2();//靜態方法
Test1.m2();
}
}
class Test1 {
// 成員變量
int a = 10;
//靜態變量
static int b = 20;
//定義一個成員方法 ---> 可以訪問 成員變量 靜態變量
public void m1() {
System.out.println(a);
System.out.println(b);
System.out.println("我是成員方法");
}
//定義一個靜態方法
public static void m2() {
//System.out.println(a);//訪問不了 成員變量 因為成員變量隨着對象的創建而存在 靜態方法先於 成員變量存在
//m1();
//非要訪問成員變量 必須創建對象
Test1 test1 = new Test1();
System.out.println(test1.a);
test1.m1();
System.out.println(b);
System.out.println("我是靜態方法");
}
}
//案例4: 關於特點4
public class Demo2 {
public static void main(String[] args) {
// TestSub testSub = new TestSub();
// testSub.m2();
// TestSub.m2();// 靜態方法可以被繼承
// TestSub.m2("劉洋");
//假設 形成的是重寫
Test t1 = new TestSub();//父類引用指向子類對象
t1.m2();//引用是什么類型 就會調用 引用中的方法 和對象無關 靜態方法沒有多態的
}
}
class Test {
//定義一個靜態方法
public static void m2() {
System.out.println("我是靜態方法");
}
//是否可以重載
public static void m2(int a) {
System.out.println("我是重載的靜態方法 m2");
}
}
class TestSub extends Test {
// 是否能夠形成子父類之間的方法的重載
public static void m2(String s){
System.out.println("我是子父類之間的方法的重載");
}
// 是否可以被重寫
//@Override // 雖然方法的格式 符合 方法的重寫 但是本質不是重寫
public static void m2(){
System.out.println("我是子類重寫后的靜態方法m2");
}
}
// 案例5: 關於特點5
public class Demo2 {
public static void main(String[] args) {
// TestSub testSub = new TestSub();
// testSub.m2();
// TestSub.m2();// 靜態方法可以被繼承
// TestSub.m2("劉洋");
//假設 形成的是重寫
Test t1 = new TestSub();//父類引用指向子類對象
t1.m2();//引用是什么類型 就會調用 引用中的方法 和對象無關 靜態方法沒有多態的
}
}
class Test {
int a = 10;
//定義一個靜態方法
public static void m2() {
int a = 20;
System.out.println(a);//20
System.out.println(this.a);
System.out.println("我是靜態方法");
}
}
修飾代碼塊
分類:
(1)局部代碼塊
(2)動態代碼塊 ---> 構造代碼塊
(3)靜態代碼塊
特點:
局部代碼塊: 定義在方法中
作用:用來限定局部變量的作用域
案例
public class Demo2 {
public static void main(String[] args) {
{
int a = 10;// 7 -- 10
}
{
int a = 20;//14 -- 15
}
}
}
動態代碼塊(構造代碼塊 初始代碼塊): 定義在類中方法外 ---> 成員位置
作用:用於在創建對象時 和成員變量 按照從上向下的順序進行初始化操作,可以將所有構造方法中共同的代碼放到動態代碼塊中。
案例:
public class Demo2 {
public static void main(String[] args) {
Test test = new Test(30);
}
}
class Test{
int a = 10;// 成員變量
{
System.out.println("我是構造代碼塊 動態代碼塊");
System.out.println("有 1000 行初始化代碼");
}
public Test(){
System.out.println("我是構造方法");
}
public Test(int a){
//System.out.println("有 1000 行初始化代碼 ");
this.a = a;
}
}
靜態代碼塊: 被static修飾的動態代碼塊
作用:在 類加載時 和靜態屬性按照順序進行執行,為類進行初始化操作,一般用於加載驅動等資源。 ----> jdbc
類加載:當jvm第⼀次使⽤⼀個類時 讀⼊這個類中的信息(包名 類名 屬性 ⽅法 靜態的變量 靜態的⽅法 。。。)並保存在虛擬機中的過程叫做類加載,
在一個程序運行周期>>內,類加載只進⾏⼀次
類加載時機:
1. 第一次創建對象的時候
2. 第一次通過類名訪問類中的靜態成員(靜態變量 靜態方法)時
3. 子類進行類加載首先會先進行父類的類加載
案例:
//案例1: 關於類加載時機 1
public class Demo2 {
public static void main(String[] args) {
//Test t1 ; //聲明引用
Test t1 = new Test();// 第一次創建對象
Test t2 = new Test();// 第二次創建對象
}
}
class Test{
static {
System.out.println("我是靜態代碼塊 我的執行可以證明類加載了");
}
public Test(){
System.out.println("構造方法執行了 對象創建完成了");
}
}
//案例2:關於類加載的時機 2
public class Demo2 {
public static void main(String[] args) {
System.out.println(Test.a);
Test.m1();
}
}
class Test {
static int a = 10;
static {
System.out.println("我是靜態代碼塊 我的執行可以證明類加載了");
}
public Test() {
System.out.println("構造方法執行了 對象創建完成了");
}
public static void m1() {
System.out.println("我是靜態方法m1");
}
}
// 案例3: 關於類加載時機 3
public class Demo2 {
public static void main(String[] args) {
System.out.println(TestSub.a);
TestSub.m1();
}
}
class Test {
static {
System.out.println("父類的靜態代碼塊執行了 父類的類加載了");
}
}
class TestSub extends Test{
static int a = 10;
static {
System.out.println("子類的靜態代碼塊執行了 子類進行類加載了");
}
public static void m1(){
System.out.println("我是子類的靜態方法");
}
}
