Java提高篇 —— Java關鍵字之static的四種用法

一、前言

?

? ? ? ?在java的關鍵字中,staticfinal是兩個我們必須掌握的關鍵字。不同于其他關鍵字,他們都有多種用法,而且在一定環境下使用,可以提高程序的運行性能,優化程序的結構。下面我們先來了解一下static關鍵字及其用法。

?

二、static關鍵字

?

1、修飾成員變量?

? ? ? ?在我們平時的使用當中,static最常用的功能就是修飾類的屬性和方法,讓他們成為類的成員屬性和方法,我們通常將用static修飾的成員稱為類成員或者靜態成員,這句話挺起來都點奇怪,其實這是相對于對象的屬性和方法來說的。請看下面的例子:(未避免程序太過臃腫,暫時不管訪問控制)

public class Person {String name;int age;public String toString() {return "Name:" + name + ", Age:" + age;}public static void main(String[] args) {Person p1 = new Person();p1.name = "zhangsan";p1.age = 10;Person p2 = new Person();p2.name = "lisi";p2.age = 12;System.out.println(p1);System.out.println(p2);}/**Output* Name:zhangsan, Age:10* Name:lisi, Age:12*///~
}

? ? ? ?上面的代碼我們很熟悉,根據Person構造出的每一個對象都是獨立存在的,保存有自己獨立的成員變量,相互不會影響,他們在內存中的示意如下:

? ? ? ?從上圖中可以看出,p1和p2兩個變量引用的對象分別存儲在內存中堆區域的不同地址中,所以他們之間相互不會干擾。但其實,在這當中,我們省略了一些重要信息,相信大家也都會想到,對象的成員屬性都在這了,由每個對象自己保存,那么他們的方法呢?實際上,不論一個類創建了幾個對象,他們的方法都是一樣的:

? ? ? ?從上面的圖中我們可以看到,兩個Person對象的方法實際上只是指向了同一個方法定義。這個方法定義是位于內存中的一塊不變區域(由jvm劃分),我們暫稱它為靜態存儲區。這一塊存儲區不僅存放了方法的定義,實際上從更大的角度而言,它存放的是各種類的定義,當我們通過new來生成對象時,會根據這里定義的類的定義去創建對象。多個對象僅會對應同一個方法,這里有一個讓我們充分信服的理由,那就是不管多少的對象,他們的方法總是相同的,盡管最后的輸出會有所不同,但是方法總是會按照我們預想的結果去操作,即不同的對象去調用同一個方法,結果會不盡相同。

? ? ? ?我們知道,static關鍵字可以修飾成員變量和方法,來讓它們變成類的所屬,而不是對象的所屬,比如我們將Person的age屬性用static進行修飾,結果會是什么樣呢?請看下面的例子:

public class Person {String name;static int age;/* 其余代碼不變... *//**Output* Name:zhangsan, Age:12* Name:lisi, Age:12*///~
}

? ? ? ?我們發現,結果發生了一點變化,在給p2的age屬性賦值時,干擾了p1的age屬性,這是為什么呢?我們還是來看他們在內存中的示意:

? ? ? ?我們發現,給age屬性加了static關鍵字之后,Person對象就不再擁有age屬性了,age屬性會統一交給Person類去管理,即多個Person對象只會對應一個age屬性,一個對象如果對age屬性做了改變,其他的對象都會受到影響。我們看到此時的age和toString()方法一樣,都是交由類去管理。

? ? ? ?雖然我們看到static可以讓對象共享屬性,但是實際中我們很少這么用,也不推薦這么使用。因為這樣會讓該屬性變得難以控制,因為它在任何地方都有可能被改變。如果我們想共享屬性,一般我們會采用其他的辦法:

public class Person {private static int count = 0;int id;String name;int age;public Person() {id = ++count;}public String toString() {return "Id:" + id + ", Name:" + name + ", Age:" + age;}public static void main(String[] args) {Person p1 = new Person();p1.name = "zhangsan";p1.age = 10;Person p2 = new Person();p2.name = "lisi";p2.age = 12;System.out.println(p1);System.out.println(p2);}/**Output* Id:1, Name:zhangsan, Age:10* Id:2, Name:lisi, Age:12*///~
}

? ? ? ?上面的代碼起到了給Person的對象創建一個唯一id以及記錄總數的作用,其中count由static修飾,是Person類的成員屬性,每次創建一個Person對象,就會使該屬性自加1然后賦給對象的id屬性,這樣,count屬性記錄了創建Person對象的總數,由于count使用了private修飾,所以從類外面無法隨意改變。

?

