Java Challengers#2:字符串比较

   Java Challengers#2:字符串比较_第1张图片

String方法,关键字和运算符如何处理String池中的比较

    在Java中,String该类封装了一个数组char。简而言之,String是一个字符数组,用于组合您想要的单词,句子或任何其他数据。

    封装是面向对象编程中最强大的概念之一。由于封装的,你不需要知道如何将字符串类的工作; 你只需要知道在它的界面上使用什么方法。

当您String在Java中查看该类时,您可以看到如何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中最常用的类。如果每次使用a都在内存堆中创建了一个新对象String,我们就会浪费大量内存。该String池通过存储仅仅一个对象的每个解决了这个问题String值,如下所示。

[ 在这个全面的12部分课程中,从初学概念到高级设计模式学习Java!]

Java Challengers#2:字符串比较_第2张图片

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

虽然我们StringDukeJuggy Strings 创建了一个变量,但只创建了两个对象并将其存储在内存堆中。有关证明,请查看以下代码示例。(回想一下,==Java 中的“ ”运算符用于比较两个对象并确定它们是否相同。)


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

此代码将返回,true因为两个Strings指向String池中的同一对象。他们的价值是一样的。

例外:'新'运算符

现在看看这段代码 - 它看起来与前面的示例类似,但是有区别。


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

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

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

原生方法

本地方法在Java中是将利用C语言进行编译,通常用于操纵存储器和优化性能的目的的方法。

字符串池和intern()方法

StringString池中存储,我们使用一种称为String实习的技术。以下是Javadoc告诉我们的intern()方法:


   / **
     *返回字符串对象的规范表示。
     *
     *一个字符串池,最初是空的,由私人维护
     * class {@code String}。
     *
     *调用实习方法时,如果池已包含
     *字符串等于此{@code String}对象,由...确定
     * {@link #equals(Object)}方法,然后是池中的字符串
     * returned. Otherwise,将此{@code String}对象添加到
     *池和对此{@code String}对象的引用被返回。
     *
     *对于任何两个字符串{@code s}和{@code t},
     * {@code s.intern()== t.intern()}是{@code true}
     *当且仅当{@code s.equals(t)}为{@code true}时。
     *
     *所有文字字符串和字符串值常量表达式
     *实习。字符串文字在3.10.5节中定义
     * Java™语言规范。
     *
     * @returns一个与该字符串具有相同内容的字符串,但是
     *保证来自一串独特的字符串。
     * @jls 3.10.5字符串文字
     * / public native String intern();

    该intern()方法用于StringString池中存储s 。首先,它验证String您创建的池中是否已存在。如果没有,它会String在池中创建一个新的。在幕后,String汇集的逻辑基于Flyweight模式。

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


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关键字示例不同,在这种情况下,比较结果是正确的。那是因为使用该intern()方法可确保Strings将存储在池中。

使用String类的Equals方法

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在快速挑战中试一下你对课程的了解。

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


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);
	}
}

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

A:02468 
B:12469 
C:12579 
D:12568

在这里检查你的答案。

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

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


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

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

接下来,我们看到:


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

这里没什么神秘之处,游泳池里的Strings也是一样的String。这种比较返回true

接下来,我们有:


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

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

接下来是:


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

字符串常见错误

可能很难知道两个Strings是否指向同一个对象,尤其是当Strings包含相同的值时。有助于记住,使用保留关键字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);

关于字符串要记住什么

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

 

回答密钥

这个Java Challengers的答案是选项D.输出将是12568

你可能感兴趣的:(编程语言)