Java 學習筆記(4)——java 常見類

上次提早說了java中的面向對象,主要是爲了使用這些常見類作打算,畢竟Java中一切都是對象,要使用一些系統提供的功能必須得經過類對象調用方法。其實Java相比於C來講強大的另外一個緣由是Java中提供了大量可用的標準庫
java

字符串

字符串能夠說是任何程序都離不開的東西,就連一個簡單的hello world程序都用到了字符串,當時C語言中對字符串的支持並不太好,C語言中的字符串實質上是一個字符數組。爲了方便不一樣的C/C++庫都有本身的字符串實現。而Java中內置了對字符串的支持,Java中的字符串是一個叫作String的對象。python

根據jdk文檔的描述,咱們須要注意一下幾點:c++

  1. Java程序中的全部字符串文字(例如"abc" )都被實現爲此類的實例
  2. String對象是能夠共享的
  3. String對象是不可變的

字符串的內存分佈

通常把相似於 "abc" 這樣直接經過字面值表示的字符串做爲字面常量,這種在Java中也是一個字符串,只是它與普通的new出來的字符串在內存的存儲上有點不同,下面請看下面的代碼正則表達式

class StringDemo{
    public static void main(String[] args){
        String a = "abc";
        String b = "abc";
        String c = new String("abc");

        System.out.println(a == b);
        System.out.println(a == c);
        System.out.println(b == c);
    }
}

針對字符串來講 == 比較的是它們的地址是否相同,這個程序分別輸出的是 true、false、false,也就是說a b 是指向的同一個地址空間,而c則不是。它們的內存分佈以下:
java string內存分佈數組

通常程序在加載到內存地址空間後,會被劃分爲4個部分,全局數據段、代碼段、堆、棧。而全局代碼段是用來存放全局變量的。在C中若是咱們寫下這樣的代碼:函數

char* psz1 = "abc";
char* psz2 = "abc";

那麼在程序加載到內存中時,在全局數據段中會存在一個連續的內存空間保存的是 'a','b','c','\0' 這4個值,一旦有char型指針指向"abc" 這樣的字符串,那麼系統會自動將這段內存的地址給賦值到對應的指針變量中,並且這個內存是隻讀內存,若是嘗試往裏面寫入數據,則會形成程序崩潰。線程

Java中也是相似的,當出現 "abc" 的時候,其實系統早就爲它在堆中建立了一個String對象,若是去閱讀String的源碼就會發現String中負責保存字符串的是一個 byte型的數組,因此在初始化的時候會再建立一個byte型數組,而後由字符串中成員變量保存它的地址,因此在內存圖中看到有String也有byte[]。並且這個字符串是保存在堆中的常量字符串池中的,它的生命週期與程序相同(或者說與主線程相同)。3d

每當直接使用 "abc" 這樣的字面常量的時候會自動將常量字符串池中相關的字符串對象的指針賦值給對應的對象。這樣形成了上述程序中 a == b 爲true的狀況。而c是經過new關鍵字在程序運行期間動態建立的。因此JVM會在程序執行到這步的時候額外建立一個對象,並將 "abc" 這個字符串對應的byte[] 中的值拷貝到新的內存中。指針

這樣就很容易理解上面的前兩條了,至於字符串不可變,能夠參考我以前寫的關於類型中的說明(字符串的值發生改變時,在內存中實際上是開闢了一塊新的內存用於保存新的字符串內容,而丟棄了從前的字符串)code

常見字符串方法

這裏再簡單的列舉一下字符串中常見的方法,這些方法均可以在JDK文檔均可以查到。

String(); //初始化新建立的 String對象,使其表示空字符序列
String(byte[] bytes); //經過使用平臺的默認字符集解碼指定的字節數組來構造新的 String
String(byte[] bytes, int offset, int length); //從bytes[] 數組中的第offset 位置開始,截取length個成員來初始化一個String
char charAt(int index); //返回指定位置處的索引
int compareTo(String anotherString); // 按字典順序比較兩個字符串的大小,爲0表示兩個字符串相同
int compareToIgnoreCase(String str); //比較兩個字符串的大小,忽略大小寫
String concat(String str) ; //字符串拼接
byte[] getBytes(Charset charset); //將字符串轉化爲byte型數組,並返回新的byte數組
int indexOf(String str); //返回字串第一次出現的位置
int length() ; //返回字符串的長度
String[] split(String regex); //按正則表達式進行分割,並返回對應的字符串數組

注意一下,這裏返回數組或者新字符串的,都是在函數內部新建的,與原來的無關。因此這裏是沒辦法拿到字符串底層的數組對象再來修改內存值的。

數組

java中數組的定義以下:

int[] Array1 = new int[10]; //定義了一個擁有10個整型數據的數組
int[] Array2 = new int[]{1, 2, 3, 4, 5, 6, 7,8, 9, 0}; //建立數組並初始化
int[] Array3 = {1,2 ,3,4,5,6,7,8,9,0};

