java个人收集面试题

喜夏-厌秋 提交于 2019-11-30 08:42:01

java基础

  • private修饰的方法可以通过反射访问,那么private的意义是什么?

(1).Java的private修饰符不是为了绝对安全设计的,而是对用户常规使用Java的
一种约束。就好比饭店厨房门口挂着“闲人免进”的牌子,但是你还是能够通过其他方法进去。
(2)、从外部对对象进行常规调用时,能够看到清晰的类结构

  • java类的初始化顺序?

(1)不考虑继承的情况下
写一个测试类验证:

public class LoadOrderHelp {
    static {
        System.out.println("1:静态块");
        b = 1;
        //这一句报错(Illegal forward reference ),即不能在b没有声明初始化前输出,到可以赋值。咦!
        //System.out.println(b); 
    }
    public static int b = 10;  //静态字段初始化
    static {
        System.out.println("2: 静态块 static b = " + b);
        b = 5;
    }

    private int a = 1;//非静态字段初始化
    {
        System.out.println("3:非静态块 a = " + a + " b = " + b);
    }

    {
        System.out.println("4:非静态块 a = " + a);
    }

    public LoadOrderHelp() {
        System.out.println("5:构造函数 a = " + a +" b = " + b);
    }

    public static void main(String[] args) {
        LoadOrderHelp loadOrderHelp = new LoadOrderHelp();
    }
}

测试结果如下:

1:静态块
2: 静态块 static b = 10
3:非静态块 a = 1 b = 5
4:非静态块 a = 1
5:构造函数 a = 1 b = 5

从输出结果上可以看出,静态内容>非静态内容>构造函数
分析:
静态代码块和静态字段初始化在类加载时就已经进行着,而非静态字段和代码块则是在创建类实例时初始化,而构造函数又在非静态字段和代码块之后执行,所以大致就是上面的结果。
总结:

  • 静态字段和块只会在类第一次加载时初始化
  • 在java中new一个对象时,先会在堆上为对象分配足够的内存,然后再将这部分内存清空,引用为null,然后执行构造函数。

(2)考虑有父类的情况

有人总结为:父类静态变量——父类静态代码块——子类静态代码块——父类非静态变量——父类非静态代码块——父类构造函数——子类非静态变量——子类非静态代码块——子类构造函数
总体上呈先静态后非静态,先父类后子类,构造函数最后的顺序。

  • 对方法区和永久区的理解以及它们之间的关系

(1)什么是方法区

在Java虚拟机中,方法区是可供各线程共享的运行时内存区域。

在不同的JDK版本中,方法区中存储的数据是不一样的。

在JDK1.6及之前,运行时常量池是方法区的一个部分,同时方法区里面存储了类的元数据信息、静态变量、即时编译器编译后的代码(比如spring 使用IOC或者AOP创建bean时,或者使用cglib,反射的形式动态生成class信息等)等。

在JDK1.7及以后,JVM已经将运行时常量池从方法区中移了出来,在JVM堆开辟了一块区域存放常量池。
(2)它们之间的关系
在Java虚拟机规范中,方法区在虚拟机启动的时候创建,虽然方法区是堆的逻辑组成部分,但是简单的虚拟机实现可以选择不在方法区实现垃圾回收与压缩。这个版本的虚拟机规范也不限定实现方法区的内存位置和编译代码的管理策略。所以不同的JVM厂商,针对自己的JVM可能有不同的方法区实现方式。

在HotSpot中,设计者将方法区纳入GC分代收集。HotSpot虚拟机堆内存被分为新生代和老年代,对堆内存进行分代管理,所以HotSpot虚拟机使用者更愿意将方法区称为老年代。

