Java基礎隨記-不定時更新

来源:https://www.cnblogs.com/zhuii/archive/2018/11/10/9940224.html
-Advertisement-
Play Games

一.hashMap與hashTable與ConcurrentHashMap: 1.HashMap是繼承自AbstractMap類,而HashTable是繼承自Dictionary類。不過它們都同時實現了map、Cloneable(可複製)、Serializable(可序列化)這三個介面。<Dicti ...


一.hashMap與hashTable與ConcurrentHashMap:

  1.HashMap是繼承自AbstractMap類,而HashTable是繼承自Dictionary類。不過它們都同時實現了map、Cloneable(可複製)、Serializable(可序列化)這三個介面。<Dictionary類是一個已經被廢棄的類>

  2.Hashtable既不支持Null key也不支持Null value。HashMap中,null可以作為鍵,這樣的鍵只有一個,可以有一個或多個鍵所對應的值為null。

  3.Hashtable是線程安全的,它的每個方法中都加入了Synchronize方法。在多線程併發的環境下,可以直接使用Hashtable,不需要自己為它的方法實現 同步,HashMap不是線程安全的,在多線程併發的環境下,可能會產生死鎖等問題。如果想要線程安全的     HashMap,可以通過Collections類的靜態方法synchronize dMap獲得線程安全的HashMap。 <Map map = Collections.synchronizedMap(new HashMap())>;

  4.hashMap的數據結構:HashMap的底層主要是基於數組和鏈表來實現的,它之所以有相當快的查詢速度主要是因為它是通過計算散列碼來決定存儲的位置。

  5.ConcurrentHashMap:底層採用分段的數組+鏈表實現,線程安全ConcurrentHashMap允許多個修改操作併發進行,其關鍵在於使用了鎖分離技術。它使用了多個鎖來控制對hash表的不同部分進行的修改。ConcurrentHashMap內部使用段(Segment)來表示這些不同的部分,每個段其實就是一個小的Hashtable,它們有自己的鎖。只要多個修改操作發生在不同的段上,它們就可以併發進行。

  JDK1.8的實現已經摒棄了Segment的概念,而是直接用Node數組+鏈表+紅黑樹的數據結構來實現,此時鎖加在key上,併發控制使用Synchronized和CAS來操作,整個看起來就像是優化過且線程安全的HashMap,雖然在JDK1.8中還能看到Segment的數據結構,但是已經簡化了屬性,只是為了相容舊版本。

二.(String)、toString、String.valueOf的區別

  1.(String):使用這種方法時,需要註意的是類型必須能轉成String類型。因此最好用instanceof做個類型檢查,以判斷是否可以轉換。instanceof 運算符是用來在運行時指出對象是否是特定類的一個實例,

父類parent,子類son, 此時 flag= son instanceof parent,flag=true。

  2.toString:String s = Object.toString(),在使用時要註意,必須保證object不是null值,否則將拋出NullPointerException異常。

  3.String.valueOf:

  內部實現:
    public static String valueOf(Object obj){
      return (obj==null) ? "null" : obj.toString()
    };
  當Object不為空時,調用toString()方法,當Object為null時,則返回一個字元串"null"!!!!

三.位元組流與字元流的區別

  位元組流:InputStream,OutputStream,程式→文件
  字元流:BufferedRead,BufferedWrite,程式→緩存區→文件
  字元流需要關閉字元流,緩存區的數據才會被寫入文件,否則會一直堆在緩存區。或者可以用flush()方法,將數據強行寫入文件。

  利用BufferedRead讀取文件:

  

public static void main(String[] args) throws Exception {
  String s= "F:/456.txt";
  File f =new File(s);
  FileReader fr = new FileReader(f);
  BufferedReader br = new BufferedReader(fr);
  String temp="";
  while((temp=br.readLine())!=null) {
    System.out.println(temp);
  }
}

四.Integer

源代碼:
  private static class IntegerCache {//靜態緩存類
    static final int low = -128;
    static final int high;
    static final Integer cache[];
    static { //靜態代碼塊
      // high value may be configured by property
      int h = 127;
      String integerCacheHighPropValue =
        sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
      if (integerCacheHighPropValue != null) {
        int i = parseInt(integerCacheHighPropValue);
        i = Math.max(i, 127);
        // Maximum array size is Integer.MAX_VALUE
        h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
      }
      high = h;

      cache = new Integer[(high - low) + 1];
      int j = low;
      for(int k = 0; k < cache.length; k++)
        cache[k] = new Integer(j++);
      }      private IntegerCache() {}

  }
  這個類就是在Integer類裝入記憶體中時,會執行其內部類中靜態代碼塊進行其初始化工作,做的主要工作就是把一位元組的整型數據(-128,127)裝包成Integer類並把其對應的引用存入cache數組中,這樣在方法區中開闢空間存放這些靜態Integer變數,同時靜態cache數組也存放在這裡,供線程享用,這也稱靜態緩存。
