阿里云【名师课堂】Java面向对象开发21 ~ 25:String类的基本特点

21、String类两种实例化方式

直接赋值

之前的讲解过程中说到并使用过,String可以采用直接赋值的方式进行处理,这一点类似于基本数据类型。这种方式较为常用。
范例:直接赋值实例化对象

public class StringDemo {
	public static void main(String args[]) {
		// str是一个对象,那么“hello”就应该保存在堆内存之中
		String str = "Hello" ;
		System.out.println(str) ;
    }
}

在这里插入图片描述

new实例化新对象

String是一个类,类中必定提供有构造方法。而在String类中恰好提供了如下构造方法:

  • public String (String str) ;
  • 注意这里的两个String,第一个是构造方法名,第二个是数据类型。
    范例:观察程序
public class StringDemo {
	public static void main(String args[]) {
		// 既然String是类,可以通过关键字new进行对象实例化
		String str = new String("Hello") ;
		System.out.println(str) ;
    }
}

在这里插入图片描述

22、字符串相等比较

众所周知,基本数据类型变量通过==进行是否相等的比较,那么String呢?
范例:观察String直接使用==的情况

public class StringDemo {
	public static void main(String args[]) {
		// 通过关键字new进行对象实例化
		String str1 = "Hello" ;
		String str2 = new String("Hello") ;
		System.out.println(str1 == str2) ;
    }
}

在这里插入图片描述
两个字符串内容是相同的,但是输出却是false,为什么?需要内存分析:
在这里插入图片描述
要知道,==进行的是数值的比较(char比较的是字符的编码。也是数值)。如果==用在String之中,所比较的就是两个对象(str1、str2)所保存的内存地址的数值,而并没有比较对象的内容。

String类提供的方法

这里暂时先学习这个方法的变形:public boolean equals(String str) ;
范例:进行String对象内容比较

public class StringDemo {
	public static void main(String args[]) {
		// 通过关键字new进行对象实例化
		String str1 = "Hello" ;
		String str2 = new String("Hello") ;
		System.out.println(str1.equals(str2)) ;
    }
}

在这里插入图片描述

总结:==equals()的区别

  • ==进行的是数值比较,比较的是两个字符串对象的内存地址数值;
  • equals()可以进行字符串内容的比较

23、字符串为匿名对象

在任何语言的底层上面都不会提供有直接的字符串类型,现在所谓的高级语言只是为了方便用户开发所提供的一个支持。所以在Java中本身也没有直接提供字符串常量的概念,所有使用""定义的内容本质上来讲都是String类的匿名对象。
范例:观察字符串操作

public class StringDemo {
	public static void main(String args[]) {
		String str = "Hello" ;
		System.out.println(str.equals("Hello")) ;  // 通过str对象调用String类
		System.out.println("Hello".equals(str)) ;  // "Hello"是匿名对象,当然也可以调用String类中的任意方法
    }
}

在这里插入图片描述
可以看出String str = "Hello" ;就是给一个匿名对象"Hello"设置名字str,并且匿名对象一定保存在堆内存之中。
提醒:在日后的开发过程中,如果要判断用户的输入是否等于指定的字符串,一定要把指定字符串写在前面。

  • 范例:观察指定字符串写在后面的情况
public class StringDemo {
	public static void main(String args[]) {
		// 用户输入操作暂时没讲解,这里暂时用input代替
		String input = null		;  // 用户输入为空
		System.out.println(input.equals("Hello")) ;
    }
}

在进行用户数据接收的时候必须要考虑用户没有输入数据的问题,这时会出现如图所示异常。
在这里插入图片描述

  • 范例:观察指定字符串写在后面的情况

因此要把指定字符串写在前面。因为任何的字符串常量都是String类的匿名对象,所以该对象永远不可能为null。

public class StringDemo {
	public static void main(String args[]) {
		// 用户输入操作暂时没讲解,这里暂时用input代替
		String input = null		;  // 用户输入为空
		System.out.println("Hello".equals(input)) ;
    }
}

在这里插入图片描述

24、String两种实例化区别

两种实例化模式中使用哪一种更好?二者的区别?

使用直接赋值

public class StringDemo {
	public static void main(String args[]) {
		// str是一个对象,那么“hello”就应该保存在堆内存之中
		String str = "Hello" ;
    }
}

在这里插入图片描述

  • 小小的问题:使用直接赋值继续创建新的字符串对象:
public class StringDemo {
	public static void main(String args[]) {
		// str是一个对象,那么“hello”就应该保存在堆内存之中
		String str1 = "Hello" ;
		String str2 = "Hello" ;
		String str3 = "Hello" ;
		System.out.println(str1 == str2) ;
		System.out.println(str1 == str3) ;
		System.out.println(str2 == str3) ;
    }
}

在这里插入图片描述
可以看出,创建新对象并没有开辟新的内存空间,而是三个栈内存指向同一个堆内存。
在这里插入图片描述

  • 为什么会这样?
    Java中有个对象池概念,字符串共享,懒得打这么多字,摸了。

new实例化新对象

在这里插入图片描述
使用new实例化对象的方法会开辟两块内存空间,其中有一块堆内存空间成为垃圾内存空间。除此之外,也会对字符串共享产生问题。
通过22、字符串相等比较我们知道,通过直接赋值和new实例化的同一个字符串无法比较用==比较是否相同,因为new出来的对象没有入池。
但是并不意味着new出来的字符串不能进入到对象池保存,关键:可以手工处理——使用String类中的public String intern() ;方法进行手工入池操作。

public class StringDemo {
	public static void main(String args[]) {
		String str1 = "Hello" ;
		String str2 = new String("Hello").intern() ;
		System.out.println(str1 == str2) ;
    }
}

在这里插入图片描述
在这里插入图片描述

总结:String类中两种实例化方式的区别

  • 直接赋值:只会开辟一块堆内存空间,并且该字符串对象可以保存在对象池中以供下次使用。
  • 构造方法:会开辟两块堆内存空间,并且其中一块会成为垃圾空间,而且实例化的对象不会自动保存在对象池之中,而是使用intern()方法手工入池。

25、字符串常量不可变更

字符串一旦定义不可改变。
再次强调:在任何语言的底层实现的都是字符数组,数组的最大缺陷:长度固定,所以在定义字符串常量的时候本身它的内容是不可改变的。
范例:观察程序

public class StringDemo {
	public static void main(String args[]) {
		String str1 = "Hello" ;
		str1 += "World" ;
		System.out.println(str1) ;
    }
}

在这里插入图片描述

  • 为什么改变了?
  • 以上字符串的变更是字符串对象的变更,而并不是常量的改变,观察内存图:
    在这里插入图片描述
    因此,在代码开发过程中不能出现这类代码(对字符串进行+-之类操作),因为会产生大量垃圾内存。

总结

  1. 字符串的使用就采用直接赋值的模式完成;
  2. 字符串的比较就使用equals()方法实现;
  3. 字符串没事别改变,迫不得已时也别改变太多。
posted @ 2020-06-08 22:38  溺水的情书  阅读(196)  评论(0编辑  收藏  举报