Java 面试总结
-
Java 语言有什么特点?
简单性、面向对象、分布性、编译和解释性、稳健性、安全性、可移植性、高性能、多线索性、动态性。
-
面向对象三大特征
封装、继承、多态
-
Java 和 C++ 的区别?
Java是解释型语言。
C++是编译型语言
C++比Java执行速度快,但是Java可以利用JVM跨平台。
Java是纯面向对象的语言,所有代码(包括函数、变量)都必须在类中定义。而C++中还有面向过程的东西,比如是全局变量和全局函数。
C++中有指针,Java中没有,但是有引用。
C++支持多继承,Java中类都是单继承的。但是继承都有传递性,同时Java中的接口是多继承,类对接口的实现也是多实现。
C++中,开发需要自己去管理内存,但是Java中JVM有自己的GC机制,虽然有自己的GC机制,但是也会出现OOM和内存泄漏的问题。C++中有析构函数,Java中Object的finalize方法。
C++运算符可以重载,但是Java中不可以。同时C++中支持强制自动转型,Java中不行,会出现ClassCastException(类型不匹配)
-
import java 和 javax 有什么区别?
java和javax都是Java的API包,java是核心包,javax的x是extension的意思,也就是扩展包。java类库是java发布之初就确定了的基础库,而javax类库则是在上面增加的一层东西,就是为了保持版本兼容要保存原来的,但有些东西有了更好的解决方案,所以,就加上些,典型的就是awt(Abstract Windowing ToolKit) 和swing
-
JVM、JDK、JRE 区别?
JVM :英文名称(Java Virtual Machine),就是我们耳熟能详的 Java 虚拟机。它只认识 xxx.class 这种类型的文件,它能够将 class 文件中的字节码指令进行识别并调用操作系统向上的 API 完成动作。所以说,jvm 是 Java 能够跨平台的核心,不同系统有不同的JVM实现
JRE :英文名称(Java Runtime Environment),我们叫它:Java 运行时环境。它主要包含两个部分,jvm 的标准实现和 Java 的一些基本类库。它相对于 jvm 来说,多出来的是一部分的 Java 类库。
JDK :英文名称(Java Development Kit),Java 开发工具包。jdk 是整个 Java 开发的核心,它集成了 jre 和一些好用的小工具。例如:javac.exe,java.exe,jar.exe 等。
这三者的关系是:一层层的嵌套关系。JDK>JRE>JVM。
-
Java 语言是编译与解释并存?
从java源程序到执行的过程可以看见,这个过程即有了编译步骤也有解释步骤。但是本质上来讲,编译的最终结果也只是.class文件,不是机器码,最终还是需要JVM来统一解释,所以更多的应该将java视为解释性语言。
由于解释性语言性能比较低,后来java引入了JIT编译,某些被频繁执行的方法或者代码块,会被JVM认定为“热点代码”。在运行时JVM会把这些热点代码编译成与本地平台相关的机器码,并且进行各种层次的优化,以提高执行效率。 -
String s = new String("xyz");创建了几个字符串对象?
1.如果String常理池中,已经创建"xyz",则不会继续创建,此时只创建了一个对象new String("xyz");
2.如果String常理池中,没有创建"xyz",则会创建两个对象,一个对象的值是"xyz",一个对象new String("xyz")。 -
是否可以继承 String 类?
不可以,String类是一个最终类,被final修饰,所以不能被继承
-
float f=3.4;是否正确?
不正确。3.4是双精度数,将双精度型(double)赋值给浮点型(float)属于下转型(down-casting,也称为窄化)会造成精度损失,因此需要强制类型转换float f =(float)3.4; 或者写成float f =3.4F;。没小数点的默认是int,有小数点的默认是 double;
-
short s1 = 1; s1 = s1 + 1;有错吗?short s1 = 1; s1 += 1;有错吗?
short s1 = 1; s1 = s1 + 1;有错吗?short s1 = 1; s1 += 1;有错吗?
答:对于short s1 = 1; s1 = s1 + 1;由于1是int类型,因此s1+1运算结果也是int 型,需要强制转换类型才能赋值给short型。而short s1 = 1; s1 += 1;可以正确编译,因为s1+= 1;相当于s1 = (short)(s1 + 1);其中有隐含的强制类型转换。
-
int 和 Interger 区别?
1、Integer是int的包装类,int则是java的一种基本数据类型
2、Integer变量必须实例化后才能使用,而int变量不需要
3、Integer实际是对象的引用,当new一个Integer时,实际上是生成一个指针指向此对象;而int则是直接存储数据值
4、Integer的默认值是null,int的默认值是0 -
new Integer(120) 与 Integer.valueOf(120) 有何区别?
Integer a=new Integer(100); Integer b=new Integer(100); Integer c=Integer.valueOf(100); Integer d=Integer.valueOf(100); System.out.println(a==b); //false System.out.println(c==d); //ture
a,b只是储存了一个地址,100在堆中的储存地址,因此a,b进行比较输出结果肯定为false。
c,d中储存的是通过Interger.valueOf隐式加包后的100,c,d中储存的类型相同值也相同两者进行比较输出结果肯定为ture -
&和&&的区别?
&是一个位运算符。
&&是一个逻辑运算符。
&是将两个二进制的数逐位相与,结果是相遇之后的结果。
&&就是判断两个表达式的真假性,只有两个表达式同时为真才为真,有一个为假则为假,具有短路性质。
-
Math.round(11.5) 等于多少?Math.round(-11.5)等于多少?
round()方法可以这样理解:
将括号内的数+0.5之后,向下取值,
比如:round(3.4)就是3.4+0.5=3.9,向下取值是3,所以round(3.4)=3;
round(-10.5)就是-10.5+0.5=-10,向下取值就是-10,所以round(-10.5)=-10
所以,Math.round(11.5)=12;
-
switch 是否能作用在 byte 上,是否能作用在 long 上,是否能作用在String上?
switch 只能是int 或 能转成int的 byte ,short ,char 。jdk 1.7 之后,string也可以。
在 switch (ecpr1)中,expr1 只能是一个整数表达式或者枚举常量,整数表达式可以是int 或 Integer 包装类型,由于 ,byte,short,char 都可以隐含转成 int ,所以这些类型以及它们的包装都可以作用在switch上。
显然,long 和 string 类型都不符合switch 的语法规定,并且不能被隐式转成int类型,所以它们不能作用于switch上。
另外 JDK1.7 中引入新特性,switch可以接收string类型的值,所以string自然也就可以作用在switch上。 -
用最有效率的方法计算2乘以8
2 << 3,
因为将一个数左移n 位,就相当于乘以了2 的n 次方,那么,一个数乘以8 只要将其左移3 位
即可,而位运算cpu 直接支持的,效率最高,所以,2 乘以8 等於几的最效率的方法是2 << 3 -
数组有没有 length() 方法?String 有没有 length() 方法?
数组没有 length()方法,有 length 的属性。
String 有 length()方法。
-
在Java中如何跳出当前的多重嵌套循环?
在Java中,要想跳出多重循环,可以在外面的循环语句前定义一个标号,
然后在里层循环体的代码中使用带有标号的break语句,即可跳出外层循环 -
构造器(constructor)是否可被重写(override)?
构造器不能被继承,因此不能被重写,但可以被重载。
-
两个对象值相同 x.equals(y) == true,但却可有不同的 hashcode,对不对?
不对,如果两个对象x 和 y 满足 x.equals(y) == true,它们的哈希码(hashCode)应当相同。
Java 对于eqauls 方法和 hashCode 方法是这样规定的:
(1)如果两个对象相同(equals 方法返回 true),那么它们的hashCode 值一定要相同;
(2)如果两个对象的 hashCode 相同,它们并不一定相同。 -
当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?(Java 没有引用传递,只有值传递)
答:是值传递。Java编程语言只有值传递参数。当一个对象实例作为一个参数被传递到方法中时,参数的值就是该对象的引用一个副本。指向同一个对象,对象的内容可以在被调用的方法中改变,但对象的引用(不是引用的副本)是永远不会改变的。
-
String 和 StringBuilder、StringBuffer的区别?
StringBuffer、StringBuilder和String一样,也用来代表字符串。String类是不可变类,任何对String的改变都 会引发新的String对象的生成;StringBuffer则是可变类,任何对它所指代的字符串的改变都不会产生新的对象。既然可变和不可变都有了,为何还有一个StringBuilder呢?相信初期的你,在进行append时,一般都会选择StringBuffer吧!
如果我们的程序是在单线程下运行,或者是不必考虑到线程同步问题,我们应该优先使用StringBuilder类;如果要保证线程安全,自然是StringBuffer。
-
重载(Overload)和重写(Override)的区别,重载的方法能否根据返回类型进行区分?
方法的重载和重写都是实现多态的方式,区别在于前者实现的是编译时的多态性,而后者实现的是运行时的多态性。重载发生在一个类中,同名的方法如果有不同的参数列表(参数类型不同、参数个数不同或者二者都不同)则视为重载;重写发生在子类与父类之间,重写要求子类被重写方法与父类被重写方法有相同的返回类型,比父类被重写方法更好访问,不能比父类被重写方法声明更多的异常(里氏代换原则)。重载对返回类型没有特殊的要求。
抽象类(abstract class)和接口(interface)有什么异同?
相同点:
都不能被实例化
接口的实现类或者抽象类的子类都必须实现了接口或抽象类中的方法后才可以被实例化
不同点:
接口只有定义,方法不能在接口中实现,实现接口的类要实现接口中所有的方法;抽象类可以有定义与实现,方法可以在抽象类中实现
接口要实现,抽象类要继承,一个类可以实现多个接口,但只能继承一个抽象类
接口强调设计理念为“has -a”的关系,抽象类强调“is -a”关系
接口中定义变量默认为public static final,且要赋初值,方法必须是public,static,且只能是这两个;抽象类中可以有自己的数据成员变量,也可以有非抽象的成员方法,而且成员变量默认为default。这些成员变量可以在子类中被重新定义,也可以重新赋值,抽象方法(有abstract修饰)不能用peivate,static,synchronized,native等访问修饰符修饰,同时方法以分号结尾,并且不带花括号
接口被运用于比较常用的功能,便于日后的维护或者添加删除方法;而抽象类更倾向于充当公共类的角色,不适用于对里面的代码进行修改
接口是一种特殊形式的抽象类,使用接口完全有可能实现与抽象类相同的操作。当子类和父类之间存在有逻辑上的层次结构时,推荐使用抽象类;当用于不同类之间,定义不同类之间的通信规则,希望支持差别较大的两个或者更多对象之间的特定交互行为时,应该使用接口。
此外,接口可以继承接口,抽象类可以实现接口,抽象类也可以继承具体类。抽象类也可以有静态的main方法。
-
char 型变量中能不能存贮一个中文汉字,为什么?
char 型变量是用来存储 Unicode 编码的字符的,unicode 编码字符集中包含了汉字,所以,
char 型变量中当然可以存储汉字啦。不过,如果某个特殊的汉字没有被包含在 unicode 编
码字符集中,那么,这个 char 型变量中就不能存储这个特殊汉字。 -
静态嵌套类(Static Nested Class)和内部类(Inner Class)的不同?
Static Nested Class是被声明为静态(static)的内部类,它可以不依赖于外部类实例被实例化。而通常的内部类需要在外部类实例化后才能实例化,其语法看起来挺诡异的,
-
抽象的(abstract)方法是否可同时是静态的(static),是否可同时是本地方法(native),是否可同时被 synchronized 修饰?
1、abstract与static
abstract:用来声明抽象方法,抽象方法没有方法体,不能被直接调用,必须在子类overriding后才能使用。
static:用来声明静态方法,静态方法可以被类及其对象调用。
static与abstract不能同时使用。
用static声明方法表明这个方法在不生成类的实例时可直接被类调用,而abstract方法不能被调用,两者矛盾。2、abstract与native
native:用来声明本地方法,该方法的实现由非java 语言实现,比如C。一般用于java与外环境交互,或与操作系统交互。
native可以与所有其它的java 标识符连用,但是abstract除外。
因为 native 暗示这些方法是有实现体的,只不过这些实现体是非java 的,但是abstract却显然的指明这些方法无实现体。3、abstract与synchronized
synchronized:用于防止多个线程同时调用一个对象的该方法,与static连用可防止多个线程同时调用一个类的该方法。
abstract与synchronized不能同时使用
从synchronized的功能也可以看出,用synchronized的前提是该方法可以被直接调用,显然和abstract连用。 -
一个类中静态(static)方法是否可以调用非静态(non-static)方法?
不可以,静态方法只能访问静态成员,因为非静态方法的调用要先创建对象,在调用静态方法时可能对象并没有被初始化
-
如何实现对象克隆?
实现 Cloneable 接口并重写 Object 类中的 clone() 方法。
实现 Serializable 接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆。
-
为什么要使用克隆?
克隆的对象可能包含一些已经修改过的属性,而 new 出来的对象的属性都还是初始化时候的值,所以当需要一个新的对象来保存当前对象的“状态”就靠克隆方法了。 -
Java 中的 final 关键字有哪些用法?
- 用来修饰数据,包括成员变量和局部变量,该变量只能被赋值一次且它的值无法被改变。对于成员变量来讲,我们必须在声明时或者构造方法中对它赋值;
- 用来修饰方法参数,表示在变量的生存期中它的值不能被改变;
- 修饰方法,表示该方法无法被重写;
- 修饰类,表示该类无法被继承
- try{}里有一个return语句,那么紧跟在这个try后的finally{}里的代码会不会被执行,什么时候被执行,在return前还是后?
①、如果finally中也有return,则会直接返回并终止程序,函数栈中的return不会被完成!;
②、如果finally中没有return,则在执行完finally中的代码之后,会将函数栈中的try中的return的内容返回并终止程序;
-
阐述 final、finally、finalize 的区别?
final :
修饰符(关键字) 如果一个类被声明为final,意味着它不能再派生新的子类,不能作为父类被继承。因此一个类不能及被声明为abstract,又被声明为final的。
将变量或方法声明为final,可以保证他们使用中不被改变。被声明为final的变量必须在声明时给定初值,而以后的引用中只能读取,不可修改,被声明为final的方法也同样只能使用,不能重载。
finally:
在异常处理时提供finally块来执行清楚操作。如果抛出一个异常,那么相匹配的catch语句就会执行,然后控制就会进入finally块,如果有的话。
finalize:
是方法名。java技术允许使用finalize()方法在垃圾收集器将对象从内存中清除之前做必要的清理工作。这个方法是在垃圾收集器在确定了,被清理对象没有被引用的情况下调用的。
-
Collection和Collections的区别?
-
Collection,是单列集合的接口,有子接口List和Set
-
Collections,是针对集合操作的工具类,其中包含对集合进行排序和二分查找的方法
public static
void sort (List list):排序,默认情况下是自然排序 public static
int binarySearch (List<?> list, T key):二分查找 public static
T max (Collection<?> coll):最大值(最小值类似用法) public static void reverse (List<?> list) :顺序反转
public static void shuffle (List<?> list):随机置换
-
-
字符型常量和字符串常量的区别?
- 形式上: 字符常量是单引号引起的一个字符; 字符串常量是双引号引起的若干个字符
- 含义上: 字符常量相当于一个整型值( ASCII 值),可以参加表达式运算; 字符串常量代表一个地址值(该字符串在内存中存放位置)
- 占内存大小 字符常量只占2个字节; 字符串常量占若干个字节(至少一个字符结束标志) (注意: char在Java中占两个字节)
-
Java 基本类型占用内存大小?
一个byte是8位。
在Java中,一个字符是2个byte字节,一个byte等于8 bit。在Java中,boolean被当成int处理,所以4个字节。
二、一个空对象占用多少个字节?
对于32位的JDK:
new一个Object对象占用4+8=12字节,其中,4个字节是引用,8个字节是堆内存。
- 对于64位的JDK:
new一个Object对象占用8+16=24字节。其中,8个字节是引用,16个字节是堆内存。
在Hotspot中,每个对象占用的总空间是以8的倍数计算的,对象占用总空间(对象头+声明变量)不足8的倍数时候,自动补齐。而,这些被填充的空间,我们可以称它为“填充物”。
- == 和 equals 区别?
- Object类中的equals方法和是一样的,没有区别,即俩个对象的比较是比较他们的栈内存中存储的内存地址。而String类,Integer类等等一些类,是重写了equals方法,才使得equals和“==不同”,他们比较的是值是不是相等。
-
在 Java 中定义一个不做事且没有参数的构造方法的作用?
Java程序在执行子类的构造方法之前,如果没有用super()来调用父类特定的构造方法,则会调用父类中“没有参数的构造方法”。因此,如果父类中只定义了有参数的构造方法,而在子类的构造方法中又没有用super()来调用父类中特定的构造方法,则编译时将发生错误,因为Java程序在父类中找不到没有参数的构造方法可供执行。解决办法是在父类里加上一个不做事且没有参数的构造方法。
-
对象的相等与指向他们的引用相等,两者有什么不同?
对象相等表示2个是同一对象,即同一快内存,而引用相等,只是2个引用的地址值相等,都指向的堆上对象的地址
-
Object 类常见的方法?
一.toString()方法
object 默认方法 toString方法,toString() 输出一个对象的地址字符串(哈希code码)!
2.可以通过重写toString方法,获取对象的属性! 快捷键 alt+shift+s创建Override toString()
二.Object类中的equals()方法
Object类equals()比较的是对象的引用是否指向同一块内存地址!
重写equals()方法比较俩对象的属性值是否相同
Object()
默认构造方法
clone()
创建并返回此对象的一个副本。
finalize()
当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。
getClass()
返回一个对象的运行时类。
hashCode()
返回该对象的哈希码值。
为什么wait notify会放在Object里边?
wait(),notify(),notifyAll()用来操作线程为什么定义在Object类中?
1、这些方法存在于同步中;
2、使用这些方法必须标识同步所属的锁;
3、锁可以是任意对象,所以任意对象调用方法一定定义在Object类中。
wait(),sleep()区别?
wait():释放资源,释放锁
sleep():释放资源,不释放锁notify()
唤醒在此对象监视器上等待的单个线程。
notifyAll()
唤醒在此对象监视器上等待的所有线程。
wait()
导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法。
wait(long timeout)
导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量。
wait(long timeout, int nanos)
导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量 -
Java 序列化中如果有些字段不想进行序列化,如何做?
对于不想进行序列化的变量,使用 transient 关键字修饰。
transient 关键字的作用是:阻止实例中那些用此关键字修饰的的变量序列化;当对象被反序列化时,被 transient 修饰的变量值不会被持久化和恢复。transient 只能修饰变量,不能修饰类和方法。
-
成员变量与局部变量区别?
1、在类中的位置不同
成员变量:在类中方法外面
局部变量:在方法或者代码块中,或者方法的声明上(即在参数列表中)
2、在内存中的位置不同,可以看看Java程序内存的简单分析
成员变量:在堆中(方法区中的静态区)
局部变量:在栈中
3、生命周期不同
成员变量:随着对象的创建而存在,随着对象的消失而消失
局部变量:随着方法的调用或者代码块的执行而存在,随着方法的调用完毕或者代码块的执行完毕而消失
4、初始值
成员变量:有默认初始值
局部变量:没有默认初始值,使用之前需要赋值,否则编译器会报错(The local variable xxx may not have been initialized)
-
为什么不能通过返回值类型区分重载?
在Java语言中,要重载一个方法,除了要与原方法具有相同的简单名称之外,还要求必须拥有一个与原方法不同的特征签名;
特征签名就是一个方法中各个参数在常量池中的字段符号引用的集合,也就是因为返回值不会包含在特征签名之中,因此Java语言里面是无法仅仅依靠返回值的不同来对一个已有方法进行重载。
-
BIO、NIO、AIO 区别?
BIO (Blocking I/O):同步阻塞I/O模式,数据的读取写入必须阻塞在一个线程内等待其完成。这里使用那个经典的烧开水例子,这里假设一个烧开水的场景,有一排水壶在烧开水,BIO的工作模式就是, 叫一个线程停留在一个水壶那,直到这个水壶烧开,才去处理下一个水壶。但是实际上线程在等待水壶烧开的时间段什么都没有做。
NIO (New I/O):同时支持阻塞与非阻塞模式,但这里我们以其同步非阻塞I/O模式来说明,那么什么叫做同步非阻塞?如果还拿烧开水来说,NIO的做法是叫一个线程不断的轮询每个水壶的状态,看看是否有水壶的状态发生了改变,从而进行下一步的操作。
AIO ( Asynchronous I/O):异步非阻塞I/O模型。异步非阻塞与同步非阻塞的区别在哪里?异步非阻塞无需一个线程去轮询所有IO操作的状态改变,在相应的状态改变后,系统会通知对应的线程来处理。对应到烧开水中就是,为每个水壶上面装了一个开关,水烧开之后,水壶会自动通知我水烧开了。
进程中的IO调用步骤大致可以分为以下四步:
- 进程向操作系统请求数据 ;
- 操作系统把外部数据加载到内核的缓冲区中;
- 操作系统把内核的缓冲区拷贝到进程的缓冲区 ;
- 进程获得数据完成自己的功能 ;
当操作系统在把外部数据放到进程缓冲区的这段时间(即上述的第二,三步),如果应用进程是挂起等待的,那么就是同步IO,反之,就是异步IO,也就是AIO 。
-
装箱和拆箱的原理?
简单一点说,装箱就是 自动将基本数据类型转换为包装器类型;拆箱就是 自动将包装器类型转换为基本数据类型。
在装箱的时候自动调用的是Integer的valueOf(int)方法。而在拆箱的时候自动调用的是Integer的intValue方法。
-
反射
运行期间,获取类的信息,进行一些操作。
- 运行时构造类的对象。
- 运行时获取类的成员变量和方法。
- 运行时调用对象的方法(属性)。
-
获取 Class 对象的方法?
(1)Class.forname(“全类名”);将字节码文件加载进内存,返回Class多用于配置文件,将类名定义在配置文件中,读取文件,加载类
(2)类名.class:通过类名的属性class获取多用于参数的传递
(3)对象.getClass();getClass()方法在object类中定义多用于获取对象的字节码文件 -
反射中创建对象的两种方法?
1.使用Class对象的newInstance()方法来创建对象:
获取类的Class对象(有三种方式可以获取,可以自行百度一下)
通过调用所获取到的Class对象的newInstance()来获得对象,该方法会返回一个Object类型的对象,所以还需要强转一下。2.通过Constructor类的newInstance()方法获取
获取一个类的一个Class实例
调用Class中的getConstructor()方法获得一个Constructor对象
调用Constructor的newInstance()方法获得一个类的实例 -
为什么重写 equals 时必须重写 hashCode 方法?
在每个覆盖了 equals() 方法的类中,也必须覆盖 hashCode() 方法,如果不这样做的话,就会违反 Object.hashCode 的通用的约定,从而导致该类无法结合所有基于散列的集合一起正常运作,这样的集合包括HashMap,HashSet 和 HashTable。
-
解决Hash碰撞冲突方法?
- 开放地址法
- 再哈希法
- 链地址法(拉链法)
-
深拷贝和浅拷贝?
深拷贝和浅拷贝最根本的区别在于是否真正获取一个对象的复制实体,而不是引用。
假设B复制了A,修改A的时候,看B是否发生变化:
如果B跟着也变了,说明是浅拷贝,拿人手短!(修改堆内存中的同一个值)
如果B没有改变,说明是深拷贝,自食其力!(修改堆内存中的不同的值
-
说说 Java 异常体系?
-
那些状态下 finally 不会被执行?
finally代码块并非一定执行,在不进入try代码块或者程序被中止时就不会执行。