有价值的面试问题

有时会看到比较有趣的面试题记录在这个随笔里面

一.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
" 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循环的指针却会下移,因此会略过下一个元素,使用迭代器删除可以避免此问题






原文地址:https://www.cnblogs.com/jiuhaoyun/p/10308921.html