2、修飾成員方法

? ? ? ?static的另一個作用,就是修飾成員方法。相比于修飾成員屬性,修飾成員方法對于數據的存儲上面并沒有多大的變化,因為我們從上面可以看出,方法本來就是存放在類的定義當中的。static修飾成員方法最大的作用,就是可以使用"類名.方法名"的方式操作方法,避免了先要new出對象的繁瑣和資源消耗,我們可能會經常在幫助類中看到它的使用:

public class PrintHelper {public static void print(Object o){System.out.println(o);}public static void main(String[] args) {PrintHelper.print("Hello world");}
}

? ? ? ?上面便是一個例子(現在還不太實用),但是我們可以看到它的作用,使得static修飾的方法成為類的方法,使用時通過“類名.方法名”的方式就可以方便的使用了,相當于定義了一個全局的函數(只要導入該類所在的包即可)。不過它也有使用的局限,一個static修飾的方法中,不能使用非static修飾的成員變量和方法,這很好理解,因為static修飾的方法是屬于類的,如果去直接使用對象的成員變量,它會不知所措(不知該使用哪一個對象的屬性)。

?

3、靜態塊

? ? ? ?在說明static關鍵字的第三個用法時,我們有必要重新梳理一下一個對象的初始化過程。以下面的代碼為例:

package com.dotgua.study;class Book{public Book(String msg) {System.out.println(msg);}
}public class Person {Book book1 = new Book("book1成員變量初始化");static Book book2 = new Book("static成員book2成員變量初始化");public Person(String msg) {System.out.println(msg);}Book book3 = new Book("book3成員變量初始化");static Book book4 = new Book("static成員book4成員變量初始化");public static void main(String[] args) {Person p1 = new Person("p1初始化");}/**Output* static成員book2成員變量初始化* static成員book4成員變量初始化* book1成員變量初始化* book3成員變量初始化* p1初始化*///~
}

? ? ? ?上面的例子中,Person類中組合了四個Book成員變量,兩個是普通成員,兩個是static修飾的類成員。我們可以看到,當我們new一個Person對象時,static修飾的成員變量首先被初始化,隨后是普通成員,最后調用Person類的構造方法完成初始化。也就是說,在創建對象時,static修飾的成員會首先被初始化,而且我們還可以看到,如果有多個static修飾的成員,那么會按照他們的先后位置進行初始化。

? ? ? ?實際上,static修飾的成員的初始化可以更早的進行,請看下面的例子:

class Book{public Book(String msg) {System.out.println(msg);}
}public class Person {Book book1 = new Book("book1成員變量初始化");static Book book2 = new Book("static成員book2成員變量初始化");public Person(String msg) {System.out.println(msg);}Book book3 = new Book("book3成員變量初始化");static Book book4 = new Book("static成員book4成員變量初始化");public static void funStatic() {System.out.println("static修飾的funStatic方法");}public static void main(String[] args) {Person.funStatic();System.out.println("****************");Person p1 = new Person("p1初始化");}/**Output* static成員book2成員變量初始化* static成員book4成員變量初始化* static修飾的funStatic方法* **************** book1成員變量初始化* book3成員變量初始化* p1初始化*///~
}

? ? ? ?在上面的例子中我們可以發現兩個有意思的地方,第一個是當我們沒有創建對象,而是通過類去調用類方法時,盡管該方法沒有使用到任何的類成員,類成員還是在方法調用之前就初始化了,這說明,當我們第一次去使用一個類時,就會觸發該類的成員初始化。第二個是當我們使用了類方法,完成類的成員的初始化后,再new該類的對象時,static修飾的類成員沒有再次初始化,這說明,static修飾的類成員,在程序運行過程中,只需要初始化一次即可,不會進行多次的初始化。

? ? ? ?回顧了對象的初始化以后,我們再來看static的第三個作用就非常簡單了,那就是當我們初始化static修飾的成員時,可以將他們統一放在一個以static開始,用花括號包裹起來的塊狀語句中:

class Book{public Book(String msg) {System.out.println(msg);}
}public class Person {Book book1 = new Book("book1成員變量初始化");static Book book2;static {book2 = new Book("static成員book2成員變量初始化");book4 = new Book("static成員book4成員變量初始化");}public Person(String msg) {System.out.println(msg);}Book book3 = new Book("book3成員變量初始化");static Book book4;public static void funStatic() {System.out.println("static修飾的funStatic方法");}public static void main(String[] args) {Person.funStatic();System.out.println("****************");Person p1 = new Person("p1初始化");}/**Output* static成員book2成員變量初始化* static成員book4成員變量初始化* static修飾的funStatic方法* **************** book1成員變量初始化* book3成員變量初始化* p1初始化*///~
}

