java的Math和Random类
文章目录
- java中String类
- String类的本质
- String类的常用方法
- String类`加号`编译器优化问题
java中String类
String类的本质
String类是在java.lang
下,经过前面的学习可以知道在这个包中的所有类可以直接调用,不需要导包。
//自动装箱
String str = "abc";
"abc"就是String类下的一个具体的对象,由于String类被final修饰着,这个String类不可以被继承,不能有子类。
接下来看一下String字符串的本质:
其实String字符串的底层就是一个char类型的数组
String类的常用方法
public class Test10 {
public static void main(String[] args) {
//声明变量,类型为String类型
String str = "abc";
System.out.println(str);
String str2 = "";
//通过构造器来创建对象
//空构造器
String s1 = new String();
String s2 = new String("abc");
String s3 = new String(new char[]{'a', 'b', 'c'});
String s4 = "abc";
System.out.println("字符串的长度为:" + s4.length());
String s5 = new String("abc");
System.out.println("字符串是否为空:" + s5.isEmpty());
System.out.println("获取字符串的下标对应的字符为:" + s5.charAt(1));
String s6 = new String("abc");
String s7 = new String("abc");
System.out.println(s6.equals(s7));
String s8 = new String("abc");
String s9 = new String("abc");
System.out.println(s8.compareTo(s9));
//字符串的截取
String s10 = "agbvasdfgas";
System.out.println(s10.substring(3));
System.out.println(s10.substring(3, 6));
//字符串的合并和拼接操作
System.out.println(s10.concat("pppp"));
//字符串中的字符进行替换
String s11= "asdfasdfasdfasdf";
System.out.println(s11.replace('a','u'));
//按照指定的字符串进行分割为数组的形式
String s12 = "a-b-c-e-fg";
String[] strs = s12.split("-");
System.out.println(Arrays.toString(strs));
//将字符串转换大小写
String s13 = "abc";
System.out.println(s13.toUpperCase());
System.out.println(s13.toUpperCase().toLowerCase());
//去除首尾空格
String s14 = " a b c ";
System.out.println(s14.trim());
//toString()
String s15 = "abc";
System.out.println(s15.toString());
//转换为String类型
System.out.println(String.valueOf(false));
}
}
- 调用String类的空构造器
String s1 = new String();
可以查看String底层的源码:
方法 | 说明 | 返回值 |
length() | 返回此字符串的长度。 | 返回int类型的数据 |
isEmpty() | 判断字符串是否为空,如果为空则返回true | 返回boolean类型的数据 |
charAt() | 获取字符串的下标对应的字符 | 返回char类型的数据 |
equals() | 将此字符串与指定对象进行比较。 | 返回boolean类型的数据 |
compareTo() | 如果这个字符串是等参数字符串那么返回值0,如果这个字符串是按字典顺序小于字符串参数那么返回小于0的值,如果此字符串是按字典顺序大于字符串参数那么返回一个大于0的值 | 返回int类型的数据 |
substring() | 截取字符串,beginIndex - 起始索引(包括),endIndex - 结束索引(不包括)。 | 返回一个新字符串,它是此字符串的一个子字符串。该子字符串从指定的 beginIndex 处开始,直到索引 endIndex - 1 处的字符。 |
concat(String str) | 将指定字符串连接到此字符串的结尾,需要创建对象才能够调用该方法 | 返回字符串类型 |
replace(char oldChar, char newChar) | 将字符串中的旧字符进行替换成新的字符 | 返回String类型 |
split(String regex, int limit) | 根据匹配给定的正则表达式来拆分字符串,其中参数str为正则表达式分隔符,参数limit:分割份数 | 返回String[]类型 |
toString() | String类重写了Object的toString方法,用于返回String的字符串值 | 返回String类型 |
toUpperCase() | 将字符串全部大写 | 返回String类型 |
toLowerCase() | 将字符串全部小写 | 返回String类型 |
trim() | 去掉字符串中的首尾空格,保留字符之间的空格 | 返回String类型 |
valueOf() | 是静态方法,可以通过类名点出来,将其他任意类型的数据转换成字符串类型 | 返回String类型 |
接下来就详细的分析一下经常用到的String类下的方法的底层源码:
- String类下的length()方法
点到length()方法中,看一下length方法的定义
private final byte[] value;
/**
* Returns the length of this string.
* The length is equal to the number of <a href="Character.html#unicode">Unicode
* code units</a> in the string.
*
* @return the length of the sequence of characters represented by this
* object.
*/
public int length() {
return value.length >> coder();
}
value.length返回的是value中存储的字符(char)的数量,也就是返回了unicode数量。
上面我们提到过String类其本质就是一个char类型的数组,在这里length方法返回的就是String字符串的长度
- String类下的isEmpty()方法
private final byte[] value;
/**
* Returns {@code true} if, and only if, {@link #length()} is {@code 0}.
*
* @return {@code true} if {@link #length()} is {@code 0}, otherwise
* {@code false}
*
* @since 1.6
*/
@Override
public boolean isEmpty() {
return value.length == 0;
}
isEmpty方法中定义了当且仅当字符串的长度为0的时候返回的是true,否则返回的是false这两个布尔类型的值
- String类下的charAt()方法
看jdk中的charAt方法的定义
private final byte[] value;
/**
* Returns the {@code char} value at the
* specified index. An index ranges from {@code 0} to
* {@code length() - 1}. The first {@code char} value of the sequence
* is at index {@code 0}, the next at index {@code 1},
* and so on, as for array indexing.
*
* <p>If the {@code char} value specified by the index is a
* <a href="Character.html#unicode">surrogate</a>, the surrogate
* value is returned.
*
* @param index the index of the {@code char} value.
* @return the {@code char} value at the specified index of this string.
* The first {@code char} value is at index {@code 0}.
* @throws IndexOutOfBoundsException if the {@code index}
* argument is negative or not less than the length of this
* string.
*/
public char charAt(int index) {
if (isLatin1()) {
return StringLatin1.charAt(value, index);
} else {
return StringUTF16.charAt(value, index);
}
}
charAt方法中的index代表了索引值,点到StringLatin1中,有这样的一段代码:
public static char charAt(byte[] value, int index) {
if (index < 0 || index >= value.length) {
throw new StringIndexOutOfBoundsException(index);
}
return (char)(value[index] & 0xff);
}
如果索引值小于0或者是大于字符串的长度时,系统会抛出异常StringIndexOutOfBoundsException(index)
(越界异常),其他情况下返回索引值对应的char类型的字符
- String类下的equals()方法
private final byte[] value;
/**
* Compares this string to the specified object. The result is {@code
* true} if and only if the argument is not {@code null} and is a {@code
* String} object that represents the same sequence of characters as this
* object.
*
* <p>For finer-grained String comparison, refer to
* {@link java.text.Collator}.
*
* @param anObject
* The object to compare this {@code String} against
*
* @return {@code true} if the given object represents a {@code String}
* equivalent to this string, {@code false} otherwise
*
* @see #compareTo(String)
* @see #equalsIgnoreCase(String)
*/
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String aString = (String)anObject;
if (!COMPACT_STRINGS || this.coder == aString.coder) {
return StringLatin1.equals(value, aString.value);
}
}
return false;
}
public static boolean equals(byte[] value, byte[] other) {
if (value.length == other.length) {
for (int i = 0; i < value.length; i++) {
if (value[i] != other[i]) {
return false;
}
}
return true;
}
return false;
}
对equals()方法的源码进行注释,这个源码需要掌握
- String类下的substring()方法:
点到substring中看一下方法的定义:
public String substring(int beginIndex, int endIndex) {
int length = length();
checkBoundsBeginEnd(beginIndex, endIndex, length);
if (beginIndex == 0 && endIndex == length) {
return this;
}
int subLen = endIndex - beginIndex;
return isLatin1() ? StringLatin1.newString(value, beginIndex, subLen)
: StringUTF16.newString(value, beginIndex, subLen);
}
static void checkBoundsBeginEnd(int begin, int end, int length) {
if (begin < 0 || begin > end || end > length) {
throw new StringIndexOutOfBoundsException(
"begin " + begin + ", end " + end + ", length " + length);
}
}
返回的是一个字符。
返回一个新字符串,它是此字符串的一个子字符串。
该子字符串从指定的 beginIndex 处开始,直到索引 endIndex - 1 处的字符。
因此,该子字符串的长度为 endIndex-beginIndex。
抛出异常
IndexOutOfBoundsException
- beginIndex 为负,
- endIndex 大于此 String 对象的长度,
- beginIndex 大于 endIndex。
String类加号
编译器优化问题
- 字符串与字符串用加号
+
拼接
刚开始接触java的时候就知道这个加号+
可以连接字符串,接下来我们看一下在底层是怎样的
package Test;
public class Test11 {
public static void main(String[] args) {
String s1 = "a"+"b"+"c";
String s2 = "ab"+"c";
String s3 = "a"+"bc";
String s4 = "abc";
String s5 = "abc"+ "";
System.out.println(s1 == s4);
System.out.println(s2 == s5);
String s6 = new String("abc");
}
}
可以在IDEA中查看对应的class文件:
可见这几种用加号拼接的形式在底层中都是相当于"abc"
可见他们是一样的。
- 变量与字符串用加号
+
进行拼接
package Test;
public class Test12 {
//有变量参与的字符串拼接
public static void main(String[] args) {
String a = "abc";
String b = a + "def";
System.out.println(b);
//a变量在编译的时候不知道a是"abc"字符串,所以不会进行编译优化,并不会直接合并为"abcdef"
}
}
虽然a = "abc"
但是编辑器不知道a="abc"
,不会进行编译优化,不会直接合并,这个就是与字符串和字符串用加号+
拼接的区别,也可以通过对应的class文件查看:
java的StringBuilder类