java面試問答

1:JDK與JRE
JDK:JAVA Development Kit, java開發工具包; 包括各種類庫和工具,當然也包括JRE
JRE:JAVA Runtime Environment,java程序運行環境,包括JAVA類庫的class文件和JVM

2:JAVA_HOME PATH CLASSPATH
JAVA_HOME :JDK的安裝目錄,很多web服務器如tomcat沒有內置JDK,它們通過JAVA_HOME找到JDK
PATH:在原有值後加“;%JAVA_HOME%\bin”;通過配置PATH,可以再任何命令提示符窗口中使用JAVAC、JAVA等命令了
CLASSPATH:用來指定JAVA程序搜索類的路徑的,JAVA程序在編譯和運行時,先搜索jre/lib/rt.jar中的類,然後搜索CLASSPATH中指定的類;一般CLASSPATH會包括當前目錄“.”

3:JAVA程序動態的指定類搜索路徑方法
利用-cp或-classpath選項,如
javac –cp D:\wrok\log4j.jar Hello.java (編譯時指定D:\wrok\log4j.jar爲搜索路徑)
java –cp D:\wrok\log4j.jar Hello

4:JAVA和C++程序在編譯及運行上的區別
C,C++這類語言的編譯器(例如 UNIX下的CC命令,WINDOWS下的CL命令)都是把源代碼直接編譯成計算機可以認識的機器碼,如EXE、DLL之類的文件,然後直接運行。
JAVA爲了實現跨平臺,多了一箇中間步驟,就是先生成字節碼文件,javac命令先把源文件編譯成計算機無法直接識別的class文件,但是它可以被JVM所認識,JVM有多個平臺版本,因此可以在多個平臺執行。

5:什麼是JVM及其工作原理
JVM是一個想象中的機器,在實際的計算機上通過軟件模擬來實現。Java虛擬機有自己想象中的硬件,如處理器、堆棧、寄存器,還有相應的指令系統。JVM在執行字節碼時,把字節碼解釋成具體平臺上的機器指令執行。

6:JAVA垃圾回收機制
JVM中棧存放的是非static的自動變量、函數參數、表達式的臨時結果和函數返回值。棧中這些實體數據的分配和釋放均是由系統自動完成的。
堆中存放的實體數據是程序員顯示分配的(new),沒有自動垃圾回收機制的系統中(有些JVM沒有垃圾回收機制)必須顯示的釋放這些實體
C、C++中也有棧和堆,對堆的管理,C是通過malloc()和free();而C++是通過new和delete

Object對象中有個finalize(),它會在對象被回收之前被調用;
System.gc();和Runtime.getRunime().gc()兩個方法都可以顯示請求開始垃圾回收線程

7:jar和war
兩者都是java可執行文件,jar是對於桌面應用程序,war是對於web應用程序;
Jar和war打包都通過JDK的jar命令

8:JAVA變量及作用範圍
分爲:靜態變量、成員變量、局部變量
靜態變量在類中用static修飾,生存週期由類決定;成員變量是類中沒有用static修飾的變量,生存週期有對象來決定;局部變量是定義在方法裏的變量、方法的參數、代碼塊裏的變量,它們的作用範圍用大括號{}來界定

9:JAVA變量分爲哪兩種大的數據類型
基本數據類型和引用數據類型 ,它們最大的區別在於引用數據類型存放的是數據所在的地址,而基本數據類型直接存放數據的值;二者都保存在棧中

10:裝箱、拆箱指的是基本基本數據類型和包裝類型的自動相互轉化

11:C++指針和JAVA引用的區別
相同:都是指向一塊內存地址
不同:
一 類型轉換:引用的類型轉換,可能拋出java.lang.ClassCastException,引用對應的類型不同的話,轉換不成功;C++指針則一定能轉換成功,指向哪兒,還是一個地址
二 初始值:引用類型的初始值爲null;C++指針是int,如不初始化,值是隨機的
三 計算:引用不可計算;指針可計算,如++或—
四 內存泄露:JAVA引用基本不會產生內存泄露;指針容易,程序員須及時回收
五 作爲參數:JAVA方法本質上只有傳值,引用作爲參數使用時,回給函數內引用的COPY,所以在函數內交換兩個引用參數是沒意義的,但改變一個引用參數的屬性是有意義的,因爲引用參數的COPY所引用的對象和引用參數是同一個對象;
C++指針作爲參數,實際上就是它所指的地址在函數中被操作。

