狂神說Java個人筆記-API,集合, IO


常用API

date

    // System.exit(0);//強制退出java程序非0是異常結束
       //long l = System.currentTimeMillis();//返回當前時間與1970年子午夜交替毫秒值
//       Date date = new Date();//返回具體日期時間
//       DateFormat dateInstance = DateFormat.getDateInstance();//獲取日期格式
//       DateFormat dateTimeInstance = DateFormat.getDateTimeInstance();//獲取具體日期時間
//       String s = dateInstance.format(date);
//       String s1 = dateTimeInstance.format(date);
//       System.out.println(s);
//       System.out.println(s1);
       String s="2020/4/4 22:22:22";
       //編寫對應日期格式,將字符串日期轉換為日期格式
       SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
       Date parse = simpleDateFormat.parse(s);
       System.out.println(parse);

 

math

int abs = Math.abs(-5);
Math.sqrt(1000.0);
Math.max(1000,2000);
Math.min(1000,2000);
Math.round(1000.6f);
Math.random();
Random random = new Random();
int i = random.nextInt(100);
System.out.println(i);

 

BigInteger類

BigInteger b1 = new BigInteger("6666666666");
BigInteger b2 = new BigInteger("2222222222");
//加、減、乘、除、取模
System.out.println(b1.add(b2));
System.out.println(b1.subtract(b2));
System.out.println(b1.multiply(b2));
System.out.println(b1.divide(b2));
System.out.println(b1.remainder(b2));

BigDecimal類

BigDecimal b3 = new BigDecimal("15.3");
BigDecimal b4 = new BigDecimal("3.0");
System.out.println(b3.divide(b4,5,BigDecimal.ROUND_HALF_UP));
//除法除不盡可以在后面加,保留幾位小數 ,屬性(四舍五入)

克隆技術

