字符串String 2019-03-12

字符串

String表示字符串类型,String虽然本身不属于基本数据类型,但是可以像基本数据类型一样使用方便,是JVM对String类做了特殊的处理

String类只所以特殊,其原因主要就是有两种不同的对象实例化方式

方式一:采用直接赋值的形式为String类进行赋值

方式二: 通过String类的构造方法完成对象实例化

范例: 通过直接赋值的方式为String类实例化对象

public static void main(String[]args){
    
        
        String str="hello world"; //定义一个字符串 并且直接赋值

        System.out.println(str);
        
    }

String明确告诉大家肯定是一个类,程序中出现的str就是String类的对象名称,String类的赋值操作就是为str这个对象进行实例化操作

范例; 通过String类的构造方法进行对象的实例化操作

public static void main(String[]args){
        
        String str=new String("hello world");

        System.out.println(str);
        
    }

通过以上的代码比较,两种方式都可以为String类进行对象的实例化操作,这两种方式有什么不同,使用哪个比较好?

字符串的比较

如果两个int类型进行比较的时候,直接使用==就可以了,现在使用==进行字符串的比较

public static void main(String[]args){
    
        
        String str1="hello";

        String str2=new String("hello");

        String str3=str2;//引用传递

        System.out.println(str1==str2); //false

        System.out.println(str1==str3); //false

        System.out.println(str2==str3); //true
    }

虽然以上的字符串的内容完全一样,但是使用了==进行比较的时候结果就不一样了,为什么不一样的结果,通过内存分析图来解答


内存分析图

通过上图的分析可以发现,使用==运算符比较的是内存的地址,对于String这个类来说使用==比较的是对象的内存地址,并没有比较字符串的内容,如果想要比较字符串的内容则必须使用String类提供的操作方法 equals()

 public boolean equals(Object anObject); 字符串内容的比较

范例:使用equals 进行方法的比较

public static void main(String[]args){
    
        String str1="hello";

        String str2=new String("hello");

        String str3=str2;//引用传递

        System.out.println(str1.equals(str2)); //true

        System.out.println(str1.equals(str3)); //true

        System.out.println(str2.equals(str3)); //true
    }

通过以上的代码的分析,可以得出如下结论:

String进行字符串比较的时候 == 与 equals的区别是什么?

== : 比较的是内存地址,属于数值比较

equals :比较的是字符串的内容,属于内容比较

字符串常量是String类的匿名对象

java中使用” ” 来定义一个字符串,在这里面每一个字符串都表示一个String类的对象,即每一个字符串常量就是一个String类的匿名对象

范例:验证字符串是对象的概念

public static void main(String[]args){
    
        
        String str="hello";

        System.out.println("hello".equals(str));
    }

从以上的程序上验证了一个字符串就是一个String类的匿名对象,通过匿名对象可以调用类中的属性与方法. 由此引出在String处理字符串比较的时候常用的用法如下

范例: 字符串比较,模拟用户输入

public static void main(String[]args){
    
        
        String str=null;

        if("hello".equals(str)){
        
            System.out.println("条件满足");
        }
        
    }

通过以上的程序,假设在处理字符串的时候,字符串是用户自己输入的时候,使用匿名对象进行字符串的比较可以避空指向异常的出现

String类的两种实例化方式的区别?

清楚了String的操作之后,现在就要分析一个问题,两种实例化方式的区别 ,在开发中使用哪个更好

范例:分析直接赋值的情况

public static void main(String[]args){
    
        String str1="hello";  //直接赋值

        String str2="hello";  //直接赋值

        String str3="hello";  //直接赋值

        System.out.println(str1==str2);

        System.out.println(str2==str3);

        System.out.println(str1==str3);
        
    }

以上的程序使用了直接赋值的方式。实例化了3个对象,本程序使用了==进行比较 发现3个字符串的内存地址完全相同,也就是3个对象实际上开辟了一块空间


image.png

对于以上的案例,直接赋值字符串都相同的原因如下:

在String类进行设计的时候,采用了一种叫做共享设计模式的概念,每一个运行的JVM底层会有一个字符串的对象池(Object Pool),如果用户采用直接赋值的时候,会将字符串的内容放到对象池中,以供其他String直接赋值方式的对象使用,如果新声明的字符串不在池中,则会新开辟一块空间,继续放到池中供下次使用

范例:分析构造方法实例化的情况

public static void main(String[]args){
    
    
        String str=new String("hello");
        
    }
image.png