12:equals()和==
==運用在基本數據類型是比較的是實際的值;用於比較引用類型時候,比較兩個引用的地址是否相同;(都是比較棧中數據)
Object有equals()方法,默認的比較方式與==相同,String類重寫了該方法,使其能比較字符串的內容;

13:JAVA三元運算符
表達式1?表達式2:表達式3 表達式1爲true則執行表達式2 ;否則執行表達式3

14:Java註釋類型
①行註釋 //
②塊註釋 /* ….. */
③文檔註釋 /* …. /
④Annotation

15:類與對象
類是一種抽象,JVM對類只加載一次
對象是類的實現,通過new創建,可以創建多個對象;

面向對象特性:封裝、繼承、多態

16:什麼是多態
本質是可發送消息給某個對象,讓該對象自行決定響應何種行爲。通過將子類對象引用賦值給超類對象引用變量(向上轉型)來實現動態方法調用

17:java中靜態成員的特點
類的靜態成員是通過static修飾的成員,主要有:靜態成員變量、靜態方法、靜態代碼塊;它們具有如下特點:
① 在類加載的時候,就進行創建、初始化或執行代碼
② 對於一個類來說,都只有一份
③ 類的所有實例都能訪問到它們

18:子類調用父類的構造函數
super([args])必須放在子類構造函數的第一行

19:抽象類和接口的區別
① 接口中的方法都是抽象方法,不必寫abstract
② 接口中的屬性爲static final 靜態不可修改的常量
③ 最大區別是一個類可以實現多個接口,但只能繼承一個抽象類
④ 抽象類中可以有非抽象方法
面向功能用接口,面向繼承用抽象類;如果屬性得繼承用抽象類;

20:內部類
成員式:靜態內部類和成員內部類
局部式:普通局部內部類和匿名內部類

① 靜態內部類:相當於外部類的靜態成員一樣,用static修飾 ,外部類加載時內部類也隨之加載,完整類名是abc.Outter.Inner;無法訪問外部類的非靜態成員
② 成員內部類:相當於外部類的普通成員一樣,沒有用static修飾,需等外部類創建了對象以後纔會被加載到JVM中;創建成員內部類方法:
Outter o = new Outter();
Outter.Inner I = o.new Inner();
③ 局部內部類:定義在一個方法體中,它往往僅作爲方法短暫的使用,只能訪問用final
修飾的局部變量
④ 匿名內部類:也定義在方法體中,但沒有一個具體的名字
如:
Public void adc(){
new OneInterface(){//OneInterface爲一個接口名
… //直接提供具體的實現
}
}

21:int和Integer有什麼區別
int 屬於8中基本數據類型之一,4字節長度,取值範圍:-231~231-1;它保存在棧中;可以用算術運算符進行加、減…;在參數傳遞時傳遞的是它的值。
Integer是int的包裝類;保存在堆中;不可以用算術運算符進行加、減…(因此得轉爲int);在參數傳遞時傳遞的是它所代表對象的引用。

int a = 10;
Integer b = new Integer(a);//int–Integer
Integer c = Integer.valueOf(a);//int-Integer
a = b.intValue()+1;//Integer–int

22:float f = 2.3(錯) 2.3默認爲double型 float f = 2.3f或float f = (float)2.3

23:類型轉換
隱式轉換:由類型字節長度小的向類型字節長度大的轉換 如int隱式轉換爲double
或者是子類對象賦值給父類的引用
顯示轉換:與上相反
當實型向整型轉換時,會出現精度的損失,而且在進行float或double進行計算時會出現奇怪的問題,這時可以用BigDecimal類進行精確計算

24:用BigDecimal類進行精確計算
BigDecimal提供add() substract() multiply() divide()方法
如:
BigDecimal b1 = new BigDecimal(Double.toString(0.2));
BigDecimal b2 = new BigDecimal(Double.toString(0.3));
System.out.println(b1.add(b2).doubleValue());

25:JAVA不能用0代表false;也不能用非0代表true; 只能用boolean類型的true和false
因此C++中 while(1){…}在JAVA是錯的

26:JAVA中 char類型採用unicode編碼格式,用2個字節表示一個字符,範圍從0到216-1
char能存儲中文,且兼容英文字母(ASCII 0~127)

27:JAVA對象池
從JDK5.0開始,JVM啓動時會實例化9個對象池。這個對象池分別用來存儲8中基本類型的包裝類對象和String對象。主要是爲了效率問題。例子:
①String str1 = “hello”;
String str2 = “hello”;
②String str3 = new String(“hello”);
System.out.println(str1==str2);//輸出true
System.out.println(str1==str3);//輸出false

①處用字符串字面量(雙引號),JVM到String對象池中去檢查是否有一個值相同的對象,如果有就取現成的對象,如果沒有,則創建一個新的對象,並加入到對象池中;
②處直接創建新的字符串,且未加入到對象池

對象池的簡單實現:
class Dog{
private String name;
private int age;
private static HashSetpool = new HashSet();
public static Dog newInstance(String name,int age){
for(Dog dog:pool){
if(dog.name.equals(name)&&dog.age==age)
return dog;
}
//如果對象池中沒有,創建並加入對象池
Dog dog = new Dog(String,name);
pool.add(dog);
return dog;
}

28:StringBuffer和StringBuilder
Java字符串String對象有個特性—不變性,它只能被創建,而不能被修改(只要一改變就新創建一個對象);因此,一些大量使用字符串的程序(如字符串拼接)可能會出現性能瓶頸,甚至內存溢出;這時需要用到StringBuffer或StringBuilder,兩者API相似,但StringBuilder能保證線程安全。
簡單示例:
StringBuffer sb = new StringBuffer();
sb.append(“a”);
String str = sb.toString();

29:如何輸出反轉過後的字符串
方法1:利用字符串存儲字符的原理,取出它的char數組,進行重新排列;
方法2:利用StringBuffer的reverse()方法

30:JAVA數組本質上是一個類,該類保存了數據類型的信息。通過成員變量的形式來保存數據,並且通過[],使用下標來訪問這些數據。將基本數據類型初始爲各自默認的初始值,如將int初始爲0(若程序員未提供初始值),將引用數據類型初始爲null

31:集合
List: 有序,允許重複
Set: 無序,不允許重複
SortedSet: 排好序的Set
Map: 鍵值對 鍵不可重複
SortedMap: 排好序的Map(根據key排序);

List和Set是Collection的子類

32:迭代器
提供一種訪問一個集合對象中各個元素的途徑,同時又不需要暴露該對象的內部細節。JAVA通過提供Iterable和Iterator兩個接口來實現集合類的可迭代性。從JAVA5.0開始,迭代器可以被foreach循環所替代,但是foreach循環的本質就是使用Iterator進行遍歷的。

33:比較器
方法1:要比較的自定義類實現Comparable接口,實現其compareTo(Object o)方法
方法2:定義比較器,實現Comparator接口,實現compare(Object o1,Object o2)方法
String類實現了Comparable,用方法1實現了比較
Collections.sort(Collections c,Comparator com)//這時用方法2定義比較器傳入sort方法
Collections.sort(Collections c)//這時用方法1

示例1:
public class Person {
private String name;
private int age;
public Person(String name,int age){
this.name = name;
this.age = age;
}
………setters and getters…
}

public class CompareByName implements Comparator{
public int compare(Object o1, Object o2) {
Person p1=null;
Person p2=null;
if(o1 instanceof Person&&o2 instanceof Person){
p1 = (Person)o1;
p2 = (Person)o2;
}

/*
    if(p1.getName().compareToIgnoreCase(p2.getName())>0){
        return 1;
    }
    if(p1.getName().compareToIgnoreCase(p2.getName())<0){
        return -1;
    }
    return 0;*/
    return (p1.getName()).compareTo(p2.getName());

}

