Java入门系列之字符串创建方式、判断相等(一)
前言
陆续从0开始学习Java出于多掌握一门语言以后的路也会更宽,.NET和Java兼顾,虽然路还很艰难,但事在人为。由于Java和C#语法相似,所以关于一些很基础的内容不会再重头讲,Java系列中所有文章都会基于我个人所看文章和博客之后的思考,有些会和C#语法进行对比,有些是全新的概念,讲解完整个基础系列,然后进入数据结构和深入学习JVM,我都会详细记录,所有系列语法都是基于Java8,我们开始吧。
字符串创建
在Java中创建字符串四种方式,一是直接通过new运算符创建字符串,二是通过字符数组创建、三是通过提取字符数组创建、四是通过定义字符串变量创建,下面我们来一一过下
(1)new运算符创建字符串
String str = new String("Jeffcky");
System.out.println(str);
(2)字符数组创建String对象
char a[] = {'j', 'e', 'f', 'f', 'c', 'k', 'y'};
String str = new String(a);
System.out.println(str);
(3)提取字符数组创建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,也就是说我们要读取几个字符。
(4)字符串常量引用赋值创建字符串
这种方式也是我们最常用创建字符串变量的方式,如下:
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/CreateMyself/p/11437026.html》),当然对于值类型使用“==”毫无疑问没毛病。
Java入门系列之字符串创建方式、判断相等(一)的更多相关文章
- Java入门系列之字符串特性(二)
前言 上一节我们讲解到字符串本质上就是字符数组,同时详细讲解了字符串判断相等需要注意的地方,本节我们来深入探讨字符串特性,下面我们一起来看看. 不可变性 我们依然借助初始化字符串的方式来探讨字符串的不 ...
- Java:多线程概述与创建方式
目录 Java:多线程概述与创建方式 进程和线程 并发与并行 多线程的优势 线程的创建和启动 继承Thread类 start()和run() 实现Runnable接口 实现Callable接口 创建方 ...
- Java入门系列-26-JDBC
认识 JDBC JDBC (Java DataBase Connectivity) 是 Java 数据库连接技术的简称,用于连接常用数据库. Sun 公司提供了 JDBC API ,供程序员调用接口和 ...
- Java入门系列-19-泛型集合
集合 如何存储每天的新闻信息?每天的新闻总数是不固定的,太少浪费空间,太多空间不足. 如果并不知道程序运行时会需要多少对象,或者需要更复杂方式存储对象,可以使用Java集合框架. Java 集合框架提 ...
- Java入门教程四(字符串处理)
Java 语言的文本数据被保存为字符或字符串类型.字符及字符串的操作主要用到 String 类和 StringBuffer 类,如连接.修改.替换.比较和查找等. 定义字符串 直接定义字符串 直接定义 ...
- Java中的多线程的创建方式
首先理清几个基本概念: 程序:为完成特定任务,用某种语言编写的一组指令的集合.即一段静态的代码(还没运行起来) 进程:是程序的一次执行过程,也就是说程序运行起来了,加载到了内存中,并占用了cpu的资源 ...
- Java多线程学习(二)---线程创建方式
线程创建方式 摘要: 1. 通过继承Thread类来创建并启动多线程的方式 2. 通过实现Runnable接口来创建并启动线程的方式 3. 通过实现Callable接口来创建并启动线程的方式 4. 总 ...
- Java多线程系列1 线程创建以及状态切换
我们知道线程线程有三种创建方式 1实现Runnable接口 2 继承Thread类 3使用Callable和Future接口创建线程.具体是创建Callable接口的实现类,并实现clall()方法. ...
- Java入门系列(九)Java API
String,StringBuilder,StringBuffer三者的区别 1.首先说运行速度,或者说是执行速度 在这方面运行速度快慢为:StringBuilder > StringBuffe ...
随机推荐
- 我想外包开发一个APP,需要多少钱,多少时间?
在一个阳光明媚的下午,我正瘫坐在椅子上改bug.忽然有人给我发微信:“我想做个app,多长时间,多少钱?” 从我从业iOS开发到现在,这个问题被问过无数次,比那句:“你是程序员,那你会修电脑吗?”还要 ...
- Java面试题和解答(五)
1.在Java中Executor和Executors的区别? Executor是线程池的顶层接口,它的实现类如下图所示: Executors是一个类,提供了多个静态方法,用于生成不同类型的线程池,如下 ...
- 集合系列 List(四):LinkedList
LinkedList 是链表的经典实现,其底层采用链表节点的方式实现. public class LinkedList<E> extends AbstractSequentialList& ...
- dotnet core 调用electron来开发UI的探索
先上仓库地址 https://github.com/lightszero/webwindow.netcore dotnet core 很喜欢,问题dotnet core 不包含GUI,经过一些尝试,觉 ...
- js之好看的鼠标点击-光标特效
1.光标特效 <script src="https://blog-static.cnblogs.com/files/axqa/bubbleCursor.js">< ...
- queue队列基础讲解
前言 似乎这种对蒟蒻最重要的概念都搜不到,对巨佬来说也根本不必要提及. 导致我也不懂. Queue 意义 queue,队列,一种数据结构. 队列是一种操作受限制的线性表: 特点: 1.元素先进先出. ...
- 工作笔记 之 Linux服务搭建
No.1 linux环境下安装nginx步骤 Nginx (engine x) 是一款轻量级的Web 服务器.反向代理服务器.电子邮件(IMAP/POP3)代理服务器,在BSD-like 协议下发行. ...
- ABAP - AT END OF 的使用
TYPES: begin of ty_tab , num() type i, str() type c, end of ty_tab. data: gw_tab TYPE ty_tab , gt_ta ...
- (转)RocketMQ工作原理
原文:https://blog.csdn.net/lyly4413/article/details/80838716 1.消息中间件的发展: 第一代以ActiveMQ为代表,遵循JMS(java消息服 ...
- 平时代码中用不到设计模式?Are you kidding me?
引子 平时我是个反应非常慢的人.有多慢呢?大概是两年前有次团队内部开会时,我听到同学说平时代码中用不到设计模式,我当时没有回答.两年后我终于反应过来了:“Are you kidding me?我每天都 ...