通过以上的画图分析,由于每一个字符串都是一个String类的匿名对象,首先会在堆内存中开辟一块空间保存字符串常量 hello ,而后又使用了关键字new 又开辟了另外一块堆内存空间,实际上使用的通过new关键字开辟的空间,匿名字符串对象则会变为垃圾空间存在等待被回收

另外使用构造方法实例化的时候,String类的对象不会保存在字符串常量池中,但是课题通过手动调用intern()方法手动入池

范例:验证入池的问题

public static void main(String[]args){
    
    
        String str1=new String("hello");  //不会进入常量池

        String str2="hello";

        String str3="hello";

        System.out.println(str1==str2);  //false

        System.out.println(str1==str3);  //false

        System.out.println(str2==str3);  //true
        
    }

以上的程序可以发现,通过构造方法实例化String类对象的时候是不会自动进入到对象常量池的,但是可以通过手动入池的方法完成

public static void main(String[]args){
    
    
        String str1=new String("hello").intern();  //不会进入常量池

        String str2="hello";

        String str3="hello";

        System.out.println(str1==str2);  //false

        System.out.println(str1==str3);  //false

        System.out.println(str2==str3);  //true
        
    }

通过以上的分析,得出如下结论:

String类的两种实例化方式的区别?

直接赋值: 只开辟一块堆内存空间,并且字符串的内容可以自动入池

构造方法:开辟两块堆内存空间,其中一块将称为垃圾空间,并且不能自动的入池,需要手动调用intern()方法进行入池

3.5 字符串的内容一旦声明则不可改变
在使用String类的时候有一个重要的特点,那就是字符串的内容一旦声明则不可改变

范例: 字符串内容声明后不可改变

public static void main(String[]args){
        
        String str="hello";

        str+="world";

        System.out.println(str);
        
    }

通过以上的程序,进行字符串的拼接操作,str这个对象经过了多次的字符串拼接内容已经进行了改变,实际上来说,改变的是对象的指向而不是堆内存中的内容.


image.png

通过上图可以发现,每一次进行字符串拼接的时候都会产生垃圾空间,并且内容没有改变,改变的只是字符串的内存地址指向,如果对字符串进行大量的拼接操作则会产生大量的垃圾

范例: 应该避免出现的代码

public static void main(String[]args){
    
    
        
        String str="";

        for(int i=0;i<100000;i++){
        
            str+=i;
        }

        System.out.println(str);
        
    }

范例:通过方法修改字符串的内容进行验证

public static void main(String[]args){
    
    
        
        String str="hello";

        fun(str);

        System.out.println(str);

    }


    public static void fun(String str){
    
        
        str+="world";
    }

通过以上的代码,进行验证说明在方法中进行字符串的拼接之后,在方法执行完毕之后,字符串的内容没有被修改,说明字符串的内容是不可被改变的

String类的常用方法

String类除了之前讲解的,intern()方法以及equals()方法之外还存在大量操作方法,这些方法可以通过java api进行查看

通过javaapi 观察String类可以得出如下分类:

构造方法

1) public String(byte[] bytes,int offset,int length)把一个字节数组转换为一个字符串
Offset 为数组的开始位置,length 长度

普通方法

  1. public char charAt(int index) 根据索引找到指定的字符
  2. public String concat(String str) 字符串的拼接方法
  3. public boolean equalsIgnoreCase(String anotherString) 字符串内容的比较忽略大小写
  4. public int indexOf(String str)
  5. public String substring(int beginIndex) 字符串的截取
  6. public String substring(int beginIndex,int endIndex) 字符串的截取
  7. public char[] toCharArray() 把一个字符串转换为字符数组
  8. public byte[] getBytes() 把字符串变为字节数组
  9. public boolean startsWith(String prefix)判断是否以指定的字符开头
  10. public boolean endsWith(String suffix) 判断是否以指定字符结尾
  11. public boolean contains(CharSequence s) 判断一个字符串子串是否存在
  12. public String replaceAll(String regex,String replacement) 字符串替换 全部替换
  13. public String replaceFirst(String regex,String replacement)替换首个
  14. public String[] split(String regex)按照指定的字符串进行拆分全部拆分
  15. public String[] split(String regex,int limit) 拆分为指定的长度
  16. public boolean isEmpty()判断字符串是否为空
  17. public String trim()去掉字符串的左右空格
  18. public String toUpperCase()把字符串全部转换为大写
  19. public String toLowerCase() 把字符串全部转换为小写

范例

范例:验证charat方法

