1.面向对象基础

  • 面向对象和面向过程的区别
    • 面向过程:吧解决的问题拆成一个个方法来执行解决问题
    • 面向对象:分析出来每个对象,每个对象做自己该做的行为(方法)以此来解决问题【更容易维护,复用性强,易扩展】
  • 对象实体与对象引用有何不同?

    对象实例在堆内存中,对象引用指向的是对象实例放在栈内存中

    【一个对象引用可以执行 0 个或 1 个对象】

    【一个对象也可以被 n 个引用指向】

  • 对象的相等和引用相等的区别

    对象相等比较的是内存中存放的内容是否相等

    引用相等比较的是指向的内存地址是否相等

  • 构造方法有哪些特点?
    • 特点
      • 名字与类名相同
      • 没有返回值,也不能用 void 声明构造函数
      • 生成类的对象时自动调用,无需调用
  • 封装

    吧一个对象的属性隐藏在对象的内部,不让外部对象直接访问内部属性,但可以提供被外部访问的方法来操作属性【就好比,看不到空调里内部的零件,但是可以通过遥控器来操作。如果隐藏了属性且不提供外界访问的方法,那也就是有了空调但没有遥控器,那本身也就毫无意义了】

  • 继承

    提取不同类型对象之间的公共部分,提高代码的复用性,节省创建新类的时间,提高开发效率【好比学生,老师登记信息的时候,都会存在姓名,年龄等相同的信息,就可以提取出来相同的信息】

  • 多态

    一个对象具有多种形态,代码表示:父类类型指向子类对象

    • 特点:
      • 对象类型和引用类型之间具有继承/实现的关系
      • 多态不能调用”只在子类存在但不存在父类中的“
      • 如果子类重写了父类的方法,执行这个方法的时候,执行的是子类覆盖的方法,如果没有覆盖,则执行父类的
  • 接口和抽象类有什么共同点和区别
    • 共同点
      • 都不能被实例化
      • 都可以包含抽象方法
      • 都可以由默认实现的方法(java 8以后可以定义默认方法)
    • 区别
      • 接口主要用于对类行为的一种约束,就是实现了某个接口,就必须存在接口内的行为。而抽象类是用于代码复用,强调的是所属关系
      • 类与类是单继承,而接口是多实现
      • 接口中成员变量只能是常量(public static final),而抽象类的成员变量默认 default,可以在子类中被重新定义和赋值
  • 什么是引用拷贝

    就是浅拷贝的情况下,被拷贝对象中还存在的引用类型和拷贝对象中的引用类型是同一个引用地址

2.Object

  • Object 类的常见方法有哪些?
    • getClass()、hashCode()、equals()、toString()等
  • hashCode
    • hashCode有什么用?

      获取哈希码,确定该某个对象在哈希表中的索引位置,提高检索的效率

    • 为什么要有 hashCode?

      提高了执行的速度。比如当吧对象添加到 HashSet 的时候,回先计算该对象的 hashCode 值来判断对象加入的位置,同时与已经存在对象的哈希值来做比较,如果没有相同的哈希值,则会添加。如果发现相同的 hashCode 值,会调用 equals() 来检查 hashCode 相等的对象是否真的相同,如果两者相同,则认为重复,则不会添加。这样就减少了 equals 的次数,提高了执行速度

    • 为什么还会同时提供两个方法?

      因为两个对象的 hashCode 值相等并不代表两个对象相等,而如果两个对象的 hashCode 值不相等,就可以直接认为两个对象是不相等的

    • 为什么两个有相同对象的 hashCode 值,也不一定是相等的

      因为 hashCode() 也许刚好会让多个对象传回相同的哈希值,所以需要继续使用 equals 来判断两个对象是否相等

  • 为什么重写 equals() 时必须重写 hashCode()方法

    因为两个相等的对象 hashCode 值也必须是相等的,就是说如果 equals 判断了两个对象是相等的,而两个对象的 hashCode 也要相等。比如当重写了 equals 却没有重写 hashCode,使用 HashMap,HashSet 的时候,就会出现问题【HashMap、HashSet存储对象位置的时候是根据 hashCode 来存放的,比如第一个对象存入了是正常的,而存储第二个相同对象的时候根据hashCode判断位置的时候,却不会放到第一个对象存入的位置,这样 hashCode 值不同,也就导致了会将相同的对象存入进去】

