从Java认识字符串

前言:字符串是程序中必不可少的操作,本篇将介绍字符串的由来,以及 Java 中字符串相关面试题。

一、字符串的由来

我们在类似Java这样的高级语言中字符串是非常重要的数据类型之一。其实,在计算机被发明时,计算机的作用很简单就是一个计算器能做好加减乘除就已经相当不错了,但是随着时代的进步,计算机的功能是越来越多,渐渐要求我们不仅能处理数值,还需要我们处理大量非数值的文件,于是在计算机中便引入了字符串的概念。
一个官方定义:字符串是由零个或多个字符组成的有限序列。

String str1="";//零个字符
String str2=" ";//空格也是字符!
String str3="123";
String str4="abc";

既然说到了字符串那就必须要提一下编码,现在不了解以后你也会经常遇到乱码问题,在计算机中的常用字符使用的是标准的ASCII编码,这是一个编码表你可以在网上查一下,但是这个码表只能表示128个字符,现在问题来了世界上字符那么多128根本就不够用呀,尤其像我们的汉字,又不是英文字母只有26个,所以就诞生了Unicode编码,这里我们只需要知道ASCII是Unicode的子集就OK了,Unicode包含6.5万多个字符,ASCII有的Unicode都有。
但是为什么我们在开发中还是会遇到各种乱码问题呢,就是因为开发前没有约定好编码方式,编码方式有很多种,中文常用的是UTF-8,英文中常用的是ISO-8859-1,常见的还有GBK、UTF-32,当然这些都是Unicode的编码方式。不论是后端想前端提供的数据,还是前端提交到后端的数据,编码方式都应保持一致,如果不一致则需要做好重新编码的操作。

7343192-b893da9be1f6d8cf.png

二、字符串的储存结构

subString()//截取字符串中的一段字符串
charAt()//返回指定索引处char值
toLowerCase()//将所有在此字符串中的字符转化为小写(使用默认语言环境的规则)
indexOf()//指出 String 对象内子字符串的开始位置

字符串提供了很多方法,具体可以查看API手册了解其使用,这里列出几个常用的,只想说明一个问题,虽然字符串有很多方法,但是每种语言提供的字符串方法大致都差不多,它们的底层实现也都差不多。而底层实现一般采用了两种储存结构:

  • 顺序储存结构,使用数组实现
  • 链式存储结构,使用链表实现

大部分方法都是采用数组实现,在这里就不讨论各自实现的优缺点,毕竟学好算法和数据结构是每个程序员的基本功。

三、实战

7343192-53008e40c9d8c99f.jpg

下面的输出结果是?(先独自完成,再看知识点,再看解析)

public class Demo {
    public static void main(String[] args) {
        String st1="abc";
        String st2="abc";
        System.out.println(st1 == st2);
        System.out.println(st1.equals(st2));
    }
}

参考答案:true、true,创建st1时,首先在常量池中创建了对象地址,当创建st2时,因为“abc”已经创建,所以直接用了st1的对象地址。这是Java中有常量优化机制

public class Demo {
   public static void main(String[] args) {
     String st1 = "a" + "b" + "c";
     String st2 = "abc";
     System.out.println(st1 == st2);
     System.out.println(st1.equals(st2));
   }

参考答案:true、true。小伙伴肯定有点懵逼,在这里虽然有 + 号,但是JVM会直接把st1作为一个常量对象,当st1拼接完成就是String st1=“abc”字符常量,此时会在常量池中进行创建,这里不会调用 + 号的重写方法,所以也不会返回一个新对象。

public class Demo {
   public static void main(String[] args) {
     String st1 = "ab";
     String st2 = "abc";
     String st3 = str1+"c";
     System.out.println(st2 == st3);
     System.out.println(st1.equals(st2));
   }

参考答案:false、true。在这里因为st1已经存在于常量池中,当str3再次拼接字符串时会调用StringBuilder中的方法生成新的对象。

public class Demo {
   public static void main(String[] args) {
     String st1 = new String("abc");
     String st2 = new String("abc");
     System.out.println(st1 == st2);
     System.out.println(st1.equals(st2));
   }

参考答案:false、true,这里创建了三个对象。首先在常量池中创建“abc”对象,然后在堆中创建 new String("abc");对象,所以执行完 String st1 = new String("abc");这句实际上创建了两个对象,一个常量对象,一个堆对象。创建st2时同理,但是st2创建时,因为常量已经存在所以直接复用,这在第一题就说了,但是new不同,new每次在堆中都是重新创建对象,所以一共创建了三个对象。

public class Demo {
    public static void main(String[] args) {
        String st1 = new String("abc").intern();
        String st3 = "abc";
        System.out.println(st1 == st3);
        System.out.println(st1.equals(st3));
    }
}

参考答案:true、true。这里主要考察 intern() 方法的作用,将指向堆内存的地址指向常量池中的地址。

7343192-8f9139da42068e03.jpg

知识点了解一下:

如果上面的题都对,恭喜,你已经熟练掌握了,相关知识点,如果靠猜过来的,快来看看知识点。

7343192-a46887ffc175fb2a.png
Java加载机制
  • 字符串一旦定义就是常量,无法改变,比如String str="abc"';是无法改变的哦,当我们调用 + 拼接字符或者StringBuilder的append()拼接字符串时,实际上返回的是一个新对象。(+ 号之所以可以拼接字符串并且返回新对象,是因为在Java中对 + 的功能进行了重写,本质上最后也是调用StringBuilder,最后调用toString()方法获得字符串)
public class Demo {
    public static void main(String[] args) {
        String st1 = "abc";
         String st2 = new StringBuilder(st1).append("d").toString();
        System.out.println(st1);
        System.out.println(st2);
    }
}

输出结果:abc、abcd,可以看到st1的值并没有改变

  • 对象的地址存放在堆中,每次看到 new 其实都会在堆中新创建一个对象地址,独一无二!
  • 常量地址存放在常量区,即常量池中。常量地址不一样,两个相同的常量是可以复用的。
  • ==和equals()方法的区别,equals()方法没有什么好说的,它在String类中经过了重写比较的就是对象的值,注意一下==,在基本数据类型中比较的是值,在对象数据类型中比较的是地址,String不属于基本数据类型而是一个类,所以比较的是地址
  • String、StringBuffer、StringBuilder之间的关系,你应该知道,篇幅原因这里不做扩展了!

每月更新两篇,我们一起进步!

猜你喜欢

转载自blog.csdn.net/weixin_33775582/article/details/87490474
今日推荐