String


String类 


(1) String代表字符串类型,字符串本身的内容不可改变,字符串存储于字符串常量池中。 

(2)String的两种实例化方式 

a:直接赋值法: 

String st=“Hello World”; 

b:通过new操作符动态实例化: 

String st=new String(“Hello World”); 

(3)一个字符串就是String类的一个匿名对象。 

所谓匿名对象,就是在堆内存中开辟了空间,但在栈内存中并没有指向的对象。

 String:表示字符串:

字符串是常量;它们的值在创建之后不能更改。

 String是一种特殊的引用类型:

默认值:null

 *构造方法:

String():无参构造

String(byte[] bytes) :将字节数组转换成字符串

public String(byte[] bytes, int index,int length):将字节数组的一部分转换成字符串

public String(char[] value):将字符数组转化成字符串   

public String(char[] value, int index, int count):将字符数组的一部分转换成字符串

public String(String original):将一个字符串常量构造成一个字符串对象

常用的方法:


public int length()返回此字符串的长度


面试题:


数组中有没有length(),字符串中有没有length(),集合中有没有length()?

数组中没有length()方法,只有length属性

字符串中有length()方法

集合中没有length()方法,要获取集合的元素数:使用size() (后面讲)

代码示例

public class StringDemo {

	public static void main(String[] args) {

		// 1)String():无参构造
		String s1 = new String();
		System.out.println("s1:" + s1);// 不是地址值:说明String类本身就重写了Object类中的toString()方法
		System.out.println("------------");
		// String(byte[] bytes) :将字节数转换成字符串
		// 定义一个字节数组
		byte[] bys = { 97, 98, 99, 100, 101 };
		String s2 = new String(bys);
		System.out.println("s2:" + s2);// abcde
		System.out.println("---------------");

		// public String(byte[] bytes, int index,int length):将字节数组的一部分转换成字符串
		String s3 = new String(bys, 1, 2);
		System.out.println("s3:" + s3);

		System.out.println("----------------");

		// public String(char[] value):将字符数组转化成字符串
		char[] ch = { '我', '爱', '高', '圆', '圆' };
		String s4 = new String(ch);
		System.out.println("s4:" + s4);

		// public String(char[] value, int index, int count):将字符数组的一部分转换成字符串
		String s5 = new String(ch, 2, 3);
		System.out.println("s5:" + s5);

		System.out.println("-----------------");
		// public String(String original):将一个字符串常量构造成一个字符串对象

		String s6 = new String("abc");
		// 在写法上:等同于:String s6 = "abc" ;

		String s7 = "";// 空字符串
		System.out.println("s7:" + s7);

		String s8 = null;// 对象是空的
	}
}

String字符串的最大的特点: 字符串一旦被赋值,其值不能被改变,只能进行基础运算(例如:给原字符串后连接一个新字符串)

代码示例

public class StringDemo2 {

	public static void main(String[] args) {

		String s = "hello";
		s += "world";
		System.out.println("s:" + s);

		System.out.println("---------------------");

		String s1 = "abc";
		String s2 = "world";
		System.out.println("s1:" + s1 + ",s2:" + s2);
		// String作为形式参数:它的效果和基本类型是一样的,形式参数的改变对对实际参数没有影响 (它一旦赋值,不能被改变)
		// StringBuffer:字符串缓冲区
		change(s1, s2);
		System.out.println("s1:" + s1 + ",s2:" + s2);
	}

	public static void change(String s1, String s2) {

		s1 = s1 + "java";// s1="abcjava"
		s2 = s2 + s1 + "hello";// worldabcjavahello

	}
}

对equals()和"=="的深层次理解

代码示例

package org.westos.c_string;

/*
 * 看程序,写结果
 */
public class StringDemo3 {

