加载中...
avatar
文章
42
标签
25
分类
21
首页
Java
Spring全家桶
  • Spring
  • SpringBoot
  • SpringCloud
JVM
源码
  • Mybatis
  • HashMap
归档
其他
  • 互联网电子书汇总
  • JAVA八股文指南
  • 历史
  • 相册
关于
Logo码农StormlingJava系列(三)| 常用类
搜索
首页
Java
Spring全家桶
  • Spring
  • SpringBoot
  • SpringCloud
JVM
源码
  • Mybatis
  • HashMap
归档
其他
  • 互联网电子书汇总
  • JAVA八股文指南
  • 历史
  • 相册
关于

Java系列(三)| 常用类

发表于2021-09-18|更新于2025-01-07|Java
|总字数:2.3k|阅读时长:8分钟|浏览量:

String

String 是 Java 基本数据类型吗?可以被继承吗?

String 是 Java 基本数据类型吗?

不是。Java 中的基本数据类型只有 8 个:byte、short、int、long、float、double、char、boolean;除了基本类型(primitive type),剩下的都是引用类型(reference type)。

String 是一个比较特殊的引用数据类型。

String 类可以继承吗?

不行。String 类使用 final 修饰,是所谓的不可变类,无法被继承。

String 和 StringBuilder、StringBuffer 的区别?

  • String:String 的值被创建后不能修改,任何对 String 的修改都会引发新的 String 对象的生成。
  • StringBuffer:跟 String 类似,但是值可以被修改,使用 synchronized 来保证线程安全。
  • StringBuilder:StringBuffer 的非线程安全版本,性能上更高一些。

String str1 = new String(“abc”) 和 String str2 = “abc” 和 区别?

两个语句都会去字符串常量池中检查是否已经存在 “abc”,如果有则直接使用,如果没有则会在常量池中创建 “abc” 对象。

但是不同的是,String str1 = new String("abc") 还会通过 new String() 在堆里创建一个 “abc“ 字符串对象实例。所以后者可以理解为被前者包含。

String s = new String(“abc”) 创建了几个对象?

很明显,一个或两个。如果字符串常量池已经有 “abc”,则是一个;否则,两个。

当字符创常量池没有 “abc”,此时会创建如下两个对象:

  • 一个是字符串字面量 “abc“ 所对应的、字符串常量池中的实例
  • 另一个是通过 new String() 创建并初始化的,内容与 “abc“ 相同的实例,在堆中。

String 不是不可变类吗?字符串拼接是如何实现的?

String 的确是不可变的,“**+**” 的拼接操作,其实是会生成新的对象。

例如:

String a = "hello ";
String b = "world!";
String ab = a + b;

在 jdk1.8 之前,a 和 b 初始化时位于字符串常量池,ab 拼接后的对象位于堆中。经过拼接新生成了 String 对象。如果拼接多次,那么会生成多个中间对象。

内存如下:

在 Java8 时 JDK 对 “+” 号拼接进行了优化,上面所写的拼接方式会被优化为基于 StringBuilder 的 append 方法进行处理。Java 会在编译期对 “+” 号进行处理。

下面是通过 javap -verbose 命令反编译字节码的结果,很显然可以看到 StringBuilder 的创建和 append 方法的调用。

stack=2, locals=4, args_size=1
     0: ldc           #2                  // String hello
     2: astore_1
     3: ldc           #3                  // String world!
     5: astore_2
     6: new           #4                  // class java/lang/StringBuilder
     9: dup
    10: invokespecial #5                  // Method java/lang/StringBuilder."<init>":()V
    13: aload_1
    14: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
    17: aload_2
    18: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
    21: invokevirtual #7                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
    24: astore_3
    25: return

也就是说其实上面的代码其实相当于:

String a = "hello ";
String b = "world!";
StringBuilder sb = new StringBuilder();
sb.append(a);
sb.append(b);
String ab = sb.toString();

此时,如果再笼统的回答:通过加号拼接字符串会创建多个 String 对象,因此性能比 StringBuilder 差,就是错误的了。因为本质上加号拼接的效果最终经过编译器处理之后和 StringBuilder 是一致的。

当然,循环里拼接还是建议用 StringBuilder,为什么,因为循环一次就会创建一个新的 StringBuilder 对象,大家可以自行实验。

intern 方法有什么作用?

JDK 源码里已经对这个方法进行了说明:

* <p>
* When the intern method is invoked, if the pool already contains a
* string equal to this {@code String} object as determined by
* the {@link #equals(Object)} method, then the string from the pool is
* returned. Otherwise, this {@code String} object is added to the
* pool and a reference to this {@code String} object is returned.
* <p>

意思也很好懂:

  • 如果当前字符串内容存在于字符串常量池(即 equals() 方法为 true,也就是内容一样),直接返回字符串常量池中的字符串
  • 否则,将此 String 对象添加到池中,并返回 String 对象的引用

Integer

Integer a= 127,Integer b = 127;Integer c= 128,Integer d = 128;,相等吗?

答案是 a 和 b 相等,c 和 d 不相等。

  • 对于基本数据类型 == 比较的值
  • 对于引用数据类型 == 比较的是地址

Integer a= 127 这种赋值,是用到了 Integer 自动装箱的机制。自动装箱的时候会去缓存池里取 Integer 对象,没有取到才会创建新的对象。

如果整型字面量的值在 - 128 到 127 之间,那么自动装箱时不会 new 新的 Integer 对象,而是直接引用缓存池中的 Integer 对象,超过范围 a1==b1 的结果是 false

public static void main(String[] args) {
        Integer a = 127;
        Integer b = 127;
        Integer b1 = new Integer(127);
        System.out.println(a == b); //true
        System.out.println(b==b1);  //false

        Integer c = 128;
        Integer d = 128;
        System.out.println(c == d);  //false
    }

什么是 Integer 缓存?

因为根据实践发现大部分的数据操作都集中在值比较小的范围,因此 Integer 搞了个缓存池,默认范围是 -128 到 127,可以根据通过设置JVM-XX:AutoBoxCacheMax=来修改缓存的最大值,最小值改不了。

实现的原理是 int 在自动装箱的时候会调用 Integer.valueOf,进而用到了 IntegerCache。

很简单,就是判断下值是否在缓存范围之内,如果是的话去 IntegerCache 中取,不是的话就创建一个新的 Integer 对象。

IntegerCache 是一个静态内部类, 在静态块中会初始化好缓存值。

private static class IntegerCache {
     static {
            //创建Integer对象存储
            for(int k = 0; k < cache.length; k++)
                cache[k] = new Integer(j++);
     } 
 }

String 怎么转成 Integer 的?原理?

PS: 这道题印象中在一些面经中出场过几次。

String 转成 Integer,主要有两个方法:

  • Integer.parseInt(String s)
  • Integer.valueOf(String s)

不管哪一种,最终还是会调用 Integer 类内中的parseInt(String s, int radix)方法。

抛去一些边界之类的看看核心代码:

public static int parseInt(String s, int radix) throws NumberFormatException
    {
        int result = 0;
        //是否是负数
        boolean negative = false;
        //char字符数组下标和长度
        int i = 0, len = s.length();
        int digit;
        //判断字符长度是否大于0,否则抛出异常
        if (len > 0) {
            while (i < len) {
                // Accumulating negatively avoids surprises near MAX_VALUE
                //返回指定基数中字符表示的数值。(此处是十进制数值)
                digit = Character.digit(s.charAt(i++),radix);
                //进制位乘以数值
                result *= radix;  
                result -= digit;
            }
        } 
        //根据上面得到的是否负数,返回相应的值
        return negative ? result : -result;
    }

去掉枝枝蔓蔓(当然这些枝枝蔓蔓可以去看看,源码 cover 了很多情况),其实剩下的就是一个简单的字符串遍历计算,不过计算方式有点反常规,是用负的值累减。

Object

Object 类的常见方法?

Object 类是一个特殊的类,是所有类的父类,也就是说所有类都可以调用它的方法。它主要提供了以下 11 个方法,大概可以分为六类:

对象比较:

  • public native int hashCode() :native 方法,用于返回对象的哈希码,主要使用在哈希表中,比如 JDK 中的 HashMap。
  • public boolean equals(Object obj):用于比较 2 个对象的内存地址是否相等,String 类对该方法进行了重写用户比较字符串的值是否相等。

对象拷贝:

  • protected native Object clone() throws CloneNotSupportedException:naitive 方法,用于创建并返回当前对象的一份拷贝。一般情况下,对于任何对象 x,表达式 x.clone() != x 为 true,x.clone().getClass() == x.getClass() 为 true。Object 本身没有实现 Cloneable 接口,所以不重写 clone 方法并且进行调用的话会发生 CloneNotSupportedException 异常。

对象转字符串:

  • public String toString():返回类的名字 @实例的哈希码的 16 进制的字符串。建议 Object 所有的子类都重写这个方法。

多线程调度:

  • public final native void notify():native 方法,并且不能重写。唤醒一个在此对象监视器上等待的线程 (监视器相当于就是锁的概念)。如果有多个线程在等待只会任意唤醒一个。
  • public final native void notifyAll():native 方法,并且不能重写。跟 notify 一样,唯一的区别就是会唤醒在此对象监视器上等待的所有线程,而不是一个线程。
  • public final native void wait(long timeout) throws InterruptedException:native 方法,并且不能重写。暂停线程的执行。注意:sleep 方法没有释放锁,而 wait 方法释放了锁 。timeout 是等待时间。
  • public final void wait(long timeout, int nanos) throws InterruptedException:多了 nanos 参数,这个参数表示额外时间(以毫微秒为单位,范围是 0-999999)。所以超时的时间还需要加上 nanos 毫秒。
  • public final void wait() throws InterruptedException:跟之前的 2 个 wait 方法一样,只不过该方法一直等待,没有超时时间这个概念

反射:

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

垃圾回收:

  • protected void finalize() throws Throwable :通知垃圾收集器回收对象。
文章作者: stormling
文章链接: http://www.stormling.top/posts/49988.html
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 码农Stormling!
Java基础核心
cover of previous post
上一篇
Java系列(四)| 异常处理及IO
Java 中异常处理体系?Java 的异常体系是分为多层的。 Java 异常体系 Throwable是 Java 语言中所有错误或异常的基类。 Throwable Error:系统内部错误比如虚拟机异常,是程序无法处理的。 Exception:程序问题导致的异常 CheckedException 受检异常:编译器会强制检查并要求处理的异常。 RuntimeException 运行时异常:程序运行中出现异常,比如我们熟悉的空指针、数组下标越界等等 异常的处理方式?针对异常的处理主要有两种方式: 遇到异常不进行具体处理,而是继续抛给调用者 (throw,throws) 抛出异常有三种形式,一是 throw, 一个 throws,还有一种系统自动抛异常。 throws 用在方法上,后面跟的是异常类,可以跟多个;而 throw 用在方法内,后面跟的是异常对象。 try catch 捕获异常 在 catch 语句块中补货发生的异常,并进行处理。 try { //包含可能会出现异常的代码以及声明异常的方法 }catch(Exception e)...
cover of next post
下一篇
Java系列(二)| 面向对象
面向对象和面向过程的区别? 面向过程 :面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候再一个一个的一次调用就可以。 面向对象 :面向对象,把构成问题的事务分解成各个对象,而建立对象的目的也不是为了完成一个个步骤,而是为了描述某个事件在解决整个问题的过程所发生的行为。目的是为了写出通用的代码,加强代码的重用,屏蔽差异性。 用一个比喻:面向过程是编年体;面向对象是纪传体。 面向对象有哪些特性...
相关推荐
cover
2021-09-19
Java系列(五)| 序列化、泛型、注解、反射
序列化什么是序列化?什么是反序列化?什么是序列化,序列化就是把 Java 对象转为二进制流,方便存储和传输。 所以反序列化就是把二进制流恢复成对象。 序列化和反序列化 类比我们生活中一些大件物品的运输,运输的时候把它拆了打包,用的时候再拆包组装。 Serializable 接口有什么用? 这个接口只是一个标记,没有具体的作用,但是如果不实现这个接口,在有些序列化场景会报错,所以一般建议,创建的 JavaBean 类都实现 Serializable。 serialVersionUID 又有什么用? serialVersionUID 就是起验证作用。 private static final long serialVersionUID = 1L; 我们经常会看到这样的代码,这个 ID 其实就是用来验证序列化的对象和反序列化对应的对象 ID 是否一致。 这个 ID 的数字其实不重要,无论是 1L 还是 IDE 自动生成的,只要序列化时候对象的 serialVersionUID 和反序列化时候对象的 serialVersionUID 一致的话就行。 如果没有显示指定...
cover
2021-09-19
Java系列(四)| 异常处理及IO
Java 中异常处理体系?Java 的异常体系是分为多层的。 Java 异常体系 Throwable是 Java 语言中所有错误或异常的基类。 Throwable Error:系统内部错误比如虚拟机异常,是程序无法处理的。 Exception:程序问题导致的异常 CheckedException 受检异常:编译器会强制检查并要求处理的异常。 RuntimeException 运行时异常:程序运行中出现异常,比如我们熟悉的空指针、数组下标越界等等 异常的处理方式?针对异常的处理主要有两种方式: 遇到异常不进行具体处理,而是继续抛给调用者 (throw,throws) 抛出异常有三种形式,一是 throw, 一个 throws,还有一种系统自动抛异常。 throws 用在方法上,后面跟的是异常类,可以跟多个;而 throw 用在方法内,后面跟的是异常对象。 try catch 捕获异常 在 catch 语句块中补货发生的异常,并进行处理。 try { //包含可能会出现异常的代码以及声明异常的方法 }catch(Exception e)...
cover
2021-09-17
Java系列(二)| 面向对象
面向对象和面向过程的区别? 面向过程 :面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候再一个一个的一次调用就可以。 面向对象 :面向对象,把构成问题的事务分解成各个对象,而建立对象的目的也不是为了完成一个个步骤,而是为了描述某个事件在解决整个问题的过程所发生的行为。目的是为了写出通用的代码,加强代码的重用,屏蔽差异性。 用一个比喻:面向过程是编年体;面向对象是纪传体。 面向对象有哪些特性...
cover
2021-09-16
Java系列(一)| 基础语法
Java 概述什么是 Java?Java 是一门面向对象的编程语言,不仅吸收了 C++ 语言的各种优点,还摒弃了 C++ 里难以理解的多继承、指针等概念,因此 Java 语言具有功能强大和简单易用两个特征。Java 语言作为静态面向对象编程语言的优秀代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程 。 Java 语言有哪些特点?Java 语言有很多优秀(可吹)的特点,以下几个是比较突出的: Java 语言特点 面向对象(封装,继承,多态); 平台无关性:Java 是 “【一次编写,到处运行(Write Once,Run any Where)】” 的语言,因此采用 Java 语言编写的程序具有很好的可移植性,而保证这一点的正是 Java 的虚拟机机制。在引入虚拟机之后,Java 语言在不同的平台上运行不需要重新编译。 支持多线程:C++ 语言没有内置的多线程机制,因此必须调用操作系统的多线程功能来进行多线程程序设计 编译与解释并存; JVM、JDK 和 JRE 有什么区别?JVM:Java Virtual Machine,Java 虚拟机,Java...

评论
ValineGitalk
avatar
stormling
文章
42
标签
25
分类
21
Follow Me
公告
欢迎大家来到Stormling博客
目录
  1. 1. String
    1. 1.1. String 是 Java 基本数据类型吗?可以被继承吗?
    2. 1.2. String 和 StringBuilder、StringBuffer 的区别?
    3. 1.3. String str1 = new String(“abc”) 和 String str2 = “abc” 和 区别?
    4. 1.4. String 不是不可变类吗?字符串拼接是如何实现的?
    5. 1.5. intern 方法有什么作用?
  2. 2. Integer
    1. 2.1. Integer a= 127,Integer b = 127;Integer c= 128,Integer d = 128;,相等吗?
    2. 2.2. String 怎么转成 Integer 的?原理?
  3. 3. Object
    1. 3.1. Object 类的常见方法?
    2. 3.2. 对象比较:
    3. 3.3. 对象拷贝:
    4. 3.4. 对象转字符串:
    5. 3.5. 多线程调度:
    6. 3.6. 反射:
    7. 3.7. 垃圾回收:
最新文章
面向八股文面试专场
面向八股文面试专场2025-01-22
【每日早报】-2025-01-21 - 星期二
【每日早报】-2025-01-21 - 星期二2025-01-21
规则引擎 Drools 8+ 快速入门
规则引擎 Drools 8+ 快速入门2024-12-11
数据库系列(二) | Mybatis Plus 3.0+快速入门
数据库系列(二) | Mybatis Plus 3.0+快速入门2024-12-09
分布式系列(二) | Redisson分布式锁
分布式系列(二) | Redisson分布式锁2024-12-05
©2019 - 2025 By stormling
码农Stormling程序员,关注公众号【码农Stormling】回复【面试】获取最全面试pdf
搜索
数据加载中