Java29道经典面试题

1.JDK、JRE和JVM之间有什么关系?


答:JDK、JRE和JVM之间是一种包含关系,范围从大到小依次为:JDK>JRE>JVM即JDK中包含JRE,JRE中包含JVM。


2.JDK安装目录下存在两个JRE,它们的作用分别是什么?


答:两个JRE路径分别为:C:\Program Files\Java\jdk1.7.0_79\jre 和 C:\Program Files\Java\jre7。(不同的安装路径选择可能有不同)

第一个JRE是JDK自带的为其开发工具提供运行环境的JRE,在JDK中有很多用Java编写的开发工具(如javac.exe,jar.exe等),

这些工具的实现代码都放置在C:\Program Files\Java\jdk1.7.0_79\lib\tools.jar里,这些代码运行时候所需的JRE由第一个目录提供。

第二个JRE用于Java程序提供运行环境。

这两个JRE均可以作为开发时Java程序的运行环境,但是JDK自带工具只能使用第一个目录下的JRE,不能使用第二个目录下的JRE。

在计算机中至少有两个JRE,那应该使用哪一个呢?这就由java.exe负责。当使用者在命令行中输入“java 字节码文件名”命令执行某字节码文件时,

java.exe的任务就是在计算机众多的JRE中选择合适的JRE来执行字节码文件。java.exe按照以下顺序来寻找并使用JRE。

(1)自己的目录下有没有JRE目录。

(2)父目录下有没有JRE目录。

(3)查询注册表路径。


3.设置Path变量和CLASSPATH变量的作用是什么?


答:设置Path变量是为了让操作系统找到指定的命令程序;设置CLASSPATH变量是为了让Java执行环境找到指定的class文件,以及在程序中载入和引用的

其他class文件。

JDK在默认情况下,会到当前目录下(变量值用“.”表示)以及JDK的lib目录下寻找所需的class文件,因此如果Java程序放在这两个目录下,即使不设置

CLASSPATH变量执行环境也可以找到。但是如果Java程序放在其他两个目录下, 运行时则需要设置CLASSPATH变量,就像印欧设置IDE工具的时候会

用到工作空间一样。

总之,设置CLASSPATH的目的在于告诉Java执行环境在哪些目录下可以找到所需的Java程序。


4.什么是编译型语言?什么是解释型语言?Java属于编译型语言还是解释型语言?


答:编译型语言是指专门的编译器,针对特定的操作系统将源代码一次性翻译成计算机能识别的机器码。例如C、C++等。

解释型语言是指专门的解释器,将源代码按顺序地解释成特定平台下的机器码,解释一句执行一行。例如ASP、PHP等。

Java不属于编译型语言也不属于解释型语言,Java是两者的结合体。

Java源文件经过Java编译器成字节码文件,再经由Java解释器运行程序。


5.简述JVM的原理及作用。


答:JVM(Java Virtual Machine),Java虚拟机是可运行Java字节码文件的虚拟计算机,是一个模拟出来的计算机,它在真实的计算机上模拟

各种计算机功能,只是结果、功能和性能相对简单一些。麻雀虽小,五脏俱全,JVM有自身完善的架构,例如处理器、堆栈和寄存器等,还

具有相应的指令系统。

JVM屏蔽了与具体操作系统平台相关的信息,从而实现了Java程序只需生成能在JVM上运行的字节码文件,就能在多平台上不加修改的运行。

不同平台对应了不同的JVM,在执行字节码时,JVM负责将要执行的字节码传给解释器,解释器再将其翻译成特定平台环境的机器指令并执行。

Java语言之所以能够实现平台无关性,就是靠的JVM。


6.Java语言中的关键字中没有任何意义但是不能在程序中作为标识符使用的是?


答:goto、const


7.Java中浮点型强制类型转换为整数,采用的是四舍五入还是去1法?


答:“去1法”,即无条件地舍弃小数点后的所有数字,不需要进行四舍五入。


8.比较“||” 与 “|” 和 “&&” 与“&” 的异同。


答:1.“||”与“|” 和 “&&” 与“&” 均可以用于逻辑运算;“|”和“&”还可用于位运算。

