String类

所有字符串用“”进行定义,也可以利用“+”实现字符串的连接

字符串不是基本数据类型。

范例:String 类的实例化

String str = "www.mldn.cn";
System.out.println(str);

String类中可以保存字符串的主要原因是由于其中定义了一个数组,也就是在String里所有的字符串中每一个字符的数据都是保存在数组中。

JDK1.8前String保存的是字符数组,

private final char[] value;

而JDK1.9后String保存的是字节数组。

private final byte[] value;

原来所谓的字符串是对数组的包装利用,既然包装的是数组,所以字符串中的内容是不能改变的。

还需注意,String类中除了可以直接赋值为对象进行实例化,也可以用传统的构造方法进行对象的实例化处理:public String(String str);

范例:利用构造方法进行实例化

package 面向对象;

public class StringDemo00 {
    public static void main(String[] args) {
        String str = "www.mldn.cn";
        System.out.println(str);

        String str1 = new String(str);
        System.out.println(str1);
    }
}

字符串的比较:

可以使用String类提供的equals方法进行比较:

public boolean equals(String str);

范例:

利用equals()实现字符串的比较

String比较重"=="与equals()的区别?

“==”进行的是数值比较,如果用于对象比较,则比较的是两个内存的地址数值;
equals():是类提供的一个比较方法,可以直接进行字符串内容的判断。

package 面向对象;

public class StringDemo00 {
    public static void main(String[] args) {

        String str = "www.mldn.cn";
        System.out.println("字符串的直接赋值结果为:");
        System.out.println(str);

        String str1 = new String(str);
        System.out.println("\n用原始构造方法给字符串赋值时的结果为:");
        System.out.println(str1);

        int x = 10;
        int y = 10;
        System.out.println("\n数值的直接比较时:");
        System.out.println(x == y);

        String strA = "mldn";
        String strB = new String("mldn");
        System.out.println("\n直接比较两个对象");
        System.out.println(strA == strB); //不同的对象地址比较

        System.out.println("\n使用String类中的equals()方法进行比较时");
        System.out.println(strA.equals(strB));  //比较对象的内容,此时相等
    }
}

输出结果:

字符串的直接赋值结果为:
www.mldn.cn

用原始构造方法给字符串赋值时的结果为:
www.mldn.cn

数值的直接比较时:
true

直接比较两个对象
false

使用String类中的equals()方法进行比较时
true

字符串常量

字符串常量是String类的匿名对象:

程序中所有的小数默认都是double类型,但是对于字符串而言,首先程序中不会提供有字符串这样的基本类型,只有String类,故任何使用""定义的字符串常量实际上描述的都是一个String类的匿名对象。

String str = "mldn"

image.png

所谓的String类的直接赋值直接描述的是,将一个匿名对象设置一个具体的名字。

范例:观察匿名对象的存在

匿名对象是一个类的实例化对象,则该匿名对象可以调用该类的方法

String str = "mldn";

System.out.println("mldn".equals(str)); //true

此时发现字符串常量可以明确的调用equals()方法实现对象相等的判断,所以可以得出结论:程序中的确没有字符串常量,只有String类的匿名对象。

关于对象相等判断的小技巧:

  • 在项目开发是,如果某些数据是用户输入,并且要求这些数据为一个指定内容的情况下, 建议将字符串常量写在前面。

equals()方法中提供有一个可以回避null的判断,所以如果将字符串常量写在前面,则调用equals()方法时永远都不可能出现"NullPointerException";因为字符串是一个匿名对象,匿名对象一定是开辟好堆内存空间的对象。

package 面向对象;


/**
 * 关于对象相等判断的小技巧:
 *
 * 在项目开发是,如果某些数据是用户输入,并且要求这些数据为一个指定内容的情况下,
 * 建议将字符串常量写在前面。
 */
public class StringDemo01 {
    public static void main(String[] args) {
        String input = "mldn";  //用户输入的内容
        System.out.println(input.equals("mldn"));  //true

        String str = null;

        //Exception in thread "main" java.lang.NullPointerException
//        System.out.println(str.equals("mldn"));  //出现空指针异常
        /*
            equals()方法中提供有一个可以回避null的判断
            所以如果将字符串常量写在前面,
            则调用equals()方法时永远都不可能出现"NullPointerException";
         */
        System.out.println("mldn".equals(str));

    }
}

输出结果:
true
false

String类两种实例化对象方法的比较

1、分析直接赋值的对象实例化模式

在程序中只需要将一个字符串赋值给String类对象就可以实现对象的实例化处理。

利用直接赋值实例化String的形式还可以实现同一个字符串对象睡的共享操作。

范例:观察String直接赋值时的数据共享

String strA = "mldn";
String strB = "mldn";
System.out.println(strA == strB); //对象的地址判断 true
结果返回为true,得出结论,这两个对象所指向的堆内存是同一个。
如图:


image.png

Java程序里面提供有一个专门的字符串池(字符串数组)。

String类池:


image.png

范例:分析字符串池

String strA = "mldn";
String strB = "mldnJava";
String strC = "mldn";
System.out.println(strA == strC); //对象的地址判断 true


