8.JavaSE之三个特殊类String、Object、包装类的常用方法以及注意点

一、String类-------java.lang.String类

1.String类的两种实例化方式

(1)直接赋值,自动入池。如果池中没有,则采用手工入池(本地方法):public native String intern();

//直接赋值,在堆上开辟空间
String str = "hello";

(2)传统方法(构造方法实例化)

//通过构造方法实例化String对象,new会新开辟一块空间。
String str1 = new String("hello");

2.字符串相等比较(比较内容)

  • 用equals()成员方法
  • pubilc boolean equals(String anotherString):成员方法
    str1.equals(anotherString);

"=="本身是进行数值比较的,如果现在用于对象比较,那么比较的是两个对象所保存的内存地址的数值。

面试题:请解释String类的“==”与“equals”的区别
1.“==”:进行的数值比较,比较的是两个字符串对象的内存地址数值。
2.“equals()”:可以进行字符串内容的比较。

3.字符串常量(" ")是String的匿名对象

public class Test{
	public static void main(String[] args){
		int i1 = 10;
		int i2 = 10;
		System.out.println(i1 == i2);//true

		String str1 = "hello";
		String str2 = new String("hello");//开辟了新空间
		
		System.out.println(str1 == str2);//false:比较的是地址,str2开辟了新空间,因而为false。
		System.out.println(str1.equals(str2));//true:比较的是内容。
	}
}

tips:以后在开发中,如果要判断用户输入的字符串是否等同于特定字符串,一定要把特定字符串(String常量)写在前面,避免NullPointerException
在这里插入图片描述

4.1.String类的两种实例化方式:
(1)直接赋值:

String str1 = "hello";
String str2 = "hello";
String str3 = "hello";
System.out.println(str1==str2);//true
System.out.println(str2==str3);//true
System.out.println(str1==str3);//true

再一次直接赋值不会开辟新的堆内存空间。而是调用同一块堆内存中的内容。如下图:
在这里插入图片描述
这是因为String类的设计采用了共享设计模式,如下:

在JVM底层会自动维护一个字符串的对象池(对象数组),如果现在采用直接赋值的形式进行String的对象实例化,该对象会自动保存在这个对象池之中。如果下次继续使用直接赋值的模式声明String对象,此时对象池中若有指定内容,则直接引用;如果没有,则开辟新的堆空间后将其保存在对象池中供下次使用。**
在这里插入图片描述

所谓的对象池就是一个对象数组(目的是减少开销)
(2)采用构造方法赋值->是标准做法。

String str = new String("hello");
String str1 = new String("hello");

分析:使用String构造方法会开辟两块堆内存空间,其中一块堆内存将成为垃圾空间,并且会产生字符串共享问题

//该字符常量并没有保存在对象池中
String str1 = new String("hello");
String str2 = "hello";
System.out.println(str1 == str2);//false

而要想入池,可采用手工入池方法:public String intern();

String str1 = new String("hello").intern();//手工入池
String str2 = "hello";
System.out.println(str1==str2);//true

手工入池后,两个对象指向的是同一块堆内存空间。而另一块存储着"hello"的空间作为了垃圾空间。

面试题:请解释String类中两种对象实例化的区别:
①直接赋值:只会开辟一块堆内存空间,并且该字符串对象可以自动保存在对象池中以供下次使用。
②构造方法:会开辟两块空间,其中一块成为垃圾空间,不会自动保存在对象池中,但可以使用intern()方法手工入池。

5.字符串常量不可变更
所有语言对字符串的实现都是字符数组,而数组最大的缺陷就是长度固定。定义字符串常量时,内容不可改变

字符串常量一旦定义后不可改变。变更的是对象/引用。

如:

String str = "hello";
str=str+"world";
str += "!!!";
System.out.println(str);//hello world!!!

在这里插入图片描述
分析:可以发现字符串没有发生变化,而是对象的引用一直在变化,因此会形成大量的垃圾空间。在开发过程中如果出现如下代码会产生大量垃圾空间:

String str = "hello";
for(int x =0;x<1000;x++){
	str =+x;
}
System.out.println(str);

此代码会产生1999个垃圾空间,不利于实际开发。
注意:在实际开发过程中,尽量少出现"
+"操作,不要超过三次。

原则:
①字符串使用,采用直接赋值。
②字符串比较,用equals()实现。
③字符串别改变太多次。

6.字符与字符串的相互转换

(1)将字符数组char[ ]—> String

public String(char[ ] value)
public String(char[ ] value,int offset,int count)

(2)将字符串转为单个字符

public char charAt(int index);

(3)将字符串变为字符数组:String -> char[ ]

