Java SE基础题(一)

1.说说你对面向对象思想的理解?

​ 总结来说,我对面向对象思想的理解就是,万物皆可对象。Java的面向对象就体现在它的三个重要特性,即封装、继承、多态,抽象也是一个体现的地方。

​ 封装就是把我们需要的一些属性和操作封装成一个对象,把它当作一个对象作为整体去考虑,帮助我们去执行一些功能,而不考虑内部的构造。

​ 继承可以是子父类之间的单继承、接口之间或者类与接口之间的多继承,它体现的也是一个对事物的共性抽取的地方,也是抽象思想的一个具象化体现,最终通过具体的对象达到我们想要的效果。

​ 继承是多态的前提,即不同对象之间的从属关系所表现出来的。

​ 总之,OOP的思想就是去关注需要做的这件事情,然后找到一个可以执行这件事的对象,然后调用这个对象去完成。


2. Java 对象初始化顺序

  1. 首先类加载过程:
    1. 判断有没有加载过这个类;
    2. 如果没有:
      1. 通过classpath全路径去找到这个类的class文件,然后获取它定义的字节流;
      2. 把这个class文件的静态存储结构转换成方法区里动态存储的结构;
      3. 在堆上new一个Class对象作为这个class文件在方法区中的入口;
      4. 验证:这个class文件合不合规范;
      5. 准备:在方法区中为其分配内存,给static成员变量初始值设置为默认值;
      6. 解析:JVM把常量池中的符号引用替换为直接引用,触发符号引用验证;
      7. 初始化:
        1. 在堆里分配一块内存空间给new的实例对象,并给默认值;(实例化对象)
        2. 首先执行父类静态的内容(静态变量,静态代码块,按顺序执行);
        3. 接着执行子类的静态的内容;
        4. 执行父类构造代码块;
        5. 执行父类的构造方法;
        6. 执行子类构造代码块;
        7. 执行子类的构造方法(初始化实例成员变量)。
    3. 如果有:
      1. 直接初始化。

3.Overload 和 Override 的区别?Overload 的方法是否可以改变 返回值的类型?

  • Overload
    1. 存在一个类里;
    2. 参数列表必须不同(可以是参数类型不同,参数数量不同,或者是不同参数类型之间的顺序不同);
    3. 和返回值没关系(可以改变);
    4. 与访问权限无关;
    5. 和异常无关。
  • Override
    1. 存在于子父类里;
    2. 参数列表必须相同;
    3. 子类的重写方法的返回值范围必须小于等于父类中该方法的返回值范围;
    4. 子类方法的权限必须大于父类方法的权限修饰符表示的权限;
    5. 父类没有抛出异常,子类就不能抛出异常;父类抛出了异常,子类可以抛出相同的异常或者这个异常的子类。

4. int 和 Integer 有什么区别?

​ int是整数型的一个基本数据类型,可以直接存储4个字节的整型数据,默认值是0。

​ Integer是一个包装类,是一个引用类型,这个类里面包含了很多有关操作int数据类型的方法,默认值是null。

​ int和Integer直接可以通过拆箱和装箱来实现转换。


5. char 型变量中能不能存贮一个中文汉字,为什么?

  • Unicode 可以使用的编码有三种,分别是:
    • UTF-8:一种变长的编码方案,使用 1~6 个字节来存储;
    • UTF-16:介于 UTF-8 和 UTF-32 之间,使用 2 个或者 4 个字节来存储,长度既固定又可变;
    • UFT-32:一种固定长度的编码方案,不管字符编号大小,始终使用 4 个字节来存储;

​ 看情况,Java默认使用的编码是 Unicode(class文件采用UTF-8,而JVM运行时使用UTF-16),char类型(2字节)的变量可以存储Unicode编码的字符,Unicode字符集中包含了汉字,一般的汉字是可以存贮的,只不过一些特殊的汉字没有被包含在字符集里,也就不可以。


6.Java 中,Serializable 与 Externalizable 的区别?

