Java入门系列之字符串(一)
前言
作为一名专注于.NET方向的技术爱好者,纠结了很久,到底要不要学习Java,最主要是自身时间和精力确实不够,任何一个方向上无论是纵向还是横向要学习的东西太多,我也表示很无奈,最终下定决心从0开始学习Java出于多掌握一门语言以后的路也会更宽,由于Java和C#语法相似,所以关于一些很基础的内容不会再重头讲,Java系列中所有文章都会基于我个人所看文章和博客之后的思考,有些会和C#语法进行对比,有些是全新的概念,我会详细记录,我们开始吧。
字符串创建
在Java中创建字符串三种方式,一是通过字符数组创建、二是通过提取字符数组创建、三是通过定义字符串变量创建,下面我们来一一过下
(1)字符数组创建String对象
char a[] = {'j', 'e', 'f', 'f', 'c', 'k', 'y'}; String str = new String(a); System.out.println(str);
(2)提取字符数组创建String对象
通过如上第一种方式直接通过new运算符获取字符数组,通过new运算符创建字符串对象还有重载,如下:
char a[] = {'j', 'e', 'f', 'f', 'c', 'k', 'y'}; String str = new String(a,0,4); System.out.println(str);
该重载方式第一个参数则是操作的字符数据,第二个参数是偏移量offset,也就是说从字符数组哪里开始截取,第三个参数是count,也就是说我们要读取几个字符。
(3)字符串常量引用赋值创建字符串
这种方式也是我们最常用创建字符串变量的方式,如下:
String str = "Jeffcky";
System.out.println(str);
字符串判断相等
判断字符串是否相等在Java和C#中处理方式不一样,接下来我们将对比C#和Java中的处理方式。我们首先来整体看看C#和Java中判断方式的不同,如下为C#
“==”和equals
static void Main(string[] args) { string str1 = new string("Jeffcky"); string str2 = new string("Jeffcky"); Console.WriteLine(str1 == str2); Console.WriteLine(str1.Equals(str2)); Console.ReadKey(); }
接下来我们再来看看Java中相同判断方式:
public static void main(String[] args) { String str1 = new String("Jeffcky"); String str2 = new String("Jeffcky"); System.out.println(str1 == str2); System.out.println(str1.equals(str2)); }
通过如上C#和Java中打印结果,想必我们就知道了不同,在C#中==对于值类型直接判断其值是否相等,而对于引用类型尤其是字符串则重写了Equals方法而直接比较字符串值,所以上述都打印出true,在C#中若想要比较引用类型地址是否相等,则使用ReferenceEquals方法,所以上述在C#中的演示代码要想得到和Java中处理结果,则演示代码变成如下:
static void Main(string[] args) { string str1 = new string("Jeffcky"); string str2 = new string("Jeffcky"); Console.WriteLine(ReferenceEquals(str1, str2)); Console.WriteLine(str1.Equals(str2)); Console.ReadKey(); }
我们反观Java中通过new操作符创建的字符串进行“==”比较是为false,这是由于通过new运算符创建了两个相同字符串对象的地址不一样,由此可见:在Java中的==并不是比较字符串的值,因为“==”仅仅只检查两个字符串的引用相等性,意味着它们是否引用相同的对象。如果将上述Java代码进行如下修改,此时两个字符串通过“==”比较则相等:
public static void main(String[] args) { String str1 = "Jeffcky"; String str2 = "Jeffcky"; System.out.println(str1 == str2); System.out.println(str1.equals(str2)); }
我们经过如上修改后,通过“==”判断此时str1和str2指向堆上同一对象Jeffcky的地址,不好理解?那么接下来我们经过如下修改则一目了然
public static void main(String[] args) { String str1, str2; str1 = "Jeffcky"; str2 = "Jeffcky"; System.out.println(str1 == str2); System.out.println(str1.equals(str2)); }
我们再来进行一行行解释,第一行字符串str1和str2引用为null,第二行在堆上创建名为Jeffcky的对象,此时将引用地址赋值给str1,第三行在堆上已有相同对象的字符串,直接将引用地址赋值给str2,所以此时str1和str2的引用对象相等打印出true。接下来我们再来看equals方法,最喜欢的则是在Java中可直接查看源码,我们看看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; }
从如上源码不难看出:String类重写从Object继承的equals方法,此方法逐个字符地比较两个字符串,而忽略它们的引用地址,也就是说如果长度且字符顺序相等,则认为它们相等。
object equals
上述我们讨论到字符串中的equals方法重写了Object类中的equals方法,那么Object类中的equals方法进行比较的逻辑又是怎样的呢?我们来看看如下代码:
import java.util.Objects; public class Main { public static void main(String[] args) { String string1 = "using objects equals"; String string2 = "using objects equals"; String string3 = new String("using objects equals"); System.out.println(Objects.equals(string1, string2)); System.out.println(Objects.equals(string1, string3)); System.out.println(Objects.equals(null, null)); System.out.println(Objects.equals(null, string1)); } }
对于上述打印结果,我们结合Object类中的equals源码来分析,如下:
public static boolean equals(Object a, Object b) { return (a == b) || (a != null && a.equals(b)); }
由此我们得出结论:Object类中equals为静态方法,首先使用它们的地址比较它们,即“==”判断,如果两个字符串相等,则该方法返回true。同时如果两个参数都为null,则返回true,如果只有一个参数为null,则返回false。否则,它只是调用传递的参数类型的类的equals方法,上述则是String的类equals方法。 此方法区分大小写,因为它在内部调用String类的equals方法。
总结
本文我们详细介绍了Java中关于字符串的比较,可能和我一样的初学者如果不是很了解内部实现的话会存在使用误区,对于字符串判断相等应该使用equals方法而不是“==”或者使用Object类的静态方法equals(因为其内置会调用对象的equals方法),因为“==”是比较引用是否相等,当然对于值类型使用“==”毫无疑问没毛病。
原文地址:https://www.cnblogs.com/jeffckywang/p/11370246.html
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释