2.“||” 用于逻辑运算时,当第一个表达式为真时,则不用再比较第二个表达式的值;“&&”用于逻辑运算时,表达式第一个为false时,

则不用比较第二个表达式的值;“|”用于逻辑运算时,第一个表达式为true,也要比较第二个表达式的值,“&”用于逻辑运算时,

表达式第一个为false,也要比较第二个表达式的值。

“&&”和“||”是短路运算,执行效率高,所以在程序开发中尽量使用“&&“和“||”。


9.下面两条语句中,哪个是正确的?

(1)short s=1; s=s+1;   (2) short s=1; s+=1; 


  答:(1)中s+1是int型,不能赋给short型,所以此语句错误。(2)对应s+=1;由于赋值运算符中隐含的强制类型转换,所以“+”会将结果提升为int型,

经过强制类型转换为short后赋给s。


10.Java中数组在内存中的分配情况。

答:Java把内存分为栈内存和堆内存。栈内存保存的只是数组的名称,即使用“数据类型 数组名[ ] ”就可开辟栈内存,但只开辟栈内存的数组是不能

被使用的。因为堆内存是用来存放数组的实体,若想使用数组则需要用new关键字来开辟堆内存,然后把堆内存的控制权交给相应的栈内存,

一个堆内存可以被多个栈内存引用。


11.Java中数组的初始化方式。

答:数组初始化是对数组进行赋值,数组的初始化方式可以分为两种。

1.静态初始化,即数组在定义的同时就为数组元素分配空间和赋值。静态初始化不但可以指定每一个数组元素的值,还可以指定数组的长度。

格式一:数据类型  数组名[  ] = { 元素值1,元素值2,元素值3.........元素值n} ;

格式二:数据类型  数组名[  ] = new  数据类型[ ] {元素值1,元素值2,元素值3.........元素值n} ;

2.动态初始化,即数组初始化时只需指定数组长度,由系统为这些数组元素赋初值。每个元素的取值数组数据类型对应的默认值。

格式:数据类型  数组名 [ ] = new   数据类型 [ 确定的数组长度 ] ;

注意:不可将静态初始化和动态初始化同时使用,即不要在数组初始化时,指定了数组长度的同时为每一个数组元素赋值。

如 String a[ ] = new String [ 5 ] { "aaaa" , "bbbb" , "cccc" ," dddd" ,"eeee" }   编译会报错。


12.String 字符串对象初始化方式。


答:格式一:使用直接赋值方式: String 字符串名 = "字符串内容";

