Java中的字符串比较

在Java中, String类封装了char数组。 简而言之, String是用于组成单词,句子或所需任何其他数据的字符数组。

封装是面向对象编程中最强大的概念之一。 由于封装的原因,您不需要知道String类是如何工作的。 您只需要知道在其接口上使用什么方法即可。

当您查看Java中的String类时,可以看到如何封装char数组:


public String(char value[]) {
    this(value, 0, value.length, null);
}

为了更好地了解封装,请考虑一个物理对象:汽车。 您是否需要知道汽车在引擎盖下的运转方式? 当然不是,但是您确实需要知道汽车的接口在做什么:油门,制动器和方向盘之类的东西。 这些接口均支持某些操作:加速,制动,左转,右转。 面向对象编程中是相同的。

我在Java Challengers系列中的第一个博客介绍了方法重载 ,这是String类广泛使用的一种技术。 重载可以使您的类真正灵活,包括String


public String(String original) {}
public String(char value[], int offset, int count) {}
public String(int[] codePoints, int offset, int count) {}
public String(byte bytes[], int offset, int length, String charsetName) {}
// And so on…...

而不是试图了解该String类作品,该Java挑战者将帮助您了解它做什么 ,以及如何使用它在你的代码。

什么是字符串池?

String可能是Java中最常用的类。 如果每次使用String在内存堆中创建一个新对象,我们将浪费大量内存。 String池通过为每个String值仅存储一个对象来解决此问题,如下所示。

该图显示了如何在字符串池中存储字符串。 拉斐尔·奇内拉托·德尔尼罗

图1.字符串池中的字符串

尽管我们为DukeJuggy String创建了一个String变量,但是只有两个对象被创建并存储在内存堆中。 为了证明这一点,请看下面的代码示例。 (回想一下Java中的“ == ”运算符用于比较两个对象并确定它们是否相同。)


String juggy = "Juggy";
String anotherJuggy = "Juggy";
System.out.println(juggy == anotherJuggy);

该代码将返回true因为两个String指向String池中的同一对象。 它们的值是相同的。

例外:“新”运算符

现在看一下这段代码,它看起来与前面的示例相似,但是有所不同。


String duke = new String("duke");
String anotherDuke = new String("duke");

System.out.println(duke == anotherDuke);

根据前面的示例,您可能认为此代码将返回true ,但实际上为false 。 添加new运算符会强制在内存堆中创建新的String 。 因此,JVM将创建两个不同的对象。

本机方法

Java中的本机方法是一种将使用C语言编译的方法,通常用于操纵内存和优化性能。

字符串池和intern()方法

要将String存储在String池中,我们使用一种称为String interning的技术。 这是Javadoc告诉我们有关intern()方法的内容:


    /**
     * Returns a canonical representation for the string object.
     *
     * A pool of strings, initially empty, is maintained privately by the
     * class {@code String}.
     *
     * 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.
     *
     * It follows that for any two strings {@code s} and {@code t},
     * {@code s.intern() == t.intern()} is {@code true}
     * if and only if {@code s.equals(t)} is {@code true}.
     * 
     * All literal strings and string-valued constant expressions are
     * interned. String literals are defined in section 3.10.5 of the
     * The Java™ Language Specification.
     *
     * @returns  a string that has the same contents as this string, but is
     *          guaranteed to be from a pool of unique strings.
     * @jls 3.10.5 String Literals
     */ public native String intern();

intern()方法用于在String池中存储String 。 首先,它验证您创建的String是否已经存在于池中。 如果没有,它将在池中创建一个新的String 。 在后台, String池化的逻辑基于Flyweight模式

现在,请注意当我们使用new关键字强制创建两个String时会发生什么:


String duke = new String("duke");
String duke2 = new String("duke");
System.out.println(duke == duke2); // The result will be false here
System.out.println(duke.intern() == duke2.intern()); // The result will be true here

与前面带有new关键字的示例不同,在这种情况下,比较结果为true。 这是因为使用intern()方法可确保将String存储在池中。

与String类相等的方法

equals()方法用于验证两个Java类的状态是否相同。 因为equals()来自Object类,所以每个Java类都继承它。 但是必须重写equals()方法以使其正常工作。 当然, String会覆盖equals()

看一看:


public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    
    if (anObject instanceof String) {
        String aString = (String)anObject;
        if (coder() == aString.coder()) {
          return isLatin1() ? StringLatin1.equals(value, aString.value)
            : StringUTF16.equals(value, aString.value);
        }
    }
    
    return false;
}

