一.java隨記筆記(備複習面試用)

一.java靜態方法只能調用靜態方法 java

1.須要知道java的編譯過程。靜態方法的代碼在項目啓動的時候就被初始化,那麼,你「主方法」是靜態的,項目啓動時須要初始化,「被調用的方法」固然也必須是靜態的,由於在「主方法」初始化的時候須要調用到「被調用的方法」,不然就沒法找到「被調用方法」而致使編譯失敗。 若是你在非靜態的方法去調用其餘的方法,那麼」被調用的方法「就不須要是靜態的了緩存

二.Java類在new的過程當中,靜態域、靜態塊、非靜態域、非靜態塊、構造函數的執行順序問題安全

1.這裏先把整理好的結論拋給你們,代碼實例驗證請點擊鏈接http://www.javashuo.com/article/p-ejdpgzba-ga.html。在Java類被new的過程當中,執行順序以下:函數

  •     實現自身的靜態屬性和靜態代碼塊。(根據代碼出現的順序決定誰先執行)
  •     實現自身的非靜態屬性和非靜態代碼塊。
  •     執行自身的構造函數。

    在實現繼承的類被new的過程當中,初始化執行順序以下:測試

  •     實現父類的公共靜態屬性和靜態塊級代碼。
  •     實現自身的靜態屬性和靜態塊級代碼。
  •     實現父類的非靜態屬性和非靜態代碼塊。
  •     執行父類的構造函數。
  •     實現自身的非靜態屬性和非靜態代碼塊。
  •     執行自身的構造函數。

三.final的對象引用優化

使用final的限制條件和侷限性.net

 當聲明一個final成員時,必須在構造函數退出前設置它的值,以下:線程

public class MyClass {
  private final int myField = 3;
  public MyClass() {
    ...
  }
}對象

或者blog

public class MyClass {
  private final int myField;
  public MyClass() {
    ...
    myField = 3;
    ...
  }
}

final關鍵字做用在對象上,指的是該對象(堆)的引用(棧)不可變非對象不可變,也就是說該引用不能指向其餘對象

須要強調的是將指向對象的成員聲明爲final只能將該引用設爲不可變的,而非所指的對象。例如若是一個list聲明以下:

private final List myList = new ArrayList();

仍然能夠修改該list

myList.add("Hello");

然而,聲明爲final能夠保證以下操做不合法:

myList = new ArrayList();
myList = someOtherList;

何時應該使用final

在匿名內部類中引用外部對象要加final修飾符呢,由於,在匿名內部類中引用的外部對象受到外部線程的做用域的制約有其特定的生命週期,
      以線程爲例,當外部的變量生命週期已經完結以後,內部的線程還在運行,怎麼樣解決這個外部生命週期已經結束而在內部卻須要繼續使用呢,
      這個時候就須要在外部變量中添加final修飾符,其實內部匿名類使用的這個變量就是外部變量的一個「複製品」,即便外部變量生命週期已經結束,內部的「複製品「依然可用。

 一個答案就是「儘量的使用」。任何你不但願改變的(基本類型,或者指向一個對象,無論該對象是否可變)通常來說都應該聲明爲final。另外一種看待此問題的方式是:

 若是一個對象將會在多個線程中訪問而且你並無將其成員聲明爲final,則必須提供其餘方式保證線程安全

  「其餘方式」能夠包括聲明成員爲volatile,使用synchronized或者顯式Lock控制全部該成員的訪問。

四.基本數據類型

java中基本類型的包裝類的大部分都實現了常量池技術,即Byte,Short,Integer,Long,Character,Boolean。

這5種包裝類默認建立了數值[-128,127]的相應類型的緩存數據,可是超出此範圍仍然會去建立新的對象。 兩種浮點數類型的包裝類Float,Double並無實現常量池技術。

1.Integer

byte(字節) 	    8         -128 - 127                                           0
shot(短整型)        16      -32768 - 32768                                         0
int(整型)           32   -2147483648-2147483648                                    0
long(長整型)        64   -9233372036854477808-9233372036854477808                  0        
float(浮點型)       32  -3.40292347E+38-3.40292347E+38                            0.0f
double(雙精度)	    64  -1.79769313486231570E+308-1.79769313486231570E+308        0.0d
char(字符型)        16         ‘ \u0000 - u\ffff ’                             ‘\u0000 ’
boolean(布爾型)     1         true/false                                         false

        Integer a=100,b=100;
        System.out.println(a==b);//true
        Integer aa=128,bb=-128;
        System.out.println(aa==bb);//false

JVM會自動維護八種基本類型的常量池,int常量池中初始化-128~127的範圍,因此當爲Integer i=127時,在自動裝箱過程當中是取自常量池中的數值,而當Integer i=128時,128不在常量池範圍內,因此在自動裝箱過程當中需new 128,因此地址不同。