	public static void main(String[] args) {
		String s1 = new String("hello");
		String s2 = new String("hello");
		System.out.println(s1 == s2);// false 进行地址值比较
		System.out.println(s1.equals(s2));// true 进行值比较,因为String类中已经对equals()方法进行了重写

		String s3 = new String("hello");
		String s4 = "hello";
		System.out.println(s3 == s4);// false
		System.out.println(s3.equals(s4));// true

		String s5 = "hello";
		String s6 = "hello";
		System.out.println(s5 == s6);// true
		System.out.println(s5.equals(s6));// true
	}

}




Object:是类层次结构的根类.每个类都使用 Object 作为超类(父类)

public int hashCode()返回该对象的哈希码值,把它理解为地址值(不是真实意义上的地址值)

 public final Class getClass()返回Object运行时的类

Class类中有一个方法:

public String getName()以 String的形式返回此Class对象所表示的实体(类、接口、数组类、

基本类型或 void)名称。

代码示例

public class ObjectDemo {
	
	public static void main(String[] args) {
		
		//创建一个学生对象
		Student s1 = new Student() ;
		System.out.println(s1.hashCode());//118352462
		
		Student s2 = new Student() ;
		System.out.println(s2.hashCode());//118352462
		
		System.out.println("-------------------------");
		
		Class c1 = s1.getClass() ;//Object运行 时的类
		System.out.println(c1);//class org.wesots_01.Student :以Class形式表示的当前类
		String name = c1.getName() ;
		System.out.println(name);//以字符串显示当前的类:org.wesots_01.Student :全类名
		
		System.out.println("-------------------------");
		
		//链式编程
		String str = s1.getClass().getName() ;//s1.getClass()获取Object运行时的类,通过类的匿名对象去调用getName()
		System.out.println(str);
		String str2 = s2.getClass().getName() ;
		System.out.println(str2);
	}
}
package org.wesots_01;

//学生类
public class Student extends Object{

}

 面试题:

String s1 = new String("abc");

String s1 = "abc" ;

 这两个分别创建了几个对象?

第一个创建了一个,第二个没有创建对象,而是直接指向了字符串常量池中存储的"abc"字符串。

代码示例

public class StringDemo4 {

	public static void main(String[] args) {
		
		String s1 = "hello" ;
		String s2 = new String("hello") ;
		
		System.out.println(s1==s2);//false
		System.out.println(s1.equals(s2));//true
	}
}

String类常用的判断功能

boolean equals(Object obj):将此字符串与指定的对象比较

boolean equalsIgnoreCase(String str)将此 String 与另一个 String 比较,不考虑大小写

boolean contains(String str):判断当前字符串中是否包含新的字符串  (重点)

boolean startsWith(String str):以当前str字符串开头(重点)

boolean endsWith(String str):以当前str字符串结尾(重点)

boolean isEmpty():判断字符串是否为空

public String concat(String str):字符串的特有功能:拼接功能和+拼接符是一个意思

代码示例

package org.westos.c_string;

/**
 * String类的常用的判断功能
 *
 * boolean equals(Object obj):将此字符串与指定的对象比较 boolean equalsIgnoreCase(String str)将此 String 与另一个 String 比较,不考虑大小写 
 * boolean contains(String str):判断当前字符串中是否包含新的字符串 (重点) 
 * boolean startsWith(String str):以当前str字符串开头(重点)
 * boolean endsWith(String str):以当前str字符串结尾(重点)
 * boolean isEmpty():判断字符串是否为空
 * public String concat(String str):字符串的特有功能:拼接功能和+拼接符是一个意思
 *
 */
public class StringDemo5 {