如您所见, String类值的状态必须为equals()而不是对象引用。 对象引用是否不同并不重要。 将比较String的状态。

最常见的String方法

在接受String比较挑战之前,您需要了解的最后一件事。 考虑一下String类的以下常见方法:


// Removes spaces from the borders
trim() 
// Gets a substring by indexes
substring(int beginIndex, int endIndex)
// Returns the characters length of the String
length() 
// Replaces String, regex can be used.
replaceAll(String regex, String replacement)
// Verifies if there is a specified CharSequence in the String
contains(CharSequences) 

接受字符串比较挑战!

让我们尝试快速挑战一下您对String类的了解。

对于这个挑战,您将使用我们探索的概念比较多个String 。 查看下面的代码,您可以确定每个结果变量的最终值吗?


public class ComparisonStringChallenge {
	public static void main(String... doYourBest) {
		String result = "";
		result += " powerfulCode ".trim() == "powerfulCode" 
				? "0" : "1";

		result += "flexibleCode" == "flexibleCode" ? "2" : "3";
		
		result += new String("doYourBest") 
				== new String("doYourBest") ? "4" : "5";

		result += new String("noBugsProject")
				.equals("noBugsProject") ? "6" : "7";

        result += new String("breakYourLimits").intern()
                == new String("breakYourLimits").intern() ? "8" : "9";

		System.out.println(result);
	}
}

哪个输出代表结果变量的最终值?

:02468
:12469
电话 :12579
电话 :12568

在这里检查您的答案。

刚才发生了什么? 了解字符串行为

在代码的第一行,我们看到:


result += " powerfulCode ".trim() == "powerfulCode" 
				? "0" : "1";

尽管在调用trim()方法之后, String将是相同的,但是String “ powerfulcode “在开始时是不同的。 在这种情况下,比较是false ,因为当trim()方法从边界中删除空格时,它将使用new运算符强制创建新的String

接下来,我们看到:


result += "flexibleCode" == "flexibleCode" ? "2" : "3";

毫无疑问, StringString池中是相同的。 此比较返回true

接下来,我们有:


result += new String("doYourBest") 
				== new String("doYourBest") ? "4" : "5";

使用new保留关键字强制创建两个新的String ,无论它们是否相等。 在这种情况下,即使String值相同,比较也将为false

接下来是:


result += new String("noBugsProject")
				.equals("noBugsProject") ? "6" : "7";

因为我们使用过equals()方法,所以将比较String的值而不是对象实例的值。 在那种情况下,对象是否不同并不重要,因为正在比较值。 此比较返回true

最后,我们有:


result += new String("breakYourLimits").intern()
                == new String("breakYourLimits").intern() ? "8" : "9";

如您之前所见, intern()方法将String放入String池中。 两个String指向同一个对象,因此在这种情况下,比较为true

视频挑战! 调试字符串比较

调试是完全吸收编程概念并改善代码的最简单方法之一。 在此视频中,您可以在调试和解释Java Strings挑战的同时进行以下操作:

字符串常见错误

很难知道两个String是否指向同一个对象,尤其是当String包含相同的值时。 记住使用保留关键字new总是会导致在内存中创建一个新对象,即使值相同。

使用String方法比较Object引用也很棘手。 关键是,如果方法更改String某些内容,则对象引用将不同。

一些示例可以帮助阐明:


System.out.println("duke".trim() == "duke".trim());; 

这种比较将是正确的,因为trim()方法不会生成新的String


System.out.println(" duke".trim() == "duke".trim()); 

在这种情况下,第一个trim()方法将生成一个新的String因为该方法将执行其操作,因此引用将有所不同。

最后,当trim()执行其操作时,它将创建一个新的String


// Implementation of the trim method in the String class
new String(Arrays.copyOfRange(val, index, index + len),
                          LATIN1);

关于字符串要记住的事情

  • String是不可变的,因此不能更改String的状态。
  • 为了节省内存,JVM将String保留在String池中。 创建新的String ,JVM会检查其值并将其指向现有对象。 如果池中没有具有该值的String ,那么JVM将创建一个新的String
  • 使用==运算符比较对象引用。 使用equals()方法比较String的值。 相同的规则将应用于所有对象。
  • 当使用new运营商,新的String将在被创建String池,即使有一个String具有相同值。

答案键

该Java挑战者的答案是选项D。输出为12568

这个故事“ Java中的字符串比较”最初是由JavaWorld发布的

翻译自: https://www.infoworld.com/article/3276354/string-comparisons-in-java.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值