80道最新java基礎部分面試題(七)

本身整理的面試題,但願能夠幫到你們,須要更多資料的能夠私信我哦,你們一塊兒學習進步!java

70、TreeSet裏面放對象,若是同時放入了父類和子類的實例對象,那比較時使用的是父類的compareTo方法,仍是使用的子類的compareTo方法,仍是拋異常!
(應該是沒有針對問題的確切的答案,當前的add方法放入的是哪一個對象,就調用哪一個對象的compareTo方法,至於這個compareTo方法怎麼作,就看當前這個對象的類中是如何編寫這個方法的)
實驗代碼:
public class Parent implements Comparable {
private int age = 0;
public Parent(int age){
this.age = age;
}
public int compareTo(Object o) {
// TODO Auto-generated method stub
System.out.println("method of parent");
Parent o1 = (Parent)o;
return age>o1.age?1:age<o1.age?-1:0;
}c++

}程序員

public class Child extends Parent {web

public Child(){
    super(3);
}
public int compareTo(Object o) {

        // TODO Auto-generated method stub
        System.out.println("method of child");

// Child o1 = (Child)o;
return 1;面試

}

}sql

public class TreeSetTest {apache

/**
 * @param args
 */
public static void main(String[] args) {
    // TODO Auto-generated method stub
    TreeSet set = new TreeSet();
    set.add(new Parent(3));
    set.add(new Child());
    set.add(new Parent(4));
    System.out.println(set.size());
}

}編程

7一、說出一些經常使用的類,包,接口,請各舉5個
要讓人家感受你對java ee開發很熟,因此,不能僅僅只列core java中的那些東西,要多列你在作ssh項目中涉及的那些東西。就寫你最近寫的那些程序中涉及的那些類。數組

經常使用的類:BufferedReader BufferedWriter FileReader FileWirter String Integer
java.util.Date,System,Class,List,HashMap緩存

經常使用的包:java.lang java.io java.util java.sql ,javax.servlet,org.apache.strtuts.action,org.hibernate
經常使用的接口:Remote List Map Document NodeList ,Servlet,HttpServletRequest,HttpServletResponse,Transaction(Hibernate)、Session(Hibernate),HttpSession
7二、java中有幾種類型的流?JDK爲每種類型的流提供了一些抽象類以供繼承,請說出他們分別是哪些類?
字節流,字符流。字節流繼承於InputStream OutputStream,字符流繼承於InputStreamReader OutputStreamWriter。在java.io包中還有許多其餘的流,主要是爲了提升性能和使用方便。
7三、字節流與字符流的區別
要把一片二進制數據數據逐一輸出到某個設備中,或者從某個設備中逐一讀取一片二進制數據,無論輸入輸出設備是什麼,咱們要用統一的方式來完成這些操做,用一種抽象的方式進行描述,這個抽象描述方式起名爲IO流,對應的抽象類爲OutputStream和InputStream ,不一樣的實現類就表明不一樣的輸入和輸出設備,它們都是針對字節進行操做的。
在應用中,常常要徹底是字符的一段文本輸出去或讀進來,用字節流能夠嗎?計算機中的一切最終都是二進制的字節形式存在。對於「中國」這些字符,首先要獲得其對應的字節,而後將字節寫入到輸出流。讀取時,首先讀到的是字節,但是咱們要把它顯示爲字符,咱們須要將字節轉換成字符。因爲這樣的需求很普遍,人家專門提供了字符流的包裝類。
底層設備永遠只接受字節數據,有時候要寫字符串到底層設備,須要將字符串轉成字節再進行寫入。字符流是字節流的包裝,字符流則是直接接受字符串,它內部將串轉成字節,再寫入底層設備,這爲咱們向IO設別寫入或讀取字符串提供了一點點方便。
字符向字節轉換時,要注意編碼的問題,由於字符串轉成字節數組,
實際上是轉成該字符的某種編碼的字節形式,讀取也是反之的道理。

講解字節流與字符流關係的代碼案例:
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.InputStreamReader;
import java.io.PrintWriter;

