Java基础面试整理

119 阅读12分钟

1. Java概述

1.1. Jdk和Jre和JVM的区别

Jdk中包括了Jre,Jre中包括了JVM

JDK :Java Development Kit,它是功能⻬全的 Java SDK。它拥有 JRE 所拥有的⼀切,还有编译器(javac)和⼯具(如 javadoc 和 jdb)。它能够创建和编译程序。
JRE :Jre大部分都是 C 和 C++ 语言编写的,是Java 运⾏时环境。它是运⾏已编译 Java 程序所需的所有内容的集合,包括 Java 虚拟机(JVM),Java 类库,Java 命令和其他的⼀些基础构件。但是,它不能⽤于创建新程序。
Jvm:在倒数第二层 由他可以在(最后一层的)各种平台上运行 Java Virtual Machine是Java虚拟机,Java程序需要运行在虚拟机上,不同的平台有自己的虚拟机,因此Java语言可以实现跨平台。

1.2. 什么是跨平台性?原理是什么

所谓跨平台性,是指java语言编写的程序,一次编译后,可以在多个系统平台上运行。
实现原理:Java程序是通过java虚拟机在系统平台上运行的,只要该系统可以安装相应的java虚拟
机,该系统就可以运行java程序。

1.3. 什么是字节码?采用字节码的最大好处是什么

字节码:Java源代码经过虚拟机编译器编译后产生的文件(即扩展为.class的文件),它不面向任何特定的处理器,只面向虚拟机。
采用字节码的好处:
Java语言通过字节码的方式,在一定程度上解决了传统解释型语言执行效率低的问题,同时又保留了解释型语言可移植的特点。所以Java程序运行时比较高效,而且,由于字节码并不专对一种特定的机器,因此,Java程序无须重新编译便可在多种不同的计算机上运行。

1.4. Java和C++的区别

都是面向对象的语言,都支持封装、继承和多态
Java不提供指针来直接访问内存,程序内存更加安全
Java的类是单继承的,C++支持多重继承;虽然Java的类不可以多继承,但是接口可以多继承。
Java有自动内存管理机制,不需要程序员手动释放无用内存

2. Java数据类型

3. 面向对象的三大特性

  • 封装
    • 封装就是把抽象出来的数据(属性)和对数据的操作(方法)封装在一起,数据封装在方法内部,我们只需要调用方法就能对数据进行操作
      • 优点
        • 提高程序的安全,保护数据
        • 隐藏代码的实现细节
        • 统一接口
        • 增加了系统可维护性
      • 属性私有
      • 方法公有
        • 方法中加逻辑代码,让设置更合理
  • 继承 extends
    • 子类继承父类,通过子类可以调用父类里面的非私有的方法和属性。
    • Java只有单继承,没有多继承
  • 多态
    • 即同一方法可以根据发送对象的不同而采用多种不同的行为方式
    • 多态存在的条件
      • 有继承关系
      • 子类重写父类方法
      • 父类引用指向子类对象
    • 被static、final、private修饰,不能使用多态
    • 目的
      • 编译时类型
        • 看左边
      • 运行时类型
        • 看右边
      • 为了扩展功能:父类方法无法满足子类需求

4. Java支持多继承和多实现吗

单继承,多实现

5. 构造方法和一般方法有什么区别呢

1:两个函数定义格式不同。

2:构造方法是在对象创建时就被调用,用于初始化,而且初始化动作只执行一次。 一般方法,是对象创建后,需要调用才执行,可以被调用多次。

6. 运行时异常都有哪些?

  • 1、NullPointerException 空指针异常
    • 访问一个空对象的属性或者方法时会出现
  • 2、ClassNotFoundException 指定的类找不到 :类的名称和路径加载错误;通常都是程序试图通过字符串来加载某个类时可能引发异常
    • 缺少jar包
  • 3、NumberFormatException 字符串转换为数字异常 :字符型数据中包含非数字型字符
    • Integer.valueOf("字符串");
  • 4、IndexOutOfBoundsException 数组下标越界异常 :常见于操作数组对象时发生
    • 访问超过指定下标的数据
  • 5、ClassCastException 数据类型转换异常
    • 强转
  • 6、SQLException SQL异常 :常见于操作数据库时的SQL语句错误
  • 7、ArithmeticException:算术异常
    • int i = 1/0;

