1.3Java面向对象--常用的类(三)

本文详细介绍了Java中的String类,包括其构造方法、字符串不变性、常量池概念以及常用的判断、获取、转换方法。讲解了字符串的创建、比较、拼接和转换等操作,并通过实例展示了String对象在内存中的存储情况。同时,文章提到了String类的intern()方法和包装类的常量池技术,帮助读者深入理解Java字符串的运用。
摘要由CSDN通过智能技术生成

文章目录

第五章 String类

教学目标

能够使用String类的构造方法创建字符串对象
能够明确String类的构造方法创建对象,和直接赋值创建字符串对象的区别
能够使用文档查询String类的判断方法
能够使用文档查询String类的获取方法
能够使用文档查询String类的转换方法

1.1 String类概述

概述
java.lang.String 类代表字符串。Java程序中所有的字符串文字(例如 “abc” )都可以被看作是实现此类的实例。类 String 中包括用于检查各个字符串的方法,比如用于1、比较字符串2、搜索字符串3、提取子字符串以及4、创建具有翻译为大写或小写的所有字符的字符串的副本
特点

  1. 字符串不变:字符串的创建后不能被更改。而是指向了另一个对象
String s1 = "abc";
        s1 += "d";
        System.out.println(s1); // "abcd" 
// 内存中有"abc","abcd"两个对象,s1从指向"abc",改变指向,指向了"abcd"
  1. 因为String对象是不可变的,所以它们可以被共享
    内存中只有一个"abc"对象被创建,同时被s1和s2共享
String s1 = "abc"; 
String s2 = "abc"; 
// 内存中只有一个"abc"对象被创建,同时被s1和s2共享。
  • "abc" 等效于 char[] data={ ‘a’ , ‘b’ , ‘c’ }
    String底层是靠字符数组实现的。
例如: 
String str = "abc"; 
相当于: 
char data[] = {'a', 'b', 'c'}; 
String str = new String(data); 
// String底层是靠字符数组实现的。
1.2 使用步骤

查看类
java.lang.String :此类不需要导入。(可以直接使用)
查看构造方法
public String()初始化新创建的 String对象,以使其表示空字符序列。
public String(char[] value) :通过当前参数中的字符数组来构造新的String。
public String(byte[] bytes) :通过使用平台的默认字符集解码当前参数中的字节数组来构造新的String。
构造举例,代码如下:

// 无参构造 
String str = new String(); 
// 通过字符数组构造 
char chars[] = {'a', 'b', 'c'}; 
String str2 = new String(chars); 
// 通过字节数组构造 
byte bytes[] = { 97, 98, 99 }; 
String str3 = new String(bytes);

常量池
常量池大体可以分为:静态常量池运行时常量池。

静态常量池 存在于class文件中,比如经常使用的javap -verbose中,常量池总是在最前面。
运行时常量池,就是在class文件被加载进了内存之后,常量池保存在了方法区中,通常说的常量池值的是运行时常量池。所以呢,讨论的都是运行时常量池字符串常量池。

最最最流行的、最典型的就是字符串了

String a = "abc"; //方法区的abc
String b = new String("abc"); //堆里的abc
System.out.println(a == b); 
----*---- 
结果:false

在这里插入图片描述
这个是第一个需要理解的地方,a指向哪片内存,b又指向哪片内存呢?对象储存在堆中,这个是不用质疑的,而a作为字面量一开始储存在了class文件中,之后运行期,转存至方法区中。它们两个就不是同一个地方存储的。知道了它之后我们就可以通过实例直接进一步了解了

实例

String s1 = "Hello"; 
String s2 = "Hello"; 
String s3 = "Hel" + "lo"; 
String s4 = "Hel" + new String("lo"); 
String s5 = new String("Hello"); 
String s6 = s5.intern(); 
String s7 = "H"; 
String s8 = "ello"; 
String s9 = s7 + s8; 
System.out.println(s1 == s2); // true 
System.out.println(s1 == s3); // true 
System.out.println(s1 == s4); // false 
System.out.println(s1 == s9); // false 
System.out.println(s4 == s5); // false 
System.out.println(s1 == s6); // true

分析:
1、s1 = = s2 很容易可以判断出来。s1 和 s2 都指向了方法区常量池中的Hello。
2、s1 = = s3 这里要注意一下,因为做+号的时候,会进行优化,自动生成Hello赋值给s3,所以也是true
3、s1 = = s4 s4是分别用了常量池中的字符串和存放对象的堆中的字符串,做+的时候会进行动态调用,最后生成的仍然是一个String对象存放在堆中。
在这里插入图片描述
s1 = = s9 在JAVA9中,因为用的是动态调用,所以返回的是一个新的String对象。所以s9和s4,s5这三者都不是指向同一块内存在这里插入图片描述
s1 = = s6 为啥s1 和 s6地址相等呢? 归功于intern方法,这个方法首先在常量池中查找是否存在一=份equal相等的字符串如果有的话就返回该字符串的引用,没有的话就将它加入到字符串常量池中,所以存在于class中的常量池并非固定不变的,可以用intern方法加入新的