public class IOTest {
public static void main(String[] args) throws Exception {
String str = "中國人";
/*FileOutputStream fos = new FileOutputStream("1.txt");

fos.write(str.getBytes("UTF-8"));
    fos.close();*/

    /*FileWriter fw = new FileWriter("1.txt");
    fw.write(str);
    fw.close();*/
    PrintWriter pw = new PrintWriter("1.txt","utf-8");
    pw.write(str);
    pw.close();

    /*FileReader fr = new FileReader("1.txt");
    char[] buf = new char[1024];
    int len = fr.read(buf);
    String myStr = new String(buf,0,len);
    System.out.println(myStr);*/
    /*FileInputStream fr = new FileInputStream("1.txt");
    byte[] buf = new byte[1024];
    int len = fr.read(buf);
    String myStr = new String(buf,0,len,"UTF-8");
    System.out.println(myStr);*/
    BufferedReader br = new BufferedReader(
            new InputStreamReader(
                new FileInputStream("1.txt"),"UTF-8"    
                )
            );
    String myStr = br.readLine();
    br.close();
    System.out.println(myStr);
}

}
7四、什麼是java序列化,如何實現java序列化?或者請解釋Serializable接口的做用。

咱們有時候將一個java對象變成字節流的形式傳出去或者從一個字節流中恢復成一個java對象,例如,要將java對象存儲到硬盤或者傳送給網絡上的其餘計算機,這個過程咱們能夠本身寫代碼去把一個java對象變成某個格式的字節流再傳輸,可是,jre自己就提供了這種支持,咱們能夠調用OutputStream的writeObject方法來作,若是要讓java 幫咱們作,要被傳輸的對象必須實現serializable接口,這樣,javac編譯時就會進行特殊處理,編譯的類才能夠被writeObject方法操做,這就是所謂的序列化。須要被序列化的類必須實現Serializable接口,該接口是一個mini接口,其中沒有須要實現的方法,implements Serializable只是爲了標註該對象是可被序列化的。

例如,在web開發中,若是對象被保存在了Session中,tomcat在重啓時要把Session對象序列化到硬盤,這個對象就必須實現Serializable接口。若是對象要通過分佈式系統進行網絡傳輸或經過rmi等遠程調用,這就須要在網絡上傳輸對象,被傳輸的對象就必須實現Serializable接口。

7五、描述一下JVM加載class文件的原理機制?
JVM中類的裝載是由ClassLoader和它的子類來實現的,Java ClassLoader 是一個重要的Java運行時系統組件。它負責在運行時查找和裝入類文件的類。

7六、heap和stack有什麼區別。
java的內存分爲兩類,一類是棧內存,一類是堆內存。棧內存是指程序進入一個方法時,會爲這個方法單獨分配一塊私屬存儲空間,用於存儲這個方法內部的局部變量,當這個方法結束時,分配給這個方法的棧會釋放,這個棧中的變量也將隨之釋放。
堆是與棧做用不一樣的內存,通常用於存放不放在當前方法棧中的那些數據,例如,使用new建立的對象都放在堆裏,因此,它不會隨方法的結束而消失。方法中的局部變量使用final修飾後,放在堆中,而不是棧中。

7七、GC是什麼? 爲何要有GC?   
GC是垃圾收集的意思(Gabage Collection),內存處理是編程人員容易出現問題的地方,忘記或者錯誤的內存回收會致使程序或系統的不穩定甚至崩潰,Java提供的GC功能能夠自動監測對象是否超過做用域從而達到自動回收內存的目的,Java語言沒有提供釋放已分配內存的顯示操做方法。

7八、垃圾回收的優勢和原理。並考慮2種回收機制。
Java語言中一個顯著的特色就是引入了垃圾回收機制,使c++程序員最頭疼的內存管理的問題迎刃而解,它使得Java程序員在編寫程序的時候再也不須要考慮內存管理。因爲有個垃圾回收機制,Java中的對象再也不有"做用域"的概念,只有對象的引用纔有"做用域"。垃圾回收能夠有效的防止內存泄露,有效的使用可使用的內存。垃圾回收器一般是做爲一個單獨的低級別的線程運行,不可預知的狀況下對內存堆中已經死亡的或者長時間沒有使用的對象進行清楚和回收,程序員不能實時的調用垃圾回收器對某個對象或全部對象進行垃圾回收。回收機制有分代複製垃圾回收和標記垃圾回收,增量垃圾回收。

