Java面试题——Java基础

1、重载与重写的区别?

  重载:发生在同一个类中,方法名必须相同参数类型不同、个数不同、顺序不同,方法返回值和访问修饰符可以不同,发生在编译时。

  重写:发生在父子类中,方法名、参数列表必须相同,返回值范围小于父类,抛出的异常范围小于父类,访问修饰符范围大于父类;如果父类方法访问修饰符为private,则子类就不能重写该方法。

2、String 和 StringBuffer、StringBuilder 的区别是什么?String 为什么是不可变的?  

  可变性
  简单的来说:String 类中使用 final 关键字字符数组保存字符串, private final char value[] ,所以 String对象是不可变的。而StringBuilder 与 StringBuffer 都继承自 AbstractStringBuilder 类,在 AbstractStringBuilder中也是使用字符数组保存字符串 char[]value 但是没有用 final 关键字修饰,所以这两种对象都是可变的
  StringBuilder 与 StringBuffer 的构造方法都是调用父类构造方法也就是 AbstractStringBuilder 实现的,大家可以自行查阅源码。
 
  AbstractStringBuilder.java
  

  线程安全性

  String中的对象是不可变的,也就可以理解为常量,线程安全。AbstractStringBuilder 是 StringBuilder 与StringBuffer 的公共父类,定义了一些字符串的基本操作,如 expandCapacity、append、insert、indexOf 等公共方法。StringBuffer对调用的方法添加了同步锁,所以是线程安全的。StringBuilder并没有对方法进行加同步锁,所以是非线程安全的。

  性能

   每次对String类型进行改变的时候,都会生成一个新的String对象,然后将指针指向新的String对象。StringBuffer每次都会对StringBuffer本身进行操作,而不是生成新的对象并改变对象引用。相同情况下使用StirngBuilder 相比使用 StringBuffer 仅能获得 10%~15% 左右的性能提升,但却要冒多线程不安全的风险。 

  对于三者使用的总结:
 
  1. 操作少量的数据 = String
  2. 单线程操作字符串缓冲区下操作大量数据 = StringBuilder
  3. 多线程操作字符串缓冲区下操作大量数据 = StringBuffer 

3、自动装箱与自动拆箱

  装箱:将基本类型用他们对应的引用类型包装起来。
  拆箱:将包装类型转换成基本数据类型。

4、 == 与 equals 

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

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

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

  举个例子:

  

 

 

  说明:

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

5、关于 final 关键字的一些总结 

  final关键字主要用在三个地方:变量、方法、类。 

  • 修饰变量,如果是基本数据类型的变量,则其数值一旦初始化之后便不能更改;如果是引用类型的变量,则在对其初始化之后便不能让其指向另一个对象。
  • 修饰方法:表示方法不能被重写。
  • 修饰类,表明这个类不能被继承。final类中的所有成员方法都会被隐式地指定为final方法。
  • 使用final方法的原因有两个:第一个原因是把方法锁定,以防任何继承类修改它的含义;第二个原因是效率。在早期的Java实现版本中,会将final方法转化成内嵌调用。但是如果方法过于庞大,可能
    可能看不到内嵌调用带来的任何性能提升(现在的Java版本已经不需要使用final方法进行这些优化了)。类中所有的private方法都隐式地指定为fianl。

6、接口和抽象类的区别是什么?

  • 接口的方法默认是public,所有方法在接口中不能有实现(Java8开始接口方法可以有默认实现),抽象类可以有抽象的方法
  • 接口中的实例变量默认都是final类型的,而抽象类则不一定
  • 一个类可以实现多个接口,但是最多只能实现(继承)一个抽象类
  • 一个类实现接口就要实现接口中所有的方法,而抽象类不一定
  • 接口不能new实例化,可以声明,但是必须引用一个实现该接口的对象,从设计层面来说,抽象是对类的抽象,是一种模板设计,接口是行为的抽象,是一种行为的规范
  备注:在JDK8中,接口也可以定义静态方法,可以直接用接口名调用。实现类和实现是不可以调用的。如果同时实现
  两个接口,接口中定义了一样的默认方法,必须重写,不然会报错。
 
  • 实现:抽象类的子类使用 extends 来继承;接口必须使用 implements 来实现接口。
  • 构造函数:抽象类可以有构造函数;接口不能有。
  • 实现数量:类可以实现很多个接口;但是只能继承一个抽象类。
  • 访问修饰符:接口中的方法默认使用 public 修饰;抽象类中的方法可以是任意访问修饰符

7、Java 中的异常处理 

  Java异常类层次结构图 
  