public char[ ] toCharArray();//通过对象调用
取得字符串长度:public int length();

7.字节(byte)与字符串

(1)将字节数组转为字符串(*******)

byte[ ] -> String
public String(byte[ ] value)
public String(byte[ ] value,int offset,int count)

(2)将字符串转为字符数组(*******)

String -> byte[ ]
public byte[ ] getBytes();

(3)将字符串按照指定编码转为字节数组

public byte[ ] getBytes(String charsetName);

8.字符串比较

(1)不区分大小写相等比较

public boolean equalsIgnoreCase(String anotherString)

(2)比较两个字符串大小

public int compareTo(String anotherString)//只要有不一样,就立即返回

  • 返回大于0:表示大于比较对象
  • 返回等于0:两者相等
  • 返回小于0:表示小于比较对象

9.字符串查找

  • public boolean contains(String str);//判断str在本字符串中是否存在
  • public boolean startsWith(String str);//判断是否以指定字符串开头
  • public boolean startsWith(String str,int index);//从指定位置开始判断是否以指定字符串开头
  • public boolean endsWith(String str);//判断是否以指定字符串结尾

10.字符串替换

  • public String replaceAll(String regex,String replacement);//替换所有内容
  • public String replaceFirst(String regex,String replacement);//替换首个内容

11.字符串拆分,如果未得到结果,则需要转义\

  • public String[] split(String regex);//将字符串按照指定格式全部拆分
  • public String[] split(String regex,int limit);//将字符串部分拆分,数组长度为limit

12.字符串截取

  • public String substring(int beginIndex):从指定位置截取到字符串结尾
  • public String substring(int beginIndex,int endIndex):截取部分内容 结果是[ 0,5 )。

13.String类的其他方法

  • 去掉左右空格 public String trim();
  • 转大小写
    public String toUpperCase();
    public String toLowerCase();
  • 判断字符串是否为空(只能判断是否为空字符串,而不是null)
    public boolean isEmpty();
    //如果为null,则运行时异常(空指针异常)。

14.两只sb(面试),方便进行字符串修改-----------java.lang自动导入

  • StringBuffer:采用同步处理,线程安全,效率较低
  • StringBuilder:异步处理,线程不安全,效率较高,String"+"底层会将String->StringBuilder
  • String的内容不可修改,两只sb可以改内容(append),频繁修改字符串的情况建议使用StringBuffer。
    字符串修改 public StringBuffer append(各种数据类型)

StringBuffer <-> String的相互转换:

①String -> StringBuffer:调用StringBuffer的构造方法或append()方法
②StringBuffer->String :StringBuffer.toString();

字符串反转 public StringBuffer reverse();
删除指定范围的数据 public StringBuffer delete(int start,int end);
插入数据 public StringBuffer insert(int offset,各种数据类型);


面试题:请解释String、StringBuffer、StringBuilder的区别:
①String的内容不可更改,StringBuffer和StringBuilder的内容可以更改。
②StringBuffer采用同步处理,属于线程安全操作;StringBuilder采用异步处理,属于线程不安全操作。

二、Object类(RealFather)— Object类是java默认提供的类。

java除了Object类,所有的类都存在继承关系,默认会继承Object父类,所有类对象都可以通过Object类进行接收。


1.取得对象信息—toString()

直接使用对象输出,默认输出一个地址编码。如果现在输出的是String对象,此时输出字符串内 容而非地址,原因在于String类覆写了Object的toString()方法。

  • System.out.println();系统输出默认会调用对象的toString()方法。
  • 如果默认给出的toString()功能不足(不想输出地址而是输出本类信息),需要在子类中覆写toString()方法。

默认toString()方法功能不足,则需要覆写toString()方法。

class Person{
    private String name;
    private int age;

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

    @Override
    public String toString() {
        return "姓名:"+this.name+",年龄:"+this.age;
    }
}
class Student{}
public class Test{
    public static void main(String[] args){
        fun(new Person("roman",18));
        fun("ok");
    }
    public static void fun(Object obj){
        System.out.println(obj.toString());
    }
}

运行结果
姓名:roman,年龄:18
ok

2.对象比较—equals()

String类对象的比较使用的是equals()方法,实际上String类的equals()方法就是覆写的Object类中的equals()方法。

class Person{
    private String name;
    private int age;

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

    @Override
    public String toString() {
        return "姓名:"+this.name+",年龄:"+this.age;
    }