類要實現克隆,需要做兩步:

  1. 實現Cloneable接口;

  2. 重寫Object的clone方法。

    Timer定時器

    Timer timer = new Timer();
    TimerTask task = new TimerTask() {

       public void run() {
           System.out.println("定時任務被執行了");
      }
    };
    //一段時間后執行定時任務
    timer.schedule(task,2000);
    //在具體時間執行任務
    timer.schedule(task,new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").parse("2020/5/18 14:56:10"));
    //在一段時間后執行任務,並且每隔多久執行一次
    timer.schedule(task,2000,3000);

    Calendar

    常用成員方法

    public int get(int field):返回給定日歷字段的值。
    public void set(int field,int value):將給定日歷字段設置給定值。
    public abstract void add(int field,int amount):根據日歷的規則,為給定的日歷字段添加或減去指定的時間量。
    public Date getTime();把日歷時間值轉換為date對象

     

    String

    String:字符串,使用一對“”引起來表示

    1. String聲明為final的,不可被繼承

    2. String實現了Serializable接口:表示字符串是支持序列化的

    3. 實現了comparable接口:表示String可以比較大小

    4. String內部定義了final char【】 value用於存儲字符串數據

    5. String:代表不可變的字符序列:簡稱:不可變性。

      體現:當對字符串重新賦值時,需要重寫指定內存區域賦值,不能使用原有的value進行賦值

    6. 通過字面量的方式給一個字符串賦值,此時的字符串值聲明在字符串常量池中,字符串常量池中是不會存儲相同內容的字符串。

      基本類型與字符串之間的轉換

      基本類型--》字符串

      1.基本類型—+“”,

      2.包裝類的靜態方法tostring(參數),不是Object的toString重載,static String toString(int i)返回一個指定整數的String對象

      3.String類的靜態方法valueof(參數)

      字符串-》基本類型

      使用包裝類大家平台方法parsexxx(“數值類型的字符串”)

      //基本類型轉換字符串
      Integer i=1;
      String s=i+"";
      String s1=Integer.toString(1);
      System.out.println(i.toString());
      System.out.println(s1+200);
      String s2=String.valueOf(i);
      //字符串轉換基本類型
      int i1=Integer.parseInt(s1);
      //字符串的操作
                 String s="貓貓貓狗貓貓貓貓貓貓狗貓貓貓貓貓狗貓貓貓貓貓貓貓";
                 //字符串檢索
                 //檢索字符串是否有該字符,返回Boolean
                 System.out.println(s.contains("狗"));//有返回true
                 //檢索字符串是否存在,存在返回位置下標,不存在返回-1
                 System.out.println(s.indexOf("狗"));//存在返回位置下標
                 //檢索字符串開始位置是否為該字符
                 System.out.println(s.startsWith("貓"));//返回Boolean
                 //檢索字符串結尾位置是否為該字符
                 System.out.println(s.endsWith("貓"));//返回Boolean

                 //字符串替換
                 System.out.println(s.replace("狗","鼠"));
                 //字符串拆分以該字符拆分並輸出0下標的字符
                 System.out.println(s.split("狗")[0]);
                 //字符的長度
                 System.out.println(s.length());
                 //字符是否為空
                 System.out.println(s.isEmpty());
                 

      StringBuilder

      StringBuilder su=new StringBuilder();
      String s=su.toString();

      集合

      image-20200519152612018

       

       

重點:HashMap

①HashMap的工作原理

HashMap基於hashing原理,我們通過put()和get()方法儲存和獲取對象。當我們將鍵值對傳遞給put()方法時,它調用鍵對象的hashCode()方法來計算hashcode,讓后找到bucket位置來儲存值對象。當獲取對象時,通過鍵對象的equals()方法找到正確的鍵值對,然后返回值對象。HashMap使用鏈表來解決碰撞問題,當發生碰撞了,對象將會儲存在鏈表的下一個節點中。 HashMap在每個鏈表節點中儲存鍵值對對象。

當兩個不同的鍵對象的hashcode相同時會發生什么? 它們會儲存在同一個bucket位置的鏈表中。鍵對象的equals()方法用來找到鍵值對。

②HashMap和Hashtable的區別

HashMap和Hashtable都實現了Map接口,但決定用哪一個之前先要弄清楚它們之間的分別。主要的區別有:線程安全性,同步(synchronization),以及速度。

  1. HashMap幾乎可以等價於Hashtable,除了HashMap是非synchronized的,並可以接受null(HashMap可以接受為null的鍵值(key)和值(value),而Hashtable則不行)。

  2. HashMap是非synchronized,而Hashtable是synchronized,這意味着Hashtable是線程安全的,多個線程可以共享一個Hashtable;而如果沒有正確的同步的話,多個線程是不能共享HashMap的。Java 5提供了ConcurrentHashMap,它是HashTable的替代,比HashTable的擴展性更好。

  3. 另一個區別是HashMap的迭代器(Iterator)是fail-fast迭代器,而Hashtable的enumerator迭代器不是fail-fast的。所以當有其它線程改變了HashMap的結構(增加或者移除元素),將會拋出ConcurrentModificationException,但迭代器本身的remove()方法移除元素則不會拋出ConcurrentModificationException異常。但這並不是一個一定發生的行為,要看JVM。這條同樣也是Enumeration和Iterator的區別。

  4. 由於Hashtable是線程安全的也是synchronized,所以在單線程環境下它比HashMap要慢。如果你不需要同步,只需要單一線程,那么使用HashMap性能要好過Hashtable。

  5. HashMap不能保證隨着時間的推移Map中的元素次序是不變的。

要注意的一些重要術語:

1) sychronized意味着在一次僅有一個線程能夠更改Hashtable。就是說任何線程要更新Hashtable時要首先獲得同步鎖,其它線程要等到同步鎖被釋放之后才能再次獲得同步鎖更新Hashtable。

2) Fail-safe和iterator迭代器相關。如果某個集合對象創建了Iterator或者ListIterator,然后其它的線程試圖“結構上”更改集合對象,將會拋出ConcurrentModificationException異常。但其它線程可以通過set()方法更改集合對象是允許的,因為這並沒有從“結構上”更改集合。但是假如已經從結構上進行了更改,再調用set()方法,將會拋出IllegalArgumentException異常。

3) 結構上的更改指的是刪除或者插入一個元素,這樣會影響到map的結構。

我們能否讓HashMap同步?