public static void main(String[]args){
    
    
        String str="hellworld";  //定义一个字符串

        char c=str.charAt(0);  //取第7个索引上的字符

        System.out.println(c);

    }

范例2:进行字符串与字符数组的转换,并且把一个小写字符串变为大写字符串,最终要把字符数组在转换为字符串

public static void main(String[]args){
    
    
        String str="hellworld";  //定义一个字符串

        char[] array=str.toCharArray(); //把字符串转换字符数组

        for(int i=0;i<array.length;i++){
        
            array[i]-=32;  //变大写
        }

        System.out.println(new String(array));  //把字符数组转换为字符串
    }

范例3:判断一个字符串是否由数字组成

public static void main(String[]args){
    
    
        String str="123"; 

        System.out.println(isNumber(str));
        
    }

    public static boolean isNumber(String temp){
    
        
        char[] data=temp.toCharArray();

        for(int i=0;i<data.length;i++){
        
            if(data[i]<'0'||data[i]>'9'){
            
                return false;
            }
        }

        return true;
    }

字符串除了与字符进行相互转换之外,还可以与字节进行转换

范例4:完成小写字母变大写字母的操作

public static void main(String[]args){
    
        String str="helloworld";  

        byte[]data=str.getBytes(); //把字符串变为字节数组

        for(int i=0;i<data.length;i++){
        
            System.out.print(data[i]+",");

            data[i]-=32;
        }

        System.out.println(new String(data));
        
        
    }

范例5:判断字符串的开头与结尾

public static void main(String[]args){
    
        
        String str="**@@hello##";

        System.out.println(str.startsWith("**"));  //判断是否以**开头


        System.out.println(str.endsWith("o"));
        
    }

范例6:查找字符串是否存在

public static void main(String[]args){
    
        
        String str="helloworld";

        System.out.println(str.contains("hello")); //查找字符串

        System.out.println(str.contains("xx")); 
        
    }

范例7: 从指定的位置开始查找字符的位置 indexOf

public static void main(String[]args){
    
        
        String str="binbin.com";

        if(str.indexOf("@")!=-1){
        
            System.out.println("符合验证");
        }
        
    }

范例8:字符串的替换操作

public static void main(String[]args){
    
        String str="hello world";

        System.out.println(str.replaceAll("l","_"));  //替换全部

        System.out.println(str.replaceFirst("l","_")); //替换首个
    }

范例9:字符串的截取

public static void main(String[]args){

        String str="helloworld";

        System.out.println(str.substring(6));  //从指定位置截取

        System.out.println(str.substring(0,5)); //从指定位置到结束位置的截取
    }

范例:字符串的拆分

public static void main(String[]args){
    
        
        String str="hello world!!";

        
        String[]result=str.split("l"); //按照空格来拆分;


        for(int i=0;i<result.length;i++){
        
            System.out.print(result[i]+",");
        }
    }

范例10:拆分为指定的个数

public static void main(String[]args){
    
        
        String str="hello world!!";

        
        String[]result=str.split("",2); //按照指定的长度拆分


        for(int i=0;i<result.length;i++){
        
            System.out.print(result[i]+",");
        }
    }

范例11:判断字符串是否为空

public static void main(String[]args){
    
        
        String str="hello";

        System.out.println(str.isEmpty()); //false

        System.out.println("".isEmpty()); //true;

        System.out.println(str.length());  //得出字符串的长度

    }

范例:去掉字符串左右空格

public static void main(String[]args){
    
        
        String str="     hello       ";

        System.out.println(str);


        System.out.println(str.trim());  //去掉左右空格
    }

总结

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,723评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,080评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,604评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,440评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,431评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,499评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,893评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,541评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,751评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,547评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,619评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,320评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,890评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,896评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,137评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,796评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,335评论 2 342

推荐阅读更多精彩内容

  • 前言 最先接触编程的知识是在大学里面,大学里面学了一些基础的知识,c语言,java语言,单片机的汇编语言等;大学毕...
    oceanfive阅读 3,037评论 0 7
  • 一、Python简介和环境搭建以及pip的安装 4课时实验课主要内容 【Python简介】: Python 是一个...
    _小老虎_阅读 5,713评论 0 10
  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,081评论 1 32
  • 一、基础知识:1、JVM、JRE和JDK的区别:JVM(Java Virtual Machine):java虚拟机...
    杀小贼阅读 2,362评论 0 4
  • 君又回,还家尔。 石台把酒半醉,落泪。 雁南飞,满纷飞。 明月无归照人,断魂。
    钧瓷阅读 349评论 0 1