如果面試官問 String,就把這篇文章丟給他!

2021-02-19 Java後端

Java中String的應用無處不在,無論是算法題還是面試題,String都獨佔一方,甚至是無數面試者心中難以名狀的痛。本文著重對String(若無特地說明,默認是JDK 1.8版本)常見的問題來進行介紹:

字符串的不可變性

JDK 1.6和JDK 1.7中substring的原理及區別

replaceFirst、replaceAll、replace區別

String對「+」的「重載」

字符串拼接的幾種方式和區別

Integer.toString()和String.valueOf()的區別

switch對String的支持(JDK 1.7及其後版本)

字符串常量池、Class常量池、運行時常量池

String.intern()方法

1. 字符串的不可變性

/** 公眾號:Java後端 */public class Test {
    public static void main(String[] args) {
        String str1 = new String("abc");
        String str2 = new String("abc");
        System.out.println("str1 == str2:" + str1 == str2);
    }
}

一般都能看出來,這運行結果肯定是false啊,可是為什麼呢?
在解釋之前,先介紹一下System.identityHashCode():
System.identityHashCode()的作用是用來判斷兩個對象是否是內存中同一個對象,跟用==判斷內存地址是否一樣的效果一樣

System.out.println("str1:" + System.identityHashCode(str1));
System.out.println("str2:" + System.identityHashCode(str2));

從關鍵詞new就可以看出,這兩個String變量在堆上不可能是同一塊內存。其表現(本圖是基於JDK1.7,至於字符串常量池後文會介紹):

String str3 = str1;
System.out.println("str1 == str3:" + str1 == str3);
str3 += "ny";
System.out.println("str1 == str3:" + str1 == str3);

第一個結果為true,而第二個結果為false。顯而易見,第二個結果出現不同是因為str3賦值為"ny",那麼這整個過程是怎麼表現的呢?當str3賦值為str1的時候,實際上是str3與str1指向同一塊內存地址:

而str3賦值為str3+「ny"時,實際上是在常量池重新創建了一個新的常量"abcny」,並且賦予了不同的內存地址,即:

總結一下:字符串一旦創建,虛擬機就會在常量池裡面為此字符串分配一塊內存,所以它不能被改變。所有的字符串方法都是不能改變自身的,而是返回一個新的字符串。如果需要改變字符串的話,可以考慮使用StringBufferStringBuilder來,否則每次改變都會創建一個新的字符串,很浪費內存。2. JDK 1.6和JDK 1.7中substring的原理及區別JDK 1.6和JDK 1.7中的substring(int beginIndex, int endIndex)方法的實現是不同的,為簡單起見,後文中用substring()代表(int beginIndex, int endIndex)方法。首先我們先連接一下substring()方法的作用:

String str = "我不是你最愛的小甜甜了嗎?";
str = str.substring(1,3);
System.out.println(str);

我們可以看到,substring()方法的作用是截取欄位並返回其[beginIndex, endIndex-1]的內容。接下來我們來看看JDK 1.6和JDK 1.7在實現substring()時原理上的不同。JDK 1.6的substringString是通過字符數組來實現的,我們先來看下源碼:

public String(int offset, int count, char value[]) {
    this.value = value;
    this.offset = offset;
    this.count = count;
}

public String substring(int beginIndex, int endIndex) {
    
    return  new String(offset + beginIndex, endIndex - beginIndex, value);
}

可以看到,在JDK 1.6中,String類包含3個重要的成員變量:char value[](存儲真正的字符串數組)、int offset(數組的第一個位置索引)、int count(字符串中包含的字符個數)。而在虛擬機中,當調用substring方法的時候,堆上會創建一個新的string對象,但是這個string與原先的string一樣,指向同一個字符數組,它們之間只是offset和count不相同而已

這種結構看上去挺好的,只需要創建一個字符數組,然後可以通過調整offset和count就可以返回不同的字符串了。但事實證明,這種情況還是比較少見的,更常見的是從一個很長很長的字符串中切割出需要用到的一小段字符序列,這種結構會導致很長的字符數組一直在被使用,無法回收,可能導致內存洩露。所以一般都是這麼解決的,原理就是生成一個新的字符並引用它。

str = str.substring(1, 3) + "";

JDK 1.7的substring所以在JDK 1.7提出了一個新的substring()截取字符串的實現:

