java面试题-基础篇(一)

试了好多博客平台,最后决定留在掘金啦。准备好好整理一下java的一些面试经典问题,文章部分来源网上加入一些自己的见解,PS: 别小看基础题

1.关于 JVM JDK 和 JRE

JVM

Java虚拟机(JVM)是运行Java字节码的虚拟机。JVM有针对不同系统的特定实现,目的是使用相同的字节码,它们都会给出相同的结果。

JVM可以理解的代码就叫做字节码(即扩展名为 .class 的文件)

Java 程序从源代码到运行一般有下面3步:


java程序运行过程

我们需要格外注意的是 .class->机器码这一步。在这一步JVM类加载器首先加载字节码文件,然后通过解释器逐行解释执行,这种方式的执行速度会相对比较慢。而且,有些方法和代码块是经常需要被调用的(也就是所谓的热点代码),所以后面引进了JIT编译器,而JIT属于运行时编译。当JIT编译器完成第一次编译后,其会将字节码对应的机器码保存下来,热点代码则下次可以直接使用而不用再次解释。而我们知道,机器码的运行效率肯定是高Java解释器的。这也解释了我们为什么经常会说Java是编译与解释共存的语言。

HotSpot采用了惰性评估法,根据二八定律,消耗大部分系统资源的只有那一小部分的代码(热点代码),而这也就是JIT所需要编译的部分。JVM会根据代码每次被执行的情况收集信息并相应地做出一些优化,因此执行的次数越多,它的速度就越快。JDK 9引入了一种新的编译模式AOT(Ahead ofTimeCompilation),它是直接将字节码编译成机器码,这样就避免了JIT预热等各方面的开销。JDK支持分层编译和AOT协作使用。但是 ,AOT 编译器的编译质量是肯定比不上 JIT 编译器的。

字节码和不同系统的 JVM 实现是 Java 语言“一次编译,随处可以运行”的关键所在。

JDK和JRE

JDK是Java Development Kit,它是功能齐全的Java SDK。它拥有JRE所拥有的一切,还有编译器(javac)和工具(如javadoc和jdb)。它能够创建和编译程序。

JRE 是 Java运行时环境。它是运行已编译 Java 程序所需的所有内容的集合,包括 Java虚拟机(JVM),Java类库,java命令和其他的一些基础构件。但是,它不能用于程序开发。

2.基础到枯的面试题-见一个加一个

  • Java 面向对象编程三大特性: 封装(private...) 继承(extends) 多态(implements)
  • 构造器 (Constructor) 不能 重写(override) 但是可以重载。
  • 抽象类和类都可以实现多个接口,但是抽象类可以不实现或选择性实现接口方法。
  • 接口可以被接口(interface)继承(extends)。
  • 字符常量相当于一个整型值( ASCII 值),可以参加表达式运算 eg: 'C'; 字符串常量代表一个地址值(该字符串在内存中存放位置) eg: "C"
  • 静态方法里面不能调用非静态变量,不能访问非静态成员变量。
  • 如果有二货问你java和javax有什么区别,emm就说是历史遗留名字而已其实没什么区别。
  • 接口在Java8 以后方法可以有默认方法和静态方法了,接口中的成员变量必须是public static final的
  • 抽象类中的抽象方法(其前有abstract修饰)不能用private、static、protected、final、synchronized、native访问修饰符修饰。
  • 外部接口和类不能被private和protected修饰,但是内部接口和内部类可以被四种访问修饰符修饰。
  • 如果同时实现两个接口,接口中定义了一样的默认方法,必须重写,不然会报错
  • 成员变量可以被 public,private,static 等修饰符所修饰,而局部变量不能被访问控制修饰符及 static 所修饰;但是,成员变量和局部变量都能被 final 所修饰

3.String StringBuild StringBuffer 用法和区别

String是不可变的,值由final修饰,StringBuild和StringBuffer都继承自AbstractStringBuilder。值可变。这也导致了每次对String类型进行改变时都会生成一个新的String对象,改变内存地址指向新的对象。而StringBuffer每次都会对StringBuffer 对象本身进行操作,而不是生成新的对象并改变对象引用,StringBuilder 与StringBuffer对象不同的地方是,StringBuilder对象没有同步锁,性能更高但同时也是线程不安全的。

使用总结:

1.操作少量的数据: 适用String(少量数据时更方便)

2.单线程操作字符串缓冲区下操作大量数据: 适用StringBuilder(线程不安全)

3.多线程操作字符串缓冲区下操作大量数据: 适用StringBuffer(有同步锁线程安全)

4.空构造器的作用

Java 程序在执行子类的构造方法之前,如果没有用 super() 来调用父类特定的构造方法,则会调用父类中“没有参数的构造方法”。因此,如果父类中只定义了有参数的构造方法,而在子类的构造方法中又没有用 super() 来调用父类中特定的构造方法,则编译时将发生错误,因为 Java 程序在父类中找不到没有参数的构造方法可供执行。解决办法是在父类里加上一个不做事且没有参数的构造方法。

也就是说很有可能被继承的类都需要一个空构造方法。

5.== 与 equals

== : 它的作用是判断两个对象的地址是不是相等。即,判断两个对象是不是同一个对象(基本数据类型==比较的是值,引用数据类型==比较的是内存地址)。

equals() : 它的作用也是判断两个对象是否相等。但它一般有两种使用情况:

  • 情况1:类没有覆盖 equals() 方法。则通过 equals() 比较该类的两个对象时,等价于通过“==”比较这两个对象。
  • 情况2:类覆盖了 equals() 方法。一般,我们都覆盖 equals() 方法来比较两个对象的内容是否相等;若它们的内容相等,则返回 true (即,认为这两个对象相等)。

举个例子:

public class test1 {
    public static void main(String[] args) {
        String a = new String("ab"); // a 为一个引用
        String b = new String("ab"); // b为另一个引用,对象的内容一样
        String aa = "ab"; // 放在常量池中
        String bb = "ab"; // 从常量池中查找
        if (aa == bb) // true
            System.out.println("aa==bb");
        if (a == b) // false,非同一对象
            System.out.println("a==b");
        if (a.equals(b)) // true
            System.out.println("aEQb");
        if (42 == 42.0) { // true
            System.out.println("true");
        }
    }
}

说明:

String 中的 equals 方法是被重写过的,因为 object 的 equals 方法是比较的对象的内存地址,而 String 的 equals 方法比较的是对象的值。
当创建 String 类型的对象时,虚拟机会在常量池中查找有没有已经存在的值和要创建的值相同的对象,如果有就把它赋给当前引用。如果没有就在常量池中重新创建一个 String 对象。

你可能感兴趣的:(java面试题-基础篇(一))