包装类的常量池技术(缓存)
简单介绍

相信学过java的同学都知道自动装箱和自动拆箱,自动装箱常见的就是valueOf这个方法,自动拆箱就是intValue方法。在它们的源码中有一段神秘的代码值得我们好好看看。除了两个包装类Long和Double 没有实现这个缓存技术,其它的包装类均实现了它。

public static Integer valueOf(int i) { 
if (i >= IntegerCache.low && i <= IntegerCache.high) 
return IntegerCache.cache[i + (-IntegerCache.low)]; 
return new Integer(i); 
}
private static class IntegerCache {
    static final int low = -128;
    static final int high;
    static final Integer cache[];
    static {
// high value may be configured by property
        int h = 127;
        String integerCacheHighPropValue =
                VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
        if (integerCacheHighPropValue != null) {
            try {
                int i = parseInt(integerCacheHighPropValue);
                i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE 
                h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
            } catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it. 
            }
        }
        high = h;
        cache = new Integer[(high - low) + 1];
        int j = low;
        for(int k = 0; k < cache.length; k++)
            cache[k] = new Integer(j++);
// range [-128, 127] must be interned (JLS7 5.1.7) 
        assert IntegerCache.high >= 127;
    }
    private IntegerCache() {}
}

分析:我们可以看到从-128~127的数全部被自动加入到了常量池里面,意味着这个段的数使用的常量值的地址都是一样的。一个简单的实例

Integer i1 = 40; 
Integer i2 = 40; 
Double i3 = 40.0; 
Double i4 = 40.0; 
System.out.println("i1=i2 " + (i1 == i2)); 
System.out.println("i3=i4 " + (i3 == i4)); 
-----结果---- 
true 
false 

原理如下:
1、== 这个运算在不出现算数运算符的情况下 不会自动拆箱,所以i1 和 i 2它们不是数值进行的比较,仍然是比较地址是否指向同一块内存
2、它们都在常量池中存储着,类似于这样
在这里插入图片描述
3、编译阶段已经将代码转变成了调用valueOf方法,使用的是常量池,如果超过了范围则创建新的对象

1.3 常用方法

判断功能的方法
public boolean equals (Object anObject) :将此字符串与指定对象内容进行比较。
public boolean equalsIgnoreCase (String anotherString) :将此字符串与指定对象内容进行比较,忽略大小写。
方法演示,代码如下:

public class String_Demo01 {
    public static void main(String[] args) {
// 创建字符串对象 
        String s1 = "hello";
        String s2 = "hello";
        String s3 = "HELLO";
// boolean equals(Object obj):比较字符串的内容是否相同 
        System.out.println(s1.equals(s2)); // true 
        System.out.println(s1.equals(s3)); // false 
        System.out.println("-----------");
//boolean equalsIgnoreCase(String str):比较字符串的内容是否相同,忽略大小写 
        System.out.println(s1.equalsIgnoreCase(s2)); // true 
        System.out.println(s1.equalsIgnoreCase(s3)); // true 
        System.out.println("-----------");
    }
}

Object 是” 对象”的意思,也是一种引用类型。作为参数类型,表示任意对象都可以传递到方法中

获取功能的方法

public int length () :返回此字符串的长度。
public String concat (String str) :将指定的字符串连接到该字符串的末尾。
public char charAt (int index) :返回指定索引处的 char值。
public int indexOf (String str) :返回指定子字符串第一次出现在该字符串内的索引。
public String substring (int beginIndex) :返回一个子字符串,从beginIndex开始截取字符串到字符串结尾。
public String substring (int beginIndex, int endIndex) :返回一个子字符串,从beginIndex到endIndex截取字符串。含beginIndex,endIndex。
方法演示,代码如下:

public class String_Demo02 {
    public static void main(String[] args) {
//创建字符串对象 
        String s = "helloworld";
// int length():获取字符串的长度,其实也就是字符个数 
        System.out.println(s.length());
        System.out.println("--------");
// String concat (String str):将将指定的字符串连接到该字符串的末尾. 
        String s = "helloworld";
        String s2 = s.concat("**hello itheima");
        System.out.println(s2);// helloworld**hello itheima 
// char charAt(int index):获取指定索引处的字符 
        System.out.println(s.charAt(0));
        System.out.println(s.charAt(1));
        System.out.println("--------");
// int indexOf(String str):获取str在字符串对象中第一次出现的索引,没有返回-1 
        System.out.println(s.indexOf("l"));
        System.out.println(s.indexOf("owo"));
        System.out.println(s.indexOf("ak"));
        System.out.println("--------");
// String substring(int start):从start开始截取字符串到字符串结尾 
        System.out.println(s.substring(0));
        System.out.println(s.substring(5));
        System.out.println("--------");
// String substring(int start,int end):从start到end截取字符串。含start,含end。 
        System.out.println(s.substring(0), s.length()));
        System.out.println(s.substring(3,8));
    }
}

转换功能的方法
public char[] toCharArray () :将此字符串转换为新的字符数组。
public byte[] getBytes () :使用平台的默认字符集将该 String编码转换为新的字节数组。
public String replace (CharSequence target, CharSequence replacement) :将与target匹配的字符串使用replacement字符串替换。
方法演示,代码如下:

public class String_Demo03 {
    public static void main(String[] args) {
//创建字符串对象 
        String s = "abcde";
// char[] toCharArray():把字符串转换为字符数组 
        char[] chs = s.toCharArray();
        for(int x = 0; x < chs.length; x++) {
            System.out.println(chs[x]);
        }
        System.out.println("-----------");
// byte[] getBytes ():把字符串转换为字节数组 
        byte[] bytes = s.getBytes();
        for(int x = 0; x < bytes.length; x++) {
            System.out.println(bytes[x]);
        }
        System.out.println("-----------");
// 替换字母it为大写IT 
        String str = "itcast itheima";
        String replace = str.replace("it", "IT");
        System.out.println(replace); // ITcast ITheima 
        System.out.println("-----------");
    }
}

CharSequence 是一个接口,也是一种引用类型。作为参数类型,可以把String对象传递到方法中。

分割功能的方法
public String[] split(String regex) :将此字符串按照给定的regex(规则)拆分为字符串数组。
方法演示,代码如下

public class String_Demo03 {
    public static void main(String[] args) {
//创建字符串对象 
        String s = "aa|bb|cc";
        String[] strArray = s.split("|"); // ["aa","bb","cc"] 
        for(int x = 0; x < strArray.length; x++) {
            System.out.println(strArray[x]); // aa bb cc 
        }
    }
}
1.4 String类的练习

拼接字符串
定义一个方法,把数组{1,2,3}按照指定个格式拼接成一个字符串。格式参照如下:
[word1#word2#word3]。

public class StringTest1 {
    public static void main(String[] args) {
//定义一个int类型的数组 
        int[] arr = {1, 2, 3};
//调用方法 
        String s = arrayToString(arr);
//输出结果 
        System.out.println("s:" + s);
    }
    /*
    \* 写方法实现把数组中的元素按照指定的格式拼接成一个字符串 
    \* 两个明确: 
    \* 返回值类型:String 
    \* 参数列表:int[] arr 
    */
    public static String arrayToString(int[] arr) {
// 创建字符串s 
        String s = new String("[");
// 遍历数组,并拼接字符串 
        for (int x = 0; x < arr.length; x++) {
            if (x == arr.length - 1) {
                s = s.concat(arr[x] + "]");
            } else {
                s = s.concat(arr[x] + "#");
            }
        }
        return s;
    }
}//结果为 s:[1#2#3]

统计字符个数
✔键盘录入一个字符,统计字符串中大小写字母及数字字符个数

public class StringTest2 {
    public static void main(String[] args) {
//键盘录入一个字符串数据 
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入一个字符串数据:");
        String s = sc.nextLine();
//定义三个统计变量,初始化值都是0 
        int bigCount = 0;
        int smallCount = 0;
        int numberCount = 0;
//遍历字符串,得到每一个字符 
        for(int x=0; x<s.length(); x++) {
            char ch = s.charAt(x);
//拿字符进行判断 
            if(ch>='A'&&ch<='Z') {
                bigCount++;
            }else if(ch>='a'&&ch<='z') {
                smallCount++;
            }else if(ch>='0'&&ch<='9') {
                numberCount++;
            }else {
                System.out.println("该字符"+ch+"非法");
            }
        }
//输出结果 
        System.out.println("大写字符:"+bigCount+"个");
        System.out.println("小写字符:"+smallCount+"个");
        System.out.println("数字字符:"+numberCount+"个");
    }
}

@完


谢谢大家的观看支持,(如有错误,烦请指正)。如果感觉写的还行的话,希望三连支持一下。
🎉🎉🎉

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

James Gosling永远滴神

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值