​ Externalizable 接口是Serializable 接口的子接口。

  • Serializable 接口

    • 一个标记接口;
    • 实现这个接口,可以直接进行序列化操作,也可以在目标类里增加两个private void的序列化和反序列化方法,总之会先去判断我们有没有这两个方法,有就调用,没有对象流内部会调用默认的方法进行序列化或者反序列化;
    • 实现这个接口的类,并不要求该类具有一个无参的构造方法,因为在反序列化的过程中实际上是去其继承树上找到一个没有实现Serializable接口的父类(这个父类必须有无参构造),然后构造该类的对象,再逐层往下的去设置各个可以反序列化的属性;
  • Externalizable 接口

    • 不是一个标记接口;
    • 实现这个接口,必须重写序列化和反序列化的两个方法,并在两个方法中写出所有需要序列化的成员变量;
    • 实现这个接口的类,必须要有无参public构造器,不然反序列化的时候会报出 InvalidClassException 异常,这时反序列化时会构造目标类的实例对象,然后会调用被序列化类的无参构造器去创建一个新的对象,再将被保存对象的字段的值分别填充到新对象中。

7.抽象类和接口有什么区别?

  1. 抽象类中的方法可以有方法体,就是能实现方法的具体功能,但是接口中的方法不行(JDK 1.8之后的默认方法可以用方法体,默认方法可以被覆盖重写;静态方法、私有方法也可以有方法体,但是不能被实现)
  2. 抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是 public static final 类型的
  3. 接口中不能含有静态代码块以及静态方法(用 static 修饰的方法,JDK 1.8之后的版本可以含有静态方法了,接口可以直接调用,而接口的实现类对象不可以调用),而抽象类是可以有静态代码块和静态方法
  4. 一个类只能继承一个抽象类,而一个类却可以实现多个接口(类与接口在继承上的区别)。
  5. 抽象类可以有构造方法,接口没有。

8.String 和 StringBuilder、StringBuffer 的区别?

​ String声明的字符串是不可变的对象,每次操作(比如说截取、拼接)都会创建一个新的字符串对象,特别是字符串字面量的操作,比如“123”、“456”两个字符串的拼接,将会产生“123456”,而且这三个在编译时就放到了class常量池,然后等class文件加载完成后转到运行时常量池,这两块常量池都在方法区中,无法被JVM垃圾回收,不适合经常的字符串操作,浪费内存。

​ StringBuffer类和StringBuilder类是用于应对经常性字符串操作的。这两个类的使用基本一致,可以产生可变的字符串,而且不会产生新的没被使用的对象,并且占用的内存是堆内存,可以被GC。

​ 不同的是,StringBuilder不保证同步,线程不安全,效率更高;StringBuffer保证同步,线程安全,效率较低。


9.阐述 final、finally、finalize 的区别。

  • final

  • 如果一个类被声明为final,意味着它不能再派生出新的子类,即不能被继承,因此它和abstract不能同时使用。

  • 将变量声明为final,可以保证它们在使用中不被改变,被声明为final的变量必须在声明时给定初值,而在以后的引用中只能读取不可修改(局部内部类只能用final的变量,但是如果保证不改变,也可以不显式声明)。

  • 被声明为final的方法只能使用,但是不能在子类中被重写。

  • finally
    通常放在try…catch…的后面构造总是执行的代码块finally,这就意味着程序无论正常执行还是发生异常,

    这里的代码只要JVM不关闭都能执行,一般用于将资源释放部分的代码写在finally块中。

  • finalize
    Object类中定义的方法,Java中允许使用finalize()方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在销毁对象时调用的,子类可以通过重写finalize()方法可以整理系统资源或者执行其他清理工作。


10.Java 中的异常处理机制的简单原理和应用。

​ Exception异常是java异常体系中的一部分,一般表示所有程序中的错误,所以一般在程序中将进行try…catch的处理。
​ 异常主要分成两类:

  • 运行期异常:运行期间发生的
  • 编译器异常:受检查的,编译器会帮我们检查

​ java中的异常处理机制主要分两种:

  1. try+catch:将可能会出现异常的代码部分套入try{}代码块中,利用catch去捕获这部分代码可能会出现的异常。一旦这部分代码出现了异常,jvm会自动实例化出现的这个异常的对象,然后我们通过捕获,可以自定义我们想要的操作,甚至是再throw一个我们的异常,即代码出错后捕获异常并执行我们的补救行为。

    需要注意的是:

    1. catch和finally不可以同时省略;
    2. 多个catch必须注意它们直接的继承关系,子类在上,父类在下。
  2. throws:当这部分代码出现后,可以不处理,直接将这个异常抛出给调用这部分代码的地方,由它来完成处理,如果最终抛到了main方法上,则交给jvm帮我们处理。

​ 应用:比如说IO流的读写数据、序列化过程、数学运算(除以0)……


版权声明:本文为weixin_44010763原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。