所以當用Integer聲明初始化變數時,會先判斷所賦值的大小是否在-128到127之間,若在,則利用靜態緩存中的空間並且返回對應cache數組中對應引用,存放到運行棧中,而不再重新開闢記憶體。若不在則new 一個新的對象放入堆中。

五.類的初始化過程

/*父類*/
  public class Person {
    public Person() {
      System.out.println("im person_1");
    }
    {
    System.out.println("im person_2");
    }
    static {
      System.out.println("im person_3");
    }
  }
/*子類*/
  public class test extends Person {
    public test() {
      System.out.println("im test_1");
    }
    {
      System.out.println("im test_2");
    }
    static {
      System.out.println("im test_3");
    }
    public static void main(String[] args) throws Exception {
      new test();
    }
  }

輸出:
  im person_3
  im test_3
  im person_2
  im person_1
  im test_2
  im test_1

解釋:在類中變數初始化時,順序為 static→變數→構造方法。

六.值傳遞,引用傳遞

public class test {
  String s="hello";
  char[] ch={'a','b','c'};
  Character ck='k';
  public static void main(String[] args) throws Exception {
    test tt = new test();
    tt.change(tt.s,tt.ch,tt.ck);
    System.out.println("--------");
    System.out.println("s+"+tt.s.hashCode());
    System.out.println("ch+"+tt.ch.hashCode());
    System.out.println("ck+"+tt.ck.hashCode());
    System.out.println("--------");
    System.out.println(tt.s);
    System.out.println(tt.ch);
    System.out.println(tt.ck);
  }
  public void change(String str,char[] ch,Character ck){
    str="world";
    ch[0]='d';
    ck='c';
    System.out.println("str+"+str.hashCode());
    System.out.println("ch+"+ch.hashCode());
    System.out.println("ckl+"+ck.hashCode());
  }
}

輸出:
  str+113318802
  ch+1828682968
  ckl+99
  --------
  s+99162322
  ch+1828682968
  ck+107
  --------
  hello
  dbc
  k

可見,String類型是不會被修改的,在編譯時,方法棧里有world,如果是輸入賦值給String應該會變,char數組傳遞的是數組的引用,Character傳遞的是值
傳值不會修改原來的,傳引用會修改原來的。

七.i++與++i

  

public static void main(String[] args) throws Exception {
  int a=1;
  int b=a++;   //先執行b=a,再執行a++
  System.out.println(b++);  //先執行print(b),再執行b++
}
輸出:1

八.==與equals的區別

  

==:
  1.在==中,如果比較的是int,long,short這種基本數據類型,那麼==比較的是它們的值
  2.若比較的引用數據類型,如類,String,那麼比較的是它們的記憶體地址,除非是同一個new一個出來的對象,此時地址相同,返回ture,否則返回false
  如:
    String a= new String("abc");
    String b=a;
    sout(a==b); //ture
  若:
    String c= new String("c");
    String c1= "c";
    sout(c==c1); //false
equals:
  1.所有類都繼承自Object,若不重寫equals()方法,那麼調用Object類中的equals()方法,源代碼:
    public boolean equals(Object obj) {
      return (this == obj);
    }
  也就是仍然是比較其地址。
  2.若重寫其方法:
    在String中:
    源代碼:
      public boolean equals(Object anObject) {
        if (this == anObject) {
          return true;
        }
        if (anObject instanceof String) {
          String anotherString = (String) anObject;
          int n = value.length;
          if (n == anotherString.value.length) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;
            while (n-- != 0) {
              if (v1[i] != v2[i])
              return false;
              i++;
            }
            return true;
          }
        }
        return false;
     }
可以看出equals()是會先用==方法,然後比較兩個String的值是否相等。