public class DemoPerson {
public static void main(String[] args) {
Person p1 = new Person(“c”,24);
Person p2 = new Person(“b”,8);
Person p3 = new Person(“a”,34);

    List<Person> list = new ArrayList<Person>();
    list.add(p1);
    list.add(p2);
    list.add(p3);

    //未排序之前
    for(Person p:list){
        System.out.println(p.getName()+":"+p.getAge());
    }

    //按年齡排序之後
    System.out.println("按年齡排序之後");
    Collections.sort(list,new CompareByAge());
    for(Person p:list){
        System.out.println(p.getName()+":"+p.getAge());
    }
}

示例2:
public class Dog implements Comparable{
private String name;
private int age;
public Dog(String name,int age){
this.name = name;
this.age = age;
}
//實現Comparable接口的方法
public int compareTo(Object o) {//參數必須是Object
Dog d = null;
if(o instanceof Dog){
d = (Dog)o;
}

    if(this.getAge()>d.getAge()){
        return 1;
    }

    if(this.getAge()<d.getAge()){
        return -1;
    }
    return 0;

}

}

public class DemoDog {
public static void main(String[] args) {
Dog d1 = new Dog(“c”,24);
Dog d2 = new Dog(“b”,8);
Dog d3 = new Dog(“a”,34);

    List<Dog> list = new ArrayList<Dog>();
    list.add(d1);
    list.add(d2);
    list.add(d3);

    //未排序之前
    for(Dog d:list){
        System.out.println(d.getName()+":"+d.getAge());
    }

    //按年齡排序之後
    System.out.println("按年齡排序之後");
    Collections.sort(list);
    for(Dog d:list){
        System.out.println(d.getName()+":"+d.getAge());
    }
}

}

34:Vector和ArrayList
Verctor的大多數成員方法都會加上synchronized關鍵字,也就是說Vector是線程安全的;也正因如此,它的執行效率沒ArrayList高;通常建議使用ArrayList

35:HashTable和HashMap的區別
① HashTable是線程安全的,HashMap不是
② HashTable不允許null值(key和value都不可以),HashMap可以
③ HashTable有個contains()方法,功能和HashMap的containsValue()一樣
④ HashTable使用Enumeration遍歷,HashMap使用Iterator

36:符合什麼條件的數據集合可以使用foreach循環
從JDK5開始可以使用foreach代替迭代器,從語法上講,數組或者實現了Iterable接口的類實例,都可以用foreach循環。

實例1:(迭代器模式方法)
public class Person {
private String name;
private int age;
public Person(String name,int age){
this.name = name;
this.age = age;
}
………setters and getters…
}

public class Persons implements Iterable{
Listpersonlist = new ArrayList();
//實現Iterable的方法
public Iterator iterator() {
PersonIterate pt = new PersonIterate();
pt.setPersonList(personlist);
return pt;

}

public void add(Person p){
    personlist.add(p);
}

}
public class PersonIterate implements Iterator{
Listpersonlist = new ArrayList();
private int index = 0;

public void setPersonList(List<Person>personlist){
    this.personlist = personlist;
}
public boolean hasNext() {
    // TODO Auto-generated method stub
    return personlist.size()>index;
}

public Person next() {
    // TODO Auto-generated method stub
    return personlist.get(index++);
    }

public void remove() {
    // TODO Auto-generated method stub
    personlist.remove(index);
}

}

這樣下面的foreach就能成功;
Persons persons = new Persons();
persons.add(new Person(“a”,1));
persons.add(new Person(“b”,2));
persons.add(new Person(“c”,3));

