返回顶部
首页 > 资讯 > 后端开发 > Python >Java面试题冲刺第一天--基础篇1
  • 896
分享到

Java面试题冲刺第一天--基础篇1

2024-04-02 19:04:59 896人浏览 薄情痞子

Python 官方文档:入门教程 => 点击学习

摘要

目录面试题1:Java 中操作字符串都有哪些类?它们之间有什么区别? 正经回答:深入追问:追问1:这三者在效率上怎么说?追问2:那StringBuffer和StringBuffer线

面试题1:Java 中操作字符串都有哪些类?它们之间有什么区别? 正经回答:

操作字符串的类有:StringStringBufferStringBuilder

String 和 StringBuffer、StringBuilder 的区别在于 String 声明的是不可变的对象,每次操作都会生成新的 String 对象,然后将指针指向新的 String 对象,而 StringBuffer、StringBuilder 可以在原有对象的基础上进行操作,所以在经常改变字符串内容的情况下最好不要使用 String。

而StringBuffer 和 StringBuilder 最大的区别在于,StringBuffer 是线程安全的,而 StringBuilder 是非线程安全的,但 StringBuilder 的性能却高于 StringBuffer,所以在单线程环境下推荐使用 StringBuilder,多线程环境下推荐使用 StringBuffer。

String StringBuffer StringBuilder
类是否可变 不可变(Final) 可变 可变
功能介绍 每次对String的操作都会在“常量池”中生成新的String对象 任何对它指向的字符串的操作都不会产生新的对象。每个StringBuffer对象都有一定的缓冲区容量,字符串大小没有超过容量时,不会分配新的容量,当字符串大小超过容量时,自动扩容 功能与StringBuffer相同,相比少了同步,执行速度更快
线程安全性 线程安全 线程安全 线程不安全
使用场景推荐 单次操作或循环外操作字符串 多线程操作字符串 单线程操作字符串

深入追问:

追问1:这三者在效率上怎么说?

StringBulider > StringBuffer > String

String <(StringBuffer,StringBuilder)的原因?

  • String:字符串常量
  • StringBuffer:字符串变量(有同步锁)
  • StringBuilder:字符串变量(无同步锁)

从上面的名字可以看到,String是"字符串常量",也就是不可改变的对象。源码如下:


public final class String{}

对于上面这句话的理解你可能会产生这样一个疑问 ,比如这段代码:


String str = "唐伯虎";
str = str + "点香烟";
System.out.print(str); // result : "唐伯虎点香烟"

我们明明改变了String型的变量str啊,为什么说是没有改变呢?我们来看一下这张对String操作时内存变化的图:

在这里插入图片描述

我们可以看到,初始String值为"唐伯虎",然后在这个字符串后面加上新的字符串"点香烟",这个过程是需要重新在栈堆内存中开辟内存空间的,最终得到了"唐伯虎点香烟"字符串也相应的需要开辟内存空间,这样短短的两个字符串,却需要开辟三次内存空间,不得不说这是对内存空间的极大浪费,执行效率同理。

为了应对经常性操作字符串的场景,Java才提供了其他两个操作字符串的类 —— StringBuffer、StringBuilder。

他们俩均属于字符串变量,是可改变的对象,每当我们用它们对字符串做操作时,实际上是在一个对象上操作的,这样就不会像String一样创建一些而外的对象进行操作了,速度自然就相对快了。

我们一般在StringBuffer、StringBuild类上的主要操作是 append 和 insert 方法,这些方法允许被重载,以接受任意类型的数据。每个方法都能有效地将给定的数据转换成字符串,然后将该字符串的字符追加或插入到字符串缓冲区中。append 方法始终将这些字符添加到缓冲区的末端;而 insert 方法则在指定的点(index)添加字符。

  1. StringBuilder一个可变的字符序列是jdk1.5新增的。此类提供一个与 StringBuffer 兼容的 api,但不保证同步。该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)。如果可能,建议优先采用S
  2. tringBuilder类,因为在大多数实现中,它比 StringBuffer 要快。且两者的方法基本相同。然而在应用程序要求线程安全的情况下,则必须使用 StringBuffer 类。