3.String

  • String、StringBuffer、StringBuilder的区别
    • 可变性

      String 是不可变的。而 StringBuffer 和 StringBuilder 都继承自 AbstractStringBuilder 类,在该类中也是使用字符数组保存字符串的,但它是可变的。该类还提供了 很多修改字符串的方法【append】

    • 线程安全性

      String 中的对象是不可变的,也就是常量,线程是安全的。AbstractStringBuilder 是 StringBuffer 和 StringBuilder 的父类,定义了一些字符串的基本方法。StringBuffer 对方法加了同步锁,所以线程是安全的。StringBuilder 并没有对方法进行同步锁,线程是非安全的

    • 性能

      每次对 String 类型进行改变的时候,都会生成一个新的 String 对象,然后指向新 String 对象。StringBuffer 每次都会对 StringBuffer 对象本身进行操作,而不是生成新的。相同情况下 StringBuilder 要比 StringBuffer 性能更好,但付出的代价就是线程不安全的风险

  • String 为什么是不可变的?

    String 类中使用 final 修饰字符数组来保存字符串,但保存的数组被 final 修饰且为私有,并且 String 类没有提供修改这个字符串的方法,再者就是 String 类被 final 修饰,导致其不能被继承,进而又避免了有子类破坏 String 不可变【在 Java 9 之后,String、StringBuffer、StringBuilder 的实现改用了 byte 数组存储字符串】

  • java 9 为何要将 String 底层实现由 char[] 改成了 byte[]?

    新版的 String 支持了两种编码方案:Latin-1 和 UTF-16。如果字符串包含的汉字没有超过 Latin-1 范围内的字符,那就拿 Latin-1 作为编码方案。而在 Latin-1 编码下,byte 占一个字节,char 占用两个字节,byte 相较 char 节省一半的内存空间

  • 字符串拼接用 + 还是 StringBuilder

    字符串对象通过 + 拼接的方式,实际上是 StringBuilder 调用了 append() 方法实现的,拼接完以后调用了 toString 得到新的 String 对象。但在循环内使用拼接的话,会导致创建过多的 StringBuilder 对象【编译器不会创建单个 StringBuilder 复用的情况,意味着每一次循环就会创建一个 StringBuilder 对象】

  • String中equals() 和 Object中equals() 有何区别

    String 中的 equals 方法是被重写过的,比较的是值是否相等,而 Object 中的 equals 方法比较的是对象的内存地址是否相等

  • 字符串常量池的作用了解吗?

    是 JVM 为了提升性能和减少内存消耗搞的一块区域,主要是为了避免字符串的重复创建

  • String s1 = new String("abc");这句话创建了几个字符串对象?

    如果字符串常量池中不存在 "abc" 字符串,则会首先在字符串常量池中创建,然后在堆内存中创建,因此创建总共两个字符串对象

    如果字符串常量池中已经存在 "abc" 字符串,则只会在堆内存中创建一个字符串对象

  • String 中 intern 方法有什么作用?

    分两种情况:1.如果字符串常量池中保存了对应的字符串对象,就直接返回该对象2.如果常量池中没有保存对应字符串对象,就在常量池中创建一个指向该字符串对象并返回

    // 在堆中创建字符串对象”Java“
    // 将字符串对象”Java“的引用保存在字符串常量池中
    String s1 = "Java";
    // 直接返回字符串常量池中字符串对象”Java“对应的引用
    String s2 = s1.intern();
    // 在堆中在单独创建一个字符串对象
    String s3 = new String("Java");
    // 直接返回字符串常量池中字符串对象”Java“对应的引用
    String s4 = s3.intern();
    // s1 和 s2 指向的是堆中的同一个对象
    System.out.println(s1 == s2); // true
    // s3 和 s4 指向的是堆中不同的对象
    System.out.println(s3 == s4); // false
    // s1 和 s4 指向的是堆中的同一个对象
    System.out.println(s1 == s4); //true
    
  • String 类型的变量喝常量做 " + " 时发生了什么?

results matching ""

    No results matching ""