String类的基本特点

  • String类的两种实例化方式的区别
  • Sring类对象的比较
  • String类对象的使用分析

String类的两种实例化方式

String并不是一个基本的数据类型,它本身属于一个类,但是这个类在设计的过程之中加入了一些Java类自己的特殊支持,所以对于这个类的对象的实例化方式就有两种形式:

  • 直接赋值:String 对象 = “内容”;
  • 构造方法:publicString(String s)。
    范例:使用直接赋值。
public class StringDemo {
	public static void main(String args[]){
		String str="Hello ";
		str=str+"World!";
		System.out.println(str);
	}
}

范例:利用构造方法

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

至少现在通过执行结果来讲,String类的两种实例化方式都是可用的。

String的相等比较

两个int型的变量进行比较时,直接使用“==”即可。
范例:两个int比较

public class StringDemo {
	public static void main(String args[]){
		int x=10;//直接赋值
		int y=10;//直接赋值
		System.out.println(x==y);//true
	}
}

发现利用直接赋值实现的程序,那么使用“==”的时候可以正常的进行相等判断。
但是如果将同样的操作形式用在String上呢?
范例:观察String的比较

public class StringDemo {
	public static void main(String args[]){
		String stra="hello";
		String strb=new String("hello");
		String strc=strb;//引用传递
		System.out.println(stra==strb);//false
		System.out.println(strb==strc);//true
		System.out.println(stra==strc);//false
	}
}

通过现在的执行,可以发现一个非常严重的问题,此时字符串的内容都是相同的,而在使用“==”比较后发现有的结果是false,为什么?
在这里插入图片描述
所以发现在程序中如果使用“= =”,比较的只是两个对象(任意的引用类型)堆内存地址的数值,属于数值内容的比较,并不是堆内存中保存内容的比较,那么要想进行String对象内容的比较,则可以利用String类中提供的一个方法完成。

  • 字符串比较(暂时将此方法进行修改):public boolean equals(String str).
    范例:利用equals()实现字符串内容的比较
public class StringDemo {
	public static void main(String args[]){
		String stra="hello";
		String strb=new String("hello");
		String strc=strb;//引用传递
		System.out.println(stra.equals(strb));//true
		System.out.println(strb.equals(strc));//true
		System.out.println(stra.equals(strc));//true
	}
}

由于内容是可控因素,地址是不可控因素,所以在日后开发中,只要是字符串的比较都使用equals()方法完成,绝对不能出现“==”。
面试题:请解释在String比较中“ = =”与“equals()”的区别.

  • “==”:是Java本身提供的关系运算符,可以进行数值比较,如果用在String上表示对象地址数值间的比较。
  • “equals()”:是String类自己定义的方法,用于进行字符串内容比较。

String匿名对象

任何的编程语言都不会提供有字符串这一数据类型。字符串的描述在很多语言中都使用字符数组表示。而在Java的设计之初为了解决这样的问题,专门提供了一个String类进行描述。但是随着发展,为了能够让程序更加易于开发,所以也提供有双引号声明的数据,而这些数据在Java中并不是普通的变量,而是属于String类的匿名对象。
范例:验证匿名对象

public class StringDemo {
	public static void main(String args[]){
		String str="hello";
		System.out.println("hello".equals(str));//true
	}
}

现在发现,此时已经可以通过字符串调用equals()方法,那么就证明一点,字符串的确是String类的匿名对象。之前 的“String 字符串对象=“字符串”;”,本质上就是为一个字符串的匿名对象起了一个名字。
假设开发中有这样的需求:用户输入一些指令,而后根据指令决定要执行的操作,那么此时有两种做法:
做法一:利用String变量调用equals()方法。

public class StringDemo {
	public static void main(String args[]){
		String input="run";
		if(input.equals("run")){
			System.out.println("*****系统开始运转*****");//true
		}
	}
}

但是,既然input的内容是由用户输入的,那么也有可能不输入。如果不输入,就有可能为null,则null调用equals()方法就有可能出现错误。
做法二:反过来写

public class StringDemo {
	public static void main(String args[]){
		String input="null";
		if("run".equals(input)){
			System.out.println("*****系统开始运转*****");//true
		}
	}
}

首先,字符串的匿名对象永远不可能是null,并且在equals()方法里支持有null的验证,所以发现要比较的内容为null返回的就是false。
字符串常量=String类的匿名对象。
比较字符串的内容是否相同时,将常量写在前面。

