面試系列(一)

一、JDK 和 JRE 有什麼區別?

JRE: Java Runtime Environment
JDK:Java Development Kit
JRE顧名思義是java運行時環境,包含了java虛擬機,java基礎類庫。是使用java語言編寫的程序運行所需要的軟件環境,是提供給想運行java程序的用戶使用的。
JDK顧名思義是java開發工具包,是程序員使用java語言編寫java程序所需的開發工具包,是提供給程序員使用的。JDK包含了JRE,同時還包含了編譯java源碼的編譯器javac,還包含了很多java程序調試和分析的工具:jconsole,jvisualvm等工具軟件,還包含了java程序編寫所需的文檔和demo例子程序。
如果你需要運行java程序,只需安裝JRE就可以了。如果你需要編寫java程序,需要安裝JDK。

二、== 和 equals 的區別是什麼?

  1.  ==是判斷兩個變量或實例是不是指向同一個內存空間,equals是判斷兩個變量或實例所指向的內存空間的值是不是相同 
  2. ==是指對內存地址進行比較 , equals()是對字符串的內容進行比較
  3. ==指引用是否相同, equals()指的是值是否相同
  4. == 比較的是變量(棧)內存中存放的對象的(堆)內存地址,用來判斷兩個對象的地址是否相同,即是否是指相同一個對象。比較的是真正意義上的指針操作。equals用來比較的是兩個對象的內容是否相等,由於所有的類都是繼承自java.lang.Object類的,所以適用於所有對象,如果沒有對該方法進行覆蓋的話,調用的仍然是Object類中的方法,而Object中的equals方法返回的卻是==的判斷。String s="abcd"是一種非常特殊的形式,和new 有本質的區別。它是java中唯一不需要new 就可以產生對象的途徑。以String s="abcd";形式賦值在java中叫直接量,它是在常量池中而不是象new一樣放在壓縮堆中。 這種形式的字符串,在JVM內部發生字符串拘留,即當聲明這樣的一個字符串後,JVM會在常量池中先查找有有沒有一個值爲"abcd"的對象,如果有,就會把它賦給當前引用.即原來那個引用和現在這個引用指點向了同一對象, 如果沒有,則在常量池中新創建一個"abcd",下一次如果有String s1 = "abcd";又會將s1指向"abcd"這個對象,即以這形式聲明的字符串,只要值相等,任何多個引用都指向同一對象.
          而String s = new String("abcd");和其它任何對象一樣.每調用一次就產生一個對象,只要它們調用。
        也可以這麼理解: String str = "hello"; 先在內存中找是不是有"hello"這個對象,如果有,就讓str指向那個"hello".

        如果內存裏沒有"hello",就創建一個新的對象保存"hello". String str=new String ("hello") 就是不管內存裏是不是已經有"hello"這個對象,都新建一個對象保存"hello"。

三、兩個對象的 hashCode()相同,則 equals()也一定爲 true,對嗎?

首先,答案肯定是不一定。同時反過來equals爲true,hashCode也不一定相同。

類的hashCode方法和equals方法都可以重寫,返回的值完全在於自己定義。

hashCode()返回該對象的哈希碼值;equals()返回兩個對象是否相等。

關於hashCode和equal是方法是有一些 常規協定 :

     兩個對象用equals()比較返回true,那麼兩個對象的hashCode()方法必須返回相同的結果。

     兩個對象用equals()比較返回false,不要求hashCode()方法也一定返回不同的值,但是最好返回不同值,億提搞哈希表性能。

     重寫equals()方法,必須重寫hashCode()方法,以保證equals方法相等時兩個對象hashcode返回相同的值。

