Contents

常见面试题-2

面向对象与面向过程的区别

  • 面向过程是将解决问题拆分成一个一个方法去一步一步执行。
  • 面向对象是将问题的相关内存封装成一个一个对象,由对象去执行方法。

对象的相等和引用相等

  • 对象的相等指的是对象所有内容相等
  • 对象的引用相等指的是对象的实际地址相等

构造方法的特点

  • 和类名相同
  • 无返回值
  • 可以重载,无法重写

面向对象三大特征

  • 封装:指将一系列属性和方法封装到一个对象中,外部不可以直接访问这些属性和方法,但是对象可以提供访问的方法。
  • 继承:对象之间可以相互继承,Java只允许单继承。子类拥有父类的所有属性和方法,但是对于private修饰的内容只是拥有无法访问。子类可以拥有自己的方法,即对父类进行拓展。
  • 多态:就是一个对象具有多个形态,例如一个动物类的具体实例可以是猫、狗,猫狗都继承了动物。多态中如果子类重写了父类的方法,那实际执行的是子类的方法,如果没重写执行的是父类的方法。一句话就是编译看左边,运行看右边。

接口与抽象类

  • 接口关键字是interface。定义了可以做什么,一个类可以实现多个接口。接口中的所有字段都必须是public final static 修饰的,并且接口无构造方法。例如SpringBoot中最常用的Service接口
  • 抽象类的关键字是abstract。主要定义了是什么。一个类只能继承一个抽象类。抽象类中的字段可以是任何修饰符进行修饰,也包含构造方法。一般作为一些子类的公共父类,抽取一些公共的方法。

深拷贝与浅拷贝

  • 浅拷贝会在堆上创建一个新的对象,但是如果对象内部某些属性值是引用类型,就只会拷贝引用类型,不会继续拷贝对象。
  • 深拷贝是对对象进行递归拷贝,引用类型也会拷贝一个实际的对象。

Object(重点)

Object常用方法

  • equals:比较两个对象的内容是否相等
  • getClass:final修饰,不允许子类重写,放回当前的对象的Class对象
  • hashCode:返回对象的哈希码
  • clone:就是拷贝一份对象返回
  • toString:就是对象的自我介绍,返回对象的字符串形式,可以打印出字段的值。
  • finalize:实例被回收时触发的方法
  • notify:一般必须放在同步代码块中使用,用于唤醒一个线程
  • wait:使得一个线程进入等待状态

== 与 equals 的区别

  • == 在基本类型时比较的是值,但是在引用类型时比较的是实际的地址值
  • equals是根据重写的方法比较两个对象的内容是否完全一致。如果没有重写的话使用的是父类的equals,实际上还是 ==
  • String包装类的equals已经重写过,并且由于字符串常量池的原因,创建一个字符串时是会先去字符串常量池查找,有就放回,没有则创建再返回。但是 new String(“abc”) 始终都会创建一个对象,但是字符串常量池没有的话会再创建一个对象放到字符串常量池并将引用赋值给创建的对象

hashCode的作用

  • hashCode是返回类的哈希编码,一般是int类型的整数
  • hashCode的存在能够帮助我们快速缩小检索的范围。例如再HashSet中,判断一个元素是否存在,会先通过hashCode获取对象的哈希码,然后直接定位到哈希表的位置,在该位置的链表或则红黑树中进一步判断是否存在重复元素。
  • 由于哈希算法对于不同的对象可能会返回相等的哈希码,所以hashCode和equals必须同步重写。

hashCode 和 equals 的三条铁律

  • 如果两个对象相等,那么hashCode和equals一定相等
  • 如果两个对象的hashCode相等,他们的equals不一定相等
  • 如果两个对象不相等,那么他们的hashCode可能相等,但是equals一定不相等

String(重点)

String、StringBuffer、StringBuilder

  • String是不可变的,其原因是其存储的字符数组(Java9中变成了字节数组)是由private final修饰符并且没有提供方法访问,以及其类名也是由final修饰的,无法被继承。
  • 只有不可变的才能确保一个String对象存在多个引用,也就是共享一个内存地址
  • String因为是不可变的,所以是线程安全的。StringBuffer也是是线程安全的,因为其在方法上加了同步锁。StringBuilder是线程不安全的。
  • 性能方面,String每次有新的对字符串就会创建一个新的对象。StringBuffer和StringBuilder是在本身的基础上进行修改,并且在数据量小的情况下StringBuilder对StringBuffer性能的提升不高
  • 总结就是操作数据少就使用String,数据大并且单线程就用StringBuilder,数据大且多线程就用StringBuffer

字符串拼接使用 + 还是 StringBuilder

  • 首先字符串拼接使用 + 本质上还是使用了StringBuilder的append方法进行拼接
  • 在单次的字符串拼接可以直接使用 +
  • 在循环中多次进行字符串拼接,使用String +的方式会多次创建StringBuilder对象,所以只用StringBuilder进行拼接较好

字符串常量池的作用

  • 在JVM模块已经详细探讨过,就是JVM用于提高的性能而专门为String创建的一块区域。创建字符串时会先去字符串常量池中进行查询,如果存在则直接返回,不存在创建对象并将引用地址加入常量池再返回。字符串常量池的实现时stringTable,本质上一个hashTable,存储字符串的key值和引用地址。

intern方法的作用

  • 判断一个对象在字符串常量池中是否是唯一的,如果已经在字符串常量池中存在则直接返回该字符串对象的引用,如果不存在则将该字符串的引用加入到字符串常量池中

字符串变量和常量的 + 凭借

先看一段代码

String str1 = "str";
String str2 = "ing";
String str3 = "str" + "ing";
String str4 = str1 + str2;
String str5 = "string";
System.out.println(str3 == str4);//false
System.out.println(str3 == str5);//true
System.out.println(str4 == str5);//false
  • 编译器对于可以确定的字符串会进行优化,因此str3就会被优化成String str3 = “string"和str5地址相同。
  • 对于str4本质上是调用StringBuilder的append方法拼接str1和str2,是引用类型的,编译时无法确定,因此其实际上是创建一个新的对象,就不喝str3或str5相等
  • 但是如果把str1和str2都用final关键字修饰,那么他就是一个可确定的不可变的常量,因此无论是str3还是str4都是会优化成"string”,一个相同的对象