java面试题
1,javaSE
-
final在java种有什么作用
- 用来修饰一个引用
- 如果引用为基本数据类型,则该引用为常量,该值无法修改。
- 如果引用为引用数据类型,比如对象、数组,则该对象、数组本身可以修改,但指向该对象或数组的地址的引用不能修改。
- 如果引用时类的成员变量,则必须当场赋值,否则编译会报错。
- 用来修饰一个方法
- 当使用final修饰方法时,这个方法将成为最终方法,无法被子类重写,但是,该方法仍然可以被继承。
- 用来修饰类
- 当用final修改类时,该类成为最终类,无法被继承,比如常用的String类就是最终类。
- 用来修饰一个引用
-
==和equals的区别是什么
- 对于基本类型,==比较的是值。
- 对于引用类型,==比较的是地址。
- 如果没有重写equals,equals就相当于==。
- 如果重写了equals方法,equals比较的是对象的内容。
- equals不能用于基本类型的比较。
-
String str="i"与 String str=new String(“i”)一样吗?
- String str="i"会将起分配到常量池中,常量池中没有重复的元素,如果常量池中存中i,就将i的地址赋给变量,如果没有就创建一个再赋给变量。
- String str=new String(“i”)会将对象分配到堆中,即使内存一样,还是会重新创建一个新的对象。
-
如何将字符串反转
- 将字符串封装到stringBuilder中,调用reverse方法反转。
-
String类常用的方法有
- length:获取字符串长度;
- charAt(int index):获取指定索引位置的字符
- indexOf(int ch):返回指定字符在此字符串中第一次出现处的索引
- substring(int start):从指定位置开始截取字符串,默认到末尾
- substring(int start,int end):从指定位置开始到指定位置结束截取字符串
- equals(Object obj): 比较字符串的内容是否相同,区分大小写
- contains(String str): 判断字符串中是否包含传递进来的字符串
- startsWith(String str): 判断字符串是否以传递进来的字符串开头
- endsWith(String str): 判断字符串是否以传递进来的字符串结尾;
- isEmpty(): 判断字符串的内容是否为空串"";
- byte[] getBytes(): 把字符串转换为字节数组;
- char[] toCharArray(): 把字符串转换为字符数组;
- toLowerCase(): 把字符串转成小写;
- toUpperCase(): 把字符串转成大写;
- concat(String str): 把字符串拼接;
- concat(String str): 把字符串拼接;
-
BIO、NIO、AIO 有什么区别?
-
同步阻塞BIO
- 一个连接一个线程
- 建立网络连接的时候采用BIO模式,先在启动服务端socket,然后启动客户端socket,对服务端通信,客户端发送请求后,先判断服务端是否有线程响应,如果没有则会一直等待或者遭到拒绝请求,如果有的话会等待请求结束后才继续执行。
-
同步非阻塞NIO
-
一个请求一个线程
-
NIO主要是想解决BIO的大并发问题,BIO是每一个请求分配一个线程,当请求过多时,每个线程占用一定的内存空间,服务器瘫痪了
-
-
异步非阻塞AIO
- 一个有效请求一个线程
-
-
什么是反射
-
所谓反射,是java在运行时进行自我观察的能力,通过class、constructor、field、method四个方法获取一个类的各个组成部分。
在Java运行时环境中,对任意一个类,可以知道类有哪些属性和方法。这种动态获取类的信息以及动态调用对象的方法的功能来自于反射机制。
-
-
88
-
为什么要使用克隆?如何实现对象克隆?深拷贝和浅拷贝区别是什么?
- 什么要使用克隆?
- 想对一个对象进行复制,又想保留原有的对象进行接下来的操作,这个时候就需要克隆了。
- 如何实现对象克隆?
- 实现Cloneable接口,重写clone方法;
- 实现Serializable接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深克隆。
- 深拷贝和浅拷贝区别是什么?
- 浅拷贝:仅仅克隆基本类型变量,不克隆引用类型变量;
- 深克隆:既克隆基本类型变量,又克隆引用类型变量;
- 什么要使用克隆?
-
throw 和 throws 的区别?
- throw:作用在方法内,表示抛出具体异常,由方法体内的语句处理,一定抛出了异常;
- 作用在方法的声明上,表示抛出异常,由调用者来进行异常处理;可能出现异常,不一定会发生异常;
-
final、finally、finalize 有什么区别?
- final可以修饰类,变量,方法,修饰的类不能被继承,修饰的变量不能重新赋值,修饰的方法不能被重写
- finally用于抛异常,finally代码块内语句无论是否发生异常,都会在执行finally,常用于一些流的关闭。
- finalize方法用于垃圾回收
-
try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗?
- 执行的顺序如下:catch——>finally——>catch中的retrun
-
常见的异常类有哪些?
- NullPointerException:空指针异常;
- SQLException:数据库相关的异常;
- IndexOutOfBoundsException:数组下角标越界异常;
- FileNotFoundException:打开文件失败时抛出;
- IOException:当发生某种IO异常时抛出;
- ClassCastException:当试图将对象强制转换为不是实例的子类时,抛出此异常;
- NoSuchMethodException:无法找到某一方法时,抛出;
- ArrayStoreException:试图将错误类型的对象存储到一个对象数组时抛出的异常;
- NumberFormatException:当试图将字符串转换成数字时,失败了,抛出;
- IllegalArgumentException 抛出的异常表明向方法传递了一个不合法或不正确的参数。
- ArithmeticException当出现异常的运算条件时,抛出此异常。例如,一个整数“除以零”时,抛出此类的一个实例。
-
hashcode是什么?有什么作用?
- Java中Object有一个方法:public native int hashcode();
- hashcode()方法的作用
- hashcode()方法主要配合基于散列的集合一起使用,比如HashSet、HashMap、HashTable。
- 当集合需要添加新的对象时,先调用这个对象的hashcode()方法,得到对应的hashcode值,实际上hashmap中会有一个table保存已经存进去的对象的hashcode值,如果table中没有改hashcode值,则直接存入,如果有,就调用equals方法与新元素进行比较,相同就不存了,不同就存入。
- equals和hashcode的关系
- 如果equals为true,hashcode一定相等;
- 如果equals为false,hashcode不一定不相等;
- 如果hashcode值相等,equals不一定相等;
- 如果hashcode值不等,equals一定不等;
- 重写equals方法时,一定要重写hashcode方法
- hashcode()方法主要配合基于散列的集合一起使用,比如HashSet、HashMap、HashTable。
-
java 中操作字符串都有哪些类?它们之间有什么区别?
- String
- String是不可变对象,每次对String类型的改变时都会生成一个新的对象。
- StringBuilder
- 线程不安全,效率高,多用于单线程。
- StringBuffer
- 线程安全,由于加锁的原因,效率不如StringBuilder,多用于多线程。
- String
-
在 Java 中,为什么不允许从静态方法中访问非静态变量?
- 静态变量属于类本身,在类加载的时候就会分配内存,可以通过类名直接访问;
- 非静态变量属于类的对象,只有在类的对象产生时,才会分配内存,通过类的实例去访问;
- 静态方法也属于类本身,但是此时没有类的实例,内存中没有非静态变量,所以无法调用。
-
多线程中 synchronized 锁升级的原理是什么?
- synchronized 锁升级原理:在锁对象的对象头里面有一个 threadid 字段,在第一次访问的时候 threadid 为空,jvm 让其持有偏向锁,并将 threadid 设置为其线程 id,再次进入的时候会先判断 threadid 是否与其线程 id 一致,如果一致则可以直接使用此对象,如果不一致,则升级偏向锁为轻量级锁,通过自旋循环一定次数来获取锁,执行一定次数之后,如果还没有正常获取到要使用的对象,此时就会把锁从轻量级升级为重量级锁,此过程就构成了 synchronized 锁的升级。
- 锁的升级的目的:锁升级是为了减低了锁带来的性能消耗。在 Java 6 之后优化 synchronized 的实现方式,使用了偏向锁升级为轻量级锁再升级到重量级锁的方式,从而减低了锁带来的性能消耗。
-
synchronized 和 ReentrantLock 区别是什么?
-
ReentrantLock 使用起来比较灵活,但是必须有释放锁的配合动作;
-
ReentrantLock 必须手动获取与释放锁,而 synchronized 不需要手动释放和开启锁;
-
ReentrantLock 只适用于代码块锁,而 synchronized 可以修饰类、方法、变量等。
-
二者的锁机制其实也是不一样的。ReentrantLock 底层调用的是 Unsafe 的park 方法加锁,synchronized 操作的应该是对象头中 mark word
-
AQS实现原理:AQS里维护了一个volatile int state变量(代表共享资源)和一个FIFO线程等待队列(多线程争用资源被阻塞时会进入此队列)。
这里volatile能够保证多线程下的可见性,当state=1则代表当前对象锁已经被占有,其他线程来加锁时则会失败,加锁失败的线程会被放入一个FIFO的等待队列中,线程会被UNSAFE.park()操作挂起,等待其他获取锁的线程释放锁才能够被唤醒。
-
**synchronized 实现原理:**对象被创建在堆中。并且对象在内存中的存储布局方式可以分为3块区域:对象头、实例数据、对齐填充,synchronized的对象锁,其指针指向的是一个monitor对象(由C++实现)的起始地址。每个对象实例都会有一个 monitor。其中monitor可以与对象一起创建、销毁;亦或者当线程试图获取对象锁时自动生成。
-
monitor是由ObjectMonitor实现:当多个线程同时访问一段同步代码时,会先存放到 _EntryList 集合中,接下来当线程获取到对象的monitor时,就会把_owner变量设置为当前线程。同时count变量+1。如果线程调用wait() 方法,就会释放当前持有的monitor,那么_owner变量就会被置为null,同时_count减1,并且该线程进入 WaitSet集合中,等待下一次被唤醒。
-
-
-
11