相比於C中數組的定義來講,Java中的定義更容易讓人理解,對應數據類型後面加一對 [] 就是對應的數組類型了。而C中,中括號是寫在變量後面的,相比於Java中的定義來講就顯的有點怪異了。或者說C中從根本上來講數組並不算是一種特別的數據類型,僅僅只是開闢相同數據類型的一塊連續的內存而已。至於[] 在C中應該只是表示尋址而已,畢竟彙編中咱們常常看到相似於 esp:[eax] 這樣的東西。

Java中的數組是一種單獨的數據類型,它是一種引用類型,也就是說它的變量名中保存的是它的地址。

它的使用十分的簡單,與C/C++中數組的使用基本相同,注意事項也是基本相同。可是有一點很重要的不一樣,Java中的數組容許動態指定長度,也就是經過變量來指定長度,而C中必須靜態的指定長度,也就是在程序運行以前就須要知道它的長度。這是由於Java中數組是引用類型,是new在堆上的,而C中數組是分配在全局變量區或者棧上的,在程序運行之初就須要爲數組分配內存。

//這樣的代碼是能夠編譯經過的
int length = 10;
int array[] = new int[length];

數組做爲函數參數

import java.util.Arrays;

class Demo{
    public static void main(String[] args){
        int length = 10;
        int array[] = new int[length];
        System.out.println(Arrays.toString(array));
        test(array);
        
        System.out.println(Arrays.toString(array));
    }

    public static void test(int[] array){
        for(int i = 0; i < array.length; i++)
        {
            array[i] = i;
        }
    }
}

運行上述的代碼,發現函數中修改array的值在函數結束後也能夠生效,這是由於數組是一個引用類型,在C中咱們說要想改變實參的值,須要傳入對應的引用或者指針。在函數中經過引用訪問,實際上在訪問對應的內存,因此這裏實際上是在修改對應內存的值。固然能夠修改實參的值了。

ArrayList類

以前在數組中,咱們說數組一旦定義,是不能改變大小的,那麼若是我後續須要使用可變大小的數組呢?Java中提供了ArrayList這樣的容器。因爲它是一個通用的容器,而java又是一個強類型的語言,因此在定義的時候須要事先指定咱們須要使用容器存儲何種類型的數據。通常ArrayList的定義以下:

ArrayList<String> array = new ArrayList();

表示容器內部存儲的是字符串。

須要注意的是容器中只能存儲引用類型,不能存儲像int、double、char這樣的基本類型,若是要存儲這樣的數據,須要存儲它們對應的封裝類。好比int 類型對應的封裝類爲 Integer。

它的經常使用方法以下:

ArrayList(); //構造方法
boolean add(E e);//添加元素
void clear(); //清空
E get(int index); //獲取指定位置的元素
int indexOf(Object o); //查詢元素第一次出現的位置
E remove(int index); //刪除指定位置的元素
E remove(Object o); //從列表中刪除指定元素的第一個出現(若是存在)
int size(); //獲取容器中元素個數
void sort(Comparator<? super E> c); //使用提供的 Comparator對此列表進行排序

鍵盤輸入

Java中的鍵盤輸入主要經過Scanner類來實現,Scanner須要提供一個輸入流,從輸入流中獲取輸入。通常經常使用的輸入流是 System.in 表示從鍵盤輸入,例如:

Scanner sc = new Scanner(System.in);

Scanner類中經常使用方法是一系列的next方法,next方法主要功能是根據指定 的分割符,從輸入流中取出下一個輸入並作相應的轉化,好比nextInt()會轉化爲int,nextBoolean() 會轉化爲boolean類型等等,next()方法會直接轉化爲字符串。

默認狀況下next函數會經過空格進行轉化。

import java.util.Scanner;
import java.util.ArrayList;

class Demo{
    public static void main(String[] args){
        ArrayList<String> array = new ArrayList<String>();
        Scanner sc = new Scanner(System.in);
        String str = sc.next();
        array.add(str);
        while(sc.hasNext()){
            array.add(sc.next()); 
        }
        

        for(int i = 0; i < array.size(); i++)
        {
            System.out.println(array.get(i));
        }
        
    }
}

這段代碼,會將輸入的數據依次存儲到ArrayList容器中。由於程序事先不知道用戶會輸入多少數據,因此這裏採用能夠可變長度的容器來存儲

//輸入(> 表示cmd的提示符)
>hello world python java c++ c lisp
// 輸入ctrl + c來退出sc.next的輸入
> ctrl+c

//輸出
>hello
world
python
java
c++
c
lisp

上述代碼首先執行到sc.next 位置,而且中斷下來,咱們輸入上述的一些字符串,而後回車,而後程序繼續執行,在循環中根據空格,依次從裏面取出每個值,並放到容器中。當沒有值時,程序會再次中斷在sc.next() 的位置,這個時候輸入 ctrl + c ,此時程序再次執行到 sc.hasNext() 這個地方會返回false,這個時候循環退出,並依次打印這些內容。

這個程序證實了上面說的,next方法會根據指定的分割符,依次從輸入流中取出下一個輸入。固然若是想要一次讀取一行,可使用 nextLine方法。

更多內容請查閱JDK文檔。

相關文章
相關標籤/搜索