Java面试题归档(二)

Java面试题归档(二)

根据网站JavaGuide整理

面向对象基础

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

  • 面向过程把解决问题的过程拆成一个个的方法,通过一个个方法的执行解决问题;
  • 面向对象会先抽象出对象,然后用对象执行方法的方式解决问题。

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

  • 对象的相等一般比较的时内存中存放的内容是否相等;
  • 引用相等一般是比较他们指向的内存地址是否相等。

面向对象的三大特征

  • 封装

    封装是指把一个对象的状态信息封装起来,提供一些可以被外界访问到的方法来操作属性。

  • 继承

    继承是使用已经存在的类的定义作为基础建立新的类的技术,提高了代码复用,提高了程序的可维护性,提高了开发效率。

    子类不能访问父类的私有属性和方法;

    子类可以用自己的方式实现父类的方法。

  • 多态

    多态的具体表现为父类的引用指向子类的实例。

    多态的特点:

    对象类型和引用类型具有继承/实现的关系;

    引用类型变量发出的方法调用是哪一个类的方法,在运行期间才能确定;

    多态不能调用只在子类中存在但是父类不存在的方法;

    如果子类重写了父类的方法,那么执行的子类重写之后的方法,如果子类没有覆盖父类中的方法,执行的是父类的方法。

接口和类的共同点和区别

  • 共同点:

    • 都不能被实例化;

    • 都可以包含抽象方法;

    • 都可以由默认实现的方法。

  • 区别:

    • 接口强调实现类的行为,抽象类强调代码复用、所属关系;

    • 一个类只能继承一个类,但是可以实现多个接口;

    • 接口中的成员变量只能是public static final 类型的,不能修改且必须有初始值,而抽象类成员变量默认default,而在子类中被重新定义

深拷贝、浅拷贝、引用拷贝

  • 浅拷贝:浅拷贝会在堆上创建一个新的对象(区别于引用拷贝), 不过,如果原对象内部的属性是引用类型的话,浅拷贝会复制内部对象的引用地址,即拷贝对象和元对象共用一个内部对象。

    clone()方法本身是浅拷贝,如果想实现深拷贝需要自己改造。

  • 深拷贝:深拷贝会完全复制整个对象,包括这个对象所包含的内部对象。

  • 引用拷贝:两个不同的引用指向一个对象。

Java常见类

Object常见的类方法有哪些

/**
*	native方法,用于返回当前运行时对象的Class对象,使用了final关键字修饰,故不允许子类重写
*/
public final native Class<?> getClass();

/**
*	native方法,用于返回对象的哈希码,主要使用在hash表中,比如jdk中的hashMap()
*/
public native int hashCode();
/**
*	用于比较2个对象的内存地址是否相等,String 类对该方法进行重写用于比较字符串的值是否相等
*/
public boolean equals(Object obj);
/**
*	native方法,用于创建并返回当前对象的一份拷贝
*/
protected native Object clone() thorws CloneNotSupportedException;
/**
*	返回对象的名字实例的哈希码的16进制的字符串,建议Object的子类都重写这个方法
*/
public String toString();
/**
*	native方法,并且不能重写,唤醒一个在此对象监视器上等待的线程(监视器相当于时锁的概念), 如果存在多个线程则会唤醒任意一个。
*/
public final native void notify();
/**
*	native方法,并且不能重写,和notify的区别时会唤醒在此对象监视器上等待的所有线程
*/
public final native void notifyAll();
/**
*	native方法,并且不能重写,暂停线程的执行。注意:sleep方法没有释放锁,而wait方法释放了锁
*/
public final native void wait();
/**
*	实例被垃圾回收器回收的时候触发的操作
*/
protected void finalize() thorws Throwable{ }

== 和 equals() 的区别

  • 对于基本数据类型来说,== 比较的是值, equals不能作用域基本数据类型的变量。
  • 对于引用类型来说,== 比较的是对象的内存地址,如果重写了equals比较的是值,没有重写比较的是地址。