九.final,static關鍵字

  final: 

  當用final修飾一個類時,表明這個類不能被繼承,比如出於安全的考慮,可修飾為final。
  如果只有在想明確禁止該方法在子類中被覆蓋的情況下才將方法設置為final的。
  對於一個final變數,如果是基本數據類型的變數,則其數值一旦在初始化之後便不能更改;如果是引用類型的變數,則在對其初始化之後便不能再讓其指向另一個對象。

  static:

  修飾類的成員變數時,每個類只有一個這個成員,而不是每個類的實例化對象都有一個這個變數。
  用static修飾後,類名.方法名,類名.屬性名,可直接調用,不用實例化對象,避免了先要new出對象的繁瑣和資源消耗。
  在創建對象時,static修飾的成員會首先被初始化。

十.sleep() 和 wait() 有什麼區別?

  sleep就是正在執行的線程主動讓出cpu,cpu去執行其他線程,在sleep指定的時間過後,cpu才會回到這個線程上繼續往下執行,如果當前線程進入了同步鎖,sleep方法並不會釋放鎖,即使當前線程使用sleep方法讓出了cpu,但其他被同步鎖擋住了的線程也無法得到執行。wait是指在一個已經進入了同步鎖的線程內,讓自己暫時讓出同步鎖,以便其他正在等待此鎖的線程可以得到同步鎖並運行,只有其他線程調用了notify方法(notify並不釋放鎖,只是告訴調用過wait方法的線程可以去參與獲得鎖的競爭了,但不是馬上得到鎖,因為鎖還在別人手裡,別人還沒釋放。如果notify方法後面的代碼還有很多,需要這些代碼執行完後才會釋放鎖,可以在notfiy方法後增加一個等待和一些代碼,看看效果),調用wait方法的線程就會解除wait狀態和程式可以再次得到鎖後繼續向下運行。

十一.得到文件下的文件

public static void FileRead(String path)throws Exception{
  File f= new File(path);
  if(!f.exists())
  System.out.println("file not exist");
  if (f.isDirectory()) {
    File[] ss = f.listFiles();
    for (File s : ss) {
    System.out.println(s.getPath());    // F:\txt\1.txt
  }
  }else{
    System.out.println(f.getName());
  }
}

十二.實現多線程的三種方法

1.繼承thread類創建線程
public class MyThread extends Thread {
  public void run() {
   System.out.println("MyThread.run()");
  }
}
  MyThread myThread1 = new MyThread();
  myThread1.start();
2.實現runnable介面創建線程
  public class MyThread extends OtherClass implements Runnable {
    public void run() {
      System.out.println("MyThread.run()");
    }
  }
3.實現Callable介面通過FutureTask包裝器來創建Thread線程

PS:別說四種,第四種無法理解

十三.抽象類與介面的區別 

主要是:單繼承(抽象類),多實現(介面)。
抽象類不能直接實例化對象,需要繼承抽象類才能實例化其子類。
從使用上來看,一個類可以實現多個介面,但是不能繼承多個抽象類。
介面的欄位只能是 static 和 final 類型的,而抽象類的欄位沒有這種限制。
介面的成員只能是 public 的,而抽象類的成員可以有多種訪問許可權。

十四.String Pool

String pool 指字元串常量池,保存著所有在編譯時就已經確定的String變數。調用String.intern()方法,可以將此String變數加入常量池中。
String pool在堆中。
String a= new String("a");
String a1= new String("a");
sout(a==a1); //false
String b="b";
String b1="b";
sout(b==b1); //true
String c= new String("c");
String c1= "c";
sout(c==c1); //false
sout(c.equals(c1)); //true
詳情見 八. ==與equals的區別

十五.ArrayList和Vector的區別

這兩個類都實現了List介面(List介面繼承了Collection介面),他們都是有序集合,即存儲在這兩個集合中的元素的位置都是有順序的,相當於一種動態的數組,我們以後可以按位置索引號取出某個元素,並且其中的數據是允許重覆的。
(1)同步性:
  Vector是線程安全的,也就是說是它的方法之間是線程同步的,而ArrayList是線程式不安全的,它的方法之間是線程不同步的。如果只有一個線程會訪問到集合,那最好是使用ArrayList,因為它不考慮線程安全,效率會高些;如果有多個線程會訪問到集合,那最   好是使用Vector,因為不需要我們自己再去考慮和編寫線程安全的代碼。
