1、類變量和類方法
對象是由屬性和行爲構成,屬性對應java類中的
成員變量(實例變量和類變量),行爲對應類中的方法。
java類的狀態是由他的成員變量的狀態決定的。
在java中被聲明爲static的成員變量和成員方法是類變量和類方法,在類加載的時候即被初始化。存放在方法區。
沒有被聲明爲static的成員變量和成員方法是實例變量和實例方法。實例變量在new 一個對象的時候初始化。實例方法應該是啥時候調用,啥時候初始化。
實例變量存放在堆區,他的生命週期與對象的相同。調用實例方法的時候,虛擬機會在棧區開闢一塊單獨的內存空間,因此實例方法內的變量是現成安全的,執行完畢後,虛擬機會收回這塊內存。
2、更多初始化的內容
執行一個類的時候,jvm首先找到類名.class,而後裝載,加載進內存,這個時候在內存中會造成一個類對象,用來表明這個類(因此咱們用對象.class.getClassName()的時候老是獲得相同的值,這個就是類對象的名字),而後進行靜態初始化,初始化類中的全部成員變量以及成員函數還有static塊。
靜態初始化只進行一次:當靜態變量或者方法被調用,類加載的時候進行!靜態的東西是屬於類的。而不是屬於對象的,過分的使用靜態是很危險的!確信使用靜態的時候才使用靜態!
java初始化的時候一個基本的原則:
先靜態後動態
先定義初始化後構造函數。
package com;
class A{
A(String who){
System.out.println("create A by "+who);
}
}
class B{
A a = new A("B");
B(String who){
System.out.println("create B by "+who);
}
}
class C{
static {
A a = new A("C static");
}
C(String who){
System.out.println("create C by "+who);
}
}
class Init{
static B b = new B("Init");
static C c = new C("Init");
//C c = new C("Init");
public static void main(String [] args){
}
}
保存爲Init.java
編譯:javac com/Init.java
執行:java com/Init
當你在cmd命令行窗口上敲入
java com/Init 的時候,
一、啓動java虛擬機。
二、到com下面查找Init.class。
三、若是有就加載進jvm,沒有就跑出一個nofound的異常。
四、jvm將Init.class加載到內存,造成類對象,而後開始靜態初始化。執行
static B b = new B("Init");
五、而後加載B.class進內存
六、而後執行new B("Init");的操做。即調用B的構造函數。
七、根據先定義初始化後構造函數的順序,會先執行
A a = new A("B");
八、jvm加載A進內存,並造成A的類對象。而後調用A的構造函數建立A 。
九、而後調用B的構造函數建立B。
十、而後執行
static C c = new C("Init");,重複上面的順序。
因此最後的打印結果是:
create A by B
create B by Init
create A by C static
create C by Init
注意:若是把
static C c = new C("Init");改爲:C c = new C("Init");打印的結果應該是:
create A by B
create B by Init
由於咱們並無用調用C的構造函數去new一個C出來,而沒有static修飾的變量不是類變量,並不在類加載的時候初始化,他是在調用此類的構造函數以前被初始化。
再來看一個java中比較有趣的東西:
package com;
class Some{
int i;
boolean b;
char c;
double d;
int k = f();
int u = g(k);
{
Init init = new Init();
}
int f(){
return 10;
}
int g(int u){
if(u==10)
return 100;
return 0;
}
void print(){
System.out.println("i:"+i+" k:"+k +" u:"+u+" b:"+b+" c:"+c+" d:"+d);
if(c=='\0'){
System.out.println("c is '\0'");
}
}
public static void main(String [] args){
Some some = new Some();
some.print();
}
}
執行結果是:
create A by B
create B by Init
create A by C static
create C by Init
i:0 k:10 u:100 b:false c: d:0.0
c is ' '
java容許在定義初始化的時候調用函數。
也容許使用{}這樣的東西來作一些特別的事情。
3、new String("a string")到底幹了什麼?
String str = new String("a string");到底作了什麼?
一、an object of String is create //在堆區內建立一個String類型的對象
二、the object is initialized by "a string"//用a string 初始化它
三、a variable as handle to String is create //在棧區內建立一個句柄,也就是引用變量str
四、the value of the handle variable is assign to the object//這個str指向堆區內的String對象
4、傳值仍是傳引用
java中函數傳遞參數通通能夠理解爲是傳值!不過要搞清楚,這個值裏面是什麼東西,是對象的引用仍是基本的數據類型。
class Letter{
char c = 'a';
}
class passObject{
static void f(Letter y){
y.c = 'z';// y.c = 'z' 就是改變這個對象的成員變量c的值,因此,x.c = ‘z’
}
public static void main(String [] args){
Letter x = new Letter();//建立一個Letter類型的變量x,x中存儲Letter對象的首地址好比0x001....
f(x);//至關於作了 y = x的操做,這個時候y與x指向同一個對象
System.out.println(x.c);
}
}
x是一個引用,他是Letter類型的變量,他存儲Letter的對象的首地址好比多是0x001(也就是他是指向Letter對象的句柄),這句話就是把對象的引用付給y 就至關於作了 y = x 操做,這個時候y與x指向同一個對象。