HashMap可以通過下面的語句進行同步: Map m = Collections.synchronizeMap(hashMap);

結論

Hashtable和HashMap有幾個主要的不同:線程安全以及速度。僅在你需要完全的線程安全的時候使用Hashtable,而如果你使用Java 5或以上的話,請使用ConcurrentHashMap吧。

ashMap和HashSet的區別是Java面試中最常被問到的問題。如果沒有涉及到Collection框架以及多線程的面試,可以說是不完整。而Collection框架的問題不涉及到HashSet和HashMap,也可以說是不完整。HashMap和HashSet都是collection框架的一部分,它們讓我們能夠使用對象的集合。collection框架有自己的接口和實現,主要分為Set接口,List接口和Queue接口。它們有各自的特點,Set的集合里不允許對象有重復的值,List允許有重復,它對集合中的對象進行索引,Queue的工作原理是FCFS算法(First Come, First Serve)。

首先讓我們來看看什么是HashMap和HashSet,然后再來比較它們之間的分別。

③HashMap和HashSet的區別

HashMap和HashSet的區別是Java面試中最常被問到的問題。如果沒有涉及到Collection框架以及多線程的面試,可以說是不完整。而Collection框架的問題不涉及到HashSet和HashMap,也可以說是不完整。HashMap和HashSet都是collection框架的一部分,它們讓我們能夠使用對象的集合。collection框架有自己的接口和實現,主要分為Set接口,List接口和Queue接口。它們有各自的特點,Set的集合里不允許對象有重復的值,List允許有重復,它對集合中的對象進行索引,Queue的工作原理是FCFS算法(First Come, First Serve)。

首先讓我們來看看什么是HashMap和HashSet,然后再來比較它們之間的分別。

什么是HashSet

HashSet實現了Set接口,它不允許集合中有重復的值,當我們提到HashSet時,第一件事情就是在將對象存儲在HashSet之前,要先確保對象重寫equals()和hashCode()方法,這樣才能比較對象的值是否相等,以確保set中沒有儲存相等的對象。如果我們沒有重寫這兩個方法,將會使用這個方法的默認實現。

public boolean add(Object o)方法用來在Set中添加元素,當元素值重復時則會立即返回false,如果成功添加的話會返回true。

什么是HashMap

HashMap實現了Map接口,Map接口對鍵值對進行映射。Map中不允許重復的鍵。Map接口有兩個基本的實現,HashMap和TreeMap。TreeMap保存了對象的排列次序,而HashMap則不能。HashMap允許鍵和值為null。HashMap是非synchronized的,但collection框架提供方法能保證HashMap synchronized,這樣多個線程同時訪問HashMap時,能保證只有一個線程更改Map。

public Object put(Object Key,Object value)方法用來將元素添加到map中。

HashSet和HashMap的區別

HashMap HashSet
HashMap實現了Map接口 HashSet實現了Set接口
HashMap儲存鍵值對 HashSet僅僅存儲對象
使用put()方法將元素放入map中 使用add()方法將元素放入set中
HashMap中使用鍵對象來計算hashcode值 HashSet使用成員對象來計算hashcode值,對於兩個對象來說hashcode可能相同,所以equals()方法用來判斷對象的相等性,如果兩個對象不同的話,那么返回false
HashMap比較快,因為是使用唯一的鍵來獲取對象 HashSet較HashMap來說比較慢

 

 

④面試題

HashMap的工作原理是近年來常見的Java面試題。幾乎每個Java程序員都知道HashMap,都知道哪里要用HashMap,知道Hashtable和HashMap之間的區別,那么為何這道面試題如此特殊呢?是因為這道題考察的深度很深。這題經常出現在高級或中高級面試中。投資銀行更喜歡問這個問題,甚至會要求你實現HashMap來考察你的編程能力。ConcurrentHashMap和其它同步集合的引入讓這道題變得更加復雜。讓我們開始探索的旅程吧!

“你用過HashMap嗎?” “什么是HashMap?你為什么用到它?”