	public static void main(String[] args) {

		// 定义字符串
		String s1 = "helloworld";
		String s2 = "HelloWorld";
		// boolean equals(Object obj):将此字符串与指定的对象比较
		System.out.println("equals:" + s1.equals(s2));

		System.out.println("---------------------------");
		// boolean equalsIgnoreCase(String str)将此 String 与另一个 String 比较,不考虑大小写
		System.out.println("equalsIgnoreCase:" + s1.equalsIgnoreCase(s2));
		System.out.println("---------------------------");
		// boolean contains(String str):判断当前字符串中是否包含新字符串 (重点)
		System.out.println("contains:" + s1.contains("llo"));
		System.out.println("contains:" + s1.contains("android"));
		System.out.println("---------------------------");

		System.out.println("---------------------------");
		// boolean startsWith(String str):以当前str字符串开头(重点)
		System.out.println("startsWith:" + s1.startsWith("he"));
        //boolean endsWith(String str):以当前str字符串结尾(重点)
		System.out.println("endsWith:"+s1.endsWith(ld));
		// boolean isEmpty():判断字符串是否为空
		System.out.println("isEmpty:" + s1.isEmpty());
	}
}

模拟登录,给三次机会,并提示还剩几次机会,如果登录成功,玩一个猜数字小游戏

 分析:

1)定义一个规则:

用户名:admin

密码:admin

2)循环三次,使用for循环

创建键盘录入对象

录入的用户名和密码和当前存在的用户名和密码进行比较,如果一致,登录成功,(break)

3)登录失败

分两种情况:

提示有几次机会

次数:2-x   

当前2-x==0,换一中提示,当前机会用完了,请联系管理员...

代码示例

public class StringTest {

	public static void main(String[] args) {
		
		//定义用户名和密码
		String username = "admin" ;
		String password = "admin" ;
		
		//模拟登录,有三次机会
		for(int x = 0 ; x <3 ; x ++) {
			//创建键盘录入对象
			Scanner sc = new Scanner(System.in) ;
			
			System.out.println("请输入用户名:");
			String InputUserName = sc.nextLine() ;
			System.out.println("请输入密码:");
			String InputPwd = sc.nextLine() ;
			
			//判断录入的和存在用户名或者密码和存在的用户名或者密码看他们是否一致
			if(username.equals(InputUserName) && password.equals(InputPwd)) {
				//一致,登录成功
				System.out.println("登录成功....");
				break ;
			}else {
				//没有登录成功:2,1,0
				if((2-x)==0) {
					System.out.println("请速联系管理员");
				}else {
					//!=0 ,2,1
					System.out.println("当前您还是有"+(2-x)+"次机会");
				}
			}
		}
	}
}



package org.westos.c_string;

import java.util.Scanner;

/**
 * Math public static double random()返回带正号的 double 值,该值大于等于 0.0 且小于 1.0。
 * random()的取值范围:[0.0,1.0);
 *
 * 获取1-100之间的随机数(int类型)
 */
public class GuessNumberGame {

	/*
	 * public static void main(String[] args) {
	 * 
	 * int num = (int)(Math.random()*100) +1 ; System.out.println(num); }
	 */

	// 构造私有化
	private GuessNumberGame() {

	}

	// 提供静态功能
	public static void start() {
		// 生成一个随机数
		int num = (int) (Math.random() * 100) + 1;

		while (true) {
			// 创建键盘录入对象
			Scanner sc = new Scanner(System.in);

			System.out.println("请输入要猜的数据:");
			int guessNumber = sc.nextInt();
			if (guessNumber > num) {
				System.out.println("你猜的值大了...");
			} else if (guessNumber < num) {// guessNumber<=num
				System.out.println("你猜的值小了...");
			} else {// guessNumber==num
				System.out.println("恭喜你,猜中了...");
				break;
			}
		}

	}
}



 Object中的一个方法:

public String toString(); 回该对象的字符串表示 

  后面讲:

Integer:是int类型的包装类类型

它里面提供了一个(静态)方法

public static String toHexString(int i):以十六进制的形式来表示对象的字符串形式

  直接输出对象名称:实际执行了Object中的toString(),输出的全类名@十六进制数据


  


  我现在输出对象名称,不想让toString()直接输出的是一个地址值(对象的地址值)


  


  就需要重写Object中的toSring(),一般情况:自动生成即可,建议所有子类都重写此方法。 

代码示例

public class ObjectDemo {