String 类型和 StringBuffer、 StringBuild类型的主要性能区别其实在于 String 是不可变的对象(final), 因此在每次对 String 类型进行改变的时候其实都等同于在堆中生成了一个新的 String 对象,然后将指针指向新的 String 对象,这样不仅效率低下,而且大量浪费有限的内存空间,所以经常改变内容的字符串最好不要用 String 。因为每次生成对象都会对系统性能产生影响,特别是当内存中的无引用对象过多了以后, JVMGC 开始工作,那速度是一定会相当慢的。另外当GC清理速度跟不上new String的速度时,还会导致内存溢出Error,会直接kill掉主程序!报错如下:

Caused by: java.lang.OutOfMemoryError: GC overhead limit exceeded

Exception in thread "I/O dispatcher 3797236" java.lang.OutOfMemoryError: GC overhead limit exceeded

追问2:那StringBuffer和StringBuffer线程安全主要差在哪里呢?

StringBuffer和StringBuilder可以算是双胞胎了,这两者的方法没有很大区别。但在线程安全性方面,StringBuffer允许多线程进行字符操作。这是因为在源代码中StringBuffer的很多方法都被关键字synchronized 修饰了,而StringBuilder没有。

synchronized的含义:   

每一个类对象都对应一把锁,当某个线程A调用类对象O中的synchronized方法M时,必须获得对象O的锁才能够执行M方法,否则线程A阻塞。一旦线程A开始执行M方法,将独占对象O的锁。使得其它需要调用O对象的M方法的线程阻塞。只有线程A执行完毕,释放锁后。那些阻塞线程才有机会重新调用M方法。这就是解决线程同步问题的锁机制。 >  了解了synchronized的含义以后,大家可能都会有这个感觉。多线程编程中StringBuffer比StringBuilder要安全多了 ,事实确实如此。如果有多个线程需要对同一个字符串缓冲区进行操作的时候,StringBuffer应该是不二选择。

注意:是不是String也不安全呢?事实上不存在这个问题,String是不可变的。线程对于堆中指定的一个String对象只能读取,无法修改。试问:还有什么不安全的呢?

实际应用场景中:

  • 如果不是在循环体中进行字符串拼接的话,直接使用 String 的 “+” 就好了;
  • 单线程循环中操作大量字符串数据 → StringBuilder.append();
  • 多线程循环中操作大量字符串数据 → StringBuffer.append();

面试题2:请你说一下Error 和 Exception 区别是什么?

正经回答:

Error 和 Exception 都是 Throwable 的子类,在Java中只有Throwable类型的实例才可以被抛出或者捕获,它是异常处理机制的基本类型。

在这里插入图片描述

  • Exception和Error体现了java平台设计者对不同异常情况的分类,Exception是程序正常运行中,可以预料的意外情况,可能并且应该被捕获,进行相应的处理。
  • Error是指正常情况下,不大可能出现的情况,绝大部分的Error都会导致程序处于非正常的、不可恢复的状态。既然是非正常情况,不便于也不需要捕获。常见的比如OutOfMemoryError之类都是Error的子类。
  • Exception又分为可检查(checked)异常和不可检查(unchecked)异常。可检查异常在源代码里必须显式的进行捕获处理,这是编译期检查的一部分。不可检查时异常是指运行时异常,像NullPointerException、ArrayIndexOutOfBoundsException之类,通常是可以编码避免的逻辑错误,具体根据需要来判断是否需要捕获,并不会在编译期强制要求。

面试题3:== 和 equals 的区别是什么

正经回答:

  • == : 它的作用是判断两个对象的地址是不是相等。即,判断两个对象是不是同一个对象。(基本数据类型 == 比较的是值,引用数据类型 == 比较的是内存地址)
  • equals(): 它的作用也是判断两个对象是否相等。但它一般有两种使用情况:

情况1:类没有覆盖 equals() 方法。则通过 equals() 比较该类的两个对象时,等价于调用了Object类的equals() 方法,也就是通过“==”比较这两个对象。


// Object类中的equals() 方法
public boolean equals(Object obj) {
    return (this == obj);
}

情况2:类覆盖了 equals() 方法。一般,我们都会覆盖 equals() 方法来两个对象的内容相等;若它们的内容相等,则返回 true (即,认为这两个对象相等)。


// String类中的equals() 方法,已覆盖,用于比较内容
public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = value.length;
        if (n == anotherString.value.length) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;
            while (n-- != 0) {
                if (v1[i] != v2[i])
                    return false;
                i++;
            }
            return true;
        }
    }
    return false;
}

深入追问:

追问1:如果我们不重写equals() 方法,会怎么样?

举例说明:

重点说明:是否重写Object类中的equals方法,会对结果造成的影响


