亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > Java > 正文

Java中一些基礎概念的使用詳解

2019-11-26 16:06:46
字體:
來源:轉載
供稿:網友

  類的初始化順序
  在Java中,類里面可能包含:靜態變量,靜態初始化塊,成員變量,初始化塊,構造函數。在類之間可能存在著繼承關系,那么當我們實例化一個對象時,上述各部分的加載順序是怎樣的?

  首先來看代碼:

復制代碼 代碼如下:

class Parent
 {
     public static StaticVarible staticVarible= new StaticVarible("父類-靜態變量1");   
     public StaticVarible instVarible= new StaticVarible("父類-成員變量1");

     static
     {
         System.out.println("父類-靜態塊");
     }

     {
         System.out.println("父類-初始化塊");
     }

     public static StaticVarible staticVarible2= new StaticVarible("父類-靜態變量2");   
     public StaticVarible instVarible2= new StaticVarible("父類-成員變量2");

     public Parent()
     {
         System.out.println("父類-實例構造函數");
     }
 }

 class Child extends Parent
 {
     public static StaticVarible staticVarible= new StaticVarible("子類-靜態變量1");   
     public StaticVarible instVarible= new StaticVarible("子類-成員變量1");

     static
     {
         System.out.println("子類-靜態塊");
     }

     public Child()
     {
         System.out.println("子類-實例構造函數");
     }

     {
         System.out.println("子類-初始化塊");
     }

     public static StaticVarible staticVarible2= new StaticVarible("子類-靜態變量2");   
     public StaticVarible instVarible2= new StaticVarible("子類-成員變量2");

    
 }

 class StaticVarible
 {
     public StaticVarible(String info)
     {
         System.out.println(info);
     }
 }

  然后執行下面的語句:
復制代碼 代碼如下:

Child child = new Child();

輸出結果如下:
復制代碼 代碼如下:

父類-靜態變量1
父類-靜態塊
父類-靜態變量2
子類-靜態變量1
子類-靜態塊
子類-靜態變量2
父類-成員變量1
父類-初始化塊
父類-成員變量2
父類-實例構造函數
子類-成員變量1
子類-初始化塊
子類-成員變量2
子類-實例構造函數

  結論  
  從上述結果可以看出,在實例化一個對象時,各部分的加載順序如下:

  父類靜態成員/父類靜態初始化塊 -> 子類靜態成員/子類初始化塊 -> 父類成員變量/父類初始化塊 -> 父類構造函數 -> 子類成員變量/子類初始化塊 -> 子類構造函數

  和String相關的一些事兒
  首先,我們聊一聊Java中堆和棧的事兒。

•棧:存放基本類型,包括char/byte/short/int/long/float/double/boolean
•堆:存放引用類型,同時一般會在棧中保留一個指向它的指針,垃圾回收判斷一個對象是否可以回收,就是判斷棧中是否有指針指向堆中的對象。
  String作為一種特殊的數據類型,它不完全等同于基本類型,也不是全部的引用類型,許多面試題都有它的身影。

  String類型變量的存儲結構
  String的存儲結構分為兩部分,我們以String a = "abc";為例,描述String類型的存儲方式:

  1)在棧中創建一個char數組,值分為是'a','b','c'。

  2)在堆中創建一個String對象。

  Java中的字符串池
  為了節省空間和資源,JVM會維護一個字符串池,或者說會緩存一部分曾經出現過的字符串。

  例如下面的代碼:

復制代碼 代碼如下:

String v1 = "ab";
String v2 = "ab";

  實際上,v1==v2,因為JVM在v1聲明后,已經對“ab”進行了緩存。

  那么JVM對字符串進行緩存的依據是什么?我們來看下面的代碼,非常有意思:

復制代碼 代碼如下:

public class StringTest {
     public static final String constValue = "ab";
     public static final String staticValue;

     static
     {
         staticValue="ab";
     }