public String(char value[], int offset, int count) {
    
    this.value = Arrays.copyOfRange(value, offset, offset + count);
}

public String substring(int beginIndex, int endIndex) {
    
    int subLen = endIndex - beginIndex;
    return new String(value, beginIndex, subLen);
}

我們可以看到,String構造函數的實現已經換成了Arrays.copyOfRange()方法了,這個方法最後會生成一個新的字符數組。也就是說,使用substring()方法截取欄位,str不會使用之前的字符數組,而是引用新生成的字符數組

總結一下:JDK 1.6與JDK 1.7在實現substring()方法時最大的不同在於,前者沿用了原來的字符數組,而後者引用了新創建的字符數組
3. replaceFirst、replaceAll、replace區別從字面上看,這三者的區別在於名稱:replace(替換)、replaceAll(替換全部)、replaceFirst(替換第一個符合條件)。在從功能、源碼上對這三者進行介紹之前,我們先來看看這道題:

public static void main(String[] args) {
  String str = "I.am.fine.";
    System.out.println(str.replace(".", "\\"));
    System.out.println(str.replaceAll(".", "\\\\"));
    System.out.println(str.replaceFirst(".", "\\\\"));
}

I\am\fine\
\\\\\\\\\\
\.am.fine.

replace結合題目中的執行replace()方法後的輸出結果,我們來看看在Java中的replace()的源碼:

public String replace(CharSequence target, CharSequence replacement) {
  return Pattern.compile(target.toString(), Pattern.LITERAL).
        matcher(this).replaceAll(Matcher.quoteReplacement(replacement.toString()));
}

可以看到replace()只支持入參為字符序列,而且實現的是完全替換,只要符合target的欄位都進行替換。replaceAll

public String replaceAll(String regex, String replacement) {
  return Pattern.compile(regex).matcher(this).replaceAll(replacement);
}

我們可以看到,replaceAll()支持入參為正則表達式,而且此方法也是實現欄位的完全替換。從運行結果中我們能看到所有的字符都被替換了,其實是因為".「在正則表達式中表示"所有字符」,如果想要只替換"."而非全部欄位,則可以這麼寫:

System.out.println(str.replaceAll("\\.", "\\\\"));


replaceFirst其實從上面的運行結果來看,也知道replaceFirst也是支持入參為正則表達式,但是此方法實現的是對第一個符合條件的欄位進行替換

public String replaceFirst(String regex, String replacement) {
    return Pattern.compile(regex).matcher(this).replaceFirst(replacement);
}

總結一下,replace不支持入參為正則表達式但能實現完全替換;replaceAll支持入參為正則表達式且能實現完全替換;replaceFirst支持入參為正則表達式,但替換動作只發生一次4. String對「+」的「重載」

private final char value[];

而且在上文我們已經提到String具有不可變性,可當我們在使用「+」對字符串進行拼接時,卻可以成功。它的原理是什麼呢?舉個慄子:

public static void main(String[] args) {
  String str = "abc";
  str += "123";
}

可以看到,雖然我們沒有用到java.lang.StringBuilder類,但編譯器為了執行上述代碼時會引入StringBuilder類,對字符串進行拼接。其實很多人認為使用」+「拼接字符串的功能可以理解為運算符重載,但Java是不支持運算符重載的(但C++支持)。運算符重載:在電腦程式設計中,運算符重載(operator overloading)是多態的一種。運算符重載就是對已有的運算符進行定義,賦予其另一種功能,以適應不同的數據類型。從反編譯的代碼來看,其實這只是一種Java語法糖。總結一下,String使用"+"進行拼接的原理是編譯器使用了StringBuilder.append()方法進行拼接,且這是一種語法糖5. 字符串拼接的幾種方式和區別字符串拼接是字符串處理中常用的操作之一,即將多個字符串拼接到一起,但從上文我們已經知道了String具有不可變性,那麼字符串拼接又是怎麼做到的呢?String.concat()拼接在介紹concat原理之前,我們先看看concat是怎麼使用的:

public static void main(String[] args) {
  String str = "我不是你最愛的小甜甜了嗎?";
    str = str.concat("你是個好姑娘");
    System.out.println(str);
}