? ? ? ?我們將上一個例子稍微做了一下修改,可以看到,結果沒有二致。

?

4、靜態導包

? ? ? ?相比于上面的三種用途,第四種用途可能了解的人就比較少了,但是實際上它很簡單,而且在調用類方法時會更方便。以上面的“PrintHelper”的例子為例,做一下稍微的變化,即可使用靜態導包帶給我們的方便:

/* PrintHelper.java文件 */
package com.dotgua.study;public class PrintHelper {public static void print(Object o){System.out.println(o);}
}
/* App.java文件 */import static com.dotgua.study.PrintHelper.*;public class App 
{public static void main( String[] args ){print("Hello World!");}/**Output* Hello World!*///~
}

? ? ? ?上面的代碼來自于兩個java文件,其中的PrintHelper很簡單,包含了一個用于打印的static方法。而在App.java文件中,我們首先將PrintHelper類導入,這里在導入時,我們使用了static關鍵字,而且在引入類的最后還加上了“.*”,它的作用就是將PrintHelper類中的所有類方法直接導入。不同于非static導入,采用static導入包后,在不與當前類的方法名沖突的情況下,無需使用“類名.方法名”的方法去調用類方法了,直接可以采用"方法名"去調用類方法,就好像是該類自己的方法一樣使用即可。

?

三、總結

static是java中非常重要的一個關鍵字,而且它的用法也很豐富,主要有四種用法:

? ? ? ?1、用來修飾成員變量,將其變為類的成員,從而實現所有對象對于該成員的共享;

? ? ? ?2、用來修飾成員方法,將其變為類方法,可以直接使用“類名.方法名”的方式調用,常用于工具類;

? ? ? ?3、靜態塊用法,將多個類成員放在一起初始化,使得程序更加規整,其中理解對象的初始化過程非常關鍵;

? ? ? ?4、靜態導包用法,將類的方法直接導入到當前類中,從而直接使用“方法名”即可調用類方法,更加方便。

?

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/446963.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/446963.shtml
英文地址,請注明出處:http://en.pswp.cn/news/446963.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

C++ 使用move來刪除用戶指定的文件

代碼 #include <iostream>bool remove_file(std::string path){if (remove(path.c_str())0){std::cout << "success!" << std::endl;}else{std::cout << "False!" << std::endl;} } int main() {std::string path "/…

Java提高篇 —— Java關鍵字之final的幾種用法

一、前言 在java的關鍵字中&#xff0c;static和final是兩個我們必須掌握的關鍵字。不同于其他關鍵字&#xff0c;他們都有多種用法&#xff0c;而且在一定環境下使用&#xff0c;可以提高程序的運行性能&#xff0c;優化程序的結構。下面我們來了解一下final關鍵字及其用法。 …

使用C++的方式實現AES算法

aes_file.h #include <iostream> #include <fstream> #include <bitset> #include <string> using namespace std; typedef bitset<8> byte; typedef bitset<32> word;const int Nr 10; // AES-128需要 10 輪加密 const int Nk 4; /…

Java提高篇 —— Java三大特性之封裝

一、封裝 封裝從字面上來理解就是包裝的意思&#xff0c;專業點就是信息隱藏&#xff0c;是指利用抽象數據類型將數據和基于數據的操作封裝在一起&#xff0c;使其構成一個不可分割的獨立實體&#xff0c;數據被保護在抽象數據類型的內部&#xff0c;盡可能地隱藏內部的細節&am…

sqlite3的backup和restore函數的使用

參考代碼 第一段這個親測可以使用 #include <sqlite3.h> #include <iostream> /* ** Perform an online backup of database pDb to the database file named ** by zFilename. This function copies 5 database pages from pDb to ** zFilename, then unlocks pD…

Java提高篇 —— Java三大特性之繼承

一、前言 在《Think in java》中有這樣一句話&#xff1a;復用代碼是Java眾多引人注目的功能之一。但要想成為極具革命性的語言&#xff0c;僅僅能夠復制代碼并對加以改變是不夠的&#xff0c;它還必須能夠做更多的事情。在這句話中最引人注目的是“復用代碼”,盡可能的復用代碼…

Java提高篇 —— Java三大特性之多態

一、前言 面向對象編程有三大特性&#xff1a;封裝、繼承、多態。 封裝&#xff1a;隱藏了類的內部實現機制&#xff0c;可以在不影響使用的情況下改變類的內部結構&#xff0c;同時也保護了數據。對外界而已它的內部細節是隱藏的&#xff0c;暴露給外界的只是它的訪問方法。 繼…