String类两种实例化对象的区别(核心

声明:在开发中如果发现,有多种方式可以实现同一结果,那么就有可能出现面试题。
此时对于String类的实例化方式出现了两种,那么这两种方式到底该使用哪种,以及两种方法的区别是什么。
分析一:分析String类对象直接实例化的形式
直接赋值是现在为止看见最多的:

public class StringDemo {
	public static void main(String args[]){
		String str="hello";
		System.out.println(str);
	}
}

开辟一块堆内存空间,并且一个栈内存将直接指向该堆内存空间。
范例:继续观察直接赋值

public class StringDemo {
	public static void main(String args[]){
		String stra="hello";
		String strb="hello";
		String strc="nihao";
		System.out.println(stra==strb);//true
		System.out.println(strb==strc);//false
		System.out.println(stra==strc);//false
	}
}

本程序的内存关系图如下:
在这里插入图片描述
解释:关于对象池的概念(Object Pool)
在Java设计过程中为了方便用户的代码编写开发,针对于几个特殊的类使用了共享设计的思路,其中String就属于这其中的一员。这种设计思路是Java自己的支持,而且只针对于直接赋值的情况。
在使用直接赋值实例化String类对象的操作之中,字符串内容定义之后实际上会自动将其保存在一个对象池之中,而后如果有其他字符串对象也采用直接赋值的形式,并且内容与之前字符串内容完全相同,那么不会开辟新的堆内存空间,而是通过对象池找到已有的堆内存空间地址,直接引用即可,所以就会造成若干个字符串如果直接赋值之后,当内容相同时,地址是完全相同的,所以“==”的结果也是相同的。这样的设计就是共享设计模式。
分析二:利用构造方法实例化对象

public class StringDemo {
	public static void main(String args[]){
		String str=new String("hello");
		System.out.println(str);//hello
	}
}

在这里插入图片描述
通过此时的内存分析可以发现 ,如果采用构造方法进行String类对象的实例化,最终将产生两块堆内存,其中有一块是垃圾空间。
如果现在使用了构造方法进行String类对象的实例化还会牵扯到一个入池的问题。

**范例**:没有入池
public class StringDemo {
	public static void main(String args[]){
		String stra=new String("hello");//构造方法
		String strb="hello";//直接赋值
		System.out.println(stra==strb);//false
	}
}

现在的代码中,如果发现使用了构造方法进行String类对象实例化,那么所产生的对象将不会存在对象池之中,也就是说此对象无法重用。
如果现在用户需要让这个对象入池,则只能通过手工的方式完成:

  • 手工入池:public String intern().
    范例:手工入池
public class StringDemo {
	public static void main(String args[]){
		String stra=new String("hello").intern();//手工入池
		String strb="hello";
		System.out.println(stra==strb);//true
	}
}

面试题:请解释String两种对象实例化区别?

  • 直接赋值(String str=“字符串”;):只会开辟一块堆内存空间,并且对象可以自动入池,以供其他对象重复使用。
  • 构造方法:(String str=new String(“字符串”);):会开辟两块堆内存空间,并且有一块堆内存将成为垃圾,同时产生的实例化对象不会自动入池,需要利用intent()方法手工入池。

字符串一旦声明则不可改变

之前学习过一个“+”,利用这一概念可以实现字符串改变
范例:分析代码

public class StringDemo {
	public static void main(String args[]){
		String str=new String("Hello ");
		str+="world";
		str=str+"!!!";
		System.out.println(str);//Hello world!!!
	}
}

根据以上程序进行内存分析。
在这里插入图片描述
可以发现整个的操作流程之中,都是String类对象的引用发生着改变,而字符串的内容没有改变,这样的操作会形成垃圾,正因为如此,所以在实际开发中,以下操作禁止出现。
范例:循环修改String

public class StringDemo {
	public static void main(String args[]){
		String str="";
		for(int x=0;x<1000;x++){
			str+=x;
		}
		System.out.println(str);//Hello world!!!
	}
}

这种代码会“重新改变引用”1000次,并且会大量产生垃圾,也就是说String不适合频繁修改。

总结

  • String开发中都使用直接赋值,并且不要频繁修改;
  • 字符串内容比较时使用equals()方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值