幾乎每個人都會回答“是的”,然后回答HashMap的一些特性,譬如HashMap可以接受null鍵值和值,而Hashtable則不能;HashMap是非synchronized;HashMap很快;以及HashMap儲存的是鍵值對等等。這顯示出你已經用過HashMap,而且對它相當的熟悉。但是面試官來個急轉直下,從此刻開始問出一些刁鑽的問題,關於HashMap的更多基礎的細節。面試官可能會問出下面的問題:

“你知道HashMap的工作原理嗎?” “你知道HashMap的get()方法的工作原理嗎?”

你也許會回答“我沒有詳查標准的Java API,你可以看看Java源代碼或者Open JDK。”“我可以用Google找到答案。”

但一些面試者可能可以給出答案,“HashMap是基於hashing的原理,我們使用put(key, value)存儲對象到HashMap中,使用get(key)從HashMap中獲取對象。當我們給put()方法傳遞鍵和值時,我們先對鍵調用hashCode()方法,返回的hashCode用於找到bucket位置來儲存Entry對象。”這里關鍵點在於指出,HashMap是在bucket中儲存鍵對象和值對象,作為Map.Entry。這一點有助於理解獲取對象的邏輯。如果你沒有意識到這一點,或者錯誤的認為僅僅只在bucket中存儲值的話,你將不會回答如何從HashMap中獲取對象的邏輯。這個答案相當的正確,也顯示出面試者確實知道hashing以及HashMap的工作原理。但是這僅僅是故事的開始,當面試官加入一些Java程序員每天要碰到的實際場景的時候,錯誤的答案頻現。下個問題可能是關於HashMap中的碰撞探測(collision detection)以及碰撞的解決方法:

“當兩個對象的hashcode相同會發生什么?” 從這里開始,真正的困惑開始了,一些面試者會回答因為hashcode相同,所以兩個對象是相等的,HashMap將會拋出異常,或者不會存儲它們。然后面試官可能會提醒他們有equals()和hashCode()兩個方法,並告訴他們兩個對象就算hashcode相同,但是它們可能並不相等。一些面試者可能就此放棄,而另外一些還能繼續挺進,他們回答“因為hashcode相同,所以它們的bucket位置相同,‘碰撞’會發生。因為HashMap使用鏈表存儲對象,這個Entry(包含有鍵值對的Map.Entry對象)會存儲在鏈表中。”這個答案非常的合理,雖然有很多種處理碰撞的方法,這種方法是最簡單的,也正是HashMap的處理方法。但故事還沒有完結,面試官會繼續問:

“如果兩個鍵的hashcode相同,你如何獲取值對象?” 面試者會回答:當我們調用get()方法,HashMap會使用鍵對象的hashcode找到bucket位置,然后獲取值對象。面試官提醒他如果有兩個值對象儲存在同一個bucket,他給出答案:將會遍歷鏈表直到找到值對象。面試官會問因為你並沒有值對象去比較,你是如何確定確定找到值對象的?除非面試者直到HashMap在鏈表中存儲的是鍵值對,否則他們不可能回答出這一題。

其中一些記得這個重要知識點的面試者會說,找到bucket位置之后,會調用keys.equals()方法去找到鏈表中正確的節點,最終找到要找的值對象。完美的答案!

許多情況下,面試者會在這個環節中出錯,因為他們混淆了hashCode()和equals()方法。因為在此之前hashCode()屢屢出現,而equals()方法僅僅在獲取值對象的時候才出現。一些優秀的開發者會指出使用不可變的、聲明作final的對象,並且采用合適的equals()和hashCode()方法的話,將會減少碰撞的發生,提高效率。不可變性使得能夠緩存不同鍵的hashcode,這將提高整個獲取對象的速度,使用String,Interger這樣的wrapper類作為鍵是非常好的選擇。

如果你認為到這里已經完結了,那么聽到下面這個問題的時候,你會大吃一驚。“如果HashMap的大小超過了負載因子(load factor)定義的容量,怎么辦?”除非你真正知道HashMap的工作原理,否則你將回答不出這道題。默認的負載因子大小為0.75,也就是說,當一個map填滿了75%的bucket時候,和其它集合類(如ArrayList等)一樣,將會創建原來HashMap大小的兩倍的bucket數組,來重新調整map的大小,並將原來的對象放入新的bucket數組中。這個過程叫作rehashing,因為它調用hash方法找到新的bucket位置。