     public static void main(String[] args)
     {
         String v1 = "ab";
         String v2 = "ab";
         System.out.println("v1 == v2 : " + (v1 == v2));
         String v3 = new String("ab");
         System.out.println("v1 == v3 : " + (v1 == v3));
         String v4 = "abcd";
         String v5 = "ab" + "cd";
         System.out.println("v4 == v5 : " + (v4 == v5));
         String v6 = v1 + "cd";
         System.out.println("v4 == v6 : " + (v4 == v6));
         String v7 = constValue + "cd";
         System.out.println("v4 == v7 : " + (v4 == v7));
         String v8 = staticValue + "cd";
         System.out.println("v4 == v8 : " + (v4 == v8));
         String v9 = v4.intern();
         System.out.println("v4 == v9 :" + (v4 == v9));
         String v10 = new String(new char[]{'a','b','c','d'});
         String v11 = v10.intern();
         System.out.println("v4 == v11 :" + (v4 == v11));
         System.out.println("v10 == v11 :" + (v10 == v11));
     }
 }

  請注意它的輸出結果:
復制代碼 代碼如下:

v1 == v2 : true
v1 == v3 : false
v4 == v5 : true
v4 == v6 : false
v4 == v7 : true
v4 == v8 : false
v4 == v9 :true
v4 == v11 :true
v10 == v11 :false

  我們會發現,并不是所有的判斷都返回true,這似乎和我們上面的說法有矛盾了。其實不然,因為

  結論
  1. JVM只能緩存那些在編譯時可以確定的常量,而非運行時常量。

    上述代碼中的constValue屬于編譯時常量,而staticValue則屬于運行時常量。

  2. 通過使用 new方式創建出來的字符串,JVM緩存的方式是不一樣的。

    所以上述代碼中,v1不等同于v3。

  String的這種設計屬于享元模式嗎?
  這個話題比較有意思,大部分講設計模式的文章,在談到享元時,一般就會拿String來做例子,但它屬于享元模式嗎?

  字符串與享元的關系,大家可以參考下面的文章:深入C#字符串和享元(Flyweight)模式的使用分析
  字符串的反轉輸出
  這種情況下,一般會將字符串看做是字符數組,然后利用反轉數組的方式來反轉字符串。

  眼花繚亂的方法調用
  有繼承關系結構中的方法調用
  繼承是面向對象設計中的常見方式,它可以有效的實現”代碼復用“,同時子類也有重寫父類方法的自由,這就對到底是調用父類方法還是子類方法帶來了麻煩。

  來看下面的代碼:

復制代碼 代碼如下:

public class PropertyTest {

     public static void main(String[] args)
     {
         ParentDef v1 = new ParentDef();
         ParentDef v2 = new ChildDef();
         ChildDef v3 = new ChildDef();
         System.out.println("=====v1=====");
         System.out.println("staticValue:" + v1.staticValue);
         System.out.println("value:" + v1.value);
         System.out.println("=====v2=====");
         System.out.println("staticValue:" + v2.staticValue);
         System.out.println("value:" + v2.value);
         System.out.println("=====v3=====");
         System.out.println("staticValue:" + v3.staticValue);
         System.out.println("value:" + v3.value);
     }
 }

 class ParentDef
 {
     public static final String staticValue = "父類靜態變量";
     public String value = "父類實例變量";
 }

 class ChildDef extends ParentDef
 {
     public static final String staticValue = "子類靜態變量";
     public String value = "子類實例變量";
 }

  輸出結果如下:
復制代碼 代碼如下:

=====v1=====
staticValue:父類靜態變量
value:父類實例變量
=====v2=====
staticValue:父類靜態變量
value:父類實例變量
=====v3=====
staticValue:子類靜態變量
value:子類實例變量

  結論
  對于調用父類方法還是子類方法,只與變量的聲明類型有關系,與實例化的類型沒有關系。

  到底是值傳遞還是引用傳遞
  對于這個話題,我的觀點是值傳遞,因為傳遞的都是存儲在棧中的內容,無論是基本類型的值,還是指向堆中對象的指針,都是值而非引用。并且在值傳遞的過程中,JVM會將值復制一份,然后將復制后的值傳遞給調用方法。

  按照這種方式,我們來看下面的代碼:

復制代碼 代碼如下:

public class ParamTest {

     public void change(int value)
     {
         value = 10;
     }

     public void change(Value value)
     {
         Value temp = new Value();
         temp.value = 10;
         value = temp;
     }

     public void add(int value)
     {
         value += 10;
     }

     public void add(Value value)
     {
         value.value += 10;
     }

     public static void main(String[] args)
     {
         ParamTest test = new ParamTest();
         Value value = new Value();
         int v = 0;
         System.out.println("v:" + v);
         System.out.println("value.value:" + value.value);
         System.out.println("=====change=====");
         test.change(v);
         test.change(value);
         System.out.println("v:" + v);
         System.out.println("value.value:" + value.value);
         value = new Value();
         v = 0;
         System.out.println("=====add=====");
         test.add(v);
         test.add(value);
         System.out.println("v:" + v);
         System.out.println("value.value:" + value.value);
     }
 }

 class Value
 {
     public int value;
 }

  它的輸出結果:
復制代碼 代碼如下:

v:0
value.value:0
=====change=====
v:0
value.value:0
=====add=====
v:0
value.value:10

  我們看到,在調用change方法時,即使我們傳遞進去的是指向對象的指針,但最終對象的屬性也沒有變,這是因為在change方法體內,我們新建了一個對象,然后將”復制過的指向原對象的指針“指向了“新對象”,并且對新對象的屬性進行了調整。但是“復制前的指向原對象的指針”依然是指向“原對象”,并且屬性沒有任何變化。

  final/finally/finalize的區別
  final可以修飾類、成員變量、方法以及方法參數。使用final修飾的類是不可以被繼承的,使用final修飾的方法是不可以被重寫的,使用final修飾的變量,只能被賦值一次。

  使用final聲明變量的賦值時機:

  1)定義聲明時賦值

  2)初始化塊或靜態初始化塊中

  3)構造函數

  來看下面的代碼:

復制代碼 代碼如下:

class FinalTest
 {
     public static final String staticValue1 = "靜態變量1";
     public static final String staticValue2;

     static
     {
         staticValue2 = "靜態變量2";
     }

     public final String value1 = "實例變量1";
     public final String value2;
     public final String value3;

     {
         value2 = "實例變量2";
     }

     public FinalTest()
     {
         value3 = "實例變量3";
     }
 }

  finally一般是和try...catch放在一起使用,主要用來釋放一些資源。

  我們來看下面的代碼:

復制代碼 代碼如下:

public class FinallyTest {

     public static void main(String[] args)
     {
         finallyTest1();
         finallyTest2();
         finallyTest3();
     }

     private static String finallyTest1()
     {
         try
         {
             throw new RuntimeException();
         }
         catch(Exception ex)
         {
             ex.printStackTrace();
         }
         finally
         {
             System.out.println("Finally語句被執行");
         }
         try
         {
             System.out.println("Hello World");
             return "Hello World";
         }
         catch(Exception ex)
         {
             ex.printStackTrace();
         }
         finally
         {
             System.out.println("Finally語句被執行");
         }
         return null;
     }

     private static void finallyTest2()
     {
         int i = 0;
         for (i = 0; i < 3; i++)
         {
             try
             {
                 if (i == 2) break;
                 System.out.println(i);
             }
             finally
             {
                 System.out.println("Finally語句被執行");
             }
         }
     }

     private static Test finallyTest3()
     {
         try
         {
             return new Test();
         }
         finally
         {
             System.out.println("Finally語句被執行");
         }
     }
 }

  執行結果如下:
復制代碼 代碼如下:

java.lang.RuntimeException
    at sample.interview.FinallyTest.finallyTest1(FinallyTest.java:16)
    at sample.interview.FinallyTest.main(FinallyTest.java:7)
Finally語句被執行
Hello World
Finally語句被執行