    @Override
    public boolean equals(Object obj) {
        if(obj == null){
            return false;
        }
        if (this == obj)
            return true;
        //不是Person类对象
        if (!(obj instanceof Person))
            return false;
        Person person = (Person) obj;//向下转型,比较属性值
        return this.age == person.age &&
                this.name.equals(person.name);
    }
}
class Student{}
public class Test{
    public static void main(String[] args){
        Person per1 = new Person("roman",18);
        Person per2 = new Person("roman",18);
        System.out.println(per1.equals(per2));//true
    }

}

3.接收引用数据类型:

在之前已经分析了Object可以接收任意的对象,因为Object是所有类的父类,但是Obejct并不局限于此,它可以接 收所有数据类型,包括:类、数组、接口。

		//Object接收数组
		Object obj = new int[]{1,3,4,5};
        int[] data = (int[])obj;
        for(int i:data){
            System.out.print(i+"、");
        }

Object可以接收接口是java中的强制要求,因为接口本身不能继承任何类。
Object接收接口对象:

interface IMessage{
    public void getMessage();
}
class MessageImp implements IMessage{
    @Override
    public String toString() {
        return "I am a biter";
    }

    @Override
    public void getMessage() {
        System.out.println("hello bit");
    }
}
public class Test{
    public static void main(String[] args) {
        IMessage msg = new MessageImp();//子类向父接口转型
        Object obj = msg;//接口向Object转型
        System.out.println(obj);
        IMessage tmp = (IMessage)obj;
        tmp.getMessage();
    }
}

运行结果:
I am a biter
hello bit

三、包装类

定义:将基本数据类型封装到类中。
Object类可以接收所有引用数据类型。然而在java中分为基本数据类型和引用数据类型。那么谁来管基本数据类型呢?在java中使用包装类封装基本数据类型。
1.分类:

(1)对象性包装类(Object的直接子类):Boolean(boolean)、 Character(char)
(2)数值型包装类(Number的直接子类),存在数值转换异常:
Byte(byte)、Short(short)、Long(long)、Double(double)、Float(float)、Integer(integer)

2.装箱与拆箱-------基本数据类型与相应包装类的数据处理

(1)装箱:将基本数据类型变为包装类对象,利用每个包装类提供的构造方法实现装箱。
(2)拆箱:将包装类中包装的基本类型值取出,利用Number类提供的xxValue()实现拆箱处理。

Integer num = new Integer(55);//手工装箱
int data = num.intValue();//手工拆箱
System.out.println(data);

JDK1.5后,提供了自动拆装箱的机制,这种机制可以直接利用包装类的对象进行各种数学计算。

//自动装箱
Integer x = 55;
//可以直接利用包装类对象操作
System.out.println(++x * 5);

上述代码中,这个时候依然存在有"=="和"equals"问题。

以下为问题解决的途径:
阿里编码规范:所有相同类型的包装类对象之间的值比较,全部使用equals方法比较。

注意对于Integer var = ? 在-128~127之间的复制,Integer对象在Integer常量池产生,会复用已有对象,这个区间内的Integer值可以直接使用 == 判断。除此之外的所有数据,都会在堆上产生,并不会复用已有对象。

public class Test{
	public static void main(String[] args){
		Integer i1 = 10;//自动装箱
		Integer i2 = new Integer(10);//手工装箱

		Integer i3 = 10;
		Integer i4 = 200;
		Integer i5 = 200;

		System.out.println(i1 == i2);//false:i2创建了一个新空间,==比较的是地址,所以i1和i2的地址不同
		System.out.println(i1 == i3);//true:已在Integer常量池中产生,可以复用已有对象。
		System.out.println(i4 == i5);//false:Integer对象的值不在-128~127之间,不可以用 == 判断
	}
}

阿里编码规范:使用int还是Integer?

【强制】 所有POJO类(简单Java类,Bean)属性必须使用包装类型
【强制】 RPC方法的返回值和参数必须使用包赚类型
【推荐】所有的局部变量使用基本类型

3.字符串与基本类型转换

(1)将字符串转为基本类型(静态方法)

调用各个包装类.parseXX(String str)
如:
Integer.parseInt(str);
Double.parseDouble(str);

字符串转为数字时,字符串的组成有非数字,那么转换就会出现错误NumberFormatException。而字符串与boolean转换就不受影响。

public class Test{
	public static void main(String[] args){
		String str = "123";
		int i = Integer.parseInt(str);
		System.out.println(i+10);

		String str1 = "123.10";
		double b = Double.parseDouble(str1);
		System.out.println(b+10);
	}
}

运行结果:
133
133.1

(2)基本类型变为字符串:

①任何数据类型使用 +" " 就变成了字符串类型。
②使用String类的valueOf()方法,此方法不产生垃圾空间(推荐)。

例:

String str = String.valueOf(100);
System.out.println(str);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值