7九、垃圾回收器的基本原理是什麼?垃圾回收器能夠立刻回收內存嗎?有什麼辦法主動通知虛擬機進行垃圾回收?
對於GC來講,當程序員建立對象時,GC就開始監控這個對象的地址、大小以及使用狀況。一般,GC採用有向圖的方式記錄和管理堆(heap)中的全部對象。經過這種方式肯定哪些對象是"可達的",哪些對象是"不可達的"。當GC肯定一些對象爲"不可達"時,GC就有責任回收這些內存空間。能夠。程序員能夠手動執行System.gc(),通知GC運行,可是Java語言規範並不保證GC必定會執行。

80、何時用assert。
assertion(斷言)在軟件開發中是一種經常使用的調試方式,不少開發語言中都支持這種機制。在實現中,assertion就是在程序中的一條語句,它對一個boolean表達式進行檢查,一個正確程序必須保證這個boolean表達式的值爲true;若是該值爲false,說明程序已經處於不正確的狀態下,assert將給出警告或退出。通常來講,assertion用於保證程序最基本、關鍵的正確性。assertion檢查一般在開發和測試時開啓。爲了提升性能,在軟件發佈後,assertion檢查一般是關閉的。
package com.huawei.interview;

public class AssertTest {

/**
 * @param args
 */
public static void main(String[] args) {
    // TODO Auto-generated method stub
    int i = 0;
    for(i=0;i<5;i++)
    {
        System.out.println(i);
    }
    //假設程序不當心多了一句--i;
    --i;
    assert i==5;        
}

}

8一、java中會存在內存泄漏嗎,請簡單描述。
所謂內存泄露就是指一個再也不被程序使用的對象或變量一直被佔據在內存中。java中有垃圾回收機制,它能夠保證一對象再也不被引用的時候,即對象編程了孤兒的時候,對象將自動被垃圾回收器從內存中清除掉。因爲Java 使用有向圖的方式進行垃圾回收管理,能夠消除引用循環的問題,例若有兩個對象,相互引用,只要它們和根進程不可達的,那麼GC也是能夠回收它們的,例以下面的代碼能夠看到這種狀況的內存回收:
package com.huawei.interview;

import java.io.IOException;

