Static關鍵字
static靜態的,可以用來修飾變數,修飾方法,程式碼塊,靜態內部類和靜態導包。 static關鍵字表明一個成員變數或方法在沒有所屬類的例項的情況下被訪問。
明確的是
Java記憶體分為,棧,堆,方法去和靜態域。 棧:存放的是區域性變數,物件的引用名,陣列的引用名。 堆:主要存放一些物件,也就是new出來的“東西”。 方法區:也叫字串常量池。 靜態域:存放類中靜態的變數。 先看如下程式碼:
public class TestStatic {
public static void main(String[] args) {
Supperman s1 = new Supperman("奧特曼", 800);
Supperman s2 = new Supperman("孫悟空", 1000);
System.out.println(s1);
System.out.println(s2);
}
}
class Supperman{
String name;
int age;
public Supperman(String name, int age) {
super();
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "man [name=" + name + ", age=" + age + "]";
}
}
複製程式碼
結果很簡單:
Supperman [name=奧特曼, age=800]
Supperman [name=孫悟空, age=1000]
複製程式碼
再看看這段程式碼的記憶體解析如下:
綜上所述:如果不是靜態的,他就會在堆空間獨立佔有一塊,你修改s1屬性的值,不會影響到s2對應的值。 同樣是上面的程式碼public class TestStatic {
public static void main(String[] args) {
Supperman s1 = new Supperman("奧特曼", 800);
Supperman s2 = new Supperman("孫悟空", 1000);
s1.sex = "男";
System.out.println(s1);
System.out.println(s2);
}
}
class Supperman{
String name;
int age;
String sex;
public Supperman(String name, int age) {
super();
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Supperman [name=" + name + ", age=" + age + ", sex=" + sex
+ "]";
}
}
複製程式碼
結果: Supperman [name=奧特曼, age=800, sex=男] Supperman [name=孫悟空, age=1000, sex=null] 現在更可以看出,你改變一個物件的屬性值,不會影響其他的物件,但是如果我們加上static呢?
static String sex;
複製程式碼
結果為:
Supperman [name=奧特曼, age=800, sex=男]
Supperman [name=孫悟空, age=1000, sex=男]
複製程式碼
再看上述程式碼的記憶體解析圖
簡單來講就是:s1.name=""僅僅改變的是s1物件中name屬性值,不會影響s2中的name的值,但是s1.sex=""改變的可是所有該類的例項物件的sex的屬性值。static修飾屬性(類變數)
當static修飾屬性時,由類建立的所有物件都共用這一個屬性。當其中一個物件對此屬性修改時,會導致其他物件對此屬性的一個呼叫,靜態變數可以通過類.類變數的形式來呼叫。類變數隨類的載入而載入的,而且只有一份,類變數的載入是早於物件的,類變數存在與靜態域中。 例如所有的中國人都有一個國家名稱,每一箇中國人都共享這個國家名稱,所以我們不必為中國人這個例項物件都單獨分配一個代表國家名稱的變數吧,這個時候就用到了static修飾變數。
static修飾方法(類方法)
static修飾方法需要說明的是: 1.隨之類的載入而載入,在記憶體中也只有一份。 2.可以直接通過類.類方法,普通的方法只能通過物件來呼叫。 3.內部可以呼叫靜態的屬性和靜態方法,不能呼叫非靜態的屬性和方法,反之,非靜態的方法卻可以呼叫靜態的屬性和方法。 4.靜態方法裡不可以有this關鍵字和super關鍵字。 5.靜態的結構,例如靜態屬性,靜態方法,靜態程式碼塊,內部類等等的生命週期要早於非靜態結構,被回收也要晚於非靜態結構。
public class TestStatic {
public static void main(String[] args) {
Supperman.run();
}
}
class Supperman{
String name;
int age;
static String sex;
public static void run(){
System.out.println("sex"+sex);
System.out.println("超人飛走了!");
}
複製程式碼
先說說屬性賦值的方法
1.預設的初始化 2.顯示的初始化或者使用程式碼塊進行初始化 3.使用構造器 4.通過屬性的setter方法進行修改
程式碼塊
程式碼塊的作用是用來初始化類的屬性,根據是否有static關鍵字修飾分為靜態程式碼塊和非靜態程式碼塊 例如有如下類:
class Order{
private int orderId;
private String orderName;
public Order() {
super();
}
public Order(int orderId, String orderName) {
super();
this.orderId = orderId;
this.orderName = orderName;
}
public int getOrderId() {
return orderId;
}
public void setOrderId(int orderId) {
this.orderId = orderId;
}
public String getOrderName() {
return orderName;
}
public void setOrderName(String orderName) {
this.orderName = orderName;
}
@Override
public String toString() {
return "Order [orderId=" + orderId + ", orderName=" + orderName + "]";
}
複製程式碼
測試程式碼如下:
public static void main(String[] args) {
Order o1 = new Order();
System.out.println(o1);
}
複製程式碼
結果為: Order [orderId=0, orderName=null] 下面就使用程式碼塊來對屬性賦值。
靜態程式碼塊
1.裡面可以有輸出語句。 2.隨著類的載入而載入,而且只被載入一次。 3.多個靜態程式碼塊按照順序一次執行 4.靜態程式碼快的執行要早於非靜態的 5.靜態的程式碼塊裡只能執行靜態的結構(靜態屬性,靜態方法)
static{
System.out.println("我是靜態程式碼塊");
}
複製程式碼
非靜態程式碼塊
1.可以對類的屬性(靜態的或者非靜態)進行初始化操作,同時也可以呼叫自身類中的方法(靜態的或者非靜態的) 2.裡面也可以有輸出語句 3.一個類也可以有多個非靜態的程式碼塊,彼此之間順序執行, 4.每建立一個物件,非靜態類就載入一次,這個和靜態程式碼塊不一樣 5.非靜態程式碼塊的執行要在於構造器 在上述Order類中加入如下程式碼
private int orderId = 1000;
private String orderName;
//初始化塊
{
orderId=1001;
orderName="AA";
}
複製程式碼
同樣的測試語句,結果為:
Order [orderId=1001, orderName=AA]
複製程式碼
程式碼塊總結
關於程式碼塊的所有知識可以通過下面這個程式碼來解釋:
public class TestOrder {
public static void main(String[] args) {
Order o1 = new Order();
System.out.println(o1);
System.out.println("============我是帥氣分隔符========");
Order o2 = new Order();
System.out.println(o2);
}
}
class Order{
private int orderId = 1000;
private String orderName;
//初始化塊
static{
System.out.println("我是靜態程式碼塊");
}
{
orderId=1001;
orderName="AA";
System.out.println("我是非靜態程式碼塊1");
}
{
orderId=1002;
orderName="BB";
System.out.println("我是非靜態程式碼塊2");
}
public Order() {
super();
}
public Order(int orderId, String orderName) {
super();
this.orderId = orderId;
this.orderName = orderName;
}
public int getOrderId() {
return orderId;
}
public void setOrderId(int orderId) {
this.orderId = orderId;
}
public String getOrderName() {
return orderName;
}
public void setOrderName(String orderName) {
this.orderName = orderName;
}
@Override
public String toString() {
return "Order [orderId=" + orderId + ", orderName=" + orderName + "]";
}
}
複製程式碼
執行結果為:
我是靜態程式碼塊
我是非靜態程式碼塊1
我是非靜態程式碼塊2
Order [orderId=1002, orderName=BB]
============我是帥氣分隔符========
我是非靜態程式碼塊1
我是非靜態程式碼塊2
Order [orderId=1002, orderName=BB]
複製程式碼
static導包
如果我們要使用靜態成員(方法和變數)我們就要用類.類方法(類變數)。如果使用了靜態導包,就不用在給出類了,如下TestStaticPackge類
public class TestStaticPackge {
public static void output(){
System.out.println("Hello world");
}
}
複製程式碼
如果我們不使用靜態導包,訪問就是這個樣子的:
public static void main(String[] args) {
TestStaticPackge.output();
}
複製程式碼
靜態導包的方法: import static 包名.類名.靜態成員變數;
import static 包名.類名.靜態成員函式;
注意匯入的是成員變數和方法名。 例如上述:
import static com.java.study.TestStaticPackge.output;
public class TestOrder {
public static void main(String[] args) {
TestStaticPackge.output();//不使用靜態導包
output();//使用靜態導包
}
}
複製程式碼
總結:
有static可以脫離物件而執行,沒有就必須依賴物件