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

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