java除了基本數據類型能夠直接用運算符==來比較變量的值之外,其餘類型(類,包括外覆類)聲明的對象若是相比較值或內容是否相等,都必須用equals,若是用==,比較的是對象引用在內存中的地址值,而不是對象引用的內容。

2.String

針對同一個對象,new出來的字符串和直接賦值給變量的字符串存放的位置是不同的,前者是在堆裏面,然後者在常量池裏面,另外,在作字符串拼接操做,也就是字符串相"+"的時候,得出的結果是存在在常量池或者堆裏面,這個是根據狀況不一樣不必定的,我寫了幾行代碼測試了一下。

    1.直接定義字符串變量的時候賦值,若是表達式右邊只有字符串常量,那麼就是把變量存放在常量池裏面。

  2.new出來的字符串是存放在堆裏面。

  3.對字符串進行拼接操做,也就是作"+"運算的時候,分2中狀況:

  i.表達式右邊是純字符串常量,那麼存放在棧裏面。

  ii.表達式右邊若是存在字符串引用,也就是字符串對象的句柄,那麼就存放在堆裏面。

       String str1 = "aaa";
        String str2 = "bbb";
        String str3 = "aaabbb";
        String str4 = str1 + str2;
        String str5 = "aaa" + "bbb";
        System.out.println(str3 == str4); // false
        System.out.println(str3 == str4.intern()); // true
        System.out.println(str3 == str5);// true

String類的intern()方法的做用

通常咱們變成不多使用到 intern這個方法,今天我就來解釋一下這個方法是幹什麼的,作什麼用的

首先請你們看一個例子:

    public static void main(String[] args) throws Exception {
        String a =  "b" ; 
        String b =  "b" ; 
        
        System.out.print( a == b); 
        
        String c = "d" ;
        String d = new String( "d" ).intern() ; 
        System.out.println( c == d);
    } 

你們能看出來這個例子打印在控制檯的消息嗎?在這裏控制檯輸出的結果都是true  true,緣由在於 intern 這個方法返回的是 返回字符串對象的規範化表示形式,當調用 intern 方法時,若是池已經包含一個等於此 String 對象的字符串(該對象由 equals(Object) 方法肯定),則返回池中的字符串。不然,將此 String 對象添加到池中,而且返回此 String 對象的引用。這時候c和d就是相等的。

        String s1 = "ab123" ;
        String s2 = new String( "ab123" ) ;
        System.out.println( s1 == s2 ); 
        String s3 = s2.intern() ; 
        System.out.println( s1 == s3 ) ; 

public static final String A;   // 常量A
public static final String B;  // 常量B
    public static void main (String [] args) {
            // 將兩個常量用+鏈接對s進行初始化 
            String s = A + B; 
            String t = "abcd"; 
            if (s == t) { 
                System.out.println("s等於t,它們是同一個對象"); 
                } 
            else { 
                System.out.println("s不等於t,它們不是同一個對象"); 
                } 
        //scheduledThreadPool();
    }
    static { A = "ab"; B = "cd"; } 

解釋:

s不等於t,它們不是同一個對象。

A和B雖然被定義爲常量,可是它們都沒有立刻被賦值。在運算出s的值以前,他們什麼時候被賦值,以及被賦予什麼樣的值,都是個變數。所以A和B在被賦值以前,性質相似於一個變量。那麼s就不能在編譯期被肯定,而只能在運行時被建立了。

若是改爲:

public static final String A = "ab"; 
    // 常量A
 public static final String B = "cd"; 

結果爲:s等於t,它們是同一個對象

String s1 = new String("xyz"); //建立了幾個對象?

解釋:

考慮類加載階段和實際執行時。

(1)類加載對一個類只會進行一次。」xyz」在類加載時就已經建立並駐留了(若是該類被加載以前已經有」xyz」字符串被駐留過則不須要重複建立用於駐留的」xyz」實例)。駐留的字符串是放在全局共享的字符串常量池中的。

(2)在這段代碼後續被運行的時候,」xyz」字面量對應的String實例已經固定了,不會再被重複建立。因此這段代碼將常量池中的對象複製一份放到heap中,而且把heap中的這個對象的引用交給s1 持有。

這條語句建立了2個對象。

 

public class TestStringEqual {
    public static void main(String[] args) {
        String hello = "Hello";
        String lo = "lo";
        System.out.println((hello == "Hello") + " "); //true
        System.out.println((Other.hello == hello) + " "); //true
        System.out.println((other.Other.hello == hello) + " "); //true
        System.out.println((hello == ("Hel"+"lo")) + " "); //true
        System.out.println((hello == ("Hel"+lo)) + " "); //false
        System.out.println(hello == ("Hel"+lo).intern()); //true}}
        
    }
}
class Other {
    static String hello = "Hello";
}

