Java 面试考点总结
一、Java基础
-
请你说明String和StringBuffer的区别
可变性:
String类中使用字符数组保存字符串,private、final、char、value[],所以String对象是不可变的。StringBuffer与StringBuilder都继承自AbstractStringBuilder类,在AbstractStringBuilder中也是使用字符数组保存字符串,char[] value,这两种对象都是可变的。
线程安全:
String中的对象是不可变的,也就可以理解为常量,线程安全。
StringBuilder是非线程安全的,StringBuffer是线程安全的。
性能:
每次对String类型进行改变的时候,都会从新生成一个新的String对象。StringBuffer每次都会对StringBuffer对象本身进行操作,而不是生成新的对象并改变对象的引用。相同情况下StringBuilder相比使用StringBuffer仅能获得10%-15%左右的性能提升,但却要冒多线程不安全的风险
对于三者使用的总结:
如果要操作少量的数据用:String
单线程操作字符串缓冲区下操作大量数据:StringBuilder
多线程操作字符串缓冲区下操作大量数据:StringBuffer -
请你说明一下int和Integer有什么区别
int是基本类型儿Integer是int的包装类
-
数组(Array)和列表(ArrayList)的区别?什么时候应该用Array而不是ArrayList?
Array可以储存基本数据类型和对象,ArrayList只能储存对象。
Array是固定大小的,ArrayList大小是自动扩展的。
Array内置方法没有ArrayList多,比如addAll、iteration等方法只有ArrayList有。 -
什么是值传递和引用传递?
值传递:值的是在方法调用的时候,传递的参数是按值的拷贝传递,传递的是值的拷贝,也就是说传递后就互相不相关了。
引用传递:指的是在方法调用时,传递的参数是按引用进行传递,其实传递的引用地址,也就是变量所对应的内存空间地址。传递的是值的引用,也就是说传递前和传递后都指向同一个引用(也就是同一个空间) -
Java支持的数据类型
基本数据类型:
数值型:整型->byte、short、int、long 浮点型->float、double
字符型:char
布尔类型:boolean
引用数据类型:类(class)、接口(interface)、数组([ ]) -
为什么会出现4.0-3.6=0.40000001这种现象?
二进制小数无法精确的表达十进制小数。在进行十进制小数的计算中需要酱十进制转化为二进制,这中间出现了错误。 -
Java8的新特性,请简单介绍一下
Lambda表达式、方法引用、默认方法、新工具、Stream API、Date Time API、Option类、Nashorn,JavaScript引擎 -
说明一下符号"==" 比较的是什么
==:在比较类型为数基本数据类型时,是比较值,引用数据类型==比较的是内存的地址 -
Object若不重写hashCode()的话,hashCode()如何计算出来?
hashCode的默认行为是对堆上的对象产生独特值。 -
为什么重写equals还要重写hashcode?
因为如果不重写hashCode的话,是根据相应对象的JVM内存地址进行计算,如果没有重写那么无论如何都是不可能相等的。 -
若对一个类不重写,它的equals()方法是如何比较的
类没有覆盖equals()方法。则通过equals()比较该类的两个对象时,等价于通过"=="比较这两个对象。
二、 关键字
-
Java里面的final关键字怎么用的?
用于修饰类、属性和方法:- 被final修饰的类不可被继承
- 被final修饰的方法不可以被重写
- 被final修饰的变量不可被改变,被final修饰不可变的是变量的引用,而不是引用指向的内容,引用指向的内容是可以改变的。
-
谈谈synchronized和lock
- 首先synchronized是Java的内置关键字,在JVM层面lock是Java的一个类;
- synchronized只能给类、方法、代码块加锁,而lock只能给代码块加锁;
- synchronized不需要手动获取锁和释放锁使用简单,发生异常会自动释放锁,不会造成死锁;lock需要自己手动加锁,释放锁,如果操作不当没有unLock()去释放锁,那么就会造成死锁
- 通过lock可以知道有没有成功获取锁,而synchronized无法办到。
-
请介绍一下volatile
对于可见性,Java 提供了 volatile 关键字来保证可见性和禁止指令重排。 volatile 提供 happens-before 的保证,确保一个线程的修改能对其他线程是可见的。当一个共享变量被 volatile 修饰时,它会保证修改的值会立即被更新到主存,当有其他线程需要读取时,它会去内存中读取新值。 -
请介绍一下Synchronized锁,如果用这个关键字修饰一个静态方法,锁住了什么?如果修饰成员方法,锁住了什么?
修饰静态方法: 也就是给当前类加锁,会作用于类的所有对象实例,因为静态成员不属于任何一个实例对象,是类成员( static 表明这是该类的一个静态资源,不管new了多少个对象,只有一份)。所以如果一个线程A调用一个实例对象的非静态 synchronized 方法,而线程B需要调用这个实例对象所属类的静态 synchronized 方法,是允许的,不会发生互斥现象,因为访问静态 synchronized 方法占用的锁是当前类的锁,而访问非静态 synchronized 方法占用的锁是当前实例对象锁。
修饰成员方法:作用于当前对象实例加锁,进入同步代码前要获得当前对象实例的锁
三、面相对象
-
Java中的方法重写(Override)和方法重载(Overload)是什么意思?
方法重载(Overload):发生在同一个类,方法名相同,参数列表不同(参数类型不同、个数不同、顺序不同),与方法返回值和访问修饰符无关,即重载的方法不同根据返回类型来区分。
方法重写(Override):发生在父子类中,方法名、参数列表、必须相同,返回值小于等于父类,抛出的异常小于等于父类,访问修饰符大于等于父类 (里氏替换原则);如果父类方法访问修饰符为private则子类中就不是重写。 -
如何通过反射获取和设置对象私有字段的值?
可以通过类对象的getDeclaredField()方法字段(Field)对象,然后再通过字段对象的setAccessible(true)将其设置为可以访问,接下来就可以通过get/set方法来获取/设置字段的值了。 -
请说明内部类可以引用它包含类的成员吗,如果可以,有没有什么限制吗?
完全可以,如果不是静态内部类,那没有什么限制! 如果你把静态嵌套类当作内部类的一种特例,那在这种情况下不可以访问外部类的普通 成员变 量,而只能访问外部类中的静态成员 -
当一个对象被当作参数传递给一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?
是值传递,Java语言的方法调用只支持值传递。当一个对象实例作为一个参数被传递到方法中时,参数的值就是对该对象的引用,对象的属性可以在被调用过程中被改变,但对对象引用的改变是不会影响到调用者的。 -
什么是泛型?
泛型,即“参数化类型”。就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数类型
-
解释一下类加载机制,双亲委派模型,好处是什么?
虚拟机把描述类的数据从class文件加载到内存,并对数据进行校验,解析和初始化最终形成可以被虚拟机直接使用的Java类型。
双亲委派模型:首先如果一个类加载器收到了类加载请求,他首先不会自己去加载这个类,而是把这个请求委派给父类加载器去完成,每一层的类加载器都是如此,这样所有的请求都会被传送到顶层的启动类加载器中,只有当父加载无法完成加载请求的时候,子加载器才会去尝试去加载类。 -
“static”关键字是什么意思?Java中是否可以重写(Override)一个private或者static方法
主要意义是在于创建独立于具体对象的域变量或方法,也就是说,即使没有创建对象,也能使用属性和调用方法。
Java中不可以Override一个private或者static方法 -
列举你知道的Object类的方法并简要说明。
Clone():创建并返回对象的副本。
getClass():返回一个运行时的类。
toString():返回该对象的字符串表示。
finalize():用于释放资源,该方法一般由垃圾回收器来调用。
equals()
hashCode()
wait():wait是Object方法,而sleep是Thread的方法。
notify():唤醒在该对象等待的某个线程。
notifyAll():唤醒在该对象的全部线程。