Java的String类、Object类、包装类
1. String类
1.1 String类的两种实例化方式:
//1.直接赋值:
String str="hello";
//2.使用构造方法new的形式赋值
String str=new String("hello");
1.2 String类定义的字符串的比较:
//2.使用"=="方法比较
String str1="hello";
String str2=new String("hello");
System.out.println(str1==str2);
//输出结果为:false
//解析:因为此时的"=="比较,是String类的对象的比较,并不是字符串本身内容的比较
具体解析进行画图,如下图所示:
//2.使用equals()方法比较
String str1="hello";
String str2=new String("hello");
System.out.println(str1.equals(str2));
//输出结果为:true
//解析:因为equals()方法进行的是字符串内容的比较
1.3 String类的两种实例化的区别:
//1.直接赋值
String str1="hello";
String str2="hell0";
String str3="hello";
System.out.println(str1==str2);
System.out.println(str2==str3);
System.out.println(str1==str3);
//输出结果为:
true
true
true
解析如下:
因为String类的设计使用了共享设计模式,在JVM底层实际上会自动维护一个对象池(字符串对象池),如果采用了直接赋值的方式进行String类的对象实例化操作,那么该实例化对象的字符串内容将自动保存在这个对象池中,如果下次继续使用直接赋值的方式声明String类对象,那么此时对象池中若有指定内容,将直接进行引用;若没有,则开辟新的字符串对象然后将其保存在对象池中以供下次使用。所以在上述代码中,字符串"hello"并没有开辟新的堆内存空间,故str1、str2、str3都指向一块堆内存空间。
//2.使用构造方法赋值
String str1=new String("hello");
String str2=new String("hell0");
System.out.println(str1==str2);
//输出结果为:false
解析如下:
第一点:使用String构造方法会在堆内存中开辟两块空间:1.字符串常量"hello"所开辟的堆内存空间 2.new所开辟的堆内存空间;然而str1指向的是new所开辟的空间,所以通过字符串常量开辟的空间就成为了垃圾空间。
第二点:只要有new关键字就会在堆内存中开辟空间,所以str1所指向的位置与str2所指向的位置不同,故输出结果为false
//3.字符串共享问题
String str1=new String("hello");
//此时的字符串常量"hello"并没有保存在对象池里
String str2="hello";
//此时的字符串"hello"保存在了对象池里
System.out.println(str1==str2);
//输出结果为:false
解析:因为str1所指向的字符串的内容没有入池,故str1和str2所指向的堆内存空间不同,所以为false
//4.使用intern()方法
String str1=new Strng("hello").intern();
//此时,new所开辟的堆空间的字符串"hello"入池
String str2="hello";
System.out.println(str1==str2);
//输出结果为:true
解析:由于new所开辟的堆内存中的字符串"hello"已入池,故直接赋值的方式的匿名对象str2就和str1指向同一块堆内存,所以输出结果为true。
1.4 解释String类中两种对象实例化的区别:
1.直接赋值:相同字符串常量只会开辟一块堆内存空间,并且该字符串对象可以自动保存在对象池中以供下次使用
2.使用构造方法赋值:会开辟两块堆内存空间,其中一块堆内存空间会成为垃圾空间,并且不会自动保存在对象池中,只有使用了intern()方法手动让new开辟的堆内存入池。
1.5 字符串常量不可变更
即字符串常量一旦定义不可改变。
//观察如下代码:
String str="hello";
str=str+"world";
str=str+"!!!";
System.out.println(str);
//输出结果为:helloword!!!
画图作出具体解析:
由上述画图分析知:以上字符串的变更是字符串对象的变更而不是字符串常量的变更。
1.6 关于字符、字符数组、字节与字符串之间的转换
//1.字符串到字符的转换
//String类的普通方法public char charAt(int index)
//功能:取得指定索引位置的字符,索引从0开始
public class Test1 {
public static void main(String[] args)
{
String str="hello";
char data=str.charAt(0);
System.out.print(data);
}
}
//输出结果:h
//2.字符串到字符数组的转换
//String类的普通方法:public char[] toCharArray()
//功能:将字符串转换为字符数组
public class Test1 {
public static void main(String[] args)
{
String str="hello";
char[] data=str.toCharArray();
for(char i:data)
{
System.out.print(i+" ");
}
}
}
//输出结果:h e l l o
//3.将字符数组转换为字符串
//String类的构造方法public String(char value[])
//功能:将字符数组中的所有内容变为字符串
public class Test1 {
public static void main(String[] args)
{
char[] data=new char[] {'h','e','l','l','o'};
String str=new String(data);
System.out.println(str);
}
}
//输出结果:hello
//4.将部分数组中的内容转换为字符串
//String类的构造方法public String(char value[],int offset,int count)
//功能:将字符数组的下标为offset开始的count个字符转换为字符串
public class Test1 {
public static void main(String[] args)
{
char[] data=new char[] {'h','e','l','l','o'};
String str=new String(data,2,3);
System.out.println(str);
}
}
//输出结果:llo
//5.将字节数组转换为字符串
//String类的构造方法public String(byte byte[])
public class Test1 {
public static void main(String[] args)
{
byte[] data=new byte[] {'h','e','l','l','o'};
String str=new String(data);
System.out.println(str);
}
}
//输出结果:hello
//6.将部分字节数组中的内容转换为字符串
//String类的构造方法public String(byte bytes[],int offset,int length)
//功能:将字节数组bytes下标为offset开始共length个字节展缓为字符串
public class Test1 {
public static void main(String[] args)
{
byte[] data=new byte[] {'h','e','l','l','o'};
String str=new String(data,1,2);
System.out.println(str);
}
}
//输出结果:el
//7.将字符串转换为字符数组
//String类的普通方法public byte[] getBytes()
//功能:将字符串以字节数组的形式返回
public class Test1 {
public static void main(String[] args)
{
String str="hello";
byte[] bytes=str.getBytes();
for(byte i:bytes)
{
System.out.print(i+" ");
}
}
}
//输出结果:104 101 108 108 111
1.7 字符串之间的比较
//1.关于字符串之间区分大小写的比较
//String类的普通方法public boolean equals(Object anObject)
public class Test1 {
public static void main(String[] args)
{
String str1="hello";
String str2="Hello";
System.out.println(str1.equals(str2));
}
}
//输出结果:false
//2.关于字符串之间不区分大小写的比较
//String类的普通方法public equalsIgnoreCase(String anotherString)
public class Test1 {
public static void main(String[] args)
{
String str1="hello";
String str2="Hello";
System.out.println(str1.equalsIgnoreCase(str2));
}
}
//输出结果:true
//3.比较两个字符串大小关系
//String类的普通方法public int compareTo(String antherString)
//功能:两个字符串相等,返回0;不相等时,返回两个字符串的ASCII的差值
public class Test1 {
public static void main(String[] args)
{
String str1="hello";
String str2="Hello";
String str3="hello";
System.out.println(str1.compareTo(str2));
System.out.println(str1.compareTo(str3));
}
}
//输出结果:32 0
1.8 字符串查找
//1.判断一个字符串是否存在
//String类的普通方法public boolean contains(CharSequence s)
public class Test1 {
public static void main(String[] args)
{
String str1="hello world";
String str2="hello";
String str3="hi";
System.out.println(str1.contains(str2));
System.out.println(str1.contains(str3));
}
}
//输出结果:true false
//2.从头开始查找指定字符串的位置,查到了返回位置的开始索引,查不到返回-1
//String类普通方法public int indexOf(String str)
public class Test1 {
public static void main(String[] args)
{
String str1="hello world";
String str2="world";
String str3="hi";
System.out.println(str1.indexOf(str2));
System.out.println(str1.indexOf(str3));
}
}
//输出结果:6 -1
//3.从指定位置开始查找子字符串的位置
//String类的普通方法public int indexOf(String str,int formIndex)
public class Test1 {
public static void main(String[] args)
{
String str1="hello world";
String str2="world";
System.out.println(str1.indexOf(str2,4));
System.out.println(str1.indexOf(str2,7));
}
}
//输出结果:6 -1
//4.右后向前查找子字符串位置
//String类的普通方法public int lastIndexOf(String str)
public class Test1 {
public static void main(String[] args)
{
String str1="hello world";
String str2="world";
String str3="hi";
System.out.println(str1.lastIndexOf(str2));
System.out.println(str1.lastIndexOf(str3));
}
}
//输出结果:6 -1
//5.从指定位置右后向前查找
//String类的普通方法public int lastIndexOf(String str,int formIndex)
public class Test1 {
public static void main(String[] args)
{
String str1="hello world";
String str2="world";
System.out.println(str1.lastIndexOf(str2,10));
System.out.println(str1.lastIndexOf(str2,2));
}
}
//输出结果:6 -1
//6.判断是否以字符串开头
//String类的普通方法public boolean startsWith(String prefix)
public class Test1 {
public static void main(String[] args)
{
String str1="hello world";
String str2="world";
String str3="hello";
System.out.println(str1.startsWith(str2));
System.out.println(str1.startsWith(str3));
}
}
//输出结果:false true
//7.从指定位置开始判断是否以指定字符串开头
//String类的普通方法public boolean startsWith(String prefix,int offset)
public class Test1 {
public static void main(String[] args)
{
String str1="hello world";
String str2="world";
String str3="hello";
System.out.println(str1.startsWith(str2,6));
System.out.println(str1.startsWith(str3,2));
}
}
//输出结果:true false
//8.判断是否以指定字符串结尾
//String类的普通方法public boolean endsWith(String suffix)
public class Test1 {
public static void main(String[] args)
{
String str1="hello world";
String str2="world";
String str3="hello";
System.out.println(str1.endsWith(str2));
System.out.println(str1.endsWith(str3));
}
}
//输出结果:true false
1.9 字符串替换
//1.替换所有的指定内容
//String类的普通方法public String replaceAll(String regex,String replacement)
public class Test1 {
public static void main(String[] args)
{
String str1="hello world";
System.out.println(str1.replaceAll("o","k"));
}
}
//输出结果:hellk wkrld
//2.替换首个内容
//String类的普通方法public String replaceFirst(String regex,String replacement)
public class Test1 {
public static void main(String[] args)
{
String str1="hello world";
System.out.println(str1.replaceFirst("o","m"));
}
}
//输出结果:hellm world
1.10 字符串拆分(可以将完整字符串按照指定的分隔符划分为若干个子字符串)
//1.将字符串全部拆分
//String类的普通方法public String[] split(String regex)
public class Test1 {
public static void main(String[] args)
{
String str1="hello world hello world";
//按照空格分隔符将str1字符串进行拆分为字符串数组
String[] array=str1.split(" ");
for(int i=0;i<array.length;i++)
{
System.out.println(array[i]);
}
}
}
//输出结果:
//hello
//world
//hello
//world
//2.将字符串部分拆分,该数组长度就是limit极限
//String类的普通方法public String[] split(String regex,int limit)
public class Test1 {
public static void main(String[] args)
{
String str1="hello world hello world";
//按照空格分隔符将str1字符串进行拆分为字符串数组
String[] array=str1.split(" ",2);
//此时,字符串数组array中含有两个字符串
for(int i=0;i<array.length;i++)
{
System.out.println(array[i]);
}
}
}
//输出结果:
//hello
//world hello world
//3.当发现有些字符串无法正常拆分时,使用"\\"进行转义
public class Test1 {
public static void main(String[] args)
{
String str1="hello.world.hello.world";
//按照空格分隔符将str1字符串进行拆分为字符串数组
String[] array=str1.split("\\.");
//以上的拆分使用了"\\"对"."进行了转义,发现如果不进行转义就不能进行拆分
for(int i=0;i<array.length;i++)
{
System.out.println(array[i]);
}
}
}
//输出结果:
//hello
//world
//hello
//world
//4.实际开发之中,经常会用到字符串的拆分,举例如下:
public class Test1 {
public static void main(String[] args)
{
String str="xie:20|sun:19|yang:19";
//将其字符串拆分成xie 20 sun 19 yang 19
String[] str1=str.split("\\|");
//此时将str拆分成str1[3]={"xie:20","sun:19","yang:19"};
for(int i=0;i<str1.length;i++)
{
System.out.println(str1[i]);
//双重拆分
String[] str2=str1[i].split(":");
for(int j=0;j<str2.length;j++)
{
System.out.println(str2[j]);
}
}
}
}
//输出结果:
//xie:20
//xie
//20
//sun:19
//sun
//19
//yang:19
//yang
//19
1.11 字符串截取
//1.从指定索引截取到结尾
//String类的普通方法public String subString(int beginIndex)
public class Test1 {
public static void main(String[] args)
{
String str="my name is xie";
String result=str.substring(8);
System.out.println(result);
}
}
//输出结果:is xie
//2.截取部分内容
//String类的普通方法public String subString(int beginIndex,int endIndex)
public class Test1 {
public static void main(String[] args)
{
String str="my name is xie";
String result=str.substring(3,7);
//截取的是左闭右开的区间
System.out.println(result);
}
}
//输出结果:name
注:以上是关于字符串相关操作的常用方法,更多的方法自行了解!
1.12 String类、StringBuffer类、StringBuilder类的区别
(1)String类的特点:任何字符串常量都是String类的对象,并且String类的常量一旦声明不再改变字符串常量的内容,改变的只是其引用的指向而已。
(2)StringBuffer类的特点:String类的字符串常量具有不可修改性,但StringBuffer类的内容可以修改,若需要频繁修改字符串的内容,建议使用StringBuffer类。在String类中使用"+"进行字符串连接,但StringBuffer类的中字符串的修改需要append()方法,举例如下:
//StringBuffer类的字符串的连接
public class Test1 {
public static void main(String[] args)
{
StringBuffer buffer=new StringBuffer();
buffer.append("hello").append("world");
System.out.println(buffer);
}
}
//输出结果为:helloworld
(3)String类和StringBuffer类之间不能直接转换,需采用如下规则:
String类变为StringBuffer类:利用StringBuffer类的构造方法或者append()方法;
StringBuffer类变为String类:调用toString()方法。
(4)StringBuilder类的用法和StringBuffer类的用法一致,但StringBuilder类没有修饰符synchronized。
(5)StringBuffer类采用同步处理,属于线程安全操作;而StringBuilder类采用异步处理,属于线程不安全操作。
2.Object类
Java中除了Object类,所有的类都存在继承关系,默认继承Object类,故所有类的对象都可以使用Object类进行接收。
2.1 使用Object类接收所有类的对象
class Person{}
class Student{}
public class Test1 {
public static void main(String[] args)
{
Object obj1=new Person();
Object obj2=new Student();
System.out.println(obj1);
System.out.println(obj2);
}
}
输出结果:
aaa@qq.com
aaa@qq.com
由上述代码说明,Object类可以接收任何类的对象。
2.2 Object类的无参构造方法
//Object类的无参构造方法
//public Object()
public class Test1 {
public static void main(String[] args)
{
Object obj=new Object();
System.out.println(obj);
}
}
输出结果:
aaa@qq.com
//目的:无参构造方法为子类实例化需要所服务。
2.3 Object类的toString()方法
//Object类的toString()方法
//public String toString()
//功能:取得对象信息
public class Test1 {
public static void main(String[] args)
{
Object obj=new Object();
System.out.println(obj.toString());
}
}
输出结果:
aaa@qq.com
默认的Object类的toString()方法只能够得到一个对象的地址,这是所有类的对象都具有的特征。若觉得Object类默认提供的toString()方法功能不足,可以在需要的子类上覆写其toString()方法。下面讲述String类覆写Object类的toString()方法的功能。
2.4 String类覆写Object类的toString()方法的功能
//String类覆写toString()方法
//功能:字符串内容的比较
public class Test1 {
public static void main(String[] args)
{
Object obj1=new String("hello");
System.out.println(obj1);
}
}
输出结果:hello
2.5 自定义类并覆写Object父类的toString方法
class Person{
private String name;
private int age;
//Person类的构造方法
public Person(String name,int age)
{
this.name=name;
this.age=age;
}
//Person类覆写Object父类的toString()方法
public String toString()
{
return "姓名:"+this.name+" 年龄:"+this.age;
}
}
public class Test1 {
public static void main(String[] args)
{
Person person=new Person("王麻子",18);
System.out.println(person);//默认输出对象调用的就是toString()方法
}
}
输出结果:姓名:王麻子 年龄:18
2.6 Object类的equals()方法
//Object类的equals方法
///功能:对象的比较
public class Test1 {
public static void main(String[] args)
{
Object obj1=new Object();
Object obj2=obj1;
Object obj3=new Object();
System.out.println(obj1.equals(obj2));
System.out.println(obj1.equals(obj3));
}
}
输出结果:
true
false
2.7 覆写Object类的equals()方法
Object类中默认提供的equals()方法用于对象的比较,但对于功能不足的要求,所以子类可以覆写父类Object的equals()方法:
//覆写Object类的equals()方法,不再是用于对象比较,而是用于属性值的比较
class Person{
private String name;
private int age;
//Person类的构造方法
public Person(String name,int age){
this.name=name;
this.age=age;
}
//Person类覆写Object父类的equals()方法
public boolean equals(Object obj)
{
if(obj==null)
return false;
if(obj==this)
return true;
//判断obj是不是由Person类实例化的
if(!(obj instanceof Person))
{
return false;
}
Person person=(Person)obj;
//比较属性值
return this.name==person.name&&this.age==person.age;
}
}
public class Test1 {
public static void main(String[] args){
Object object1=new Person("xie",20);
Object object2=new Person("xie",20);
Object object3=new Person("sun",19);
System.out.println(object1.equals(object2));
System.out.println(object1.equals(object3));
}
}
输出结果:
true
false
2.8 Object类接收引用数据类型。之前分析Object类接收任意类的对象,因为Object类是所有类的父类,下面介绍关于Object类接收引用数据类型:类、数组、接口。
//1.使用Object类接收数组对象
public class Test1 {
public static void main(String[] args)
{
//Object类接收数组对象,是向上转型
Object obj=new int[] {1,2,3,4,5,6};
//Object类对象的向下转型
int[] data=(int[])obj;
for(int i:data)
{
System.out.print(i+" ");
}
}
}
输出结果:1 2 3 4 5 6
//2.Object类接收接口,这是Java中强制要求的,因为接口本身不能继承任何类
interface INew
{
void fun();
}
class NewA implements INew{
public void fun() {
System.out.println("NewA类实现INew接口");
}
}
public class Test1 {
public static void main(String[] args)
{
//子类向父接口转型
INew inew1=new NewA();
//Object类接收接口对象
Object object=inew1;
System.out.println(object);
}
}
输出结果:aaa@qq.com
总结:Object类真正实现了参数统一,如果一个类希望接收所有的数据类型,就用Object
3.包装类
包装类就是将基本数据类型封装到类中。
3.1 自定义一个int数据类型的包装类
class IntClass
{
private int data;
public IntClass(int data)
{
this.data=data;
}
public int intValue()
{
return this.data;
}
}
//此时的IntClass就相当于int数据类型的包装类
public class Test1 {
public static void main(String[] args)
{
//利用Object类接收自定义包装类的实例化对象
Object obj=new IntClass(55);
//向上转型后,进行向下转型
IntClass data=(IntClass)obj;
//利用intValue()方法取出基本数据类型int的值
System.out.println(data.intValue());
}
}
输出结果:55
总结:1.为什么一定要将基本数据类型包装成一个类对象?实则为了使用Object类进行接收处理,达到参数统一。
2.Java中的八种基本数据类型如果都按照以上方式提供其对应的包装类的话,存在以下问题:
(1)开发中代码重复
(2)在进行数值计算的时候,必须使用明确的方法将包装类中的数据取出来才可以计算
3.Java为了方便开发,专门提供了包装类的使用,对于包装类的使用,提供了两种类型:
(1)对象型(Object类的直接子类):Boolean、Character
(2)数值型(Number类的直接子类):Byte、Double、Short、Long、Integer、Float
3.2 装箱与拆箱
装箱:将基本数据类型变成包装类对象,利用每一个包装类提供的构造方法实现装箱处理。
拆箱:将包装类中包装的基本数据类型的值取出,利用Number类中提供的六种方法。
//1.下面以int和Integer举例
public class Test1 {
public static void main(String[] args)
{
Integer data=new Integer(55); //装箱
int num=data.intValue(); //拆箱
System.out.println(num);
}
}
输出结果:55
以上采用的是手工的装箱与拆箱,在JDK1.5以后提供了自动拆装箱的机制,从而可以直接利用包装类的对象进行各种数值计算。
//2.自动拆装箱
public class Test1 {
public static void main(String[] args)
{
Integer data=55; //自动装箱
int num=data+5; //自动拆箱
System.out.println(num);
}
}
输出结果:60
但在自动拆装箱中存在"=="与"equals()"问题,下面具体介绍是什么问题
//3.手动拆装箱中的"=="与"equals"
public class Test1 {
public static void main(String[] args)
{
Integer data1=new Integer(11);
Integer data2=new Integer(11);
System.out.println(data1==data2);
System.out.println(data1.equals(data2));
}
}
输出结果:
false
true
总结:"=="进行的是对象的比较,"equals"进行的是数值的比较
//4.自动拆装箱中的"=="和"equals"
public class Test1 {
public static void main(String[] args)
{
Integer data1=11;
Integer data2=11;
Integer data3=129;
Integer data4=129;
System.out.println(data1==data2);
System.out.println(data1.equals(data2));
System.out.println(data3==data4);
System.out.println(data3.equals(data4));
}
}
输出结果:
true
true
false
false
解析:对于自动装箱Integer data=数值,数值在-128到127范围内时,Integer对象是在IntegerCache.cache产生,会复用已有对象,这个区间内的Integer值可以直接用"=="判断大小,但在这个区间之外的所有数据,都会在堆上产生,并不会复用已有对象,故在今后的开发之中,对于数值的比较,建议使用equals()方法进行判断。
3.3 字符串与基本数据类型转换
1.String变为Integer(int):public static int parseInt(String s)
2.String变为Double(double):public static double parseDouble(String s)
3.String变为Boolean(boolean):public static boolean parseBoolean(String s)
//1.字符串变为int型
public class Test1 {
public static void main(String[] args)
{
String str="123";
int num=Integer.parseInt(str);
System.out.println(num);
}
}
输出结果:123
//2.字符串变为double型
public class Test1 {
public static void main(String[] args)
{
String str="123";
double data=Double.parseDouble(str);
System.out.println(data);
}
}
输出结果:123.0
但在字符串转换为数字的时候,若字符串中含有非数字,那么转换就会出现错误(NumberFormatExpection)。
//3.字符串中含有非数字时,转换出现错误
public class Test1 {
public static void main(String[] args)
{
String str="123abc";
double data=Double.parseDouble(str);
System.out.println(data);
}
}
出现错误,错误信息如下:
Exception in thread "main" java.lang.NumberFormatException: For input string: "123abc"
at sun.misc.FloatingDecimal.readJavaFormatString(Unknown Source)
at sun.misc.FloatingDecimal.parseDouble(Unknown Source)
at java.lang.Double.parseDouble(Unknown Source)
at Test1.main(Test1.java:5)
//4.字符串与boolean的转换
public class Test1 {
public static void main(String[] args)
{
String str1="123abc";
String str2="true";
boolean data1=Boolean.parseBoolean(str1);
boolean data2=Boolean.parseBoolean(str2);
System.out.println(data1);
System.out.println(data2);
}
}
输出结果:
false
true
在字符串到boolean转换时,只有当字符串为"true"时,boolean为true,其他任何字符串转换时,boolean都是false。
推荐阅读
-
Java日期时间API系列5-----Jdk7及以前的日期时间类TimeUnit在并发编程中的应用
-
Java日期时间API系列12-----Jdk8中java.time包中的新的日期时间API类,日期格式化,常用日期格式大全
-
Java String类相关知识梳理(含字符串常量池(String Pool)知识)
-
Java中Date()类 日期转字符串、字符串转日期的问题
-
java类成员默认的可访问性是什么?你猜
-
木卯先生的笔记---Object类
-
Java日期时间API系列8-----Jdk8中java.time包中的新的日期时间API类的LocalDate源码分析
-
java包装类和值类型的关系
-
Java中数组操作 java.util.Arrays 类常用方法的使用
-
C#使用Object类实现栈的方法详解