如果你能夠回答這道問題,下面的問題來了:“你了解重新調整HashMap大小存在什么問題嗎?”你可能回答不上來,這時面試官會提醒你當多線程的情況下,可能產生條件競爭(race condition)。

當重新調整HashMap大小的時候,確實存在條件競爭,因為如果兩個線程都發現HashMap需要重新調整大小了,它們會同時試着調整大小。在調整大小的過程中,存儲在鏈表中的元素的次序會反過來,因為移動到新的bucket位置的時候,HashMap並不會將元素放在鏈表的尾部,而是放在頭部,這是為了避免尾部遍歷(tail traversing)。如果條件競爭發生了,那么就死循環了。這個時候,你可以質問面試官,為什么這么奇怪,要在多線程的環境下使用HashMap呢?:)

熱心的讀者貢獻了更多的關於HashMap的問題:

    1. 為什么String, Interger這樣的wrapper類適合作為鍵? String, Interger這樣的wrapper類作為HashMap的鍵是再適合不過了,而且String最為常用。因為String是不可變的,也是final的,而且已經重寫了equals()和hashCode()方法了。其他的wrapper類也有這個特點。不可變性是必要的,因為為了要計算hashCode(),就要防止鍵值改變,如果鍵值在放入時和獲取時返回不同的hashcode的話,那么就不能從HashMap中找到你想要的對象。不可變性還有其他的優點如線程安全。如果你可以僅僅通過將某個field聲明成final就能保證hashCode是不變的,那么請這么做吧。因為獲取對象的時候要用到equals()和hashCode()方法,那么鍵對象正確的重寫這兩個方法是非常重要的。如果兩個不相等的對象返回不同的hashcode的話,那么碰撞的幾率就會小些,這樣就能提高HashMap的性能。

    2. 我們可以使用自定義的對象作為鍵嗎? 這是前一個問題的延伸。當然你可能使用任何對象作為鍵,只要它遵守了equals()和hashCode()方法的定義規則,並且當對象插入到Map中之后將不會再改變了。如果這個自定義對象時不可變的,那么它已經滿足了作為鍵的條件,因為當它創建之后就已經不能改變了。

    3. 我們可以使用CocurrentHashMap來代替Hashtable嗎?這是另外一個很熱門的面試題,因為ConcurrentHashMap越來越多人用了。我們知道Hashtable是synchronized的,但是ConcurrentHashMap同步性能更好,因為它僅僅根據同步級別對map的一部分進行上鎖。ConcurrentHashMap當然可以代替HashTable,但是HashTable提供更強的線程安全性。看看這篇博客查看Hashtable和ConcurrentHashMap的區別。

IO流

image-20200520104215113

文件操作

File file =new File("C:\\Users\\A450\\Desktop\\bbb");
 //file.createNewFile();//創建一個文件,File寫具體目錄到創建的文件名
 file.mkdir();//創建一個目錄
 System.out.println(file.exists());//判斷是否存在
 System.out.println(file.isFile());//判斷是否為一個文件
 System.out.println(file.isDirectory());//判斷是否為一個目錄
 System.out.println(Arrays.toString(file.list()));//獲取目錄里的文件名以數組方式打印
// file.delete();//刪除文件
 file.renameTo(new File("C:\\Users\\A450\\Desktop\\ccc"));//改名字

 

字節輸入流

//字節輸入流FileInputStream
public static void main(String[] args) throws IOException {
    File file = new File("C:\\Users\\A450\\Desktop\\aaa\\1.txt");
    FileInputStream fis=null;
    try {
       fis= new FileInputStream(file);//
        System.out.println(fis.available());//讀取文件長度
        System.out.println(fis.read());//讀取文件並返回位置如果讀取完返回-1
        byte[] b=new byte[1024];//准備一個byte數組放入讀取文件
        int len = fis.read(b);//讀取內容放入數組
        while(len!=-1){
            String s=new String(b);//將byte轉換字符串
            System.out.println(s);//輸出讀到的字符串
            len = fis.read(b);
        }

    } catch (Exception e) {
        e.printStackTrace();
    }finally {
        fis.close();
        
    }

}