四、final 在 java 中有什麼作用?

  1. 一、final關鍵字的基本用法

    在Java中,final關鍵字可以用來修飾類、方法和變量(包括成員變量和局部變量)。下面就從這三個方面來了解一下final關鍵字的基本用法。

    1、修飾類

       當用final修飾一個類時,表明這個類不能被繼承。也就是說,如果一個類你永遠不會讓他被繼承,就可以用final進行修飾。final類中的成員變量可以根據需要設爲final,但是要注意final類中的所有成員方法都會被隱式地指定爲final方法。

    在使用final修飾類的時候,要注意謹慎選擇,除非這個類真的在以後不會用來繼承或者出於安全的考慮,儘量不要將類設計爲final類。

  2. 2、修飾方法

         下面這段話摘自《Java編程思想》第四版第143頁:

      “使用final方法的原因有兩個。第一個原因是把方法鎖定,以防任何繼承類修改它的含義;第二個原因是效率。在早期的Java實現版本中,會將final方法轉爲內嵌調用。但是如果方法過於龐大,可能看不到內嵌調用帶來的任何性能提升。在最近的Java版本中,不需要使用final方法進行這些優化了。“

      因此,如果只有在想明確禁止 該方法在子類中被覆蓋的情況下才將方法設置爲final的。即父類的final方法是不能被子類所覆蓋的,也就是說子類是不能夠存在和父類一模一樣的方法的。

         final修飾的方法表示此方法已經是“最後的、最終的”含義,亦即此方法不能被重寫(可以重載多個final修飾的方法)。此處需要注意的一點是:因爲重寫的前提是子類可以從父類中繼承此方法,如果父類中final修飾的方法同時訪問控制權限爲private,將會導致子類中不能直接繼承到此方法,因此,此時可以在子類中定義相同的方法名和參數,此時不再產生重寫與final的矛盾,而是在子類中重新定義了新的方法。(注:類的private方法會隱式地被指定爲final方法。)

  3. 3、修飾變量      修飾變量是final用得最多的地方,也是本文接下來要重點闡述的內容。

          final成員變量表示常量,只能被賦值一次,賦值後值不再改變。

      當final修飾一個基本數據類型時,表示該基本數據類型的值一旦在初始化後便不能發生變化;如果final修飾一個引用類型時,則在對其初始化之後便不能再讓其指向其他對象了,但該引用所指向的對象的內容是可以發生變化的。本質上是一回事,因爲引用的值是一個地址,final要求值,即地址的值不發生變化。

      final修飾一個成員變量(屬性),必須要顯示初始化。這裏有兩種初始化方式,一種是在變量聲明的時候初始化;第二種方法是在聲明變量的時候不賦初值,但是要在這個變量所在的類的所有的構造函數中對這個變量賦初值。

      當函數的參數類型聲明爲final時,說明該參數是隻讀型的。即你可以讀取使用該參數,但是無法改變該參數的值。

  4. 二、深入理解final關鍵字

    在瞭解了final關鍵字的基本用法之後,這一節我們來看一下final關鍵字容易混淆的地方。

    1、類的final變量和普通變量有什麼區別?

         當用final作用於類的成員變量時,成員變量(注意是類的成員變量,局部變量只需要保證在使用之前被初始化賦值即可)必須在定義時或者構造器中進行初始化賦值,而且final變量一旦被初始化賦值之後,就不能再被賦值了。

  5. 2、被final修飾的引用變量指向的對象內容可變嗎?

    引用變量被final修飾之後,雖然不能再指向其他對象,但是它指向的對象的內容是可變的

  6. 3、final參數的問題

         在實際應用中,我們除了可以用final修飾成員變量、成員方法、類,還可以修飾參數、若某個參數被final修飾了,則代表了該參數是不可改變的。如果在方法中我們修改了該參數,則編譯器會提示你:The final local variable i cannot be assigned. It must be blank and not using a compound assignment。

    java採用的是值傳遞,對於引用變量,傳遞的是引用的值,也就是說讓實參和形參同時指向了同一個對象,因此讓形參重新指向另一個對象對實參並沒有任何影響。

五.java 中的 Math最常用的方法?

ceil的英文意義是天花板,該方法就表示向上取整

floor的英文意義是地板,該方法就表示向下取整

round求本身的四捨五入

max與min,比較兩個數的最大值,最小值

abs求本身的絕對值

六、String 屬於基礎的數據類型嗎?

String不是基本的數據類型,是final修飾的java類,java中的基本類型一共有8個,它們分別爲:

字符類型:byte,char

基本整型:short,int,long

浮點型:float,double

布爾類型:boolean

七、java 中操作字符串都有哪些類?它們之間有什麼區別?

String、StringBuffer、StringBuilder

String是Java中基礎且重要的類,並且String也是Immutable類的典型實現,被聲明爲final class,除了hash這個屬性其它屬性都聲明爲final,因爲它的不可變性,所以例如拼接字符串時候會產生很多無用的中間對象,如果頻繁的進行這樣的操作對性能有所影響。

StringBuffer就是爲了解決大量拼接字符串時產生很多中間對象問題而提供的一個類,提供append和add方法,可以將字符串添加到已有序列的末尾或指定位置,它的本質是一個線程安全的可修改的字符序列,把所有修改數據的方法都加上了synchronized。但是保證了線程安全是需要性能的代價的。

在很多情況下我們的字符串拼接操作不需要線程安全,這時候StringBuilder登場了,StringBuilder是JDK1.5發佈的,它和StringBuffer本質上沒什麼區別,就是去掉了保證線程安全的那部分,減少了開銷。

StringBuffer 和 StringBuilder 二者都繼承了 AbstractStringBuilder ,底層都是利用可修改的char數組(JDK 9 以後是 byte數組)。

所以如果我們有大量的字符串拼接,如果能預知大小的話最好在new StringBuffer 或者StringBuilder 的時候設置好capacity,避免多次擴容的開銷。擴容要拋棄原有數組,還要進行數組拷貝創建新的數組