在 Java 中,所有的异常都有一个共同的祖先java.lang包中的 Throwable类。Throwable: 有两个重要的子类:Exception(异常) 和 Error(错误) ,二者都是 Java 异常处理的重要子类,各自都包含大量子类。Error(错误):是程序无法处理的错误,表示运行应用程序中较严重问题。大多数错误与代码编写者执行的操作无关,而表示代码运行时 JVM(Java 虚拟机)出现
的问题。例如,Java虚拟机运行错误(Virtual MachineError),当JVM 不再有继续执行操作所需的内存资源时,将出现 OutOfMemoryError。这些异常发生时,Java虚拟机(JVM)一般会选择线程终止。这些错误表示故障发生于虚拟机自身、或者发生在虚拟机试图执行应用时,如Java虚拟机运行错误(VirtualMachineError)、类定义错误(NoClassDefFoundError)等。
这些错误是不可查的,因为它们在应用程序的控制和处理能力之 外,而且绝大多数是程序运行时不允许出现的状况。对于设计合理的应用程序来说,即使确实发生了错误,本质上也不应该试图去处理它所引起的异常状况。在 Java中,错误通过Error的子类描述。Exception(异常):是程序本身可以处理的异常。Exception 类有一个重要的子类 RuntimeException。RuntimeException
异常由Java虚拟机抛出。NullPointerException(要访问的变量没有引用任何对象时,抛出该异常)、ArithmeticException(算术运算异常,一个整数除以0时,抛出该异常)和ArrayIndexOutOfBoundsException (下标越界异常)。
 
注意:异常和错误的区别:异常能被程序本身可以处理,错误是无法处理。
  • Throwable类常用方法
  • public string getMessage():返回异常发生时的详细信息
  • public string toString():返回异常发生时的简要描述
  • public string getLocalizedMessage():返回异常对象的本地化信息。使用Throwable的子类覆盖这个方法,可
  • 以声称本地化信息。如果子类没有覆盖该方法,则该方法返回的信息与getMessage()返回的结果相同
  • public void printStackTrace():在控制台上打印Throwable对象封装的异常信息
异常处理总结
  • try 块:用于捕获异常。其后可接零个或多个catch块,如果没有catch块,则必须跟一个fifinally块。catch 块:用于处理try捕获到的异常。
  • fifinally 块:无论是否捕获或处理异常,fifinally块里的语句都会被执行。当在try块或catch块中遇到return语句
  • 时,fifinally语句块将在方法返回之前被执行。
在以下4种特殊情况下,fifinally块不会被执行:
  1. 在fifinally语句块中发生了异常。
  2. 在前面的代码中用了System.exit()退出程序。
  3. 程序所在的线程死亡。
  4. 关闭CPU。 

 8、两个对象的 hashCode() 相同, 那么 equals() 也一定为 true吗?

  不对,两个对象的 hashCode() 相同,equals() 不一定 true。

  代码示例:

String str1 = "keep";
String str2 = "brother";
System. out. println(String. format("str1:%d | str2:%d",  str1. hashCode(),str2. hashCode()));
System. out. println(str1. equals(str2));

 

 

  执行的结果:

str1:1179395 | str2:1179395

false

  代码解读:很显然“keep”和“brother”的 hashCode() 相同,然而 equals() 则为 false,因为在散列表中,hashCode() 相等即两个键值对的哈希值相等,然而哈希值相等,并不一定能得出键值对相等

9、Java 中的 Math. round(-1. 5) 等于多少?

  Math.round(-1.5)的返回值是-1。四舍五入的原理是在参数上加0.5然后做向下取整。

public class test {
    public static void main(String[] args){
        System.out.println(Math.round(1.3));   //1
        System.out.println(Math.round(1.4));   //1
        System.out.println(Math.round(1.5));   //2
        System.out.println(Math.round(1.6));   //2
        System.out.println(Math.round(1.7));   //2
        System.out.println(Math.round(-1.3));  //-1
        System.out.println(Math.round(-1.4));  //-1
        System.out.println(Math.round(-1.5));  //-1
        System.out.println(Math.round(-1.6));  //-2
        System.out.println(Math.round(-1.7));  //-2
    }
}

 

10、String 属于基础的数据类型吗?

  String是final修饰的java类,java中的基本类型一共有8个,它们分别为:

  • 字符类型:byte,char
  • 基本整型:short,int,long
  • 浮点型:float,double
  • 布尔类型:boolean

11、如何将字符串反转?

  使用 StringBuilder 或者 stringBuffer 的 reverse() 方法。

  示例代码:

// StringBuffer reverse
StringBuffer stringBuffer = new StringBuffer();
stringBuffer. append("abcdefg");
System. out. println(stringBuffer. reverse()); // gfedcba
// StringBuilder reverse
StringBuilder stringBuilder = new StringBuilder();
stringBuilder. append("abcdefg");
System. out. println(stringBuilder. reverse()); // gfedcba

 

12、String 类的常用方法都有那些?

  • indexOf():返回指定字符的索引。
  • charAt():返回指定索引处的字符。
  • replace():字符串替换。
  • trim():去除字符串两端空白。
  • split():分割字符串,返回一个分割后的字符串数组。
  • getBytes():返回字符串的 byte 类型数组。
  • length():返回字符串长度。
  • toLowerCase():将字符串转成小写字母。
  • toUpperCase():将字符串转成大写字符。
  • substring():截取字符串。
  • equals():字符串比较。

13、抽象类必须要有抽象方法吗?

  不需要,抽象类不一定非要有抽象方法。

  示例代码:

abstract class Cat {
    public static void sayHi() {
        System. out. println("hi~");
    }
}

 

   上面代码,抽象类并没有抽象方法但完全可以正常运行。

14、普通类和抽象类有哪些区别?

  • 普通类不能包含抽象方法,抽象类可以包含抽象方法。
  • 抽象类不能直接实例化,普通类可以直接实例化。

15、抽象类能使用 final 修饰吗? 

  不能,定义抽象类就是让其他类继承的,如果定义为 final 该类就不能被继承,这样彼此就会产生矛盾,所以 final 不能修饰抽象类,如下图所示,编辑器也会提示错误信息:

  

16、 Java 中 IO 流分为几种?

  按功能来分:输入流(input)、输出流(output)。

  按类型来分:字节流和字符流。

  字节流和字符流的区别是:字节流按 8 位传输以字节为单位输入输出数据,字符流按 16 位传输以字符为单位输入输出数据。

17、BIO、NIO、AIO 有什么区别?

  • BIO:Block IO 同步阻塞式 IO,就是我们平常使用的传统 IO,它的特点是模式简单使用方便,并发处理能力低。
  • NIO:Non IO 同步非阻塞 IO,是传统 IO 的升级,客户端和服务器端通过 Channel(通道)通讯,实现了多路复用。
  • AIO:Asynchronous IO 是 NIO 的升级,也叫 NIO2,实现了异步非堵塞 IO ,异步 IO 的操作基于事件和回调机制。

18、Files的常用方法都有哪些?

  • Files. exists():检测文件路径是否存在。
  • Files. createFile():创建文件。
  • Files. createDirectory():创建文件夹。
  • Files. delete():删除一个文件或目录。
  • Files. copy():复制文件。
  • Files. move():移动文件。
  • Files. size():查看文件个数。
  • Files. read():读取文件。

 19、多态的好处

  允许不同类对象对同一消息做出响应,即同一消息可以根据发送对象的不同而采用多种不同的行为方式(发送消息就是函数调用).主要有以下优点:

  1. 可替换性:多态对已存在代码具有可替换性.
  2. 可扩充性:增加新的子类不影响已经存在的类结构.
  3. 接口性:多态是超类通过方法签名,向子类提供一个公共接口,由子类来完善或者重写它来实现的.
  4. 灵活性:
  5. 简化性:

20、父类的静态方法能否被子类重写?

  不能.重写只适用于实例方法,不能用于静态方法,而子类当中含有和父类相同签名的静态方法,我们一般称之为隐藏.

21、java 创建对象的几种方式

  java中提供了以下四种创建对象的方式:

  • new创建新对象
  • 通过反射机制
  • 采用clone机制
  • 通过序列化机制

  前两者都需要显式地调用构造方法. 对于clone机制,需要注意浅拷贝和深拷贝的区别,对于序列化机制需要明确其实现原理,在java中序列化可以通过实现Externalizable或者Serializable来实现.

22、& 和 &&的区别

  基础的概念不能弄混:&是位操作,&&是逻辑运算符.需要记住逻辑运算符具有短路特性,而&不具备短路特性.来看看一下代码执行结果? 

public class Test{
    static String name;
 
    public static void main(String[] args){
        if(name!=null&userName.equals("")){
            System.out.println("ok");
        }else{
            System.out.println("erro");
        }
    }
}

  上述代码将会抛出空指针异常,如果是&&,当 name!=null为false时,就不会继续执行&&后面的语句(这就是短路),而后面的语句会导致空指针异常,所以不会发生空指针异常。而使用&就会导致空指针异常

 23、什么是 Java 虚拟机(JVM)?为什么 Java 被称作是“平台无关的编程语言”?

  Java虚拟机是一个可执行Java字节码的虚拟机进程。Java源文件被编译成能被Java虚拟机执行的字节码文件。

  Java被设计成允许应用程序可以运行在任意平台,而不需要程序员为每一个平台单独重写或者重新编译。Java虚拟机让这个变为可能,因为他知道底层硬件平台的指令程度和其他特性。

24、JDK、JRE、JVM 分别是什么关系?

  JDK 即为 Java 开发工具包,包含编写 Java 程序所必须的编译、运行等开发工具以及 JRE。开发工具如:用于编译 Java 程序的 javac 命令、用于启动 JVM 运行 Java 程序的 Java 命令、用于生成文档的 Javadoc 命令以及用于打包的 jar 命令等等。 

  JRE 即为 Java 运行环境,提供了运行 Java 应用程序所必须的软件环境,包含有 Java 虚拟机(JVM)和丰富的系统类库。系统类库即为 Java 提前封装好的功能类,只需拿来直接使用即可,可以大大的提高开发效率。

  JVM 即为 Java 虚拟机,提供了字节码文件(.class)的运行环境支持。 简单说,就是 JDK 包含 JRE 包含 JVM。

 

参考文章:https://zhuanlan.zhihu.com/p/94095050

posted @ 2021-07-12 16:48  潜跃  阅读(75)  评论(0编辑  收藏  举报