jdk学习-String类

目录

String类简介

String类的定义

通过构造器方式

双引号直接定义

两种定义方式的区别

String类一些常用的方法

int length()

boolean isEmpty()

char charAt(int index)

boolean equals(Object anObject)

boolean equalsIgnoreCase(String anotherString)

public boolean startsWith(String prefix)

boolean endsWith(String suffix)

int indexOf(String str)

String substring(int beginIndex) 

String substring(int beginIndex, int endIndex) 

boolean contains(CharSequence s)

String replaceAll(String regex, String replacement)

String[] split(String regex)

String join(CharSequence delimiter,Iterable elements)

String trim()

结尾


  • String类简介

        String类标识字符串,Java程序中的所有字符串文字都是此类的实例,字符串是常量,它们的值在创建后不能修改,如果需要频繁修改的字符串建议使用StringBuffer或者StringBuilderStringBuffer自带同步锁。String类不是Java的基本数据类型,内部是维护了一个char数组来储存字符串。

  • String类的定义

        String类的定义有两种方式,一种是通过String类提供的构造器,另一种是使用双引号直接定义。

  • 通过构造器方式

        String类提供了十几种构造器,下面列举几个具有代表性的。

构造方法示例
public String(String original)String s=new String("abc");
public String(char value[])

char[] chars = {'a', 'b', 'c'};

String s = new String(chars);

public String(byte bytes[])byte[] bytes = new byte[1024];
String s = new String(bytes);
public String(char value[], int offset, int count)char[] chars = {'a', 'b', 'c'};
String s = new String(chars, 1, 2);
public String(StringBuffer buffer)StringBuffer sb = new StringBuffer();
String s = new String(sb);
public String(StringBuilder builder)StringBuilder sb = new StringBuilder();
String s = new String(sb);
  • 双引号直接定义

String s = "abc";
  • 两种定义方式的区别

        这两种定义方式的区别在于,第一种方式定义的字符串会创建一个对象并分配内存,字符串的具体值是储存在运行时内存区里;第二种方式定义的字符串不会创建对象,字符串的具体值储存在字符串常量里,同其他字符串(同样通过此方式定义)共享。下面举几个例子演示一下。

        String s1 = new String("abc");
        String s2 = new String("abc");
        System.out.println(s1 == s2);
        String s3 = "abc";
        String s4 = "abc";
        System.out.println(s3 == s4);
        System.out.println(s1 == s3);

         从结果可以看来,通过构造器方式定义的s1s2由于创建了不同的对象,所以不相等,而通过双引号定义的s3s4不创建对象,而是在字符串常量池中新建一个abc的常量,并且共享给s1s2,所以它们相等,s1s3相比较,s1是对象,有对象的具体地址,而s3并未创建对象,所以自然不相等。

        String类也单独提供了方法,可以让已创建的字符串对象加入字符串常量池。

public native String intern();

         这是一个本地方法,功能就是把当前字符串对象带入字符串常量池中进行比较,如果有存在相同的常量,则返回常量池的地址,否则把当前字符串加入常量池,并且返回地址。下面演示一下。

        String s1 = new String("abc");
        String s2 = "abc";
        String s3 = s1.intern();
        System.out.println(s1 == s2);
        System.out.println(s2 == s3);

  • String类一些常用的方法

    • int length()

        方法描述:返回当前字符串的长度。

    public int length() {
        return value.length;
    }

        返回字符串的长度,实际上返回的是内部维护的字符数组的长度

