本文为joshua317原创文章,转载请注明:转载自joshua317博客 https://www.joshua317.com/article/204
1.字符串常量和字符串对象比较
String str1 = "joshua317";
String str2 = new String("joshua317");
System.out.println(str1 == str2);//false
System.out.println(str1.equals(str2));//true
/**
str1没有使用new关键字,在堆中没有开辟空间,其值"joshua317"在常量池中,str2使用new关键字创建了一个对象,在堆中开辟了空间,"=="比较的是对象的引用,即内存地址,所以str1与str2两个对象的内存地址是不相同的;
而equals() 方法用于将字符串与指定的对象比较。String 类中重写了 equals() 方法,用于比较两个字符串的内容是否相等。
**/
2.Java字符串内存结构剖析
package com.joshua317;
public class Main {
String str = new String("joshua317");
char[] ch = {'j','a','v','a'};
public static void main(String[] args) {
Main main = new Main();
main.change(main.str, main.ch);
System.out.print(main.str + "and");
System.out.print(main.ch);
//输出结果为joshua317andgava
}
public void change(String str,char ch[]){
str = "str change";
ch[0]='g';
}
}
/**
在方法调用时,在change方法中对str的值进行修改,是将str指向了常量池中的"str change",而主方法中的ex.str仍然指向的是常量池中的"joshua317"。字符型数组在方法调用时,将主方法中ex.ch的引用传递给change方法中的ch,指向是堆中的同一堆空间,所以修改ch[0]的时候,ex.ch可以看到相同的修改后的结果。
**/
3.Java中所有引用类型的默认值都是null
package com.joshua317;
public class Main {
public static void main(String[] args) {
String[] strings = new String[2];
System.out.println(strings[0]);//null
System.out.println(strings[1]);//null
Integer[] integers = new Integer[2];
System.out.println(integers[0]);//null
System.out.println(integers[1]);//null
int[] ints = new int[2];
System.out.println(ints[0]);//0
System.out.println(ints[1]);//0
}
}
/**
对象、数组都是引用数据类型。
所有引用类型的默认值都是null。
基本数据类型,根据类型不同,默认值不同,比如int默认值为0,float默认值是 0.0f
**/
4.字符串常量比较,字符串对象比较
package com.joshua317;
public class Main {
public static void main(String[] args) {
String s1 = new String("joshua317");
String s2 = new String("joshua317");
System.out.print(s1 == s2);//false
String s3 = "joshua317";
String s4 = "joshua317";
System.out.print(s3 == s4);//true
s1 = s3;
s2 = s4;
System.out.print(s1 == s2);//true
}
}
/**
字符串常量在常量池中;
对象在堆中开辟空间
**/
5.Java中字符串数据的比较
package com.joshua317;
public class Main {
public static void main(String[] args) {
String a = "joshua317";
String b = new String("joshua317");
String c = "joshua" + "317";
String str1 = "joshua";
String str2 = "317";
String d = str1 + str2;
System.out.println(a == b);//false
System.out.println(a == c);//true
System.out.println(a.equals(b));//true
System.out.println(a.equals(c));//true
System.out.println(a.intern() == b.intern());//true
System.out.println(a == b.intern());//true
System.out.println(c == d);//false
System.out.println(c.equals(d));//true
System.out.println(b.intern() == d.intern());//true
System.out.println(c.intern() == d.intern());//true
System.out.println(b == d.intern());//false
}
}
/**
字符串比较分为两种形式
一种使用比较运算符"=="比较,他们比较的是各自的字符串在内存当中的地址值是否相同;
一种是使用equals()方法进行比较,比较的是两个字符串的内容是否相同!
String类的intern()方法,含义如下:返回字符串对象的规范化表示形式。它遵循以下规则:
对于任意两个字符串 s 和 t,当且仅当 s.equals(t) 为 true 时,s.intern() == t.intern() 才为 true。
尽管在输出中调用intern方法并没有什么效果,但是实际上后台这个方法会做一系列的动作和操作。在调用b.intern()方法的时候会返回"joshua317",但是这个方法会首先检查字符串池中是否有"joshua317"这个字符串,如果存在则返回这个字符串的引用,否则就将这个字符串添加到字符串池中,然会返回这个字符串的引用。
字符串常量相加时,先相加,然后在字符串常量池找,如果有就直接返回,否则就创建。
字符串常量相加,jvm 会进行优化,不会创建 StringBuilder 对象
字符串变量相加时,先开辟空间再相加;
字符串变量加上常量,会创建 StringBuilder 对象,然后调用 append 方法
**/
6.字符串如何转换为int类型
package com.joshua317;
public class Main {
public static void main(String[] args) {
String str = "123";
int num1 = Integer.parseInt(str);
int num2 = Integer.valueOf(str);
int num3 = new Integer(str);
System.out.println(num1);//123
System.out.println(num2);//123
System.out.println(num3);//123
}
}
7.String类型是基本数据类型吗?
(1)java.lang.String类是引用数据类型,并且是final类型的,因此不可以继承这个类、不能修改这个类。为了提高效率节省空间,我们应该用StringBuffer类
(2)基本数据类型包括byte、short、int、long、char、float、double、boolean
8.Java语言中,String类中的indexOf()方法返回值的类型是int
9.String类是否可以被继承
不可以,因为String类有final修饰符,而final修饰的类是不能被继承的,实现细节不允许改变。
10.String类为什么是final的
(1) 为了效率。若允许被继承,则其高度的被使用率可能会降低程序的性能。
(2) 为了安全。JDK中提供的好多核心类比如String,这类的类的内部好多方法的实现都不是java编程语言本身编写的,好多方法都是调用的操作系统本地的API,这就是著名的“本地方法调用”,也只有这样才能做事,这种类是非常底层的,和操作系统交流频繁的,那么如果这种类可以被继承的话,如果我们再把它的方法重写了,往操作系统内部写入一段具有恶意攻击性质的代码什么的,这不就成了核心病毒了么?不希望别人改,这个类就像一个工具一样,类的提供者给我们提供了, 就希望我们直接用就完了,不想让我们随便能改,其实说白了还是安全性,如果随便能改了,那么java编写的程序肯定就很不稳定,你可以保证自己不乱改, 但是将来一个项目好多人来做,管不了别人,再说有时候万一疏忽了呢?他也不是估计的, 所以这个安全性是很重要的,java和C++相比,优点之一就包括这一点。
11.同一个字符串变量被修改,是否是对初始化变量指向空间内容的修改
package com.joshua317;
public class Main {
public static void main(String[] args) {
String str = "hello";
str += "world";
System.out.println(str);//helloworld
}
}
/**
首先不是对初始化变量str指向空间内容的直接修改。
因为String被设计成不可变(immutable)类,所以它的所有对象都是不可变对象。在这段代码中,s原先指向一个String对象,内容是 "Hello",然后我们对s进行了+操作,那么s所指向的那个对象是否发生了改变呢?答案是没有。这时,s不指向原来那个对象了,而指向了另一个 String对象,内容为"Hello world!",原来那个对象还存在于内存之中,只是s这个引用变量不再指向它了。
通过上面的说明,我们很容易导出另一个结论,如果经常对字符串进行各种各样的修改,或者说,不可预见的修改,那么使用String来代表字符串的话会引起很大的内存开销。因为 String对象建立之后不能再改变,所以对于每一个不同的字符串,都需要一个String对象来表示。这时,应该考虑使用StringBuffer类,它允许修改,而不是每个不同的字符串都要生成一个新的对象。并且,这两种类的对象转换十分容易。
对于字符串常量,如果内容相同,Java认为它们代表同一个String对象。而用关键字new调用构造器,总是会创建一个新的对象,无论内容是否相同。
至于为什么要把String类设计成不可变类,是它的用途决定的。其实不只String,很多Java标准类库中的类都是不可变的。在开发一个系统的时候,我们有时候也需要设计不可变类,来传递一组相关的值,这也是面向对象思想的体现。不可变类有一些优点,比如因为它的对象是只读的,所以多线程并发访问也不会有任何问题。当然也有一些缺点,比如每个不同的状态都要一个对象来代表,可能会造成性能上的问题。所以Java标准类库还提供了一个可变版本,即 StringBuffer。
**/
12.String 和StringBuilder、StringBuffer 的区别
我们知道Java平台提供了两种类型的字符串:String和StringBuffer / StringBuilder
相同点:
它们都可以储存和操作字符串,同时三者都使用final修饰,都属于终结类不能派生子类,操作的相关方法也类似例如获取字符串长度等;
不同点:
其中String是只读字符串,也就意味着String引用的字符串内容是不能被改变的,而StringBuffer和StringBuilder类表示的字符串对象可以直接进行修改,在修改的同时地址值不会发生改变。StringBuilder是JDK 1.5中引入的,它和StringBuffer的方法完全相同,区别在于它是在单线程环境下使用的,因为它的所有方面都没有被synchronized修饰,因此它的效率也比StringBuffer略高。在此重点说明一下,String、StringBuffer、StringBuilder三者类型不一样,无法使用equals()方法比较其字符串内容是否一样!
13.实现字符串的反转,如:输入joshua317,输出713auhsoj
package com.joshua317;
public class Main {
public static void main(String[] args){
String str1 = "joshua317";
String str2 = reverse(str1);
System.out.println(str1);
System.out.println(str2);
}
public static String reverse(String str) {
StringBuilder stringBuilder = new StringBuilder("");
char[] chArra = str.toCharArray();
for(int i = chArra.length-1; i >= 0; i--){
char ch=chArra[i];
stringBuilder.append(ch);
}
return stringBuilder.toString();
}
}
14.String类中replaceAll() 方法,使用给定的参数 replacement 替换字符串所有匹配给定的正则表达式的子字符串
将字符串中的数字全部转为6
package com.joshua317;
public class Main {
public static void main(String[] args){
String str1 = "joshua317";
System.out.println(str1);
System.out.println(str1.replaceAll("\\d", "6"));
}
}
本文为joshua317原创文章,转载请注明:转载自joshua317博客 https://www.joshua317.com/article/204