[Java 泥水匠] Java Components 之一:Java String (肯定有你不懂的)
作者:泥沙砖瓦浆木匠 网站:http://blog.csdn.net/jeffli1993 个人签名:打算起手不凡写出鸿篇巨作的人,往往坚持不了完成第一章节。 |
1.1 前言
说起String,大家最熟悉不过了。我也是那么说过,但是仿佛这熟悉的里面也有很多细节,或者是我们没掌握的东西。往往有很多旧东西里面爆出很多光点。比如,作者泥瓦匠近期在冬天的牛仔裤里面搜出了一张100现金(不宜乐乎)。回到正题,我们下面以下几点讲下String。分两个部分:
基础部分:(JDK源码 文档)
- 1.2 你好 String
- 1.3 String字符串操作
扩展部分:
- 1.3 == 与 equals 不是亲家
- 1.4 也不难 泥瓦匠再出奇招
- 1.5 equals碰到n长字符串呢?
- 1.6 intern妙用
楼主不是大牛级别的人物,泥瓦匠一直认为的是“打算起手不凡写出鸿篇巨作的人,往往坚持不了完成第一章节。”所以,操着键盘,听着喜欢的音乐。幽默的对你说我的理解体会。
(希望大牛指出错误,万分感谢!)
1.2 你好 String
怀着初次见你的心情,泥瓦匠和你一起打开JDK1.7文档。我最近想写一些关于JDK1.7的理解,都知道JDK8出来了,新特性我准备下阶段有空学习。
泥瓦匠想说,阅读E文文档有利于体会原汁原味。但毕竟国内大牛翻译的很不错了,咱们不加评判,喜欢哪种自己挑。能抓老鼠,能解决实际项目,适应业务环境的就是你学到了。请看下面的小例子:
清单1.1
String abc = "abc";
char data[] = {'a','b','c'};
String abcStr = new String(data);
System.out.println("abc");
String cde = "cde";
System.out.println("abc" + cde);
String c = "abc".substring(2,3);
String d = cde.substring(1, 2);
System.out.println(c);
System.out.println(d);
泥瓦匠,你不是在忽悠我吗?这么简单的程序,你想说什么。说实在确实是基础,但基础扎实才能有更高的突破。就想泥瓦匠默默为自己,为家人为未来打基础。
可以见,String是不需要用new来创建一个新对象的类。它是不可变的(Constant),其值(像"abc"创建后,不可改变)。自然,String其实实现了基本类型char的序列的功能,因此中文名“字符串”。这里大家有可能疑惑,泥瓦匠就找到JDK源码证据给你们看:
这段代码是来自JDK1.7源码里面的,char型value数组的形式组成了String类的内容。其操作就是针对value数组操作。这样想是否豁然开朗,然后心里自喜“so easy”。其实难点下面,大家慢慢看下去。
1.3 String字符串操作
依旧看代码清单1.1,Java提供了一个特殊的连接操作符(concatenation operator)+ 用于直接来拼接字符串。其中操作常用的方法罗列如下:
方法 作用
s.length() 返回s字符串长度 s.charAt(1) 返回s字符串中下标为1的字符 s.substring(0, 2) 返回s字符串中下标0到2的子字符串 s.indexOf("nsg") 返回子字符串"nsg"的下标 s.startsWith(" ") 判断s是否以空格开始 s.endsWith("end") 判断s是否以"end"结束
跟着泥瓦匠运行下清单1.1,你可以看到打印出来:
abc
abccde
c
d
很简单的发现答案就是我们心目中想要的。这里我不打算很详细的解释api,这样会失去文章的趣味和读者的兴趣。我喜欢用例子来引导出,对于String在我项目和经验中的总结。
下面就以我们substring()方法来解释下源码,可以看到其中实现的细节:
逻辑大致归纳如下:
1. 首先判断传入值得可靠性,判断传入的开始和结束,还有子字符串的长度。这是在每个系统开发需要在细节中关心的。关心细节,才能干大事。
2. 然后判断是不是原String,是的话,直接返回this,如果不是就new一个子串。这个构造函数实现也不难,如果有兴趣可以看看,其实也就是实现char数组的拷贝。
就String基础部分泥瓦匠就介绍这里,在这里我们可以得出的结论是:设计源于生活,源于简单。像一个方法和一个类结构的设计,单一简单。所以我们学习以后设计方法要简单,耦合度不能太高。
到这里,读者可以先听首歌,比如什么的钢琴曲,什么月光曲。休息会继续讲。
1.3 == 与 equals 不是亲家
有人看到这个会大吃一惊,然后质问说“老师说,String 和 == 没关系,你是不是瞎扯淡”。哈哈,我只能说,只不过修行在实际。举个小栗子吧。
看下面清单1.2
static String b = "ab";
private static void test(){
String a = "a" + "b";
System.out.println(a == b); }
看到这里,你是否觉得这么简单,心里想着肯定是“false,泥瓦匠真逗。”运行下,结果却是
true
结论: 关于 == ,我们要知道 == 用于匹配内存单元的内容。Java中对比的就是两个内存单元的内容(其实就是一串数字)。至于八个基本类型直接比较值。例如清单1.2,比较的是两个引用,两个引用对比的是引用的对象的逻辑值(也就是两个对象对应内存单元的内容)。
泥瓦匠的记忆宫殿:就是相当于 泥瓦匠和我的亲姐姐比较我们两个的爸爸,毕竟的爸爸都是那一个,当然是true。
"a" + "b"的生命是怎么样的呢?网络牛人有些反编译会发现其实是类似下面的过程:
StringBuilder temp = new StringBuilder();
temp.append("a").append("b");
return temp.toString();
究竟JVM是怎么把"a" + "b"和"ab"知道他们是一样的呢。我们回顾下,因为String是不可变类,也就是静态Java语言的特点。这涉及到JVM的优化方案。但JVM很死板,它不会很人工智能的像人脑,它会的只是它能处理的,所以好好了解JVM有助于开发更好的额程序。比如定义一个ab字符串常量够了,它不会在再 子串 a b。这就是它的优化方案。
泥瓦匠的记忆宫殿:这就是偷懒思想,今天我要见我爸爸,明天姐姐要见爸爸。合并下呗,后天一起去见爸爸。
就此我们可以得出结论:编译器给我带来它对程序的优化,为了提升程序的效率和内存资源等,所以我们可以明白,如何掌握其特性写出更好的代码。
1.4 也不难 泥瓦匠再出奇招
补充个例子,看看你们真的掌握没?
private static String getA(){ return "a";}
private static void test2(){
String a = "a";
String b = a + "b";
String e = getA() + "b";
System.out.println(b == "ab");
System.out.println(e == "ab");
}
这涉及了JVM的优化,答案是:
false
false
如果猜到了,证明你真懂了。泥瓦匠还是耐心的讲解下:
第一个false:b是包括了一个常量和一个引用的值,所以。
第二个false: 你也可以猜到外部方法的常量在本方法只是一个引用。所以。
结论如下:我们现在如果不知道JVM怎么在编译时期优化,我们就慢慢了解它们。
1.5 equals碰到n长字符串呢?
这个例子不好写,泥瓦匠就带你们看看源码等。equals并不陌生,相信大家的系统里面有很多设计到这个方法。
其实equals是实现了Object的equals方法,而在Object的equals:
它其实就是实现了 == 比较内存的内容。
Q:泥瓦匠,为什么String要重写Object,这不导致意义不一致了吗?
A:非也非也,String是String,String用来处理的事物逻辑和业务和Object完全不同。equals顾名思义等于,等于不表示完全相等。而是一样或者相似。正所谓业务看情况,比如泥瓦匠处理得金融数据一般小数点10几位,那请问你还会在乎小数点10位后的的值吗,当它们比较的时候,你不会在乎,所以这就是相似。
那么我们就看一下String实现的equals方法:
简单描述下,就是遍历两个数组最好的条件下,就是要么长度不同,要么前面几个不同。直接返回false。
Q:如果碰到大字符串这就悲剧了。所以一些大字符串怎么处理呢。
A:其实实际中,大字符串也难见。但说处理的话,大字符串匹配可以考虑分割匹配或是啥的这里就不展开了。
Q:equals重写 和 hashCode 有关系吗?
A:这里我们要先说明hashCode方法提供对象的hashCode值,返回与默认的System.identityHashCode()一致。其广泛用于集合框架。到后面我也会讲到。hashCode的源于计算机的比较源于数字,而不是对象。所以一个hashCode值标识一个对象,产生了对象相关的很多算法。但是默认的hashCode犯法会发起对本地的调用开销很大。
好累好累,泥瓦匠喝口水,讲完下面这个,我们String到此结束。
1.6 intern妙用
intern大家就有点陌生了。咱们首先得普及下常量池的概念,常量池(constant pool)指的是在编译期被确定,并被保存在已编译的.class文件中的一些数据。它包括了关于类、方法、接口等中的常量,也包括字符串常量。然后看看下面的例子:
private static void test5(){
String a = "a";
String b = a + "b";
String c = "ab";
String d = new String("ab");
System.out.println(c == d.intern());
System.out.println(b.intern() == d.intern());
}
当调用 intern()方法时,JVM 会在这个常量池中通过 equals()方法查找是否存在等值的 String,如果存在,则直接返回常量池中这个 String 对象的地址;没有找到,则会创建等值的字符串,返回其地址。
思考提升:这有什么用呢?
答曰:可以用于一些常量的存储比较,枚举(枚举底层就是字符串,哈哈)。当想常量比常量,多数的情况下,考虑效率则选择 intern()而不是equals。
总结
String是Java基础组件重要的一部分。我慢慢的总结的J2EE Java的组件体系,然后增加内容进去。还是那句话,泥瓦匠想说:
如以上文章或链接对你有帮助的话,别忘了在文章按钮或到页面右下角点击 “赞一个” 按钮哦。你也可以点击页面右边“分享”悬浮按钮哦,让更多的人阅读这篇文章
[Java 泥水匠] Java Components 之一:Java String (肯定有你不懂的)的更多相关文章
- [Java 泥水匠] Java Components 之二:算法篇之项目实践中的位运算符(有你不懂的哦)
作者:泥沙砖瓦浆木匠网站:http://blog.csdn.net/jeffli1993个人签名:打算起手不凡写出鸿篇巨作的人,往往坚持不了完成第一章节. 交流QQ群:[编程之美 365234583] ...
- Java总结篇系列:Java String
String作为Java中最常用的引用类型,相对来说基本上都比较熟悉,无论在平时的编码过程中还是在笔试面试中,String都很受到青睐,然而,在使用String过程中,又有较多需要注意的细节之处. 1 ...
- Java面试炼金系列 (1) | 关于String类的常见面试题剖析
Java面试炼金系列 (1) | 关于String类的常见面试题剖析 文章以及源代码已被收录到:https://github.com/mio4/Java-Gold 0x0 基础知识 1. '==' 运 ...
- Java学习笔记之:Java String类
一.引言 字符串广泛应用在Java编程中,在Java中字符串属于对象,Java提供了String类来创建和操作字符串. 创建字符串最简单的方式如下: String str= "Hello w ...
- java.sql.SQLException: Invalid parameter object type. Expected 'java.util.Map' but found 'java.lang.String 转载
java.sql.SQLException: Invalid parameter object type. Expected 'java.util.Map' but found 'java.lang. ...
- JAVA中Integer.valueOf, parsetInt() String.valueOf的区别和结果
先来看段代码 public class IntegerDemo { public static void main(String[] args) { String num = null; System ...
- JAVA基础复习与总结<五> String类_File类_Date类
String类 .Java字符串就是Unicode字符序列,例如串“Java”就是4个Unicoe字符组成. .Java没有内置的字符串类型,而是在标准java类库中提供了一个预定义的类String, ...
- java字符数组char[]和字符串String之间的转换
java字符数组char[]和字符串String之间的转换 觉得有用的话,欢迎一起讨论相互学习~Follow Me 使用String.valueOf()将字符数组转换成字符串 void (){ cha ...
- Java编程的逻辑 (29) - 剖析String
本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http: ...
- 不使用java内置函数,将String字符串转换为int类型
package com.test; public class AtoiTest { public static void main(String[] args) throws Exception { ...
随机推荐
- 在datasnap 中使用unidac 访问数据(客户端)
前面我们讲了如何使用unidac 在datasnap 的服务端访问数据库,今天大概讲一下客户端如何访问 前面做的服务器?其实这个客户端适合任何datasnap 服务端. 首先我们建一个应用,并加入一个 ...
- FeatureTools
featuretools一种自动特征工程的工具.可快速生成较多类型的特征,取得不错的效果. 1.输入:把原始数据转换成featuretools的输入 2. 可以适当调整特征个数,防止训练的模型过拟合 ...
- JMeter接口压测——ServerAgent监控服务端性能指标
ServerAgent作为一个服务端性能监控插件,结合JMeter自身插件PerfMon可以实现JMeter压测的图形化实时监控,具有良好的实用性.下面讲解一个应用实例 思路: 1. 插件准备 2.打 ...
- git遇到的问题-- Another git process seems to be running in this repository
执行git add .时,报错 fatal: Unable to create '/Users/lily/ForWork/forReBaomai/bm-fe/.git/index.lock': Fil ...
- explicit_defaults_for_timestamp引发的狗血剧情
今天就碰到了一个较初级的问题,居然为找这个参数花了好半天时间,深以为不齿.需求是这样的,有个表的某个字段需要从datetime改成timestamp类型.原结构如下:create table tmp1 ...
- Jquery动态添加/删除表格行和列
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- 初学者必看的文章:在VM12中安装 RedHat RHEL7.2 系统的详细步骤:看我如何操纵RHEL系统
一.开始安装 1)新建虚拟机 RHEL7.2 2)成功引导系统--开机出现此画面 Install Red Hat EnterpriseLinux 7.2 安装RHLE7.2 操作系统 Test th ...
- alfred3配置
搜索功能配置 github https://github.com/search?utf8=%E2%9C%93&q={query} github'{query}' g baidu http:// ...
- c++实现对windwos 下socket 的封装(实现封包及拆包处理)
SuperSocket.h #pragma once #include<string> #include<iostream> #include <WINSOCK2.H&g ...
- Debian 8.x / Ubuntu 16.04.x 搭建 Ghost 教程
Ghost 是一款使用 Node.js 开发的博客系统,相对于使用 PHP 开发的 WordPress 更轻巧友好,所以本站已经从 WordPress 切换至 Ghost,本文介绍在 Debian 8 ...