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 ...
随机推荐
- LeetCode 49: 字母异位词分组 Group Anagrams
LeetCode 49: 字母异位词分组 Group Anagrams 题目: 给定一个字符串数组,将字母异位词组合在一起.字母异位词指字母相同,但排列不同的字符串. Given an array o ...
- jQuery-实现简单的Ajax请求封装
封装的意义在于复用,在于减少重复的代码. 我在项目中做了简单的Ajax请求封装,实现方式如下: //封装Ajax请求 $.extend({ ajaxDirect:function(url,type,d ...
- 为什么老外不愿意用MyBatis?
作者:陈龙 www.zhihu.com/question/309662829 Spring 团队的Josh Long自己在Twitter上做了一个调查.1625次投票,样本量不算大,但也能说明问题.和 ...
- Spring Boot Redis 解析
redis使用示例 本示例主要内容 使用lettuce操作redis redis字符串存储(RedisStringController.java) redis对象存储(RedisObjectContr ...
- RocketMQ(二):producer客户端实践
MQ解耦了生产者和消费者,前提是有一个稳定强大的消息服务,我们只管与之通信即可. 所以,和MqServer通信是什么样的?难否? 0. 发送端demo /** * This class demonst ...
- JMeter内存溢出:java.lang.OutOfMemoryError: Java heap space解决方法
一.问题原因 用JMeter压测,有时候当模拟并发请求较大或者脚本运行时间较长时,JMeter会停止,报OOM(内存溢出)错误. 原因是JMeter是一个纯Java开发的工具,内存由java虚拟机JV ...
- 剑指offer 23:从上往下打印二叉树
题目描述 从上往下打印出二叉树的每个节点,同层节点从左至右打印. 解题思路 按照从左往右从上到下的顺序打印节点,需要我们维护一个队列,这个队列放入元素的顺序是访问队头节点(起始先放入根节点),则若当前 ...
- Django 注意知识点(一)
本篇概述 Django Admin后台显示 多对多字段(如何) Django 模板 显示 多对多字段(如何) Django 将表单中上传的多对多字段存入数据库 (如何) Django 上传文件 ( ...
- 中间人攻击,HTTPS也可以被碾压
摘要: 当年12306竟然要自己安装证书... 原文:知道所有道理,真的可以为所欲为 公众号:可乐 Fundebug经授权转载,版权归原作者所有. 一.什么是MITM 中间人攻击(man-in-the ...
- CentOS7 安装frp与开机启动
1. 下载frp程序文件 https://github.com/fatedier/frp/releases 2. 解压文件 下载后解压到自己的目录,我这里解压到/usr/local/frp: 3. 添 ...