有价值的面试问题
有时会看到比较有趣的面试题记录在这个随笔里面
一.private修饰的方法可以通过反射访问,那么private的意义是什么?
答:简单来说,private并不是解决“安全”问题的。private想表达的不是“安全性”的意思,而是OOP的封装概念,是一种编译器可以帮助你的设计上的hint。这就像是一家没人的店挂了个牌子“闲人免进”,
但你真要进去还是有各种办法可以办到。所以private,以及所有其他的access modifier都有一层隐含的含义:如果你按照遵守这套规则,开发者可以保证不问题(不考虑bug的情况下);否则,后果自负。
二.Java类初始化顺序?
答:父类--静态变量 → 父类--静态初始化块 → 子类--静态变量 → 子类--静态初始化块 → 子类main方法 → 父类--变量 → 父类--初始化块 → 父类--构造器 →子类--变量 →子类--初始化块 → 子类--构造器
三.一个java文件有3个类,编译后有几个class文件?
答:一个Java文件有几个class编译后就会有几个class文件。 参考博客:https://blog.csdn.net/loongstyle/article/details/82875140
四.局部变量使用前需要显式地赋值,否则编译通过不了,为什么这么设计?
答:局部变量不默认赋值的原因是因为怕编码者忘记赋值,导致系统出问题。
五.写一个你认为最好的单例模式? 答: public class Singleton { private static volatile Singleton singleton; private Singleton() {} public static Singleton getInstance() { if (singleton == null) { synchronized (Singleton.class) { if (singleton == null) { singleton = new Singleton(); } } } return singleton; } }
六.写一个死锁 答: /** * 一个简单的死锁类 * 当DeadLock类的对象flag==1时(td1),先锁定o1,睡眠500毫秒 * 而td1在睡眠的时候另一个flag==0的对象(td2)线程启动,先锁定o2,睡眠500毫秒 * td1睡眠结束后需要锁定o2才能继续执行,而此时o2已被td2锁定; * td2睡眠结束后需要锁定o1才能继续执行,而此时o1已被td1锁定; * td1、td2相互等待,都需要得到对方锁定的资源才能继续执行,从而死锁。 */ public class DeadLock implements Runnable { public int flag = 1; //静态对象是类的所有对象共享的 private static Object o1 = new Object(), o2 = new Object(); @Override public void run() { System.out.println("flag=" + flag); if (flag == 1) { synchronized (o1) { try { Thread.sleep(500); } catch (Exception e) { e.printStackTrace(); } synchronized (o2) { System.out.println("1"); } } } if (flag == 0) { synchronized (o2) { try { Thread.sleep(500); } catch (Exception e) { e.printStackTrace(); } synchronized (o1) { System.out.println("0"); } } } } public static void main(String[] args) { DeadLock td1 = new DeadLock(); DeadLock td2 = new DeadLock(); td1.flag = 1; td2.flag = 0; //td1,td2都处于可执行状态,但JVM线程调度先执行哪个线程是不确定的。 //td2的run()可能在td1的run()之前运行 new Thread(td1).start(); new Thread(td2).start(); } }
七.cpu 100%怎样定位? 答: 1.先用top定位最耗cpu的java进程 例如: 12430 2.然后用top -p 12430 -H 定位到最耗cpu的线程 的ID 例如:12483 3.把第二步定位的线程ID ,转成16进制,printf "%x\n" 12483 得到 :30c3 4.从jstack 输出的线程快照中找到线程的对堆栈信息 jstack 12430 |grep 30c3 -A 60 |less
八.String a = "ab"; String b = "a" + "b"; a == b 是否相等,为什么?
答:不相等,String是引用类型,引用类型用==比较的是地址不是值。
九.可以用for循环直接删除ArrayList的特定元素吗?可能会出现什么问题?怎样解决?
答:不能,ArrayList的底层结构是数组类型,数组这种数据结构的特点是删除其中某个元素时,后面的所有元素索引都会前移,此时for循环的指针却会下移,因此会略过下一个元素,使用迭代器删除可以避免此问题