我們可以看到,concat()方法是String類的,且是將原本的字符串與參數中的字符串進行拼接。現在我們來看看它的源碼:

public String concat(String str) {
    int otherLen = str.length();
    if (otherLen == 0) {
        return this;
    }
    int len = value.length;
    char buf[] = Arrays.copyOf(value, len + otherLen);
    str.getChars(buf, len);
    return new String(buf, true);
}

可以看到,concat()的拼接實際上是,創建一個長度為已有字符串和待拼接字符串的長度之和的字符數組,然後將兩個字符串的值賦值到新的字符數組中,最後利用這個字符數組創建一個新的String對象StringBuilder.append()拼接上文在介紹String的"+"拼接時,StringBuilder已經出來混個臉熟了,現在我們看個例子:

public static void main(String[] args) {
  StringBuilder sb = new StringBuilder("我不是你最愛的小甜甜了嗎?");
  sb.append("你是個好姑娘");
  System.out.println(sb.toString());
}

運行結果同上,接下來我們來看看StringBuilder的實現原理。StringBuilder內部同String類似,也封裝了一個字符數組:與String相比,StringBuilder的字符數組並不是final修飾的,即可修改。而且字符數組中不一定所有位置都已經被使用了,StringBuilder有一個專門記錄使用字符個數的實例變量:而StringBuilder.append()的源碼如下:

public StringBuilder append(String str) {
  super.append(str);
  return this;
}

可以看到StringBuilder.append()方法是採用父類AbstractStringBuilder的append()方法

public AbstractStringBuilder append(String str) {
  if (str == null)
    returpublic AbstractStringBuilder append(String str) {
  if (str == null)
    return appendNull();
    int len = str.length();
    ensureCapacityInternal(count + len);
    str.getChars(0, len, value, count);
    count += len;
    return this;
}n appendNull();
    int len = str.length();
    ensureCapacityInternal(count + len);
    str.getChars(0, len, value, count);
    count += len;
    return this;
}

ensureCapacityInternal()方法用於擴展字符數組長度(有興趣的讀者可以查看其擴展的方法),所以這裡的append方法會直接拷貝字符到內部的字符數組中,如果字符數組長度不夠,則進行擴展StringBuffer.append()拼接StringBuffer和StringBuilder結構類似,且父類都是AbstractStringBuilder,二者最大的區別在於StringBuffer是線程安全的,我們來看下StringBuffer.append()的源碼:

public synchronized StringBuffer append(String str) {
    toStringCache = null;
    super.append(str);
    return this;
}

可以看到,StringBuffer.append()方法是使用synchronized進行聲明,說明這是一個線程安全的方法,而上文StringBuilder.append()則不是線程安全的方法。StringUtils.join()拼接

public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("我不是你最愛的小甜甜了嗎?");
        list.add("你是個好姑娘");
        String s = new String();
        s = StringUtils.join(list, s);
        System.out.println(s);
}

public static String join(Collection var0, String var1) {
        StringBuffer var2 = new StringBuffer();

        for(Iterator var3 = var0.iterator();
            var3.hasNext(); var2.append((String)var3.next())) {
            if (var2.length() != 0) {
                var2.append(var1);
            }
        }
        return var2.toString();
    }

StringUtils.join()方法中依然是使用StringBuffer和Iterator迭代器來實現,而且如果集合類中的數據不是String類型,在遍歷集合的過程中還會強制轉換成String。總結一下,加上上文介紹的使用「+」進行字符串拼接的方式,此文一共介紹了五種字符串拼接的方式,分別是:使用"+"、使用String.concat()、使用StringBuilder.append()、使用StringBuffer.append()、使用StringUtils.join()。需要強調的是:使用StringBuilder.append()的方式是效率最高的;如果不是在循環體中進行字符串拼接,用"+"方式就行了;如果在並發場景中進行字符串拼接的話,要使用StringBuffer代替StringBuilder。6. Integer.toString()和String.valueOf()的區別Integer.toString()方法和String.valueOf()方法來進行int類型轉String,舉個慄子:

public static void main(String[] args) {
    int i = 1;
    String integerTest = Integer.toString(i);
    String stringTest = String.valueOf(i);
}