public class GarbageTest {

/**
 * @param args
 * @throws IOException 
 */
public static void main(String[] args) throws IOException {
    // TODO Auto-generated method stub
    try {
        gcTest();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    System.out.println("has exited gcTest!");
    System.in.read();
    System.in.read();       
    System.out.println("out begin gc!");        
    for(int i=0;i<100;i++)
    {
        System.gc();
        System.in.read();   
        System.in.read();   
    }
}

private static void gcTest() throws IOException {
    System.in.read();
    System.in.read();       
    Person p1 = new Person();
    System.in.read();
    System.in.read();       
    Person p2 = new Person();
    p1.setMate(p2);
    p2.setMate(p1);
    System.out.println("before exit gctest!");
    System.in.read();
    System.in.read();       
    System.gc();
    System.out.println("exit gctest!");
}

private static class Person
{
    byte[] data = new byte[20000000];
    Person mate = null;
    public void setMate(Person other)
    {
        mate = other;
    }
}

}

java中的內存泄露的狀況:長生命週期的對象持有短生命週期對象的引用就極可能發生內存泄露,儘管短生命週期對象已經再也不須要,可是由於長生命週期對象持有它的引用而致使不能被回收,這就是java中內存泄露的發生場景,通俗地說,就是程序員可能建立了一個對象,之後一直再也不使用這個對象,這個對象卻一直被引用,即這個對象無用可是卻沒法被垃圾回收器回收的,這就是java中可能出現內存泄露的狀況,例如,緩存系統,咱們加載了一個對象放在緩存中(例如放在一個全局map對象中),而後一直再也不使用它,這個對象一直被緩存引用,但卻再也不被使用。
檢查java中的內存泄露,必定要讓程序將各類分支狀況都完整執行到程序結束,而後看某個對象是否被使用過,若是沒有,則才能斷定這個對象屬於內存泄露。

若是一個外部類的實例對象的方法返回了一個內部類的實例對象,這個內部類對象被長期引用了,即便那個外部類實例對象再也不被使用,但因爲內部類持久外部類的實例對象,這個外部類對象將不會被垃圾回收,這也會形成內存泄露。

下面內容來自於網上(主要特色就是清空堆棧中的某個元素,並非完全把它從數組中拿掉,而是把存儲的總數減小,本人寫得能夠比這個好,在拿掉某個元素時,順便也讓它從數組中消失,將那個元素所在的位置的值設置爲null便可):
我實在想不到比那個堆棧更經典的例子了,以至於我還要引用別人的例子,下面的例子不是我想到的,是書上看到的,固然若是沒有在書上看到,可能過一段時間我本身也想的到,但是那時我說是我本身想到的也沒有人相信的。
    public class Stack {
    private Object[] elements=new Object[10];
    private int size = 0;
    public void push(Object e){
    ensureCapacity();
    elements[size++] = e;
    }
    public Object pop(){
    if( size == 0)
    throw new EmptyStackException();
    return elements[--size];
    }
    private void ensureCapacity(){
    if(elements.length == size){
    Object[] oldElements = elements;
    elements = new Object[2 * elements.length+1];
    System.arraycopy(oldElements,0, elements, 0, size);
    }
    }
    }
    上面的原理應該很簡單,假如堆棧加了10個元素,而後所有彈出來,雖然堆棧是空的,沒有咱們要的東西,可是這是個對象是沒法回收的,這個才符合了內存泄露的兩個條件:無用,沒法回收。
    可是就是存在這樣的東西也不必定會致使什麼樣的後果,若是這個堆棧用的比較少,也就浪費了幾個K內存而已,反正咱們的內存都上G了,哪裏會有什麼影響,再說這個東西很快就會被回收的,有什麼關係。下面看兩個例子。
    例子1
    public class Bad{
    public static Stack s=Stack();
    static{
    s.push(new Object());
    s.pop(); //這裏有一個對象發生內存泄露
    s.push(new Object()); //上面的對象能夠被回收了,等因而自愈了
    }
    }
    由於是static,就一直存在到程序退出,可是咱們也能夠看到它有自愈功能,就是說若是你的Stack最多有100個對象,那麼最多也就只有100個對象沒法被回收其實這個應該很容易理解,Stack內部持有100個引用,最壞的狀況就是他們都是無用的,由於咱們一旦放新的進取,之前的引用天然消失!

內存泄露的另一種狀況:當一個對象被存儲進HashSet集合中之後,就不能修改這個對象中的那些參與計算哈希值的字段了,不然,對象修改後的哈希值與最初存儲進HashSet集合中時的哈希值就不一樣了,在這種狀況下,即便在contains方法使用該對象的當前引用做爲的參數去HashSet集合中檢索對象,也將返回找不到對象的結果,這也會致使沒法從HashSet集合中單獨刪除當前對象,形成內存泄露。

8二、能不能本身寫個類,也叫java.lang.String?

能夠,但在應用的時候,須要用本身的類加載器去加載,不然,系統的類加載器永遠只是去加載jre.jar包中的那個java.lang.String。因爲在tomcat的web應用程序中,都是由webapp本身的類加載器先本身加載WEB-INF/classess目錄中的類,而後才委託上級的類加載器加載,若是咱們在tomcat的web應用程序中寫一個java.lang.String,這時候Servlet程序加載的就是咱們本身寫的java.lang.String,可是這麼幹就會出不少潛在的問題,原來全部用了java.lang.String類的都將出現問題。

雖然java提供了endorsed技術,能夠覆蓋jdk中的某些類,具體作法是….。可是,可以被覆蓋的類是有限制範圍,反正不包括java.lang這樣的包中的類。

(下面的例如主要是便於你們學習理解只用,不要做爲答案的一部分,不然,人家懷疑是題目泄露了)例如,運行下面的程序:
package java.lang;

public class String {

/**
 * @param args
 */
public static void main(String[] args) {
    // TODO Auto-generated method stub
    System.out.println("string");
}

}
報告的錯誤以下:
java.lang.NoSuchMethodError: main
Exception in thread "main"
這是由於加載了jre自帶的java.lang.String,而該類中沒有main方法。

  1. Java代碼查錯
  2. abstract class Name {
       private String name;
       public abstract boolean isStupidName(String name) {}
    }
    大俠們,這有何錯誤?
    答案: 錯。abstract method必須以分號結尾,且不帶花括號。

  3. public class Something {
       void doSomething () {
           private String s = "";
           int l = s.length();
       }
    }
    有錯嗎?
    答案: 錯。局部變量前不能放置任何訪問修飾符 (private,public,和protected)。final能夠用來修飾局部變量
    (final如同abstract和strictfp,都是非訪問修飾符,strictfp只能修飾class和method而非variable)。