image.png

2、分析构造方法实例化

String类为了满足于设计的结构要求,也提供有构造方法实例化的做法。

String strA = new String("mldn");
对于本程序而言,可以通过内存关系图进行查看:


image.png

此时会开辟两块堆内存空间,而后只会使用一块,而另外一块由于字符串常量所定义的匿名对象将成为垃圾空间。

直接赋值与构造方法实例化的区别:


image.png

此时会开辟两块堆内存空间,而后只会使用一块,而另外一块由于字符串常量所定义的匿名对象将成为垃圾空间。

除了以上的特点之外,在使用构造方法实例化string对象时不会出现自动保存到字符串池的处理。

范例:观察构造防范实例化对象时的操作

package 面向对象;

public class StringDemo02 {
    public static void main(String[] args) {
        String strA = "mldn";
        String strB = new String("mldn");
        System.out.println(strA == strB); //对象的地址判断  false

    }
}

可以发现构造方法实例化的对象实际上是一种自己专用的内存空间,但是在String类中也提供有帮助开发者实现手工入池的处理情况,该方法时:public String intern();

范例:观察手工入池

package 面向对象;

public class StringDemo02 {
    public static void main(String[] args) {
        String strA = "mldn";

        //字符串手工入池
        String strB = new String("mldn").intern();
        System.out.println(strA == strB); //对象的地址判断  true

    }
}

在使用构造方法定义对象后,由于使用了intern()方法,即便是构造出来的String对象内容也可以手工进入字符串池,但是该方法太啰嗦了。

面试题:请解释下String类两种实例化方式的区别?

1、直接赋值:只会产生一个实例化对象,并且可以自动保存到对象池中,以实现该字符串实例的重用。

2、构造方法:会产生两个实例化对象,并且不会自动入池,无法实现对象重用,可以利用intern()方法实现手工入池。

String对象(常量)池:

对象池的主要目的是实现数据的共享处理。以String对象池为例,里面的内容主要是为了重用,而重用实际上就是共享设计。

Java中对象池可以分为两种:

1、静态常量池

程序在加载时会自动将此程序中保存的字符串、普通的常量、类和方法的信息等全部进行分配;

2、运行时常量池

当一个程序加载后,里面可能有一些变量,这个时候提供的常量池

范例:静态常量池

package 面向对象;

public class StringDemo02 {
public static void main(String[] args) {
String strA = "www.mldn.cn";
String strB = "www" + ".mldn" + ".cn";
System.out.println(strA == strB); //对象的地址判断 true

}

}
输出结果为true

分析:本程序中所给出的内容都是静态常量数据(字符串的常量都是匿名对象),所以在程序加载时会自动帮助开发者处理好相应的连接。


image.png

所以在实际开发中可能会遇到这样的情况,尽量输入的内容和实际内容一样,但是判断结果仍然不相等。那就要用equals()方法比较两个对象的内容。因为用==,会出现静态常量池和运行时常量池两种情况。

字符串内容不可修改

在String类中包含的是一个数组,当设置了一个字符串后,会自动进行数组空间的开辟,那么开辟的内容,长度是固定的。

String内容的保存:JDK1.9后String是以byte数组形式保存


image.png

范例:

package 面向对象;

public class StringDemo02 {
    public static void main(String[] args) {
        String str = "www.";
        str += "mldn.";
        str = str + "cn";
        System.out.println(str);
    }
}
输出:www.mldn.cn

分析:


image.png

通过此时程序发现,在整个处理过程中,字符串常量的内容并没有发生任何改变,改变的只是一个string类对象的引用,并且这种改变有可能带来大量的垃圾空间。

范例:

package 面向对象;

public class StringDemo02 {
public static void main(String[] args) {
String str = "www.";
for (int i = 0; i < 10; i++) {
str += i;
}
System.out.println(str);
}
}
输出结果:

www.0123456789

如果本程序这样写,将会产生很多垃圾空间,并且String对象的指向要修改很多次,这种程序的性能非常差,因此String类在以后的开发中不要进行内容的频繁修改。

Java中的主方法:

主方法组成:

public static void main(String[] arg)

public:描述的一种访问权限,主方法是一切的开始点,开始点一定是公共的;

static:程序的执行是通过类名称完成的,所以表示此方法是由类直接调用;

void:主方法是一切的起点,起点一旦开始就不能回去

main:是一个系统定义好的方法名称

String[] args:字符串的数组,可以实现程序启动参数的接收;

范例:输出启动参数
范例:输出启动参数

package 面向对象;

public class StringDemo02 {
    public static void main(String[] args) {
       for(String arg: args) {
           System.out.print(arg + ",");
       }
    }
}

在用命令实现程序执行的时候可以设置参数,每一个参数之间使用空格分割
如:Java StringDemo02 first second

但是千万要记住几点:如果参数本身拥有空,则必须用""进行包装。

如;Java StringDemo02 "hello world" "hello mldn"

以后可以暂时通过这种暂时启动参数实现数据的输入的模拟。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容