Java基础
- 请你谈谈StringBuffer和StringBuilder有什么区别,底层实现上呢?
- StringBuffer线程安全,StringBuilder线程不安全,底层实现上的话,StringBuffer其实就是比StringBuilder多了Synchronized修饰符。
- String str = new String(“abc”)到底创建了几个对象?
- 答:2个对象。一个对象是”abc”,另一个是指向”abc”的引用对象”s”;
- 你对String对象的intern()熟悉吗?
- 什么是不可变对象?不可变对象有什么好处?Java为什么要将String声明为final?
- 对象创建之后,值就不可改变。
- 好处?
- 常量池限制:多个字符串变量指向池中同一个。提高效率。只用复制地址。如果String不声明为不可变对象,则常量池失去意义。
- 安全性:不可变的话,账号密码这类字符串就不会被串改。
- 线程安全:保证多线程下的安全。
- hashCode固定,适合作为map的key。
- 衍生:如何改变String的final char[] value的值?
- 反射
- 衍生:String是不可变对象,而StringBuffer StringBuilder是可变对象。
- 为什么重写了equals还要重写hashcode?
- HashCode相同的对象,equals也相同吗?如何理解?
- HashCode相同,Equal不一定相同、==不一定相同
- 什么是值传递和引用传递?
- int和Integer的区别? int 和Integer谁占用的内存更多?
- Integer是int的包装类型,在拆箱和装箱中,二者自动转换。int是基本类型,直接存数值,而integer是对象,用一个引用指向这个对象。
- Integer 对象会占用更多的内存。Integer是一个对象,需要存储对象的元数据。但是 int 是一个原始类型的数据,所以占用的空间更少。
- Java中拆箱与装箱的原理?
- 自动装箱:编译器调用valueOf()将原始类型值转成对象;
- 自动拆箱:编译器通过类似intValue(),doubleValue()这些方法将对象转换成原始类型值。
- 接口和抽象类的区别?
- 继承实现。接口可以继承和多实现,抽象类只能单继承;
- 构造方法。接口没有构造方法,抽象类有;
- 变量。抽象类中的变量可以使用任何权限修饰符,接口中默认public static final;
- (静态、抽象)方法。抽象类中的方法可以不是抽象的,接口中的方法默认都是抽象的;抽象类中可以包含静态方法,接口中不能。
- jdk8。接口支持lambda表达式FunctionInterface\default修饰,抽象类不支持;
- 抽象是对类的抽象,是一种模板设计;接口是一种行为规范。
- 反射的原理是什么?
- class.forname和classloader区别?
- Class.forName()是加载类并初始化(执行static方法),但是ClassLoader的loadClass()只加载类,并不进行初始化。
- try catch finally块中return的执行顺序
- 当没有异常发生时,优先级finally>try
- 当有异常发生时,优先级finally>catch>捕获异常最外面的return
- 请说明Comparable和Comparator接口的作用以及它们的区别。
- Comparable:可以和自己比较
- Comparator:不支持和自己比较。比较的是两个相同类的实例。更加灵活。
- 快速失败(fail-fast)和安全失败(fail-safe)的区别是什么?
- Iterator的安全失败是基于对底层集合做拷贝,因此,它不受源集合上修改的影响。java.util包下面的所有的集合类都是快速失败的,而java.util.concurrent包下面的所有的类都是安全失败的。快速失败的迭代器会抛出ConcurrentModificationException异常,而安全失败的迭代器永远不会抛出这样的异常。
- 请你讲讲wait方法的底层原理?
- ObjectSynchronizer::wait方法通过object的对象中找到ObjectMonitor对象调用方法 void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) 通过ObjectMonitor::AddWaiter调用把新建立的ObjectWaiter对象放入到 _WaitSet 的队列的末尾中然后在ObjectMonitor::exit释放锁,接着 thread_ParkEvent->park 也就是wait。
- 关于 final 关键字的一些总结
主要修饰类、方法、变量
- 修饰类:不能被继承。所有成员方法都会隐式指定为final。
- 修饰方法:继承类不能修改。
- 修饰变量:对于基础数据类型,初始化之后不可修改;对于引用数据类型,初始化之后不能更改引用。
- short s1= 1; s1 = s1 + 1; 该段代码是否有错,有的话怎么改?
有错误,short类型在进行运算时会自动提升为int类型,也就是说s1+1的运算结果是int类型。
short s1= 1; s1 += 1; 该段代码是否有错,有的话怎么改?
+=操作符会自动对右边的表达式结果强转匹配左边的数据类型,所以没错。
- finalize 方法是在对象被回收之前调用的方法,给对象自己最后一个复活的机会,但是什么时候调用 finalize 没有保证
- 64位的JVM当中,int的长度是多少?
Java 中,int 类型变量的长度是一个固定值,与平台无关,都是 32 位。意思就是说,在 32 位 和 64 位 的Java 虚拟机中,int 类型的长度是相同的。
- java中int char,long各占多少字节? | 类型 | 位数 | 字节数 | | —- | —- | —- | | short | 2 | 16 | | int | 4 | 32 | | long | 8 | 64 | | float | 4 | 32 | | double | 8 | 64 | | char | 2 | 16 |
- Java的深拷贝和浅拷贝
a. 引用拷贝和对象拷贝就是浅拷贝和深拷贝吗?
— 不是。浅拷贝和深拷贝都属于对象拷贝。浅拷贝仅复制属性的引用而不复制属性引用所指的对象。深拷贝直接复制该属性指向的对象(即原对象和新对象的属性地址不同)。
b. 如何实现浅拷贝?如何实现深拷贝?
— 浅拷贝:1. 实现Cloneable接口并重写clone方法。
— 深拷贝:1. 实现Cloneable接口并重写clone方法。
1. 通过Apache Serializable序列化方式实现。SerializableUtils.clone(obj)
1. 通过Gson()/Jackson序列化实现
1. 通过构造函数
c. Objct对象的clone()方法为什么要声明为protected? —// todo
- Java中的++操作符线程安全吗?
— 线程不安全。
— 解决办法:加锁
- 什么是ThreadLocal?
为使用该变量的每个线程维护一份独立的变量副本,每个线程都可以改变自己的副本,而不影响其他线程的副本;
- Object对象有哪些方法?
- wait/notify
- public native Object clone() throws CloneNotSupportedException
- hashCode
- equals
- toString
- finialize
- getClass
- private static native void registerNatives();
- wait/notify机制
- 在wait/notify之前,为什么要先获取synchronized锁?(即 wait notify为什么必须放在同步块中?)
- 线程A获取了锁,执行wait方法挂起,线程B又如何再获取锁?
- wait/notify底层实现原理?
— 解答:
- 在wait/notify之前,为什么要先获取synchronized锁?(即 wait notify为什么必须放在同步块中?
— native wait0()的注释
意思是:线程执行lock.wait方法时,必须拥有该lock的monitor,而synchronized的字节码拥有monitorEnter、monitorExit指令,所以需要放在synchronized同步块中。
进一步说:
详解:JVM源码分析之Object.wait/notify实现
- 讲讲类的实例化顺序,比如父类静态数据,构造函数,字段,子类静态数据,构造函数,字段,当new的时候,他们的执行顺序。
IO
- Java NIO常用的三个类
- 同步IO和异步IO
- IO操作分2个步骤,请求IO和实际IO,同步IO和异步IO的主要区别是第二步是否阻塞。
- 若实际IO操作阻塞请求进程(即请求进程轮询查看IO是否就绪),则为同步IO。
- 若实际IO操作并不阻塞请求进程(即由OS进行实际IO操作并返回结果),则为异步IO。
- 阻塞IO和非阻塞IO
- 阻塞和非阻塞IO的区别在于第一步是否阻塞。
- 若发起IO请求后,请求线程一直等待时间实际IO操作完成,则为阻塞IO。
- 若发起IO请求后,请求进程返回而不等待,则为非阻塞IO。
- BIO、NIO、AIO
- BIO-同步阻塞
- NIO-同步非阻塞
- AIO-异步非阻塞
- 同步IO和异步IO
集合
- JAVA8的ConcurrentHashMap为什么放弃了分段锁,有什么问题吗,如果你来设计,你如何设计。
- HashMap为什么长度超过8会转成树结构?为什么<=6会还原成链表?
- 红黑树的平均查找长度为O(logN),长度为8是,平均查找长度为3,如果继续使用链表,则查找长度为8/2=4
- 如果长度<=6,则链表的平均查找长度为3,所以会转换成链表 - 选择6和8,中间缓冲一个7可以有效防止链表和树之间的频繁转换
- 红黑树的平均查找长度为O(logN),长度为8是,平均查找长度为3,如果继续使用链表,则查找长度为8/2=4
线程
- 线程状态有哪些? 线程池状态转换是怎么样的?
JUC
MySQL
其他
- 为什么阿里巴巴禁止把SimpleDateFormat定义为static类型的?
- 解决方案
- 加锁
- 使用JDK1.8的DateTimeFormatter
- 使用ThreadLocal
- 解决方案
- 如何防止CSRF攻击?
- Java9 深入理解模块化
- 模块化
- http2—java.net.http
- jshell
- G1设置为默认垃圾回收期,取代Parallel GC
- Java8中的函数式编程
- 接口默认方法;
- Lambda表达式;
- StreamAPI;
- Metaspace替换PermGem
- TODO
- 方便后期和Jrocket VM统一
- Java10的新特性