    for(Person p:persons){
        System.out.println(p.getName()+":"+p.getAge());
    }

實例2:(內部類方法)
public class Persons2 implements Iterable{
Listpersonlist = new ArrayList();
public void add(Person p){
personlist.add(p);
}
public Iterator iterator() {

    // TODO Auto-generated method stub
    return new Iterator<Person>(){ //用局部內部類實現
        private int index=0;
        public boolean hasNext() {
            return personlist.size()>index;//可以訪問外部類成員
        }

        public Person next() {
            return personlist.get(index++);            
        }

        public void remove() {
            personlist.remove(index);
        }      
    }; 
}

}

這樣也能進行foreach循環了

說明:Persons也可直接實現Iterator接口,並實現其hasNext(),next()等方法,但是這樣的話Persons必須維護一個索引index,其index值是不確定的,如進行循環一次,index變爲a,緊接着進行第二次循環遍歷會得到空結果;
方法1和方法2每次進行循環迭代都將產生一個新的索引爲0;

37:目錄和文件操作
Java提供了java.io.File類對目錄和文件進行操作,主要操作方法包括:路徑字符串的構造方法、isDirectory、isFile、createNewFile、list(返回文件數組)、getName、delete、getLastModify(返回最近修改時間)、listFile(返回文件名數組)等

38:隨機存取文件RandomAccessFile類
主要方法包括new RandomAccessFile(“路徑”,”rw|r|w…”);
length()方法獲得文件內容長度
seek()定位
read()獲取當前位置數據
write()寫數據
close()關閉打開的文件
示例:(將文件中所有字母a替換成c)
RandomAccessFile raf =new RandomAccessFile(“d:/1.txt”, “rw”);
int len = (int) raf.length();//length()返回long類型
for(int i=0;i

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