Finally語句被執行

Finally語句被執行
Finally語句被執行
Test實例被創建
Finally語句被執行


  注意在循環的過程中,對于某一次循環,即使調用了break或者continue,finally也會執行。

  finalize則主要用于釋放資源,在調用GC方法時,該方法就會被調用。

  來看下面的示例:

復制代碼 代碼如下:

class FinalizeTest
 {
     protected void finalize()
     {
         System.out.println("finalize方法被調用");
     }

     public static void main(String[] args)
     {
         FinalizeTest test = new FinalizeTest();
         test = null;
         Runtime.getRuntime().gc();
     }
 }

  執行結果如下:
復制代碼 代碼如下:

finalize方法被調用

  關于基本類型的一些事兒
  基本類型供分為9種,包括byte/short/int/long/float/double/boolean/void,每種基本類型都對應一個“包裝類”,其他一些基本信息如下:
復制代碼 代碼如下:

. 基本類型:byte 二進制位數:8
. 包裝類:java.lang.Byte
. 最小值:Byte.MIN_VALUE=-128
. 最大值:Byte.MAX_VALUE=127
. 基本類型:short 二進制位數:16
. 包裝類:java.lang.Short
. 最小值:Short.MIN_VALUE=-32768
. 最大值:Short.MAX_VALUE=32767
. 基本類型:int 二進制位數:32
. 包裝類:java.lang.Integer
. 最小值:Integer.MIN_VALUE=-2147483648
. 最大值:Integer.MAX_VALUE=2147483647
. 基本類型:long 二進制位數:64
. 包裝類:java.lang.Long
. 最小值:Long.MIN_VALUE=-9223372036854775808
. 最大值:Long.MAX_VALUE=9223372036854775807
. 基本類型:float 二進制位數:32
. 包裝類:java.lang.Float
. 最小值:Float.MIN_VALUE=1.4E-45
. 最大值:Float.MAX_VALUE=3.4028235E38
. 基本類型:double 二進制位數:64
. 包裝類:java.lang.Double
. 最小值:Double.MIN_VALUE=4.9E-324
. 最大值:Double.MAX_VALUE=1.7976931348623157E308
. 基本類型:char 二進制位數:16
. 包裝類:java.lang.Character
. 最小值:Character.MIN_VALUE=0
. 最大值:Character.MAX_VALUE=65535

  關于基本類型的一些結論(來自《Java面試解惑》)
•未帶有字符后綴標識的整數默認為int類型;未帶有字符后綴標識的浮點數默認為double類型。
•如果一個整數的值超出了int類型能夠表示的范圍,則必須增加后綴“L”(不區分大小寫,建議用大寫,因為小寫的L與阿拉伯數字1很容易混淆),表示為long型。
•帶有“F”(不區分大小寫)后綴的整數和浮點數都是float類型的;帶有“D”(不區分大小寫)后綴的整數和浮點數都是double類型的。
•編譯器會在編譯期對byte、short、int、long、float、double、char型變量的值進行檢查,如果超出了它們的取值范圍就會報錯。
•int型值可以賦給所有數值類型的變量;long型值可以賦給long、float、double類型的變量;float型值可以賦給float、double類型的變量;double型值只能賦給double類型變量。
  關于基本類型之間的轉換
  下面的轉換是無損精度的轉換:

•byte->short
•short->int
•char->int
•int->long
•float->double
  下面的轉換是會損失精度的:

•int->float
•long->float
•long->double
  除此之外的轉換,是非法的。

  和日期相關的一些事兒
  Java中,有兩個類和日期相關,一個是Date,一個是Calendar。我們來看下面的示例:

復制代碼 代碼如下:

public class DateTest {

     public static void main(String[] args) throws ParseException
     {
         test1();
         test2();
         test3();
     }

     private static void test1() throws ParseException
     {
         Date date = new Date();
         System.out.println(date);
         DateFormat sf = new SimpleDateFormat("yyyy-MM-dd");
         System.out.println(sf.format(date));
         String formatString = "2013-05-12";
         System.out.println(sf.parse(formatString));
     }