FileOutputStream

//字符輸出流FileOutputStream
public static void main(String[] args) {
    String s="你好,世界!";
    FileOutputStream fos=null;
    try {
        //寫入文件,name:文件路徑append:默認寫入是覆蓋寫入;有true為追加寫入
        fos=new FileOutputStream("C:\\Users\\A450\\Desktop\\aaa\\2.txt",true);
        byte[] b=s.getBytes();//將寫入的文件轉換為字節數組
        fos.write(b,0,b.length);//寫入文件,從0開始,到寫入的長度
        fos.flush();//清空緩沖區,強制寫入緩沖區文件
    } catch (Exception e) {
        e.printStackTrace();
    }finally{
        fos.close();
    }
}

FileReader

//FileReader字符輸入流
public static void main(String[] args) throws IOException {
    File file=new File("C:\\Users\\A450\\Desktop\\aaa\\1.txt");
    FileReader fr=null;
    try {
         fr=new FileReader(file);
         char[] c=new char[1024];//用字符保存讀入的數據
        int len = fr.read();
        while (len!=-1){
            String s=new String(c);
            System.out.println(s);
            len=fr.read();
        }
    } catch (Exception e) {
        e.printStackTrace();
    }finally{
        fr.close();
    }
}

FileWriter

     //FileWriter字節輸出流
    public static void main(String[] args) throws IOException {
        String s="你好!世界ssss";
        FileWriter fw=null;
        try {
            fw=new FileWriter("C:\\Users\\A450\\Desktop\\aaa\\2.txt",true);
            fw.write(s);
            fw.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            fw.close();
        
    }
}

BufferReader&BufferWriter

緩沖流

//緩沖流BufferedReader BufferedWriter
public static void main(String[] args) throws IOException {
    File file=new File("C:\\Users\\A450\\Desktop\\aaa\\1.txt");
    BufferedReader br=null;
    BufferedWriter bw=null;
    try {
        br= new BufferedReader(new FileReader(file));
        bw=new BufferedWriter(new FileWriter("C:\\Users\\A450\\Desktop\\aaa\\2.txt"));
        String s=br.readLine();//逐行讀取
        while (s!=null){
            System.out.println(s);
            bw.write(s+"\r\n");
            bw.flush();
           s= br.readLine();
        }
    } catch (Exception e) {
        e.printStackTrace();
    }finally{
        br.close();
        bw.close();
    }
}

FileWriter

//打印流
public static void main(String[] args) {
    PrintWriter pw=null;
    try {
        pw=new PrintWriter(new FileWriter("C:\\Users\\A450\\Desktop\\aaa\\2.txt"),true);
        pw.print("hello world");
    } catch (IOException e) {
        e.printStackTrace();
    }finally {
        pw.close();
        
    }

}

ObjectOutputStream

//對象輸入流 調用的學生類必須引用接口Serializable
public static void main(String[] args) throws IOException {
   Student stu1=new Student("趙東",11);
   Student stu2=new Student("趙2",12);
   Student stu3=new Student("趙3",13);
   Student stu4=new Student("趙4",14);
   ArrayList<Student> al=new ArrayList<Student>();
   al.add(stu1);
   al.add(stu2);
   al.add(stu3);
   al.add(stu4);
   ObjectOutputStream oos=null;
   try {
       oos=new ObjectOutputStream(new FileOutputStream("C:\\Users\\A450\\Desktop\\aaa\\3.txt"));
       oos.writeObject(al);
       oos.flush();
  } catch (IOException e) {
       e.printStackTrace();
  }finally {
       oos.close();

  }
}

ObjectInputStream

//對象輸入流ObjectInputStream
public static void main(String[] args) {
   ObjectInputStream ois=null;
   try {
       ois=new ObjectInputStream(new FileInputStream("C:\\Users\\A450\\Desktop\\aaa\\3.txt"));
       ArrayList<Student> al=(ArrayList<Student>)ois.readObject();
       for (Student student : al) {
           System.out.println("姓名"+student.name+"年齡"+student.age);
      }
  } catch (Exception e) {
       e.printStackTrace();
  }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM