string是java关键字吗_Java基础-关键字-String_weixin_30423065的博客-程序员宅基地

技术标签: string是java关键字吗  

1、String的本质

线程安全

打开String的源码,类注释中有这么一段话“Strings are constant; their values cannot be changed after they are created. String buffers support mutable strings.Because String objects are immutable they can be shared.”。这句话总结归纳了String的一个最重要的特点:String是值不可变(immutable)的常量,是线程安全的(can be shared)。

不可继承

String类使用了final修饰符,表明了String类的第二个特点:String类是不可继承的。

在Java中,被final修饰的类是不允许被继承的,并且该类中的成员方法都默认为final方法。在早期的JVM实现版本中,被final修饰的方法会被转为内嵌调用以提升执行效率。而从Java SE5/6开始,就渐渐摈弃这种方式了。因此在现在的Java SE版本中,不需要考虑用final去提升方法调用效率。只有在确定不想让该方法被覆盖时,才将方法设置为final。

值不可变,存储方式为字符数组

private final charvalue[];private final int count;

从final的修饰可以看出其不可变性

其中的String类的 concat方法为起扩容,如果方法的参数长度等于0这返回this,否则并组成一个新的string,并紧随其后拼接参数后返回新的string

我们看String类的concat方法。实现该方法第一步要做的肯定是扩大成员变量value的容量,扩容的方法重新定义一个大容量的字符数组buf。第二步就是把原来value中的字符copy到buf中来,再把需要concat的字符串值也copy到buf中来,这样子,buf中就包含了concat之后的字符串值。下面就是问题的关键了,如果value不是final的,直接让value指向buf,然后返回this,则大功告成,没有必要返回一个新的String对象。但是。。。可惜。。。由于value是final型的,所以无法指向新定义的大容量数组buf,那怎么办呢?“return new String(0, count + otherLen, buf);”,这是String类concat实现方法的最后一条语句,重新new一个String对象返回。这下真相大白了吧!

String类其实是通过char数组来保存字符串的。

总结:String实质是字符数组,两个特点:1、该类不可被继承;2、不可变性(immutable)。

public String substring(int beginIndex, intendIndex) {if (beginIndex < 0) {throw newStringIndexOutOfBoundsException(beginIndex);

}if (endIndex >count) {throw newStringIndexOutOfBoundsException(endIndex);

}if (beginIndex >endIndex) {throw new StringIndexOutOfBoundsException(endIndex -beginIndex);

}return ((beginIndex == 0) && (endIndex == count)) ? this:new String(offset + beginIndex, endIndex -beginIndex, value);

}publicString concat(String str) {int otherLen =str.length();if (otherLen == 0) {return this;

}char buf[] = new char[count +otherLen];

getChars(0, count, buf, 0);

str.getChars(0, otherLen, buf, count);return new String(0, count +otherLen, buf);

}public String replace(char oldChar, charnewChar) {if (oldChar !=newChar) {int len =count;int i = -1;char[] val = value; /*avoid getfield opcode*/

int off = offset; /*avoid getfield opcode*/

while (++i

}

}if (i

buf[j]= val[off+j];

}while (i

buf[i]= (c == oldChar) ?newChar : c;

i++;

}return new String(0, len, buf);

}

}return this;

从上面的三个方法可以看出,无论是sub操、concat还是replace操作都不是在原有的字符串上进行的,而是重新生成了一个新的字符串对象。也就是说进行这些操作后,最原始的字符串并没有被改变。

“对String对象的任何改变都不影响到原对象,相关的任何change操作都会生成新的对象”。

2、String的内存机制

JVM运行时,会将内存分为两个部分:堆和栈。堆中存放的是创建的对象,而栈中存放的方法调用过程的局部变量或引用。而设计Java字符串对象内存实现的时候,在堆中又开辟了一块很小的内存,称之为字符串常量池,专门用来存放特定的字符串对象。

创建Java字符串对象有两种常用的方式:

String 引用变量名="字符串内容";

String 应用变量名=new String();

我们先来看看创建字符串对象的第一种方式内存如何分配的,代码如下:

String s1="osEye.net";

String s2="osEye.net";

052ab4471827727511e4b807aa5a9700.png

如上图描述了引用对象的关系,以及内存的分配。Java实现的步骤如下:

查看字符串常量池中是否存在内容与“osEye.net”相同的字符串对象。

若没有,则新创建一个包含该内容的字符串对象,并让引用变量指向该对象。例如,创建字符串s1的时候,字符串常量池中没有,则创建一个新对象,并让引用s1指向该对象。

若已经存在包含该内容的字符串对象,则让字符串引用直接指向该对象。例如,在创建字符串s2的时候,字符串常量池中已经有包含该内容的对象了,所以引用s2直接指向已有的对象。

在来看看第二种创建字符串对象的方式:

String s1="osEye.net";

String s2=new String("osEye.net");

如上图描述了引用对象的关系,以及内存的分配。Java实现的步骤如下:

首先在堆(不是常量池)中创建一个包含指定内容的字符串对象,并将字符串引用指向该对象。例如上述代码中,使用new创建字符串s3,其会直接在堆中创建一个内容为“osEye.net”的字符串对对象,并将引用s3指向该对象。

去字符串常量池中查看,是否有包含该内容的对象。

若有,则将new出来的字符串对象与字符串常量池中内容相同的对象联系起来。例如,本例中s3所指向的对象与s1所指向的联系起来。

若没有,则在字符串常量池再创建一个包含该内容的字符串对象,并将堆中的对象与字符串常量池中新创建出来的对象联系起来。

我们知道,new出来的字符串对象和字符串常量池中的对象是有联系的,可以通过intern方法来查看,方法签名:

public String intern()

此方法将指定的字符串引用在字符串常量池中对应的对象,若其指向的对象本身就在字符串常量池中,则直接将自己指向的对象返回;若该字符串引用指向的对象在堆中,则返回字符串常量池中与其联系的对象。实例如下:

packagenet.oseye;public classExceptionTest {public static voidmain(String[] args) {

String s1="osEye.net";

String s2=new String("osEye.net");if(s1==s2){

System.out.println("字符串引用s1和字符串引用s2所指向的是同一个对象");

}else{

System.out.println("字符串引用s1和字符串引用s2所指向的不是同一个对象");

}if(s1.intern()==s2.intern()){

System.out.println("字符串引用s1和字符串引用s2在字符串常量池中联系的是同一个对象");

}else{

System.out.println("字符串引用s1和字符串引用s2在字符串常量池中联系的不是同一个对象");

}

}

}

输出结果:

字符串引用s1和字符串引用s2所指向的不是同一个对象

字符串引用s1和字符串引用s2在字符串常量池中联系的是同一个对象

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_30423065/article/details/114388016

智能推荐

Linux基础(第一章)Linux安装和环境配置_hwq317622817的博客-程序员宅基地

安装虚拟机由于目前只是学习使用Linux系统,并没有专门的主机来给我们安装Linux系统,所以需要借助虚拟机来实现学习目的。常用的就是Vmware WorkStation,推荐不要用最新版本,资源网上找。Vmware WorkStation的安装就是一直下一步,只是安装路径需要设置。安装Linux系统1、下载一个Linux系统,Linux系统的版本有很多,因为它是开源的。一般常用的是RedHat、CentOS和Ubuntu,我使用的是CentOS7,资源网上找,像阿里云什么的上面就可以找到;2、打

第22讲:验证码反爬虫的基本原理_埃菲尔没有塔尖的博客-程序员宅基地_验证码反爬虫

我们在浏览网站的时候经常会遇到各种各样的验证码,在多数情况下这些验证码会出现在登录账号的时候,也可能会出现在访问页面的过程中,严格来说,这些行为都算验证码反爬虫。本课时我们就来介绍下验证码反爬虫的基本原理及常见的验证码和解决方案。验证码验证码,全称叫作 Completely Automated Public Turing test to tell Computers and Humans Apart,意思是全自动区分计算机和人类的图灵测试,取了它们关键词的首字母变成了 CAPTCHA,它是一种用来区分

计算机辅助英语教学mti,计算机辅助翻译与翻译硕士(MTI)专业建设_思一缘的博客-程序员宅基地

摘要:本选题旨在通过概括国内外开设的计算机辅助翻译(CAT)课程现状,分析课程目前存在的问题,针对新兴的翻译硕士专业学位(MTI)的开设,提出符合我国社会需要的MTI-CAT教学体系,并构建适应时代需求的新型翻译教学模式。 在竞争日益激烈的当今世界,如能更高效高质完成自己的工作,就会占据优势。计算机辅助翻译与繁重的手工翻译相比,可以大大提高翻译效率与翻译质量,具有更大的竞争优势。在翻译市场需求不断...

【JavaScript的ES6语法】9、generator函数之yield关键字_光仔December的博客-程序员宅基地_javascript yield

上一篇我们学习了generator的基本概念 ,知道它可以将方法暂停挂起,需要继续执行的时候再继续执行,在暂停方法的时候,我们使用到了一个关键字“yield”,本篇我们就来重点讲解一下这个关键字。“yield”的主要作用就是放弃当前的方法执行进程,等待新的执行指令后,再继续执行后续的逻辑代码。yield除了发挥刚刚的作用,实际上它还可以传参,也可以返回数据。一、yield传参例如下面的generator方法:&lt;script type="text/javascript"&gt;..

eclipse+webservice开发实例_瓜瓜东西的博客-程序员宅基地

此文有几处错误需要更正,一个是要建立web项目第二 小心路径要引用对,service的路径,要有选择方法的步骤,都没有的话肯定错了1.参考文献:1.利用Java编写简单的WebService实例  http://nopainnogain.iteye.com/blog/7915252.Axis2与Eclipse整合开发Web Service  http:/

Java的诞生_whyyoualwayssilly的博客-程序员宅基地

Java是由James Gosling、Patrick Naughton、Chris Warth、Ed Frank 和 Mike Sheridan 于1991年在Sun公司构想出来的。开发第一个版本花费了18个月。这种语言最初称为Oak,在1995年被命名为Java。从1992年秋Oak最初实现到1995年春Java语言的公开发布,许多人对Java的设计和改进作出了贡献。Bill Joy、Ar

随便推点

服务器安全软件 服务器安全狗 V3.3.01132版_weixin_34220963的博客-程序员宅基地

2019独角兽企业重金招聘Python工程师标准&gt;&gt;&gt; ...

抽象类、接口和内部类(下)_羽翼冰蓝的博客-程序员宅基地

Top抽象类、接口和内部类(下)面向对象汇总1. 抽象类、接口和内部类(下)1.1. 多态1.1.1. 多态的意义前面所讲解的现象就是多态,多态即多种形态,主要有两个方面的表现。首先,一个类型的引用在指向不同的对象时会有不同的实现,看如下的代码:copytextpop-up达内职员 emp1 = new 达内讲师(); 达内职

python中threading产生死锁_Python中死锁的形成示例及死锁情况的防止_止蚀的博客-程序员宅基地

死锁示例搞多线程的经常会遇到死锁的问题,学习操作系统的时候会讲到死锁相关的东西,我们用Python直观的演示一下。死锁的一个原因是互斥锁。假设银行系统中,用户a试图转账100块给用户b,与此同时用户b试图转账200块给用户a,则可能产生死锁。2个线程互相等待对方的锁,互相占用着资源不释放。#coding=utf-8importtimeimportthreadingclassAccount:def ...

高中数学基础01:集合与函数_追梦小乐的博客-程序员宅基地_集合与函数

内容来自百度百科知识以及东方耀老师笔记内容的整合1、集合1.1 集合的定义由一个或多个确定的元素所构成的整体叫做集合。若x是集合A的元素,则记作x∈A。1.2 集合的三个特征确定性(集合中的元素必须是确定的)。 互异性(集合中的元素互不相同)。例如:集合A={1,a},则a不能等于1)。 无序性(集合中的元素没有先后之分),如集合{3,4,5}和{3,5,

vue 上拉加载更多_会做饭的技术男的博客-程序员宅基地

var _this=this; var goods_id = _this.$route.query.id; var isscroll = true; _this.$nextTick(() =&gt; { var el = document.querySelector(".rating_cnt_scroll"); var offsetHeight = el.offsetHeight; el.onscroll = () =&gt; {

使用kubeadm搭建高可用的K8s集群_zhangfei_bk的博客-程序员宅基地_k8s 高可用

kubeadm是官方社区推出的一个用于快速部署kubernetes集群的工具。这个工具能通过两条指令完成一个kubernetes集群的部署:# 创建一个 Master 节点$ kubeadm init# 将一个 Node 节点加入到当前集群中$ kubeadm join &lt;Master节点的IP和端口 &gt;1. 安装要求在开始之前,部署Kubernetes集群机器需要满足以下几个条件:一台或多台机器,操作系统 CentOS7.x-86_x64硬件配置:2GB或更多RAM,2

推荐文章

热门文章

相关标签