private final char value[];
    public static void main(String[] args) {
        String s1 = "abc";
        String s2 = " ";
        String s3 = "";
        System.out.println("s1字符串的长度:" + s1.length());
        System.out.println("s2字符串的长度:" + s2.length());
        System.out.println("s3字符串的长度:" + s3.length());
    }

       

  • boolean isEmpty()

        方法描述:判断当前字符串对象是否为空。

    public boolean isEmpty() {
        return value.length == 0;
    }

        判断当前字符串是否为空,实现就是判断当前字符数组的长度是否为0。

    public static void main(String[] args) {
        String s1 = "abc";
        String s2 = " ";
        String s3 = "";
        System.out.println("s1字符串是否为空:" + s1.isEmpty());
        System.out.println("s2字符串是否为空:" + s2.isEmpty());
        System.out.println("s3字符串是否为空:" + s3.isEmpty());
    }

  • char charAt(int index)

        方法描述:返回指定索引处的字符值。

    public char charAt(int index) {
        if ((index < 0) || (index >= value.length)) {
            throw new StringIndexOutOfBoundsException(index);
        }
        return value[index];
    }

        返回字符串某一索引位置的字符,传入了一个索引,直接当做字符数组的下标,返回该位置的字符,如果传入的索引小于0或超出数组长度,则抛出异常。

    public static void main(String[] args) {
        String s1 = "abc";
        char c = s1.charAt(1);
        System.out.println("s1索引1位置的字符是:" + c);
    }

  • boolean equals(Object anObject)

        方法描述:判断该字符串与指定对象是否相等。

    public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

        String类重写了Objectequals方法,先直接比较对象地址是否相等,然后如果是字符串的类型并且长度相等,再遍历字符数组,判断字符数组每个元素是否相等。

    public static void main(String[] args) {
        String s1 = new String("abc");
        String s2 = "abc";
        System.out.println("s1和s2是否相等:"+s1.equals(s2));
    }

  • boolean equalsIgnoreCase(String anotherString)

        方法描述:判断该字符串与指定对象是否相等,切忽略字母大小写

    public boolean equalsIgnoreCase(String anotherString) {
        return (this == anotherString) ? true
                : (anotherString != null)
                && (anotherString.value.length == value.length)
                && regionMatches(true, 0, anotherString, 0, value.length);
    }

         比较当前字符串对象和另一个字符串是否相等,且忽略字母大小写,方法里先进行了一些简单的比较和判断,然后调用了regionMatches方法,我们来看一下这个方法的实现。

    public boolean regionMatches(boolean ignoreCase, int toffset,
            String other, int ooffset, int len) {
        char ta[] = value;
        int to = toffset;
        char pa[] = other.value;
        int po = ooffset;
        // Note: toffset, ooffset, or len might be near -1>>>1.
        if ((ooffset < 0) || (toffset < 0)
                || (toffset > (long)value.length - len)
                || (ooffset > (long)other.value.length - len)) {
            return false;
        }
        while (len-- > 0) {
            char c1 = ta[to++];
            char c2 = pa[po++];
            if (c1 == c2) {
                continue;
            }
            if (ignoreCase) {
                // If characters don't match but case may be ignored,
                // try converting both characters to uppercase.
                // If the results match, then the comparison scan should
                // continue.
                char u1 = Character.toUpperCase(c1);
                char u2 = Character.toUpperCase(c2);
                if (u1 == u2) {
                    continue;
                }
                // Unfortunately, conversion to uppercase does not work properly
                // for the Georgian alphabet, which has strange rules about case
                // conversion.  So we need to make one last check before
                // exiting.
                if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) {
                    continue;
                }
            }
            return false;
        }
        return true;
    }

        同样也是先进行了一些判断,排除了不相等的条件,然后再遍历字符串内部的字符数组,并且通过Character.toUpperCase()方法将字符转换为大写再进行比较,从而实现了忽略字符大小写的功能。写个简单的示例。

    public static void main(String[] args) {
        String s1 = "abc";
        String s2 = "aBc";
        System.out.println("不忽略字符大小写是否相等:" + s1.equals(s2));
        System.out.println("忽略字符大小写是否相等:" + s1.equalsIgnoreCase(s2));
    }

  • public boolean startsWith(String prefix)

        方法描述:判断字符串是否以指定前缀开头。

        当前字符串是否是以某个字符串为前缀开始,此方法的实现调用了另一个重载方法public boolean startsWith(String prefix, int toffset),除了传入开始的字符串前缀之外还加入了一个偏移量,表示要从字符串的哪个位置开始进行判断。

    public boolean startsWith(String prefix) {
        return startsWith(prefix, 0);
    }
    public boolean startsWith(String prefix, int toffset) {
        char ta[] = value;
        int to = toffset;
        char pa[] = prefix.value;
        int po = 0;
        int pc = prefix.value.length;
        // Note: toffset might be near -1>>>1.
        if ((toffset < 0) || (toffset > value.length - pc)) {
            return false;
        }
        while (--pc >= 0) {
            if (ta[to++] != pa[po++]) {
                return false;
            }
        }
        return true;
    }

        方法里同样首先排除了不相等的条件,然后再根据需要判断的前缀字符串的内部字符数组长度作为条件进行循环,从当前字符串的偏移量位置起,和前缀字符串的第0个也就是起始位置一一进行比较,如果某一位置的字符串不相等就返回false,遍历结束就返回true,注意此方法是不会忽略大小写的。写个简单的示例。

    public static void main(String[] args) {
        String s1 = "hello,bingo";
        String s2 = "HELLO,bingo";
        String prefix = "hello";
        System.out.println(s1 + "是否是以" + prefix + "开始:" + s1.startsWith(prefix));
        System.out.println(s2 + "是否是以" + prefix + "开始:" + s2.startsWith(prefix));
    }

  • boolean endsWith(String suffix)

        方法描述:判断字符串是否以指定前缀结尾。

        当前字符串是否是以某个后缀结束,此方法的实现也是调用的boolean startsWith(String prefix, int toffset)方法。

    public boolean endsWith(String suffix) {
        return startsWith(suffix, value.length - suffix.value.length);
    }

        相当于把当前字符串的长度与需要判断后缀的字符串的长度的差值当成偏移量,那么当前字符串剩下的长度就等于需要判断是否为后缀的字符串的长度,不用再单独写实现逻辑。 写个简单的示例。

    public static void main(String[] args) {
        String s1 = "hello,bingo";
        String s2 = "hello,BINGO";
        String suffix = "bingo";
        System.out.println(s1 + "是否是以" + suffix + "结尾:" + s1.endsWith(suffix));
        System.out.println(s2 + "是否是以" + suffix + "结尾:" + s2.endsWith(suffix));
    }

  • int indexOf(String str)

        方法描述:返回字符串对象第一次出现指定字符的索引。

    public int indexOf(String str) {
        return indexOf(str, 0);
    }

        获取某个字符传的索引位置,该方法同样调用的是重载方法int indexOf(String str, int fromIndex),除了传入要查找索引位置的字符串外,还传入了一个起始的位置下标,代表从当前字符串的哪个位置开始查找,但是我们基本上常用的就是只传一个字符串的方法,不会再传一个起始的索引位置,此方法也不会忽略字母大小写,我们看一下最终重载方法的具体实现。注释中提到的示例也在下面。

   /**
     * @param source       进行查找的源字符串,示例中为变量s1
     * @param sourceOffset 进行查找的源字符串的偏移量,示例中该值等于0
     * @param sourceCount  进行查找的源字符串的长度,示例中为变量s1的长度
     * @param target       进行查找的目标字符串,示例中为变量target
     * @param targetOffset 进行查找的目标字符串查找偏移量,示例中该值等于0
     * @param targetCount  进行查找的目标字符串的长度,示例中为变量target变量的长度
     * @param fromIndex    进行查找的源字符串的起始索引位置,示例中该值为0
     * @return 在源字符串中字符串出现的第一个字符索引位置,未找到返回-1
     */
    static int read_indexOf(char[] source, int sourceOffset, int sourceCount,
                            char[] target, int targetOffset, int targetCount,
                            int fromIndex) {
        if (fromIndex >= sourceCount) {
            return (targetCount == 0 ? sourceCount : -1);
        }
        if (fromIndex < 0) {
            fromIndex = 0;
        }
        if (targetCount == 0) {
            return fromIndex;
        }

        //从目标字符串中取出第一个进行查找匹配的字符
        char first = target[targetOffset];
        //定义最大遍历的次数,因为下面的循环的初始值i=sourceOffset + fromIndex
        //便于理解我们可以直接去掉sourceOffset的值,相当于遍历的最大次数就是sourceCount - targetCount - fromIndex
        int max = sourceOffset + (sourceCount - targetCount);

        for (int i = sourceOffset + fromIndex; i <= max; i++) {
            /* Look for first character. */
            if (source[i] != first) {
                // 第一步
                // while循环,直到从源字符串中找到与目标字符串首个字符匹配的索引
                while (++i <= max && source[i] != first) ;
            }

            /* Found first character, now look at the rest of v2 */
            if (i <= max) {
                // 第二步
                // 根据上一步找到第一个源字符串中匹配的索引位置开始遍历
                // j是源字符串的下标,是从第一个与目标字符串匹配的下一个索引开始
                // end可以理解为j加上目标字符串的长度
                // 依次从源字符串和目标字符串中取出字符进行判断
                // 直到遍历次数等于查找字符串的长度或者取出的字符不相等则跳出循环
                int j = i + 1;
                int end = j + targetCount - 1;
                for (int k = targetOffset + 1; j < end && source[j]
                        == target[k]; j++, k++)
                    ;

                //如果j==end,说明跳出循环满足的条件是遍历次数等于查找的字符串的长度,而不是取出的字符不相等
                //说明已经从源字符串中找到了全匹配的目标字符串
                //在第一步中找到的首个匹配的字符索引位置i就是返回的结果(sourceOffset在最上面的注释中医提到,可以直接忽略便于理解)
                if (j == end) {
                    /* Found whole string. */
                    return i - sourceOffset;
                }
            }
        }
        //循环结束,说明没有在源字符串中没找到与目标字符全匹配,返回-1
        return -1;
    }

        为了阅读方便,我是直接把源码复制到自己代码里,并且加了注释,如果读者觉得注释看不清楚建议复制到自己的ide里查看,这个查找字符串的算法自己以后写算法或者程序都可以使用。下面写个简单的方法使用示例。

    public static void main(String[] args) {
        String s1 = "hello,bingo";
        String s2 = "hello,world";
        String s3 = "hello,BINGO";
        String target = "bingo";
        System.out.println(s1.indexOf(target));
        System.out.println(s2.indexOf(target));
        System.out.println(s3.indexOf(target));
    }

  • String substring(int beginIndex) 

        方法描述:返回此字符串对象的子字符串。

    public String substring(int beginIndex) {
        if (beginIndex < 0) {
            throw new StringIndexOutOfBoundsException(beginIndex);
        }
        int subLen = value.length - beginIndex;
        if (subLen < 0) {
            throw new StringIndexOutOfBoundsException(subLen);
        }
        return (beginIndex == 0) ? this : new String(value, beginIndex, subLen);
    }

        获取当前字符串的子串,需要传入截取子串的开始索引,可以看到,内部实现其实就是先计算出子串的长度,然后调用了String的构造方法,传入了当前字符串的字符数组,开始索引,和子串长度三个参数,下面我们看来一下这个构造方法的实现。

    public String(char value[], int offset, int count) {
        if (offset < 0) {
            throw new StringIndexOutOfBoundsException(offset);
        }
        if (count <= 0) {
            if (count < 0) {
                throw new StringIndexOutOfBoundsException(count);
            }
            if (offset <= value.length) {
                this.value = "".value;
                return;
            }
        }
        // Note: offset or count might be near -1>>>1.
        if (offset > value.length - count) {
            throw new StringIndexOutOfBoundsException(offset + count);
        }
        this.value = Arrays.copyOfRange(value, offset, offset+count);
    }

        可以看到,构造方法内部先做了一些判断校验,最后调用了Arrays.copyOfRange()方法来拷贝字符数组,作者继续追源码发现,拷贝数组的方法调用了System.arraycopy()方法,且是一个本地方法,拷贝的最终实现逻辑不是由java完成,由非java代码配合cpu完成拷贝,感兴趣的话可以读者自行探索研究。下面写一个简单的方法示例。

    public static void main(String[] args) {
        String s1 = "hello,bingo";
        System.out.println(s1.substring(0));
        System.out.println(s1.substring(6));
        System.out.println(s1.substring(999));
    }

  • String substring(int beginIndex, int endIndex) 

        方法描述:返回此字符串对象的子字符串。

    public String substring(int beginIndex, int endIndex) {
        if (beginIndex < 0) {
            throw new StringIndexOutOfBoundsException(beginIndex);
        }
        if (endIndex > value.length) {
            throw new StringIndexOutOfBoundsException(endIndex);
        }
        int subLen = endIndex - beginIndex;
        if (subLen < 0) {
            throw new StringIndexOutOfBoundsException(subLen);
        }
        return ((beginIndex == 0) && (endIndex == value.length)) ? this
                : new String(value, beginIndex, subLen);
    }

        获取当前字符串的子串,传入起始索引和结束索引两个参数,内部实现也是先计算出子串长度,然后调用了String的构造函数,最后调用Arrays.copyOfRange()方法拷贝字符数组。下面是简单的使用示例。

    public static void main(String[] args) {
        String s1 = "hello,bingo";
        System.out.println(s1.substring(0,5));
    }

  • boolean contains(CharSequence s)

        方法描述:判断此字符串对象是否包含指定字符序列。

    public boolean contains(CharSequence s) {
        return indexOf(s.toString()) > -1;
    }

         判断当前字符串是否包含某一字符值序列,方法里直接调用了indexOf()方法进行判断,indexOf()方法在上面已经介绍过,这里就不重复探究了,不过要注意此方法不会忽略字母大小写。下面是使用示例。

    public static void main(String[] args) {
        String s1 = "hello,bingo";
        String subStr1 = "bingo";
        String subStr2 = "BINGO";
        System.out.println(s1.contains(subStr1));
        System.out.println(s1.contains(subStr2));
    }

  • String replaceAll(String regex, String replacement)

        方法描述:用给定的字符替换此字符串中与给定正则表达式匹配的每个子字符串。

    public String replaceAll(String regex, String replacement) {
        return Pattern.compile(regex).matcher(this).replaceAll(replacement);
    }

          替换全部字符串对象,返回替换后的新字符串,内部实现使用的是正则表达式的替换方法,所以这里也支持传入正则表达式,具体的实现逻辑后面学习到正则相关的类时进行探究。

    public static void main(String[] args) {
        String s1 = "hello,bingo;hello,tom;hello,jerry";
        String s2 = "1,bingo;222,tom;333,jerry";
        String replace1 = s1.replaceAll("hello", "hi");
        String replace2 = s2.replaceAll("\\d+", "hi");
        System.out.println(replace1);
        System.out.println(replace2);
    }

  • String[] split(String regex)

        方法描述:围绕给定正则表达式的匹配项拆分此字符串。

    public String[] split(String regex) {
        return split(regex, 0);
    }

         根据传入的正则表达式对字符串进行分割,返回分割后的数组,并且会删除数组末尾的空字符串。这是我们常用的字符串切割方法,经常用来对前端传入的参数进行分割并转换为数组,并且参数是正则表达式字符串,这个方法的实现调用了另一个重载方法,增加了一个限制数量的参数,可以强制限制分割的次数,控制返回数组的长度,并且此参数需要大于0才有会意义,下面我们看一下具体的实现逻辑。

    public String[] split(String regex, int limit) {
        /* fastpath if the regex is a
         (1)one-char String and this character is not one of the
            RegEx's meta characters ".$|()[{^?*+\\", or
         (2)two-char String and the first char is the backslash and
            the second is not the ascii digit or ascii letter.
         */
        char ch = 0;
        //如果满足下列条件(长度为1并且不是列举的字符,或者长度是2并且是英文字母),就用下面的逻辑进行分割
        //如果不满足就直接调用正则表达式的分割方法
        if (((regex.value.length == 1 &&
                ".$|()[{^?*+\\".indexOf(ch = regex.charAt(0)) == -1) ||
                (regex.length() == 2 &&
                        regex.charAt(0) == '\\' &&
                        (((ch = regex.charAt(1))-'0')|('9'-ch)) < 0 &&
                        ((ch-'a')|('z'-ch)) < 0 &&
                        ((ch-'A')|('Z'-ch)) < 0)) &&
                (ch < Character.MIN_HIGH_SURROGATE ||
                        ch > Character.MAX_LOW_SURROGATE))
        {
            int off = 0;
            int next = 0;
            boolean limited = limit > 0;
            ArrayList<String> list = new ArrayList<>();
            //调用indexOf方法找到下标
            while ((next = indexOf(ch, off)) != -1) {
                if (!limited || list.size() < limit - 1) {
                    //如果没有超过限制或者是最后分割,调用substring方法截取出对应的字符串
                    list.add(substring(off, next));
                    off = next + 1;
                } else {    // last one
                    //assert (list.size() == limit - 1);
                    //如果达到了限制数量,或者是最后分割,直接取剩余所有的字符
                    list.add(substring(off, value.length));
                    off = value.length;
                    break;
                }
            }
            // If no match was found, return this
            if (off == 0)
                //如果没有进行遍历,说明没有符合条件的字符,直接把当前字符串对象加入一个新的数组
                return new String[]{this};

            // Add remaining segment
            if (!limited || list.size() < limit)
                //如果没有达到限制数量,加入最后分割的字符串
                list.add(substring(off, value.length));

            // Construct result
            int resultSize = list.size();
            if (limit == 0) {
                //减去末尾排列的空串
                while (resultSize > 0 && list.get(resultSize - 1).isEmpty()) {
                    resultSize--;
                }
            }
            String[] result = new String[resultSize];
            //将集合转换为数组并返回
            return list.subList(0, resultSize).toArray(result);
        }
        //如果不满足最开始的if条件,直接调用正则的分割方法
        return Pattern.compile(regex).split(this, limit);
    }

        如果是一位字符,并且符合if里面的条件的话直接是通过算法和String的方法截取的数据,并且过滤了末尾的空字符串,否则的话是通过正则表达式的split方法进行分割。下面写一个简单的示例。

    public static void main(String[] args) {
        String s1 = "bingo;bingo;bingo";
        String s2 = "bingo1bingo222bingo333333";
        String[] splitArr1 = s1.split(";");
        String[] splitArr2 = s2.split("\\d+");
        for (String s : splitArr1) {
            System.out.println(s);
        }
        System.out.println("------------------");
        for (String s : splitArr2) {
            System.out.println(s);
        }
    }

 

         再来演示一下空字符串的情况

    public static void main(String[] args) {
        String s1 = ";;;bingo;bingo;bingo;;;";
        String s2 = "111bingo1bingo222bingo333333";
        String[] splitArr1 = s1.split(";");
        String[] splitArr2 = s2.split("\\d+");
        for (String s : splitArr1) {
            System.out.println(s);
        }
        System.out.println("------------------");
        for (String s : splitArr2) {
            System.out.println(s);
        }
    }

        从结果上看,无论是通过String类内部的实现,还是通过正则的分割方法,都只会过滤尾部的空字符串,而不会过滤头部的空字符串,在日常开发过程中还是应该手动避免这内情况发生。

  • String join(CharSequence delimiter,Iterable<? extends CharSequence> elements)

        方法描述:返回一个新的字符串,用加入的元素列表拼接指定字符串构成。

    public static String join(CharSequence delimiter, CharSequence... elements) {
        Objects.requireNonNull(delimiter);
        Objects.requireNonNull(elements);
        // Number of elements not likely worth Arrays.stream overhead.
        StringJoiner joiner = new StringJoiner(delimiter);
        for (CharSequence cs: elements) {
            joiner.add(cs);
        }
        return joiner.toString();
    }

        内部实现是新建了一个StringJoiner类,这个类的作用主要就是用于构造一个由分隔符分隔的字符序列,StringJoiner内部是定义了前缀、分隔符、后缀、当前值等变量,然后调用的join方法实际上是这些变量配合StringBuilder的append方法实现。下面演示一下基本使用。

        List<String> list = Arrays.asList("a", "b", "c");
        String join1 = String.join(";", list);
        String join2 = String.join(",", "1", "2", "3");
        System.out.println(join1);
        System.out.println(join2);

 

  • String trim()

        方法描述:返回一个值为该字符串的字符串,并删除所有前导和尾随空格。

    public String trim() {
        int len = value.length;
        int st = 0;
        char[] val = value;    /* avoid getfield opcode */

        //正序遍历,得到不为空字符的下标
        while ((st < len) && (val[st] <= ' ')) {
            st++;
        }
        //反序遍历,得到不为空字符的下标
        while ((st < len) && (val[len - 1] <= ' ')) {
            len--;
        }
        //调用substring去截取字符串
        return ((st > 0) || (len < value.length)) ? substring(st, len) : this;
    }

        使用正序遍历和反序遍历分别获取头和尾不为空字符的下标,调用substring方法截取字符串。下面是方法示例。

    public static void main(String[] args) {
        String s="  bingo  ";
        System.out.println(s);
        System.out.println(s.trim());
    }

 

 

结尾

        作者是本着巩固学习和交流的目的编写,如果有问题或者不足之处请多多指导,感谢!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值