八、String str="i"與 String str=new String("i")一樣嗎?

  1. String s="abce"是一種非常特殊的形式,和new 有本質的區別。它是java中唯一不需要new 就可以產生對象的途徑。以String s="abce";形式賦值在java中叫直接量,它是在常量池中而不是象new一樣放在壓縮堆中。這種形式的字符串,在JVM內部發生字符串拘留,即當聲明這樣的一個字符串後,JVM會在常量池中先查找有有沒有一個值爲"abcd"的對象,如果有,就會把它賦給當前引用.即原來那個引用和現在這個引用指點向了同一對象,如果沒有,則在常量池中新創建一個"abcd",下一次如果有String s1 = "abcd";又會將s1指向"abcd"這個對象,即以這形式聲明的字符串,只要值相等,任何多個引用都指向同一對象.
      而String s = new String("abcd");和其它任何對象一樣.每調用一次就產生一個對象,只要它們調用。

9.如何將字符串反轉?

遞歸方法:

public static String reverse1(String s) {
  int length = s.length();
  if (length <= 1){
     return s;
    }
  String left = s.substring(0, length / 2);
  String right = s.substring(length / 2, length);
  return reverse1(right) + reverse1(left);
 }

通過 charAt(int index)返回char值進行字符串拼接

public static String reverse2(String s) {
  int length = s.length();
  String reverse = "";
  for (int i = 0; i < length; i++)
   reverse = s.charAt(i) + reverse;
  return reverse;
 }

把字符串轉換成字符數組倒敘拼接然後返回值

public static String reverse3(String s) {
  char[] array = s.toCharArray();
  String reverse = "";
  for (int i = array.length - 1; i >= 0; i--)
   reverse += array[i];
  return reverse;
 }

調用StringBuffer中的reverse方法

public static String reverse4(String s) {
  return new StringBuffer(s).reverse().toString();
 }

把字符串轉換成字符數組首位對調位置

public static String reverse5(String orig) {
  char[] s = orig.toCharArray();
  int n = s.length - 1;
  int halfLength = n / 2;
  for (int i = 0; i <= halfLength; i++) {
   char temp = s[i];
   s[i] = s[n - i];
   s[n - i] = temp;
  }
  return new String(s);
 }

十、String 類的常用方法都有那些

public int length()//返回該字符串的長度

public char charAt(int index)//返回字符串中指定位置的字符

public String substring(int beginIndex)//該方法從beginIndex位置起,從當前字符串中取出剩餘的字符作爲一個新的字符串返回。
public String substring(int beginIndex, int endIndex)//該方法從beginIndex位置起,從當前字符串中取出到endIndex-1位置的字符作爲一個新的字符串返回。

public int compareTo(String anotherString)//該方法是對字符串內容按字典順序進行大小比較,通過返回的整數值指明當前字符串與參數字符串的大小關係。若當前對象比參數大則返回正整數,反之返回負整數,相等返回0。
public int compareToIgnore(String anotherString)//與compareTo方法相似,但忽略大小寫。
public boolean equals(Object anotherObject)//比較當前字符串和參數字符串,在兩個字符串相等的時候返回true,否則返回false。
public boolean equalsIgnoreCase(String anotherString)//與equals方法相似,但忽略大小寫

public String concat(String str)//將參數中的字符串str連接到當前字符串的後面,效果等價於"+"

public int indexOf(int ch/String str)//用於查找當前字符串中字符或子串,返回字符或子串在當前字符串中從左邊起首次出現的位置,若沒有出現則返回-1。
public int indexOf(int ch/String str, int fromIndex)//改方法與第一種類似,區別在於該方法從fromIndex位置向後查找。
public int lastIndexOf(int ch/String str)//該方法與第一種類似,區別在於該方法從字符串的末尾位置向前查找。
public int lastIndexOf(int ch/String str, int fromIndex)//該方法與第二種方法類似,區別於該方法從fromIndex位置向前查找

public String toLowerCase()//返回將當前字符串中所有字符轉換成小寫後的新串
public String toUpperCase()//返回將當前字符串中所有字符轉換成大寫後的新串

public String replace(char oldChar, char newChar)//用字符newChar替換當前字符串中所有的oldChar字符,並返回一個新的字符串。
public String replaceFirst(String regex, String replacement)//該方法用字符replacement的內容替換當前字符串中遇到的第一個和字符串regex相匹配的子串,應將新的字符串返回。
public String replaceAll(String regex, String replacement)//該方法用字符replacement的內容替換當前字符串中遇到的所有和字符串regex相匹配的子串,應將新的字符串返回

String trim()//截去字符串兩端的空格,但對於中間的空格不處理

boolean statWith(String prefix)boolean endWith(String suffix)//用來比較當前字符串的起始字符或子字符串prefix和終止字符或子字符串suffix是否和當前字符串相同,重載方法中同時還可以指定比較的開始位置offset

contains(String str)//判斷參數s是否被包含在字符串中,並返回一個布爾類型的值

String[] split(String str)//將str作爲分隔符進行字符串分解,分解後的字字符串在字符串數組中返回

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章