字符串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

范例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'9'){
            
                return false;
            }
        }

        return true;
    }

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

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

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

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

        for(int i=0;i

范例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

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

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

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


        for(int i=0;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());  //去掉左右空格
    }

总结

你可能感兴趣的:(字符串String 2019-03-12)