简而言之,如果没有重写equals,则两者没有区别,重写之后equals比较的是值(String类重写过)。

hashCode有什么用

  • hashCode() 的作用是 获取哈希码(int整数), 也称为散列码。哈希码的作用是确定该对象在哈希表中的索引位置,将对象的内存地址转换为整数后返回。

  • hashCode都是用于比较两个对象是否相等。

    • 为什么JDK要同时提供这两个方法?

      因为在一些容器(比如HashMap, HashSet)中,有了hashCode()后,判断元素是否在对应容器中的效率更高;

    • 为什么不只提供hashCode方法呢?

      这是因为两个对象的hashCode值相等并不代表两个对象就相等;

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

      因为hashCode()所使用的算法也许会让多个对象回传相同的hashCode值

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

  • 两个相等的对象的hashCode值必须是相等,不重写的话很有可能equals()方法判断是相等的两个对象的hashCode值却不相等。

String

String、StringBuffer、StringBuilder的区别?

  • 可变性

    • String 是不可变的(源码中Stirng 类是由final修饰的且为私有,没有暴露修改字符串的方法)。

    • StringBuilder 和 StringBuffer 都继承自 AbstractStringBuilder 类,在 AbstractStringBuilder 中也是使用字符数组保存字符串,不过没有使用 final 和 private 关键字修饰。最关键的是 AbstractStringBuilder 类还提供了许多修改字符串的方法,比如 append 方法。

  • 线程安全性

    • String 中的对象是不可变的,线程安全。
    • AbstractStringBuilder 定义了一些字符串的基本操作,StringBuffer 对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的,StirngBuilder 是线程非安全的。
  • 性能

    • 每次对 String 类型进行改变的时候,都会生成一个新的 String 对象,然后将指针指向新的 String 对象。
    • StringBuffer 每次都会对 StirngBuffer 对象本身进行操作,而不是生成新的对象并改变引用。
    • StringBuilder 比 StringBuffer 更快,但是要承担线程不安全的风险。

字符串拼接用 “+” 还是 StringBuilder

在循环内使用 “+” 进行字符串拼接的话,存在比较明显的缺陷:编译器不会创建单个StringBuilder以复用,会导致创建太多的StringBuilder对象。如果直接使用字符串拼接的话,就不会存在这个问题了。

String#equals() 和 Object#equals()有何区别

String#equals() 是被重写过的,比较String字符串是否相等,Object#equals() 比较的是对象的内存地址。

字符串常量池

字符串常量池是JVM为了提升性能和减少内存小号针对字符串(String类)专门开辟的一块区域,主要目的是为了避免字符串的重复创建。

// 在堆中创建字符串对象"ab"
// 将字符串对象"ab"的引用保存在字符串常量池中
String aa = "ab";
// 直接返回字符串常量池中的字符串对象"ab"的引用
String bb = "ab";
System.out.println(aa==bb); //true
  • String s1 = new String(“abc”);这句话创建了字符串对象?

    会创建1到2个字符串对象。

    • 如果字符串常量池中不存在字符串对象“abc”的引用,那么会在堆中创建2个字符串对象“abc”;
    • 如果字符串常量池中已经存在了字符串对象的引用,那么只会在堆中创建1个字符串对象“abc”。
  • intern 方法有什么作用?

    • 如果字符串常量池中保存了对应字符串对象的引用,那么就返回该引用;
    • 如果没有保存,那么就创建一个并且返回。

String 类型的变量和常量做+运算时发生了什么?

常量折叠:把常量表达式的值求出来作为常量嵌在最终生成的代码中。对于 String str3 = “str” + “ing”; 会优化成 String str3 = “string”;

引用的值在程序编译期间是无法确定的,编译器无法对其进行优化。

对象引用和“+”的字符串拼接方式,实际上是通过StringBuilder调用append() 方法进行实现的,拼接完成后会调用toString() 得到一个String对象。

String str4 = new StringBuilder().append(str1).append(str2).toString();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值