備註:對於Vector&ArrayList、Hashtable&HashMap,要記住線程安全的問題,記住Vector與Hashtable是舊的,是java一誕生就提供了的,它們是線程安全的,ArrayList與HashMap是java2時才提供的,它們是線程不安全的。所以,我們講課時先講老的。
(2)數據增長:
  ArrayList與Vector都有一個初始的容量大小,當存儲進它們裡面的元素的個數超過了容量時,就需要增加ArrayList與Vector的存儲空間,每次要增加存儲空間時,不是只增加一個存儲單元,而是增加多個存儲單元,每次增加的存儲單元的個數在記憶體空間利用與程式效率之間要取得一定的平衡。Vector預設增長為原來兩倍,而ArrayList的增長策略在文檔中沒有明確規定(從源代碼看到的是增長為原來的1.5倍)。ArrayList與Vector都可以設置初始的空間大小,Vector還可以設置增長的空間大小,而ArrayList沒有提供設置增長空間的方法。
總結:即Vector增長原來的一倍,ArrayList增加原來的0.5倍。

十六.Java 中Collections類里的reverse (反轉方法)

public static void reverse(List<?> list) {
  int size = list.size();
  if (size < REVERSE_THRESHOLD || list instanceof RandomAccess) {
    for (int i=0, mid=size>>1, j=size-1; i<mid; i++, j--)
    swap(list, i, j);
  } else {
    ListIterator fwd = list.listIterator();
    ListIterator rev = list.listIterator(size);
    for (int i=0, mid=list.size()>>1; i<mid; i++) {
      Object tmp = fwd.next();
      fwd.set(rev.previous());
      rev.set(tmp);
    }
  }
}
此方法可反轉數組的值.


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 學了100多天java知道了要抓住本質、最底層學習,比如堆和棧啊,類是怎麼載入的啊,再深一點的話就要看編譯原理了,還是羡慕電腦專業的。 靜態成員不可調用非靜態成員,static稱為靜態,靜態成員的最根本作用是區分屬性,方法,內部類,初始化塊成員到底屬於類本身,還是屬於類的實例,有static修飾的 ...
  • 1、PHP 自帶函數 getallheaders() 目前 getallheaders() 只能用於 apache 中。如果想在 nginx 中也能使用,可以使用自定義函數。 2、自定義函數 ...
  • 創建項目 使用idea(版本2018.2),新建項目,使用spring initalizr,項目命名為名字為producer,選擇integration里的rabbitmq,確定。 配置rabbitmq服務 將預設生成的application.properties重命名為application.ym ...
  • 之前寫過一篇閉包的使用(點擊此處進入),這次深入彙總下php中匿名函數的深入用法和理解: php中的匿名函數 也叫閉包函數 允許指定一個沒有名稱的函數。把匿名函數賦值給變數,通過變數來調用,舉個簡單的例子: 技巧1: 將匿名函數放在普通函數中,也可以將匿名函數返回,:這樣就構成了一個簡單的閉包 技巧 ...
  • 公司的項目沒那麼忙了,而且可能項目組很快要去深圳了! 自己的引擎方面去掉了一些不必要的層級,儘量輕量級,簡單架構,模擬著一個新人接觸怎樣能上手來重新整理了一下! 游戲方面增加了C++類之後寫代碼熟多了,但是整體上大部分還是在藍圖中,有一些函數什麼的還在摸索! 女朋友還是一樣的每周末都住一下,好像一下 ...
  • HashMap的put操作源碼解析 [toc] 1、官方文檔 1.1、繼承結構 1.2、類型參數: 2、put(key, value) HashMap是一種以鍵——值對的形式來存儲數據的數據結構。HashMap允許使用 null 值和 null 鍵,它並不能保證你存放數據和取出的順序是一致的。 接下 ...
  • 本文旨在用最通俗的語言講述最枯燥的基本知識 學過Java基礎的人都知道:值傳遞和引用傳遞是初次接觸Java時的一個難點,有時候記得了語法卻記不得怎麼實際運用,有時候會的了運用卻解釋不出原理,而且坊間討論的話題又是充滿爭議:有的論壇帖子說Java只有值傳遞,有的博客說兩者皆有;這讓人有點摸不著頭腦,下 ...
  • 1.Python變數 比C語言,Java語言更加簡潔,不需要加int等等類型定義,直接變數名 = 值,Python里甚至不需要分號。有些特定的不能當做變數名,變數只能由字母、數字和下劃線組成,下劃線可以放在開頭,甚至可以有很多(只是很少有人會這麼做),數字不能作為開頭。 2.Python註釋 # 代 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...