平常我們在使用這兩個方法來進行int類型轉String時,並沒有對其加以區分,這次就來深究一下它們之間有何區別,以及使用哪個方法比較好Integer.toString()方法以下為Integer.toString()的實現源碼,其中的stringSize()方法會返回整型數值i的長度,getChars()方法是將整型數值填充字符數組buf:

public static String toString(int i) {
    if (i == Integer.MIN_VALUE)
      return "-2147483648";
    int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
    char[] buf = new char[size];
    getChars(i, size, buf);
    return new String(buf, true);
}

可以看到,Integer.toString()先是通過判斷整型數值的正負性來給出字符數組buf的大小,然後再將整型數值填充到字符數組中,最後返回創建一個新的字符串並返回。在包裝類中不僅是Integer,同理Double、Long、Float等也有對應的toString()方法String.valueOf()方法String.valueOf()相對於Integer.toString()方法來說,有大量的重載方法,在此列舉出幾個典型的方法。public static String valueOf(Object obj)這個方法的入參是Object類型,所以只需要調用Object的toString()方法即可(在編寫類的時候,最好重寫其toString()方法)。

public static String valueOf(Object obj) {
  return (obj == null) ? "null" : obj.toString();
}


public static String valueOf(char data[])當入參為字符數組時,看過上文的String.concat()方法的原理,我們幾乎可以下意識地反應:這裡的字符數組,應該是用於創建一個新的字符串對象來並返回該字符串了

public static String valueOf(char data[]) {
  return new String(data);
}

除了字符數組外,字符也是通過轉換成字符數組後,創建一個新的字符串對象來返回字符串。public static String valueOf(boolean b)其實布爾型數值的返回結果只有兩種:true或false,所以只要對這兩個數值進行字符處理即可。

public static String valueOf(boolean b) {
  return b ? "true" : "false";
}


public static String valueOf(int i)上文我們介紹了Integer.toString()方法,這方法String.valueOf()就用到了。而且重載的入參類型不止int,還有long、float、double等。

public static String valueOf(int i) {
  return Integer.toString(i);
}

總結一下,我們看到String.valueOf()有許多重載方法,且關乎於包裝類如Integer等的方法內部還是調用了包裝類自己的方法如Integer.toString()。因其內部重載了不同類型轉換成String的處理,所以推薦使用String.valueOf()方法7. switch對String的支持(JDK 1.7及其後版本)在JDK 1.7之前,switch只支持對int、short、byte、char這四類數據做判斷,而在JVM內部實際上只支持對int類型的處理。因為虛擬機在處理之前,會將如short等類型數據轉換成int型,再進行條件判斷。在JDK 1.7的中switch增加了對String的支持,照常,先舉個慄子:

public static void main(String[] args) {
    String str = "abc";
    switch (str) {
        case "ab":
            System.out.println("ab");
            break;
        case "abc":
            System.out.println("abc");
            break;
        default:
          break;
    }
}

因為switch關鍵詞不像是類和方法,可以直接查看源碼,所以這裡採用查看編譯後的Class文件和查看反編譯的方式。首先我們查看編譯後的Class文件:

public static void main(String[] var0) {
  String var1 = "abc";
  byte var3 = -1;
    switch(var1.hashCode()) {
    case 3105:
        if (var1.equals("ab")) {
          var3 = 0;
        }
      break;
    case 96354:
        if (var1.equals("abc")) {
          var3 = 1;
        }
    }
    .
}

可以看到,switch的入參為字符串"abc"的hashCode,switch進行判斷的依然還是整數,而且進行判斷的字符串也被轉換成整型數值,在case中還使用了equals()方法對字符串進行判斷,以確認是否進行case內代碼的下一步操作。接下來我們看看反編譯之後的情況:

看到黃色框的代碼,我們可以知道String需要轉換成int類型的整型數據之後才能進行在switch中進行判斷。而紅色框中的代碼中我們可以看到,這個過程不止使用了hashCode()方法,還使用了equals()方法對字符串進行判斷。但也因switch判斷字符串的實現原理是求出String的hashCode,所以String不能賦值為null,否則會報NullPointerException。總結一下,switch支持String本質上還是switch在對int類型數值進行判斷8. 字符串常量池、Class常量池、運行時常量池在Java的內存分配中經常聽到關於常量池的描述,但名聲最大的還是運行時常量池,對於字符串常量池和Class常量池近乎沒有印象,甚至是混在一起,在此將這幾個概念進行區分。字符串常量池在不知道這個名詞之前,筆者以為字符串會跟類的其他信息一樣存儲在方法區(或永久代)中,但遇到它之後,筆者發覺這事情沒那麼簡單。JDK 1.7,將字符串常量池移出了永久代,搬到了DataSegument中,一個在堆中一個相對特殊的位置(失去唯一引用也不會被回收)字符串常量池中的內容是在字符串對象實例的引用值(字符串常量池中存儲的是引用值,具體的字符串對象實例存放在堆的另一塊空間),而且在HotSpot VM中實現的字符串常量池是一個由C++實現的StringTable,結構跟Hashtable類似,但區別在於不能自動擴容。這個StringTable在每個HotSpot VM中是被所有的類共享的。這麼說可能有點抽象,不如使用HSDB來親眼看看吧。舉個慄子:

class NY{
    String str = "nyfor2020";
}
public class Test {
    public static void main(String[] args) {
        NY ny1 = new NY();
        NY ny2 = new NY();
        try {
            System.in.read();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

在命令提示符中輸入「jps」查看進程號後,在命令提示符中輸入:

java -classpath "%JAVA_HOME%/lib/sa-jdi.jar" sun.jvm.hotspot.HSDB

打開HSDB,輸入進程號後使用Object Histogram找到相應類之後,可以找到兩個NY對象引用的字符串的地址是同一個。

Class常量池在《深入理解Java虛擬機》中對Class常量池的介紹是從這裡引入:Class文件中除了有類的版本、欄位、方法、接口等描述信息外,還有一項信息是常量池(Constant Pool Table),用於存放編譯期生成的各種字面量和符號引用,這部分內容將在類加載後進入方法去的運行時常量池中存放。字面量即常量概念,如文本字符串、被聲明為final的常量值等。而符號引用即一組符號來描述所引用的目標,符號可以是任何形式的字面量,只要使用的時候能直接定位到目標即可。關於常量池中的每一個常量表示什麼含義在此就不贅述,想了解的朋友可以參考《深入理解Java虛擬機》的第六章。舉個慄子:

public class Test {
    public static void main(String[] args) {
        String s1 = "nyfor2020";
    }
}

javap -verbose Test.class

在反編譯之後我們可以直接看到Class常量池中的內容,有類的全限定名、方法的描述符和欄位的描述符。也就是說,當Java文件被編譯成Class文件的過程之後,就會生成Class常量池。那麼運行時常量池又是什麼時候產生的呢?運行時常量池運行時常量池是方法區的一部分,用於存放Class文件編譯後生成的Class常量池等信息。接下來我們結合類加載過程來認識這幾個常量池之間的關係:

在JVM進行類加載過程中必須經過加載、連接、初始化這三個階段(在《Java的繼承(深入版)》中有介紹),而連接過程又包括了驗證、準備和解析這三個階段。當類加載到內存後,JVM就會將Class常量中的內容存放到運行時常量池中。而在Class常量池中存儲的是字面量和符號引用,而非真正的對象實例,所以在經過解析之後,會將符號引用替換為直接引用,而在解析過程中會去查詢字符串常量池,以保證運行時常量池所應用的字符串與字符串常量池中的信息一致。9. String.intern()方法在了解三個常量池之間的區別之後,我們來看看與字符串常量池有關的intern()方法.

/**
     * Returns a canonical representation for the string object.
     * <p>
     * A pool of strings, initially empty, is maintained privately by the
     * class {@code String}.
     * <p>
     * When the intern method is invoked, if the pool already contains a
     * string equal to this {@code String} object as determined by
     * the {@link #equals(Object)} method, then the string from the pool is
     * returned. Otherwise, this {@code String} object is added to the
     * pool and a reference to this {@code String} object is returned.
     * <p>
     * It follows that for any two strings {@code s} and {@code t},
     * {@code s.intern() == t.intern()} is {@code true}
     * if and only if {@code s.equals(t)} is {@code true}.
     * <p>
     * All literal strings and string-valued constant expressions are
     * interned. String literals are defined in section 3.10.5 of the
     * <cite>The Java&trade; Language Specification</cite>.
     *
     * @return  a string that has the same contents as this string, but is
     * guaranteed to be from a pool of unique strings.
     */
    public native String intern();

我們可以看到,intern()方法是一個本地方法,注釋描述的大致意思是:「當intern()方法被調用時,如果常量池中存在當前字符串,就會直接返回當前字符串;如果常量池中沒有此字符串,會將此字符串放入常量池中後,再返回」。該方法的作用就是把字符串加載到常量池中。剛剛在介紹字符串常量池時提到它在JDK 1.6和JDK 1.7的內存位置發生了變化,所以在不同版本的JDK中intern()方法的表現也有所差別。舉個慄子:

public static void main(String[] args) {
    String str1 = new String("1") + new String("1");
    str1.intern();
    String str2 = "11";
    System.out.println(str1 == str2);
}

在JDK 1.6中的運行結果為false,在JDK 1.7中的運行結果為true。為什麼會出現這種情況呢?主要是字符串常量池的內存位置變了,導致intern()的內部實現也發生了變化。在JDK 1.6中的intern()intern()方法將字符串複製到字符串常量池,然後返回一個該字符串在常量池的引用,但是str1並沒接收到這個應用,所以str1指向的還是堆,但是str2指向的是常量區,所以這兩個地址不一樣

在JDK 1.7中的intern()在JDK 1.7中的intern()方法,(在字符串常量池找不到該字符串時)將該字符串對象在堆裡的引用註冊到常量池,以後在使用相同字面量聲明的字符串對象則都指向該地址,也就是該字符串在堆中的地址。

等等,如果把intern()的位置下移一行之後呢?(基於JDK 1.7)

public static void main(String[] args) {
    String str1 = new String("1") + new String("1")
    String str2 = "11";
    str1.intern();
    System.out.println(str1 == str2);
    System.out.println(System.identityHashCode(str1));
    System.out.println(System.identityHashCode(str2));
}

可以看到intern()的執行順序改變之後,字符串常量池已經存儲了"1"和"11"引用了,所以str2依然指向的是常量池中的引用,而str1指向的是new出來的字符串對象地址。結語在日常使用的時候,我們對於String的態度就像是對待空氣,只有在出問題了才會發現之前沒對它加以了解。此文以String問題為契機,對String相關原理進行回顧。如果本文對你的學習有幫助,請給一個贊吧,這會是我最大的動力

https://www.cnblogs.com/qingergege/p/5701011.html

在Java虛擬機中,字符串常量到底存放在哪

https://blog.csdn.net/weixin_34413802/article/details/88009934

了解JDK 6和JDK 7中substring的原理及區別

https://www.cnblogs.com/dsitn/p/7151624.html

java的replaceFirst和(反斜槓)[replace、replaceAll和replaceFirst的區別]

https://blog.csdn.net/lonfee88/article/details/7333883

String 重載 「+」 原理分析

https://blog.csdn.net/codejas/article/details/78662146

字符串拼接的幾種方式和區別

https://www.cnblogs.com/lujiahua/p/11408689.html

Java—String.valueof()和Integer.toString()的不同

https://blog.csdn.net/whp1473/article/details/79935082

java switch是如何支持String類型的?

https://blog.csdn.net/guohengcook/article/details/81267768

JVM | 運行時常量池和字符串常量池及 intern()

https://hacpai.com/article/1581300080734

Java中幾種常量池的區分

http://tangxman.github.io/2015/07/27/the-difference-of-java-string-pool/

《深入理解Java虛擬機》                           

 

相關焦點

  • 美團面試官問我一個字符的String.length()是多少,我說是1,面試官說你回去好好學一下吧
    /** * Returns the length of this string.喬哥:前幾天我寫的一篇文章:面試官問你編碼相關的面試題,把這篇甩給他就完事![1]裡面對於Java的字符使用的編碼有介紹:Java中 有內碼和外碼這一區分簡單來說•內碼:char或String在內存裡使用的編碼方式。•外碼:除了內碼都可以認為是「外碼」。(包括class文件的編碼)而java內碼:unicode(utf-16)中使用的是utf-16.
  • 求職面試篇:面試官都會問哪些問題
    說明:此類文章沒有合適圖片配圖,但是純文本閱讀又比較累,所以給大家放一些風景圖,緩解閱讀疲勞!(圖片主要來自暱圖網,圖行天下等)面試的時候,面試官拷問問題是不可避免的,所以,回答問題是重要的一環。如果在網上搜集一下就會發現,面試官問的很多問題,有一些問題是具有共同性的。
  • 大學生求職面試篇:面試官都會問哪些問題
    一、 針對簡歷的提問準備前面我們在《大學生初入職場如何寫一份優秀的簡歷(簡歷系列1/3篇)》這篇文章中,介紹了一份簡歷需要具備的最基本的要素,比如基本信息、求職意向、工作經歷、教育經歷、項目經歷、職業技能、
  • 面試官問我離職原因,我到底該如何回答?這篇文章算是講透了
    2、一次,老王幫助某房地產集團公司招聘一位工程部總監,面試一個人很有意思。當老王問他現在的公司還不錯,待遇也行,怎麼想著離職呢?他回答,出乎老王所料。他給出兩點原因:A、老闆的親侄子也在他們部門,感覺做事情好像被監控一樣,一點好處都不敢佔。
  • 面試官問:能否模擬實現JS的call和apply方法
    前言這是面試官問系列的第三篇,旨在幫助讀者提升JS基礎知識,包含new、call、apply、this、繼承相關知識。面試官問系列文章如下:感興趣的讀者可以點擊閱讀。1.面試官問:能否模擬實現JS的new操作符2.面試官問:能否模擬實現JS的bind方法3.面試官問:能否模擬實現JS的call和apply方法4.面試官問:JS的this指向5.面試官問:JS的繼承之前寫過兩篇《面試官問:能否模擬實現JS的new操作符》和《面試官問:能否模擬實現JS的bind
  • 面試官:如果求職者問我這7個問題,我當場讓他離場!
    在面試快要結束的時候,很多的面試官都會向求職者詢問:「你還需要了解什麼嗎?」求職者在回答問題時應該儘量考慮提問。無論您是否打算,您提出的每個問題都有可能反映出您對公司的了解,對職位的興趣和職業道德。這就是為什麼花時間為每次面試提出深思熟慮的問題是很重要的。以下是一系列面試問題,可以讓您將僱主用作創建自己問題列表的起點。另一方面,有些問題不適合詢問面試官。以下是在面試時從不向僱主提問的問題清單,以及有關您不應該問他們的原因的信息。
  • 職場中,面試官問你有什麼問題要問他應怎樣回答?不妨看看這3個
    本文章由職場小徐獨家奉送,歡迎各位讀者朋友們前來閱讀!在我們的職場當中,面試官一般在最後的時候都會問,有什麼問題要問他,那麼我們在這個時候應該如何回答呢?當然一般在最後,面試官問這樣的一個問題,他們的第一個回答應該就是為工作潛力。但是也一定要搞清楚,現在你只是在面試,並沒有到這個公司來進行工作,所以說在這個時候儘量能不問這個問題,就不問這個問題。第二就是問團隊氣氛。
  • 面試官:如果問前領導,他會怎麼評價你?小夥當場打電話被錄取
    在現在的面試中,面試者的壓力真是越來越大了,不管要面對眾多套路問題,還要時時提防面試官的反套路和各種刁鑽問題,可謂是非常心累。而在這眾多的應聘者中總有那些不走尋常路的人,讓人對他們刮目相看。而小飛就是他們其中的一員。
  • 面試談離職原因,不要說這四種理由,爭取給面試官個好印象
    應聘的時候,面試官問他,「你這麼的優秀,為何從原單位辭職呀?」他一時語塞,不知道該怎麼回答,老老實實說原單位的薪資待遇太低,不能滿足自己的期待。結果好不容易殺入重圍,就因為這個問題沒應對好,莫名其妙就被刷下來了。職場上類似的情況比比皆是,新人面對這個問題,千萬不能說下面這四個理由,想要了解的朋友們,趕緊跟隨小編一起來看看這篇文章吧!
  • 程式設計師面試心得——非技術篇(該向面試官問什麼)
    在面試結束之前,HR通常會問上一句:「你還有什麼要問的嗎?」一定要問!一定要問!一定要問!重要的事情說三遍。當面試官問你還有什麼想問的時候,這是一個最好的也是最後的機會讓你在沒有入職前了解公司和工作情況。
  • 面試官:老是問我深淺拷貝問題,自己看文章
    面試官:老是問我深淺拷貝問題,自己看文章你如果出去面試,面試官老是會問你一些很神奇,但又不得不去了解的問題,今天這個問題就是其中之一,在工作中,其實我們經常使用對象拷貝,數組拷貝,但是往往會忽略了其中的原理,今天我們就來一探究竟。
  • 看了這篇,面試官問你APP體積優化再也不用怕了
    本文作者:Only_1.為什麼要做體積瘦身別問!問就是為了應付面試。哈哈,開個玩笑。大家生活中都會遇到一個場景,在某個需要緊急打開App的時候,發現使用的App半天打不開!WTF!而另外一款相同功能的App卻可以瞬間打開。哪個App能夠挽留更多的用戶就不言而喻了吧!
  • 面試反客為主:問倒面試官
    解讀面試官的反饋:如果面試官表示這個職位的職能已經超出最原始的範圍(並且還在不停擴大),那麼這個職位在這家公司就會有非常好的發展機會。如果好幾年這個職位停滯不前,那就別指望它能開花結果了。當然Palmer也表示,根據自己的職業期望,後一種情況也並非一定是壞事。
  • 面試官:怎麼用10塊請10萬人吃飯?他的回覆讓面試官心服口服
    面試是每個求職者必經的道路,但是,面試時面試官提出的古怪問題也是令每個求職者都很頭疼的事情。本來信心滿滿地去參加面試,卻被面試官提出的「奇葩」問題打亂了思路,一不小心就「原形畢露」,劇本和自己設想的完全不一樣了。
  • 面試結束時問面試官這些問題,一舉驚豔面試官!
    很多同學則會覺得面試已經結束,問一些不著邊際的問題,有些腦子一空白,不知道如何向僱主提出問題。面試是雙向的交流,你的面試官想你提問問題來了解你的技能。同時,你需要準備好問題來了解這個職位,你未來的老闆,以及確認這個公司和崗位對你是合適的。所以,如果大家不準備聰明的回答,那麼面試官則可能會覺得你對這個職位不了解或者完全不感興趣。
  • 面試過程中,如果面試官問你有什麼優勢該怎麼回答?
    在回答這個問題的時候,首先我們應該站在面試官的角度上來分析一下,為什麼面試官會問這樣的問題?他問這樣的問題是希望你如何去回答他?對於面試官來說,他問你有什麼優勢,其實他就在考量你,你自己所認為的優勢和你所要做的工作之間有什麼關係,你的這個優勢能不能很好的用在以後的工作過程當中,在工作中為公司創造更大的價值。
  • 你準備怎麼回答面試官的問題?面試官必問「秘訣」
    4.自我介紹內容不可太簡單,會給人感覺空洞;也不可展開細節說太多,一方面會佔用過長的時間,另一方面,要留給面試官繼續挖掘的餘地。5.自我介紹時該提的亮點、個人能力以及特長都需要提到,因為你永遠不知道面試官會留給你幾分鐘時間,後面還會不會問到你的優勢。謹記!
  • 面試懵了:StringBuilder為什麼線程不安全
    的Java資料是我師傅當年給我的,免費分享給大家(已修復)下一篇:2020年網際網路大廠最新面試真題以及2000道常見Java面試題(附答案)作者:千山qianshan來源:juejin.im/post/5d6228046fb9a06add4e37fe引言周五去面試又被面試的一個問題問啞巴了
  • 面試官問:「你的興趣愛好是什麼?」這樣回答,面試官最滿意
    1 面試官為什麼要問這道題?面試官時間是很寶貴的,在短短一個小時之內,需要對候選人深入的了解,所以問任何問題都是有目的性的,那面試官問:「你的興趣愛好是什麼?」有什麼目的呢?面試官問你有什麼體育運動方面的愛好,他可不是想尋找球友,而是想從側面了解你的工作精力和活力以及身體健康程度。面試官問你是否喜歡看書,他可能是想從側面看看你是否愛好學習。同時, 面試官也想了解候選人是否有不良嗜好,如果這個不良嗜好對於崗位有影響,可能就不不能要。
  • 面試題:StringBuilder為什麼線程不安全?
    點擊上方「搜雲庫技術團隊」關注,選擇「設為星標」引言周五去面試又被面試的一個問題問啞巴了