public static void main(String[] args) {
    // 字符串比较
    String a = "陈哈哈";
    String b = "陈哈哈";
    if (a == b) {// true  a==b
        System.out.println("a==b");
    }
    if (a.equals(b)) {// true  a.equals(b)
        System.out.println("a.equals(b)");
    }
    // StringBuffer 对象比较,由于StringBuffer没有重写Object的equal方法,因此结果出现错误
    StringBuffer c = new StringBuffer("陈哈哈");
    StringBuffer d = new StringBuffer("陈哈哈");
    if (c == d) {// false  c != d
        System.out.println("c == d");
    } else {
        System.out.println("c != d");
    }
    if (c.equals(d)) { // false 调用了Object类的equal方法
        System.out.println("StringBuffer equal true");
    }else {
        System.out.println("StringBuffer equal false");
    }
}
  • object的equals方法是比较的对象的内存地址,而String的equals方法比较的是对象的值。
  • 因为String中的equals方法是被重写过的,而StringBuilder没有重写equals方法,从而调用的是Object类的equals方法,也就相当于用了 ==;

追问2:重写equals的同时,我们需要重写hashCode()方法么?为什么?

在重写equals()方法时,也有必要对hashCode()方法进行重写,尤其是当我们自定义一个类,想把该类的实例存储在集合中时。  

hashCode方法的常规约定为:值相同的对象必须有相同的hashCode,也就是equals()结果为相同,那么hashcode也要相同,equals()结果为不相同,那么hashcode也不相同;

当我们使用equals方法比较说明对象相同,但hashCode不同时,就会出现两个hashcode值,比如在HashMap中,就会认为这是两个对象,因此会出现矛盾,说明equals方法和hashCode方法应该成对出现,当我们对equals方法进行重写时,也要对hashCode方法进行重写。

可以通过ide快捷键快速生成两个方法,假设现在有一个学生Student类,其中有 age 和 name 两个特征。生成代码如下:


@Override
public boolean equals(Object o){
//首先比较两个的地址值是否相同,如果相同,那内容也一定相同
	if(this == o) return true;
//如果o为空值或者两个对象的类型是否相同,如果类型不同或者o为空值则内容一定不同
	if(o == null || getClass() != o.getClass()) return false;
//将object类型的实例强转为Student类型
  	Student student = (Student)o;
//比较两个实例的age是否相同
	if(age != student.age) return false;
//在比较name是否相同
	return name != null ? name.equals(student.name ) : student.name == null;
}
@Override
public int hashCode() {
	int result = age;
	result = 31 * result + (name != null ? name.hashCode() : 0);
	return result;
}

总结

本篇文章就到这里了,希望能给你带来帮助,也希望您能够多多关注编程网的更多内容!

--结束END--

本文标题: Java面试题冲刺第一天--基础篇1