package other;
public class Other {
    public static String hello = "Hello";
}

解釋:

在同包同類下,引用自同一String對象.

在同包不一樣類下,引用自同一String對象.

在不一樣包不一樣類下,依然引用自同一String對象.

在編譯成.class時可以識別爲同一字符串的,自動優化成常量,引用自同一String對象.

在運行時建立的字符串具備獨立的內存地址,因此不引用自同一String對象.

3.Float類型 減法運算時精度丟失問題

   Float xx = 2.0f;
   Float yy = 1.8f;
   Float tt = xx - yy;
   System.out.println("tttttt-----" + tt);

果真輸出結果是: tttttt-----0.20000005

測試了幾個float類型的減法,除了*.0這樣的相減沒有異議以外,都存在這個問題,就是說float在相減的時候精度丟失了。後來在網上找到一段解決這個問題的辦法,記在這裏:

   Float xx = 2.2f;
   Float yy = 2.0f;
   Float tt = xx - yy;
  
   BigDecimal b1 = new BigDecimal(Float.toString(xx));
   BigDecimal b2 = new BigDecimal(Float.toString(yy));
   float ss = b1.subtract(b2).floatValue(); 
   System.out.println("ssss----" + ss);
   System.out.println("tttttt-----" + tt);

ssss----0.2
tttttt-----0.20000005

這樣一對比,差別就很明顯了。

解決了問題,再找了一下爲何會產生這種差別:

網上有篇文章寫得很詳細,標題爲《剖析float型的內存存儲和精度丟失問題》,全文內容以下:

問題提出:12.0f-11.9f=0.10000038,"減不盡"爲何?

如今咱們就詳細剖析一下浮點型運算爲何會形成精度丟失?

http://blog.csdn.net/fancylovejava/article/details/12027039

五:if裏填什麼能能輸出ab   if(){
           System.out.println("a");
        }else{
           System.out.println("b");
        }

聯想Java中print、printf、println的區別

printf主要是繼承了C語言的printf的一些特性,能夠進行格式化輸出
print就是通常的標準輸出,可是不換行
println和print基本沒什麼差異,就是最後會換行
System.out.printf("the number is: d",t);

參照JAVA API的定義以下:
'd' 整數 結果被格式化爲十進制整數
'o' 整數 結果被格式化爲八進制整數
'x', 'X' 整數 結果被格式化爲十六進制整數
'e', 'E' 浮點 結果被格式化爲用計算機科學記數法表示的十進制數
'f' 浮點 結果被格式化爲十進制數
'g', 'G' 浮點 根據精度和舍入運算後的值,使用計算機科學記數形式或十進制格式對結果進行格式化。
'a', 'A' 浮點 結果被格式化爲帶有效位數和指數的十六進制浮點數
println("test")至關於print("testn")就是通常的輸出字符串

printprintlnprintf的區別
print將它的參數顯示在命令窗口,並將輸出光標定位在所顯示的最後一個字符以後。
println 將它的參數顯示在命令窗口,並在結尾加上換行符,將輸出光標定位在下一行的開始。
printf是格式化輸出的形式。

 int i = 4;
   double j = 5;

   System.out.print("用print輸出i:"+ i);
   System.out.println( "用println輸出i:"+ i);
   System.out.printf("i的值爲%d,j的值爲%f", i,j);

 

用print輸出i:4用println輸出i:4
i的值爲4,j的值爲5.000000

能夠看到,用print輸出i後,沒有換行,用println輸出的結果直接在print輸出語句後面,而輸出println後換行了,因此用printf輸出時,在第二行

咱們再來看printf 「i的值爲%d,j的值爲%f」這個字符串中的"%d"變爲i的值了,而"%f"變爲了j的值了! 這裏,"%d"的意思是一個int值的佔位符,"%f"爲一個double 或float值的點位符,這個變量的參數在後面提供。注意的是實參名必須按順序排。否則就會錯了。並且類型也要相符。若是咱們把語句改成System.out.printf("i的值爲%d,j的值爲%f", j,i);//i和j位置反了 這時就有錯了由於"%d"對應的參數變爲j,"%f"對應的變爲i了,而j是double的,與"%d"是int形的不一致。因此有錯了。 還有"%s"是一個字符串值的點位符的意思。"%c"是一個字符值的點位符的意思。 可能讀者還會問爲何j輸出變成了5.000000?那是由於double是默認有6位小數的(這個可能和系統電腦有關,有的不是6位吧)可是若是你想只要輸出兩位小數行不行?能夠啊!只要改下語句就好了! System.out.printf("i的值爲%d,j的值爲%.2f", i,j); 這裏的"%.2f"的意思是輸出兩位小數點。若是想輸出三位那就"%.3f"。 說到這裏你會發現原來printf也頗有用的。這樣能夠控制輸出的格式。

相關文章
相關標籤/搜索