	public static void main(String[] args) {

		// 创建学生类对象
		Student s1 = new Student();
		System.out.println(s1);// org.wesots_02.Student@70dea4e

		String str2 = s1.toString();
		System.out.println(str2);

		System.out.println("--------");
		Class c1 = s1.getClass();
		String name = c1.getName(); //
		System.out.println(name);// org.wesots_02.Student

		// 使用Integer类调用static方法
		String str = Integer.toHexString(s1.hashCode());
		System.out.println(str);// 70dea4e

		System.out.println("--------------------");

		System.out.println(s1.getClass().getName() + '@' + Integer.toHexString(s1.hashCode()));
		// org.wesots_02.Student@70dea4e

		System.out.println("--------------------");

		// 创建一个学生对象
		Student s2 = new Student();
		System.out.println(s2);

		s2.setName("高圆圆");
		s2.setAge(27);
		System.out.println(s2);

	}
}

重写toString方法

代码示例

package org.wesots_02;

public class Student {

	private String name;
	private int age;

	public Student() {
		super();
	}

	public Student(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	// 自己去完成的逻辑:输出对象名,打印成员变量的值
	/*
	 * @Override public String toString() {
	 * 
	 * //在测试类中输出对象名称,显示的是对象的成员变量的值 return name+"----"+age ; }
	 */
	@Override
	public String toString() {
		return "Student [name=" + name + ", age=" + age + "]";
	}

}

public boolean equals(Object obj)

表示其他对象是否与此对象“相等”,默认比较的是两个对象的地址值是否相等,相等为

true,不相等为false。

==:比较的是地址值是否相等(地址值)。

equals:Object类中的方法,默认比较的是两个对象的地址值是否相同。

按照正常情况:equals方法底层实际在执行的是两个对象==操作,比较是地址值;假如:学生的年龄和姓名一致,看成同一个人

在自定义的类中,重写Object中的equals()方法,比较的是两个对象的成员变量的值是否相同。

代码示例

public class ObjectDemo {
	
	public static void main(String[] args) {
		//创建两个学生对象
		Student s1 = new Student("高圆圆",27);
		Student s2 = new Student("高圆圆",27) ;
		System.out.println(s1==s2); //比较的是地址值   
		System.out.println("---------------------");
		System.out.println(s1.equals(s2)); //false :默认的地址值
		//重写之后,应该比较当前对象的成员变量的值是否一致
		
		Student s3 = new Student("高圆圆",38);
		System.out.println(s1.equals(s3));
		
		Student s4= s1 ; //直接将对象s1的地址值赋值给了s4
		System.out.println(s1.equals(s4));
		
		/**
		 * 观察Object中的equals方法
		 *   public boolean equals(Object obj) {
        			return (this == obj); //在底层实际走了一个==:比较的是地址值
        			//this:s1
        			//obj:s2
    			}
		 */
		
	}
}

重写equals()方法

代码示例

package org.wesots_03;

public class Student extends Object{
	
	private String name ;
	private int age ;
	
	public Student() {
		super();
	}

	public Student(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	
	//重写了Object中的equals方法
	@Override
	public boolean equals(Object obj) {//传入对对象
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())//this.getClass ();正在运行的那个类:格式为class 包名.类名
			return false;
		Student other = (Student) obj;//向下转型 由Object转换为Student
		if (age != other.age)//this.age  other:传入的s2
			return false;
		if (name == null) {//this.name
			if (other.name != null) //传入的姓名不为null
				return false;
		} else if (!name.equals(other.name))//name!=null
			return false;
		else {
			return true;
		}
	}

protected Object clone()创建并返回此对象的一个副本 

Object 类的 clone 方法执行特定的复制操作。首先,如果此对象的类不能实现接口 Cloneable,则会抛出 

CloneNotSupportedException。

注意,所有的数组都被视为实现接口 Cloneable

代码示例

public class ObjectDemo {
	