方法区和永久代的关系很像Java中接口和类的关系,类实现了接口,而永久代就是HotSpot虚拟机对虚拟机规范中方法区的一种实现方式。前者是 JVM 的规范,而后者则是 JVM 规范的一种实现。

  • 一个Java源程序文件中定义几个类和接口,则编译该文件后生成几个以.class为后缀的字节码文件?
    答案是正确的
    在这里插入图片描述
  • 局部变量使用前需要显式地赋值,否则编译通过不了,为什么这么设计?
    成员变量是可以不经初始化的,在类加载过程的准备阶段即可给它赋予默认值,但局部变量使用前需要显式赋予初始值,javac不是推断不出不可以这样做,而是没有这样做,对于成员变量而言,其赋值和取值访问的先后顺序具有不确定性,对于成员变量可以在一个方法调用前赋值,也可以在方法调用后进行,这是运行时发生的,编译器确定不了,交给jvm去做比较合适。而对于局部变量而言,其赋值和取值访问顺序是确定的。这样设计是一种约束,尽最大程度减少使用者犯错的可能(假使局部变量可以使用默认值,可能总会无意间忘记赋值,进而导致不可预期的情况出现)。
  • ReadWriteLock读写之间互斥吗
    一篇讲解读写锁的文章
  • 写一个单例模式
  • 单例一共有几种实现方式:饿汉、懒汉、静态内部类、枚举、双检锁,要是写了简单的懒汉式可能就会问:要是多线程情况下怎样保证线程安全呢,面试者可能说双检锁,那么聊聊为什么要两次校验,接着会问光是双检锁还会有什么问题,这时候基础好的面试者就会说了:对象在定义的时候加上volatile关键字,接下来会继续引申讨论下原子性和可见性、java内存模型、类的加载过程。

其实没有最好,枚举方式、静态内部类、双检锁都是可以的,就想听下对不同的单例写法认识程度,写个双检锁的方式吧:

为什么在同步块内还要再检验一次?因为可能会有多个线程一起进入同步块外的 if,如果在同步块内不进行二次检验的话就会生成多个实例了。

public class Singleton {
    private Singleton() {
    }

    private volatile static Singleton instance;

    public static Singleton getInstance() {
        if (null == instance) { 
            synchronized (Singleton.class) {  
                if (null == instance) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }

}

这段代码看起来很完美,很可惜,它是有问题。主要在于instance = new Singleton()这句,这并非是一个原子操作,事实上在 JVM 中这句话大概做了下面 3 件事情。

  • 给 instance 分配内存
  • 调用 Singleton 的构造函数来初始化成员变量
  • 将instance对象指向分配的内存空间(执行完这步 instance 就为非 null 了)

但是在 JVM 的即时编译器中存在指令重排序的优化。也就是说上面的第二步和第三步的顺序是不能保证的,最终的执行顺序可能是 1-2-3 也可能是 1-3-2。如果是后者,则在 3 执行完毕、2 未执行之前,被线程二抢占了,这时 instance 已经是非 null 了(但却没有初始化),所以线程二会直接返回 instance,然后使用,然后顺理成章地报错。

我们只需要将 instance 变量声明成 volatile 就可以了。

有些人认为使用 volatile 的原因是可见性,也就是可以保证线程在本地不会存有 instance 的副本,每次都是去主内存中读取。但其实是不对的。使用 volatile 的主要原因是其另一个特性:禁止指令重排序优化。也就是说,在 volatile 变量的赋值操作后面会有一个内存屏障(生成的汇编代码上),读操作不会被重排序到内存屏障之前。比如上面的例子,取操作必须在执行完 1-2-3 之后或者 1-3-2 之后,不存在执行到 1-3 然后取到值的情况。从「先行发生原则」的角度理解的话,就是对于一个 volatile 变量的写操作都先行发生于后面对这个变量的读操作(这里的“后面”是时间上的先后顺序)。

但是特别注意在 Java 5 以前的版本使用了 volatile 的双检锁还是有问题的。其原因是 Java 5 以前的 JMM (Java 内存模型)是存在缺陷的,即时将变量声明成 volatile 也不能完全避免重排序,主要是 volatile 变量前后的代码仍然存在重排序问题。这个 volatile 屏蔽重排序的问题在 Java 5 中才得以修复,所以在这之后才可以放心使用 volatile。

原文链接:https://blog.csdn.net/tian31233/article/details/79664649

后续进行补充…

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!