  4. abstract class Something {
       private abstract String doSomething ();
    }
    這好像沒什麼錯吧?
    答案: 錯。abstract的methods不能以private修飾。abstract的methods就是讓子類implement(實現)具體細節的,怎麼能夠用private把abstract
    method封鎖起來呢? (同理,abstract method前不能加final)。

  5. public class Something {
       public int addOne(final int x) {
           return ++x;
       }
    }
    這個比較明顯。
    答案: 錯。int x被修飾成final,意味着x不能在addOne method中被修改。

  6. public class Something {
       public static void main(String[] args) {
           Other o = new Other();
           new Something().addOne(o);
       }
       public void addOne(final Other o) {
           o.i++;
       }
    }
    class Other {
       public int i;
    }
    和上面的很類似,都是關於final的問題,這有錯嗎?
    答案: 正確。在addOne method中,參數o被修飾成final。若是在addOne method裏咱們修改了o的reference
    (好比: o = new Other();),那麼如同上例這題也是錯的。但這裏修改的是o的member vairable
    (成員變量),而o的reference並無改變。

  7. class Something {
        int i;
        public void doSomething() {
            System.out.println("i = " + i);
        }
    }
    有什麼錯呢? 看不出來啊。
    答案: 正確。輸出的是"i = 0"。int i屬於instant variable (實例變量,或叫成員變量)。instant variable有default value。int的default value是0。

  8. class Something {
        final int i;
        public void doSomething() {
            System.out.println("i = " + i);
        }
    }
    和上面一題只有一個地方不一樣,就是多了一個final。這難道就錯了嗎?
    答案: 錯。final int i是個final的instant variable (實例變量,或叫成員變量)。final的instant variable沒有default value,必須在constructor (構造器)結束以前被賦予一個明確的值。能夠修改成"final int i = 0;"。

  9. public class Something {
         public static void main(String[] args) {
            Something s = new Something();
            System.out.println("s.doSomething() returns " + doSomething());
        }
        public String doSomething() {
            return "Do something ...";
        }
    }
     看上去很完美。
    答案: 錯。看上去在main裏call doSomething沒有什麼問題,畢竟兩個methods都在同一個class裏。但仔細看,main是static的。static method不能直接call non-static methods。可改爲"System.out.println("s.doSomething() returns " + s.doSomething());"。同理,static method不能訪問non-static instant variable。

  10. 此處,Something類的文件名叫OtherThing.java
    class Something {
        private static void main(String[] something_to_do) {       
            System.out.println("Do something ...");
        }
    }
     這個好像很明顯。
    答案: 正確。歷來沒有人說過Java的Class名字必須和其文件名相同。但public class的名字必須和文件名相同。
    10.
    interface  A{
       int x = 0;
    }
    class B{
       int x =1;
    }
    class C extends B implements A {
       public void pX(){
          System.out.println(x);
       }
       public static void main(String[] args) {
          new C().pX();
       }
    }
    答案:錯誤。在編譯時會發生錯誤(錯誤描述不一樣的JVM有不一樣的信息,意思就是未明確的x調用,兩個x都匹配(就象在同時import java.util和java.sql兩個包時直接聲明Date同樣)。對於父類的變量,能夠用super.x來明確,而接口的屬性默認隱含爲 public static final.因此能夠經過A.x來明確。

  11. interface Playable {    void play();}interface Bounceable {    void play();}interface Rollable extends Playable, Bounceable {    Ball ball = new Ball("PingPang");}class Ball implements Rollable {    private String name;    public String getName() {        return name;    }    public Ball(String name) {        this.name = name;            }   public void play() {        ball = new Ball("Football");        System.out.println(ball.getName());    }}這個錯誤不容易發現。答案: 錯。"interface Rollable extends Playable, Bounceable"沒有問題。interface可繼承多個interfaces,因此這裏沒錯。問題出在interface Rollable裏的"Ball ball = new Ball("PingPang");"。任何在interface裏聲明的interface variable (接口變量,也可稱成員變量),默認爲public static final。也就是說"Ball ball = new Ball("PingPang");"其實是"public static final Ball ball = new Ball("PingPang");"。在Ball類的Play()方法中,"ball = new Ball("Football");"改變了ball的reference,而這裏的ball來自Rollable interface,Rollable interface裏的ball是public static final的,final的object是不能被改變reference的。所以編譯器將在"ball = new Ball("Football");"這裏顯示有錯。

相關文章
相關標籤/搜索