     private static void test2()
     {
         Date date = new Date();
         System.out.println("Year:" + date.getYear());
         System.out.println("Month:" + date.getMonth());
         System.out.println("Day:" + date.getDate());
         System.out.println("Hour:" + date.getHours());
         System.out.println("Minute:" + date.getMinutes());
         System.out.println("Second:" + date.getSeconds());
         System.out.println("DayOfWeek:" + date.getDay());
     }

     private static void test3()
     {
         Calendar c = Calendar.getInstance();
         System.out.println(c.getTime());
         System.out.println(c.getTimeZone());
         System.out.println("Year:" + c.get(Calendar.YEAR));
         System.out.println("Month:" + c.get(Calendar.MONTH));
         System.out.println("Day:" + c.get(Calendar.DATE));
         System.out.println("Hour:" + c.get(Calendar.HOUR));
         System.out.println("HourOfDay:" + c.get(Calendar.HOUR_OF_DAY));
         System.out.println("Minute:" + c.get(Calendar.MINUTE));
         System.out.println("Second:" + c.get(Calendar.SECOND));
         System.out.println("DayOfWeek:" + c.get(Calendar.DAY_OF_WEEK));
         System.out.println("DayOfMonth:" + c.get(Calendar.DAY_OF_MONTH));
         System.out.println("DayOfYear:" + c.get(Calendar.DAY_OF_YEAR));
     }
 }

  輸出結果如下:
復制代碼 代碼如下:

Sat May 11 13:44:34 CST 2013
-05-11
Sun May 12 00:00:00 CST 2013
Year:113
Month:4
Day:11
Hour:13
Minute:44
Second:35
DayOfWeek:6
Sat May 11 13:44:35 CST 2013
sun.util.calendar.ZoneInfo[id="Asia/Shanghai",offset=28800000,dstSavings=0,useDaylight=false,transitions=19,lastRule=null]
Year:2013
Month:4
Day:11
Hour:1
HourOfDay:13
Minute:44
Second:35
DayOfWeek:7
DayOfMonth:11
DayOfYear:131

  需要注意的是,Date中的getxxx方法已經變成deprecated了,因此我們盡量使用calendar.get方法來獲取日期的細節信息。
  另外,注意DateFormat,它不僅可以對日期的輸出進行格式化,而且可以逆向操作,將符合Format的字符串轉換為日期類型。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