7. 抽象类和接口的区别

  • 1、定义:接口定义:interface;抽象类:abstrat;
  • 2、抽象类有构造器,但是不能创建对象,目的是为了供子类调用,接口没有构造器;
  • 3、接口的所有方法都是抽象方法,所有属性都是静态常量;而抽象类中可以有非抽象方法和非常量的属性;
  • 4、抽象类只能单继承,而接口之间可以多继承,接口之间的继承用extexds,类实现接口用implements.
    • 一个类可以继承一个类,同时实现多个接口;
  • 抽象类描述的是事物的本质【是一个什么东西】,是用来被继承的。接口描述的功能或者规范【有什么东西】,是用来被实现的
    • 防盗门
      • 抽象类
      • 接口
        • 照相
        • 指纹

8. ==和equals()

  • ==
    • 基本数据类型,比值
    • 引用数据类型,比内存地址
  • equals()
    • 是Object类的方法,底层跟 == 是一样的
    • 有需求会重写 equals() 方法,把对象的属性值一一比较。如果都相同,则返回true,否则false
    • 八大基本数据类型对应的包装类和String都重写了equlas方法和hashCode方法

9. 为什么重写equals方法,还必须要重写hashcode方法

  • 总结
    • 保证是同一个对象,如果重写了equals方法,而没有重写hashcode方法,会出现equals相等的对象,hashcode不相等的情况,重写hashcode方法就是为了避免这种情况的出现。
    • 使用hashcode方法提前校验,可以避免每一次比对都调用equals方法,提高效率
    • 减少了equals的使用次数,执行效率就大大提高了
  • 重写后两个方法的关系
    • equals()相等的两个对象,hashcode()一定相等;
    • hashcode()不等,一定能推出equals()也不等;
    • hashcode()相等,equals()可能相等,也可能不等。
    • 所以先进行hashcode()判断,不等就不用equals()方法了。
    • 但equels是是根据对象的特征进行重写的,有时候特征相同,但hash值不同,也不是一个对象。 所以两个都重写才能保障是同一个对象。

10. String、StringBuffer、StringBuilder

  • String,常量类,放在方法区中。不适合经常变动
  • StringBuffer、StringBuilder
    • 操作String的一个可变工具类,可以对同一个字符串进行多次修改,不会创建新的对象
    • StringBuffer
      • 线程安全,每个方法都加了同步锁,适合多线程环境执行
    • StringBuilder
      • 线程不安全,适合单线程环境执行

11. String常量池

  • String常量池就是“字符串常量池”,位于JVM的堆内存中,专门用来存储字符串常量,可以提高内存的使用率,避免开辟多块空间存储相同的字符串,在创建字符串时 JVM 会首先检查字符串常量池,如果该字符串已经存在池中,则返回它的引用,如果不存在,则实例化一个字符串放到池中,并返回其引用。
  • String str = new String("abc");
    • 创建了几个对象?
    • JDK8之前:两个
      • abc
      • new String("abc");
    • JDK8之后:一个

12. Object常用方法

  • eqluas
    • 默认地址⽐较
      如果没有重写equals方法,那么Object类中默认进行**==**运算符 的对象地址比较,只要不是同一个对象,结果必然是false.
    • 对象内容⽐较
      如果希望进行对象的内容比较,即所有或指定的部分成员变量相同就判定两个对象相同,则可覆盖重写equals方法
  • toString()
    • 返回该对象的字符串表示,该字符串内容就是对象的类型+@+内存地址值
    • 如果不希望使⽤toString⽅法的默认⾏为,则可以对它进⾏覆盖重写
  • hashCode
    • native方法,用于返回对象的哈希吗
  • clone
    • 深克隆:复制对象 是复制一份全新的,属性内容一致的对象,但内存中的地址值一定不一样
    • 浅克隆:复制引用
  • getClass()
    • 返回此 Object 的运行时类
    • Java的引用变量有两个类型,编译时类型和运行时类型。
      1.编译时类型由声明该变量时使用的类型决定。(=左边)
      2.运行时类型由实际赋给该变量的对象决定。(=右边)
    • object.作用:对象通过该方法,可以获得对应的类的字节码对象
      xx.java ->xx.class ->JVM
    • 类加载-方法区-字节码对象
      加载:类只加载一次,所以方法区中类型信息只有一个,对应的字节码对象都是同一个。
    • 加载触发的条件:
      1.实例化对象 new
      2.静态方法/静态变量
      3.使用子类,父类必须先加载
      4.class.forName(“java.lang.Sting”)–手动加载指定的类
      5.Strin.class->获得字节码对象
  • wait(),wait(long timeout),wait(long timeout, int nanos)
    • native 方法,并且不能重写。
      作用是:暂停线程的执行。
      注意:sleep() 方法没有释放锁,wait释放了锁。timeout 是等待时间。nanos参数,表示额外的时间
  • notify
    • native方法,并且不能重写。
      唤醒一个在此对象监视器上等待的线程(监视器相当于就是锁的概念)
      如果有多个线程在等待只会唤醒一个。
  • notifyAll
    • native方法,并且不能重写。
      作用跟 notify() 一样,只不过会唤醒在此对象监视器上等待的所有线程,而不是一个线程。
  • finalize
    • GC时会调用。GC垃圾回收机制
    • 内存溢出:在内存中没有存储的地方
      内存泄漏:内存被无效对象占用
      一个对象分配内存之后,在使用是没有来得释放,导致一直在占用内存,使得实际内存变少
      GC 垃圾回收机制,定时清理内存
      1.在程序运行时自动启动,不定时回收内存中标记的垃圾(没有引用的对象,会被内存标记为垃圾)
      2.GC是自动调用的,也可以手动调用GC -System.gc();
      总结:原则上java中是不存在内存泄漏的