光盤刻錄制作Ubuntu等操作系統的啟動盤

前提條件 軟媒刻錄 空白光盤&#xff08;至少4.7G&#xff09;電腦&#xff08;最好使用外置的光驅&#xff09;系統鏡像&#xff08;ISO格式&#xff09; 具體操作 打開軟媒魔方選擇光盤刻錄按照標紅的進行選擇選擇鏡像->選擇或者拖拽都可以選擇刻錄機->如果使用外部刻…

Java提高篇 —— 抽象類與接口

一、前言 接口和內部類為我們提供了一種將接口與實現分離的更加結構化的方法。 抽象類與接口是java語言中對抽象概念進行定義的兩種機制&#xff0c;正是由于他們的存在才賦予java強大的面向對象的能力。他們兩者之間對抽象概念的支持有很大的相似&#xff0c;甚至可以互換&…

C++ const相關內容學習

const 作用 修飾變量&#xff0c;說明變量不可以被修改修飾指針&#xff0c;分為指向常量的指針&#xff08;pointer to const&#xff09;和自身是常量的指針&#xff08;常量指針&#xff0c;const pointer&#xff09;修飾引用&#xff0c;指向常量的引用&#xff08;refe…

Java提高篇 —— Java淺拷貝和深拷貝

一、前言 我們知道在Java中存在這個接口Cloneable&#xff0c;實現該接口的類都會具備被拷貝的能力&#xff0c;同時拷貝是在內存中進行&#xff0c;在性能方面比我們直接通過new生成對象來的快&#xff0c;特別是在大對象的生成上&#xff0c;使得性能的提升非常明顯。然而我們…

openssl里面AES算法主要函數的參數的介紹

注意事項 使用API的時候&#xff0c;需要特別小心數據長度&#xff0c;一般沒有指定長度的參數&#xff0c;默認都是16&#xff08;AES_BLOCK_SIZE&#xff09;個字節。輸出數據的長度一般都是16字節的倍數&#xff0c;否則會出現數組越界訪問。以下API中&#xff0c;encrypt表…

Java提高篇 —— Java內部類詳解

一、簡介 內部類是一個非常有用的特性但又比較難理解使用的特性。 內部類我們從外面看是非常容易理解的&#xff0c;無非就是在一個類的內部在定義一個類。 public class OuterClass {private String name ;private int age;public String getName() {return name;}public voi…

Ubuntu修改界面的大小

命令 xrandr 就會顯示ubuntu支持的屏幕比例使用命令 xrandr --size 1680x1050 切換屏幕大小

Java提高篇 —— String緩沖池

一、String緩沖池 首先我們要明確&#xff0c;String并不是基本數據類型&#xff0c;而是一個對象&#xff0c;并且是不可變的對象。查看源碼就會發現String類為final型的&#xff08;當然也不可被繼承&#xff09;&#xff0c;而且通過查看JDK文檔會發現幾乎每一個修改String對…

C++最新使用開源openssl實現輸入是文件,輸出是文件的AES加解密的代碼

AES.h頭文件 #include <cstring> #include <fstream> #include <iostream> #include <openssl/aes.h>//AES文件加密函數 int aes_encrypt_file(const std::string &original_backup_file_path,const std::string &encrypted_file_path,const …

Java基礎 —— JVM內存模型與垃圾回收

目錄一、概述二、運行時數據區方法區運行時常量池堆棧本地方法棧程序計數器三、對象訪問四、垃圾回收如何定義垃圾1、引用計數法2、可達性分析垃圾回收方法1、Mark-Sweep標記-清除算法2、Copying復制算法3、Mark-Compact標記-整理算法4、Generational Collection 分代收集垃圾收…

Report Design

ERP_ENT_STD-CSDN博客

規范化流程化提交自己代碼到遠程gitlab服務器

流程 進入到build目錄使用make命令進行編譯 make -j 6&#xff0c;前提是cmake命令已經執行../format.py rungit add .. 添加文件git checkout -b xxx 創建xxx分支&#xff0c;其中xxx是分支名字git branch 查看分支git commit -m "[chy/backup] modify parameters for…

Java提高篇 ——Java注解

目錄一、注解注解的定義注解的應用元注解RetentionDocumentedTargetInheritedRepeatable注解的屬性Java 預置的注解DeprecatedOverrideSuppressWarningsSafeVarargsFunctionalInterface二、注解的提取三、注解與反射四、注解的使用場景五、親手自定義注解完成某個目的六、注解應…