久久精品精品电影网| 亚洲999一在线观看www| 亚洲无限av看| 欧美日韩国产中文精品字幕自在自线| 91国内揄拍国内精品对白| 久久精品成人一区二区三区| 国产午夜精品免费一区二区三区| 成人国产精品久久久| 国产一区二区视频在线观看| 欧美野外wwwxxx| 亚洲黄页视频免费观看| xvideos成人免费中文版| 久久综合久中文字幕青草| 不卡av电影在线观看| 国产精品白嫩美女在线观看| 在线观看日韩www视频免费| 国产精自产拍久久久久久蜜| 中文字幕欧美视频在线| 国产成人精品免费久久久久| 亚洲一区二区三区视频| 欧美激情视频一区二区三区不卡| 欧美大秀在线观看| 国产精品成人v| 日韩av网站大全| 欧美另类老肥妇| 神马久久桃色视频| 欧美猛少妇色xxxxx| 456亚洲影院| 日韩欧美大尺度| 欧美一级在线播放| 亚洲精品小视频| 欧美做受高潮1| 国产网站欧美日韩免费精品在线观看| 北条麻妃一区二区在线观看| 日韩av中文字幕在线| 久久精视频免费在线久久完整在线看| 黑丝美女久久久| 这里精品视频免费| 成人欧美一区二区三区在线湿哒哒| 欧美老女人性视频| 欧美电影免费观看网站| 国产精品视频地址| 一区二区在线视频播放| 国内外成人免费激情在线视频网站| 日韩欧美成人精品| 亚洲最大av在线| 国产精品高精视频免费| 欧亚精品中文字幕| 日韩在线中文视频| 国产欧美在线播放| 日韩高清中文字幕| 欧美肥婆姓交大片| 日韩视频亚洲视频| 日本久久久久久久久| 日韩精品在线私人| 欧美日韩成人黄色| 国产91av在线| 久久高清视频免费| 欧美午夜激情小视频| 国产精品揄拍500视频| 久久九九有精品国产23| 亚洲国产另类 国产精品国产免费| 亚洲人成亚洲人成在线观看| 91久久精品久久国产性色也91| 91探花福利精品国产自产在线| 午夜免费日韩视频| 亚洲精品自在久久| 精品国产自在精品国产浪潮| 亚洲国产欧美一区| 亚洲人成在线观看网站高清| 精品国内产的精品视频在线观看| 日韩乱码在线视频| 91理论片午午论夜理片久久| 亚洲曰本av电影| 在线观看国产精品日韩av| 亚洲伊人久久综合| 亚洲成人黄色网址| 国产精品极品美女粉嫩高清在线| 亚洲日韩欧美视频| 综合国产在线视频| 亚洲永久在线观看| 精品美女永久免费视频| 国产福利视频一区| 国产视频一区在线| 91深夜福利视频| 日韩经典中文字幕| 国产成人综合av| 日韩中文字幕在线视频播放| 欧美日韩国内自拍| 国产精品男人爽免费视频1| 色av中文字幕一区| 一区二区三区国产视频| 久久久久久久久久国产精品| 亚洲欧洲成视频免费观看| 国产精品都在这里| 欧美久久精品午夜青青大伊人| 欧美肥臀大乳一区二区免费视频| 姬川优奈aav一区二区| 日韩av综合网站| 国产精品福利久久久| 97在线精品国自产拍中文| 亚洲护士老师的毛茸茸最新章节| 久久99国产精品自在自在app| 亚洲综合自拍一区| 午夜欧美大片免费观看| 国产精品视频在线观看| 日韩中文字幕第一页| 国产福利视频一区二区| 日韩欧美在线中文字幕| 亚洲人成人99网站| 日韩精品电影网| 国产亚洲欧美日韩一区二区| 国产成人精品999| 久久露脸国产精品| 久久九九热免费视频| 国产成人综合精品在线| 欧洲s码亚洲m码精品一区| 国产精品xxx视频| 国产一区二区三区中文| 日本久久久久久久| 日韩欧美在线视频免费观看| 亚洲一区二区久久久久久久| 欧美激情免费看| 不卡av在线网站| 久久国产精品久久精品| 中文字幕一区二区三区电影| 亚洲天堂久久av| 亚洲一区国产精品| 国产成人激情小视频| 日韩在线视频线视频免费网站| 7777kkkk成人观看| 伊人亚洲福利一区二区三区| 成人性生交大片免费观看嘿嘿视频| 在线观看精品国产视频| 亚洲美女精品成人在线视频| 精品免费在线观看| 久热精品视频在线| 一本大道香蕉久在线播放29| 热门国产精品亚洲第一区在线| 亚洲国产成人在线视频| 欧美肥臀大乳一区二区免费视频| 粗暴蹂躏中文一区二区三区| 久久久欧美一区二区| 精品久久久久久中文字幕大豆网| 亚洲黄在线观看| 美女啪啪无遮挡免费久久网站| 国产a级全部精品| 69视频在线免费观看| 欧美亚洲另类视频| 久久精品视频播放| 欧美日韩午夜视频在线观看| 久久av在线看| 另类专区欧美制服同性| 欧美激情在线视频二区| 亚洲一区久久久| 最好看的2019年中文视频| 91久久久国产精品| 日韩欧美在线第一页| 97在线视频精品| 亚洲人成网站999久久久综合| 日韩视频一区在线| 亚洲尤物视频网| 欧美日韩国产va另类| 日韩专区在线播放|