13. String常用方法

  • concat
和长度有关的方法
返回类型      方法名               作用
int        length()        得到一个字符串的字符个数


和数组有关的方法
返回类型        方法名             作用
byte[]        getBytes()       将一个字符串转换成字节数组
char[]        toCharArray()    将一个字符串转换成字符数组
String[]      split(String)    将一个字符串按照指定内容劈开


和判断有关的方法
返回类型        方法名                         作用
boolean       equals(String)                判断两个字符串的内容是否一模一样
boolean       equalsIgnoreCase(String)      忽略大小写的比较两个字符串的内容是否一模一样
boolean       contains(String)              判断一个字符串里面是否包含指定的内容
boolean       startsWith(String)            判断一个字符串是否以指定的内容开头
boolean       endsWith(String)              判断一个字符串是否以指定的内容结尾


和改变内容有关的方法    
和改变内容有关的方法,都不会直接操作原本的字符串
而是将符合条件的字符串返回给我们,所以注意接收
返回类型        方法名                         作用
String        toUpperCase()                 将一个字符串全部转换成大写
String        toLowerCase()                 将一个字符串全部转换成小写
String        replace(String,String)        将某个内容全部替换成指定内容
String        replaceAll(String,String)     将某个内容全部替换成指定内容,支持正则
String        repalceFirst(String,String)   将第一次出现的某个内容替换成指定的内容
String        substring(int)                从指定下标开始一直截取到字符串的最后
String        substring(int,int)            从下标x截取到下标y-1对应的元素
String        trim()                        返回字符串副本,去除一个字符串的前后空格
String        split(String regex)           根据给定正则表达式的匹配拆分此字符串
String        Join(string separator, string[] value)将多个字符串元素连接成一个字符串,元素之间用指定的分隔符隔开。
String        concat()                       对当前字符串追加字符串


和位置有关的方法返回类型        方法名                     作用
char          charAt(int)               得到指定下标位置对应的字符
int           indexOf(String)           得到指定内容第一次出现的下标
int           lastIndexOf(String)       得到指定内容最后一次出现的下标

14. java怎么创建对象?

  • 使用 new 关键字
    • 调用构造器
  • 使用 newInstance() 方法,反射
    • 反射调用无参构造器
    • 通过类的全限定名获取 Class 对象,并使用该对象的 newInstance() 方法创建对象。这种方式可以创建没有直接可访问构造方法的对象,并且可以动态地根据类名创建对象

  • 使用 clone() 方法
    • 通过实现 Cloneable 接口,并重写 clone() 方法,我们可以使用 clone() 方法创建对象的副本。clone() 方法会创建一个新的对象,将原始对象的字段值复制到新对象中。需要注意的是,进行对象克隆时,应该考虑深拷贝和浅拷贝的问题。

  • 使用反序列化的 readObject() 方法
    • 序列化是将对象转换为字节流的过程,而反序列化则是将字节流转换回对象的过程。
    • 通过实现 Serializable 接口,我们可以将对象写入到字节流中,并从字节流中重新创建对象。这种方式可以在网络传输或者持久化对象时使用。