格式二:使用String类的构造方法:String 字符串名 = new String ("字符串内容”);

以上两种格式生成的字符串效果是相同的,但是存储机制却存在很大的区别。

Java为String类提供了一种称为缓冲机制的功能。当使用格式一时,直接赋值生成字符串,Java编译器总是先到缓冲池去寻找是否存在相同内容的字符串。

如果存在就可以直接使用,若不存在则在缓冲池内创建一个新的字符串。一个字符串就是一个String类的匿名对象,格式一就是一个String类的匿名对象,

只需开辟一个堆内存空间。

若是使用格式二,用new关键字调用构造方法的方式,则每次调用都会生成一个新的String对象。分别需要开辟一个栈内存和一个堆内存。

格式一使用缓冲池机制执行效率高,节约内存,推荐使用。

关于字符串更多请点击:Java String 缓冲池概念


13.关于String、StringBuffer、StringBuilder。

答:简单点说,String是不可变的,StringBuffer是可变的,因此如果经常会变化字符串值推荐使用StringBuffer。

StringBuilde是JDK1.5后新增的,同StringBuffer一样是字符串变量,但是StringBuffer是线程安全的,StringBuilder不是。

如果涉及多线程同步等情况时,推荐使用StringBuffer。如果仅仅是单线程的话,用StringBuilder就可以。

详情请参考:String、StringBuffer、StringBuilder的区别


14.关于StringBuffer的容量问题。


答:capacity()方法返回的是StringBuffer变量的容量,就像一个水杯的容量一样,表示这个水杯可以装多少水。

length()方法返回的是StringBuffer变量包含的字符串长度,就像一个水杯装了多少体积的水。

在创建StringBuffer对象时,没有指定容量的大小,系统就会默认为16字符的容量。若指定了容量大小,则指定多少就是多少。

若直接用字符串创建StringBuffer变量,那容量大小为16+字符串长度。如果StringBuffer变量中修改后的字符串内容大于其容量,

则增长规律为(容量+1)*2。若按照容量增长规律后还是不够的话,那么它的容量就等于字符串的长度。


15.对象和实例的区别。

答:在Java内存分配中,足以看出对象和实例的区别。对象是保存在堆内存的,实例是保存在栈内存中的。实例其实只是对象的一个引用,

就是对象的指针,只能通过实例操作对象,并不能直接操作对象。


16.什么是匿名对象?

答:匿名对象是指没有栈空间的对象,即没有明确给出名字的对象。匿名对象使用的是堆内存,是通过关键字new进行开辟,

因为没有对应的栈空间引用,所以对象只能使用一次。

匿名对象通常使用在以下两种情况:

1、如果对一个对象只需使用一次,那么就可以使用匿名对象。若一个对象进行多个成员的调用,就必须给这个对象取个名字。

2、将匿名对象作为实际参数进行传递。

注意:匿名对象只能使用一次,使用完成后将会等待JVM垃圾收集器收集。


17.默认构造的封装。已知下面的两个类,1. class Person( )  2. public class Person( )请问它们的默认构造方法是?


答:如果一个类没有显式提供构造方法,Java将自动添加一个无参、无执行语句的“空”构造方法,称为默认构造方法。

但是并非所有的默认构造方法都是public,构造方法的修饰符与所在类的访问修饰符一致。就是说,如果类是public的,

那么它的构造方法也是public的,如果类是无访问修饰符的,那么它的默认构造方法也是没有访问修饰符的。

答案1. Person()  2. public  Person()


18.成员变量和局部变量的生命周期问题。


答:静态成员变量在类被加载时创建,其生命周期与该类的生命周期相同;

成员变量在类的实例被创建时产生,其生命周期与该类的实例对象的生命周期相同;

局部变量在定义该变量的方法被调用时创建,在方法调用结束后,该变量也被撤销。

程序中优先使用局部变量,能使用局部变量的就不要用成员变量。因为成员变量放置在堆内存中,成员变量的作用域

扩大到类存在的范围或对象存在的范围,其生命周期也会变长。这样会带来两个缺点:一是增加生命周期,系统开销

也会增加;二是扩大了作用域,不利于程序的内聚性。


19.普通代码块?构造代码块?静态代码块?

答:直接在一个方法或语句中出现的{ }就称为普通代码块。

直接在类中定义的且没有加static关键字的代码块{ }就称为构造代码块。构造块在创建对象时会被调用,每次调用对象时

都会被调用,并且构造块的执行次序优先于类构造函数。

使用static关键字声明的代码块称为静态代码块。静态块主要用于初始化类,为类的静态属性初始化。JVM在加载类的时候

会执行静态代码块,所以静态代码块先于主方法执行。每个静态代码块只执行一次。


20.怎样调用构造方法?

答:构造方法重载的目的是以不同的方式实例化对象。构造方法重载时,可以在构造方法中使用this()调用其他构造方法。

值得注意的是,使用this调用其他构造方法时,必须放在构造方法的第一行。


21.请简述对象中成员变量初始化的步骤。

答:第一:父类静态成员和静态初始化块,按在代码中出现的顺序依次执行。

第二:子类静态成员和静态初始化块,按在代码中出现的顺序依次执行。

第三:父类实例成员和实例初始化块,按在代码中出现的顺序依次执行。

第四:执行父类构造方法。

第五:子类实例成员和实例初始化块,按在代码中出现的顺序依次执行。

第六:执行子类构造方法。


22.装箱和拆箱。


答:在程序设计中,有时候需要将基本数据类型转换为对象以便操作,这就需要用到装箱和拆箱。

装箱是指把基本数据类型转变为对应的封装的过程,如将int型封装成Integer对象类型,其他基本数据类型封装成相对应的封装类。

拆箱是指把封转类转变为对应的基本数据类型的过程,如将Integer对象类型封装为int型,其他封装类也是可以封装成相对应的基本数据类型。

在Java的装箱和拆箱中可分为手动装箱与拆箱和自动装箱和拆箱。在JDK1.5前只能使用手动装箱和拆箱,但从JDK1.5后增加了自动装箱和拆箱的功能。


23.最终类可以用在哪几方面?


答:1.鉴于安全原因,类的实现行为不允许有改动。

2.不是专门为继承而设计的类,类本身的方法调用关系复杂。

3.创建设计模式时,确定该类不会再被扩展。


24.什么是匿名内部类?使用时需要注意哪些方面?


答:匿名内部类是指在定义时没有名称的内部类,必须在声明时使用new语句类声明类。

虽然匿名内部类没有类名,匿名内部类必须拓展一个基类或者一个接口。匿名内部类

不会自动继承Object类,所以每个匿名内部类都要明确的指出它继承的类或实现的接口。

匿名内部类总是使用父类的构造方法来创建实例,如果实现的是接口,那么匿名内部类的构造方法

就是Object()。在使用匿名内部类时,需要注意以下几点:

1.匿名内部类没有构造方法, 但是可以调用父类的构造方法。

2.匿名内部类可以访问外部类的所有成员,但匿名内部类定义在方法之中时,只能访问方法中的final类型的参数和局部变量。


25.Java异常处理机制。


答:异常的本质是一个程序在执行期间发生的一个事件,该事件中断了正常执行流程。在Java方法内部发生错误时,该方法会

创建一个Exception类型的对象返回给JVM,该Exception类型的对象包含异常的类型、发生异常的程序状态等异常信息,JVM

会寻找一个适合的方法类处理这个异常。例如当产生了数组越界异常时,JVM检查到数组越界时,它就会创建一个新的异常对象

实例,然后引发该异常。在有合适的捕获异常处理程序的情况下,该异常会被捕获并立即被处理。但是程序中没有任何异常处理

程序的话,该异常会被JVM的默认异常处理程序捕获。只要不是被程序员捕获的异常,最终都是被默认异常处理程序处理。

默认处理程序会打印出异常的类型和异常发生时所处的堆栈,并且立即终止运行。


26.实现同步的方法。


答:为了避免多线程在共享资源时发生冲突,所以要在线程使用该资源时,就为资源上一把“锁”。

1.同步代码块。用synchronized关键字修饰代码块。格式 synchronized ( Object  object) {  //需要同步的代码 }

object表示的是任意对象,可以是实际存在的也可以是假设的。在Java中,任意一个对象都有一个同步锁。

2.同步方法。格式:[ 访问控制符 ]  [ static | final ] synchronized返回类型 方法名(参数列表) { //需要同步的代码}

3.同步锁。同步锁是在JDK1.5之后出现的,可以通过java,util,concurrent.locks.ReettrantLock类的对象调用lock( )方法来实现加锁操作,

此时可以进行同步操作。同步操作结束后,调用unlock()方法释放同步锁。


27.Java随机数。


答:这里所谓的随机数并不是完全是随机数,而是计算机通过某种特定的概率算法生成的。

在进行随机时,随机算法的起源数字称为种子数。在种子数的基础上进行一定的变换,从而产生需要的随机数字。

两个种子数相同的Random对象,第一次生成的随机数字完全相同,第二次生成的随机数字也完全相同。


28.什么是受限泛型?如何设置其上限和下限?


答:在使用泛型类创建泛型对象,类型参数只能为某个接口(包含某个接口的实现类)或某种类型(包含某种类型的子类)时,

可以通过设置类型参数的上限来实现,即使用关键字extends对接口和类的类型进行限制。

设置类型形参的上限: 定义类:< 泛型类型标识 extends 泛型类型1 & 泛型类型2 .......>

设置类型形参的下限: <  ? super 泛型类型 >


29.Collection与Collections的区别。


答:Collection是java.util包中的接口,是集合类的基本接口,主要的子接口有List和Set。

Collections是java.util包中的类,是针对集合的一个实用工具类,它包含了对各种集合的搜索、排序和线程安全等一系列的静态方法。


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值