本文链接: https://lsjlt.com/news/130351.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Java面试题冲刺第一天--基础篇1
    目录面试题1:Java 中操作字符串都有哪些类?它们之间有什么区别? 正经回答:深入追问:追问1:这三者在效率上怎么说?追问2:那StringBuffer和StringBuffer线...
    99+
    2024-04-02
  • Java面试题冲刺第五天--基础篇2
    目录面试题1:说一下抽象类和接口有哪些区别?正经回答:深入追问:追问1:说一说你对抽象类的理解吧,他到底是干啥用的追问2:用抽象类实现一个接口,和普通类实现接口会有什么不同么?追问3...
    99+
    2024-04-02
  • Java面试题冲刺第十七天--基础篇3
    目录面试题1:JDK1.8的新特性有哪些?接口的默认和静态方法:Lambda 表达式:方法与构造函数引用:函数式接口:Annotation 注解:支持多重注解:新的日期时间 API:...
    99+
    2024-04-02
  • Java面试题冲刺第二天--Redis篇
    目录面试题1:为什么要用 Redis ?业务在哪块儿用到的?正经回答:深入追问: 追问1:Redis里有哪些数据类型?追问2:Redis与Memcached有哪些区别?追问3:那Re...
    99+
    2024-04-02
  • Java面试题冲刺第七天--Spring框架1
    目录面试题1:能简单说一下你对Spring框架的理解么?追问1:常见的Core组件有哪些?面试题2:谈谈对Spring IOC的理解追问1:Spring中的bean的作用域有...
    99+
    2024-04-02
  • Java面试题冲刺第二十天--算法(1)
    目录手撸算法1:查找数组中重复元素和重复元素的个数1. 两层循环比较方式2. 转成Map集合处理方式手撸算法2:写个二分查找demo吧手撸算法3:把两个有序数组合并成一个有序数组总结...
    99+
    2024-04-02
  • Java面试题冲刺第二十一天--JVM
    目录面试题1:你遇到过哪些OOM情况,什么原因造成的?怎么解决的?Java heap spaceGC overhead limit exceeded Permgen spa...
    99+
    2024-04-02
  • Java面试题冲刺第十一天--集合框架篇(2)
    目录面试题1:说一下 HashMap 的实现原理?正经回答:深入追问: 追问1:如何实现HashMap的有序?追问2:那TreeMap怎么实现有序的?追问3:put方法原理是怎么实现...
    99+
    2024-04-02
  • Java面试题冲刺第六天--网络编程1
    目录面试题1:说一下TCP连接的三次握手和四次挥手吧正经回答:深入追问:追问1:为什么连接的时候是三次握手,关闭的时候却是四次握手?追问2:如果已经建立了连接,但是客户端突然出现故障...
    99+
    2024-04-02
  • Java面试题冲刺第三天--集合框架篇
    目录面试题1:对比 Vector、ArrayList、LinkedList 有何区别?适合在什么场景下使用正经回答:深入追问:追问1:多线程场景下就不能使用ArrayList么?追问...
    99+
    2024-04-02
  • Java面试题冲刺第九天--MyBatis
    目录面试题1:你怎么理解ORM框架,常见的ORM框架都有哪些?正经回答:追问1:大家都在用Mybatis,Mybatis都有哪些优势?面试题2:相比较Hibernate与Mybati...
    99+
    2024-04-02
  • Java面试题冲刺第十天--MyBatis2
    目录面试题1:说说你对Mybatis的理解?追问1:说一下MyBatis的工作原理和流程吧。追问2:列举几个MyBatis的核心组件,说说分别干啥用?面试题2:(问几个实际使用的问题...
    99+
    2024-04-02
  • Java面试题冲刺第四天--数据库
    目录面试题1:你对数据库优化有哪些了解呀?正经回答:深入追问:追问1:那你对SQL优化方面有哪些技巧呢?追问2:嗯,那你说一下为什么不建议用SELECT * 呢?二、SELE...
    99+
    2024-04-02
  • Java面试题冲刺第二十二天-- Nginx
    目录面试题1:谈一下你对 Nginx 的理解为啥我们总说Nginx好用?追问1:正向代理和反向代理区别在哪?正向代理面试题2:常用的 Nginx 做负载均衡的策略有哪些?1.指定权重...
    99+
    2024-04-02
  • Java面试题冲刺第二十七天--JVM2
    目录面试题1:简单说一下java的垃圾回收机制。面试题2:JVM会在什么时候进行GC呢?追问1:介绍一下不同代空间的垃圾回收机制 追问2:能说一下新生代空间的构成与执行逻辑...
    99+
    2024-04-02
  • Java面试题冲刺第二十九天--JVM3
    目录面试题1:如何判断对象是否存活1.引用计数算法2.可达性分析算法面试题2:哪些对象可以作为GC Roots?面试题3:你了解的对象引用方式都有哪些?1 强引用2 软引用3 弱引用...
    99+
    2024-04-02
  • Java面试题冲刺第八天--Spring框架2
    目录面试题1:聊一下你对AOP的理解吧?追问1:Advice通知的类型有哪几种?追问2:在同一个切面(Aspect)中,不同Advice的执行顺序面试题2:AspectJ AOP 和...
    99+
    2024-04-02
  • Java面试题冲刺第十四天--PRC框架
    目录面试题1:说说你对RPC框架的理解?追问1:RPC框架实现原理是什么样的1、建立通信2、服务寻址3、网络传输4、服务调用面试题2:常见的RPC框架有哪些?面试题3:说说RPC和S...
    99+
    2024-04-02
  • Java面试题冲刺第十二天--数据库(2)
    目录面试题2:并发场景下事务会存在哪些数据问题? 正经回答:深入追问:追问1:那Innodb是如何解决幻读问题的呢?面试题3:说一下MySQL中你都知道哪些锁?正经回答:深入追问: ...
    99+
    2024-04-02
  • Java面试题冲刺第十三天--数据库(3)
    目录面试题1:MySQL有哪些数据类型?追问1:char 和 varchar 的区别是什么?1、固定长度 & 可变长度2、存储方式3、存储容量4、思考:既然VARCHAR长度...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作