	public static void main(String[] args) throws CloneNotSupportedException {
		
		//创建学生类对象
		Student s1 = new  Student("高圆圆",27);
		
		System.out.println(s1.getName()+"---"+s1.getAge());
	
		//复制操作
		//调用clone方法
		Object obj = s1.clone() ;//clone()的返回值类型为Object类型,将s1的内容克隆一份给obj
		//向下转型
		Student s2 = (Student)obj;
		System.out.println(s2.getName()+"---"+s2.getAge());
		
		System.out.println("--------------------------");
		
		//在没有接触过Object的clone方法之前,如何复制对象的
		Student s3 = s1 ;
		System.out.println(s3.getName()+"---"+s3.getAge());
	}
}

重写clone()方法

代码示例

package org.wesots_04;

public class Student implements Cloneable {

	private String name;
	private int age;

	public Student() {
		super();
	}

	public Student(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	// 重写clone方法
	@Override
	protected Object clone() throws CloneNotSupportedException {
		return super.clone();// Object.clone();
	}

}


Scanner类:简单文本扫描器。


 


  回想:键盘录入的步骤

1)需要创建键盘录入对象

Scanner sc =new Scanner(System.in);

2)导入包:import java.util.Scanenr;   ctrl+shift+o

3)接收数据

XXX 变量名= sc.nextXXX();

构造方法:

public Scanner(InputStream source): 以输入流的形式录入数据

InputStream:字节输入流:

InputStream  in = System.in ; //底层返回的是一个字节输入流(标准输入流)

代码示例

public class ScannerDemo {
	
	public static void main(String[] args) {
		
		//创建键盘录入对象
		Scanner sc = new Scanner(System.in) ;
		
		//接收数据
		int a = sc.nextInt() ;
		
		System.out.println("a:"+a);
	}
}

Scanner类的一些常见的方法:

XXX 变量名 = 键盘录入对象.nextXXX();

 在Scanner类中它提供一个判断功能:

public boolean hasNextXXX():当前扫描器判断是否有下一个可以录入的XXX类型数据

nextXXX();

java.util.InputMismatchException:录入的数据和接收的数据类型不匹配异常

代码示例

public class ScannerDemo2 {
	
	public static void main(String[] args) {
	
		//创建键盘录入对象
		Scanner sc = new Scanner(System.in) ;
		
		//录入数据
		System.out.println("请输入一个数据:");
		if(sc.hasNextInt()) {
			int num = sc.nextInt() ;
			System.out.println("num:"+num);
		}else {
			System.out.println("您输入的数据类型不匹配...");
		}
		
	}
}

键盘录入两个int类型的数据,分别输出,没有问题


 

键盘录入两个String类型的数据,分别输出:没有问题。


  

先录入一个String类型的数据,再录入一个int类型的数据,没有问题。


  

先录入一个int类型的数据,再录入一个String类型的数据就会有问题,第二个数据类型是字符串类型,但是由于录入下一个数据时要敲"空格",而空格本身也是一个字符串,就会把空格当作String类型数据给接收了,导致真正要输入的String类型数据无法接收。


如何解决:重新创建键盘录入对象

代码示例

public class ScannerDemo3 {
	
	public static void main(String[] args) {
		
		//录入两个int类型的数据
		Scanner sc = new Scanner(System.in) ;
		
	/*	int a = sc.nextInt() ;
		int b = sc.nextInt() ;
		
		System.out.println("a:"+a+",b:"+b);*/
		
		/*String str1 = sc.nextLine() ;//录入字符串
		String str2 = sc.nextLine() ;
		System.out.println("str1:"+str1+",str2:"+str2);*/
		
		/*String a = sc.nextLine() ;
		int  b = sc.nextInt() ;
		System.out.println("a:"+a+",b:"+b);*/
		
		int a = sc.nextInt() ;
//		String b = sc.nextLine() ;
		//需要重新创建键盘录入对象
		Scanner sc2 = new Scanner(System.in) ;
		String b = sc2.nextLine() ;
		System.out.println("a:"+a+",b:"+b);
		
	}
}