今天来总结一下Java中的三大特殊类:String类, Object类, 和包装类
一,String类

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

String str = "Hello World" ; // str是一个对象,那么"Hello World" 就应该保存在堆内存中 
System.out.println(str) ;

★ 传统方法(构造法):

String str = new String("Hello Bit") ; 
System.out.println(str) ;

● 两种实例化的区别:
1).采用直接赋值:

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

采用了直接赋值的模式进行String类的对象实例化操作,那么该实例化对象(字符串内容)将自动保存到这个对象池之中。如果下次继续使用直接赋值的模式声明String类对象,此时对象池之中如若有指定内容,将直接进行引用;如若没有,则开辟新的字符串对象而后将其保存在对象池之中以供下次使用。
所谓的对象池就是一个对象数组(目的就是减少开销)

2).采用构造方法

String str = new String("hello") ;

如果使用String构造方法,则在程序编译期会先去字符串常量池检查,是否存在“hello”,如果不存在则开辟一块空间存放“hello”,存在的话就不会开辟,然后在堆内存中开辟一块空间来存放new出来的String实力,再在战中开辟一块空间命名为str,存放堆内存中String实例的地址。
在String类中提供有方法入池操作 public String intern() ;

// 该字符串常量并没有保存在对象池之中    
   String str1 = new String("hello") ;       
   String str2 = "hello" ;       
   System.out.println(str1 == str2); // false
//方法入池后   
   String str1 = new String("hello").intern() ;  
   String str2 = "hello" ;        
   System.out.println(str1 == str2); // true

总结:
String类中两种对象实例化的区别 :
1). 直接赋值:只会开辟一块堆内存空间,并且该字符串对象可以自动保存在对象池中以供下次使用。
2). 构造方法:会开辟两块堆内存空间,其中一块成为垃圾空间,不会自动保存在对象池中,可以使用 intern()方法手工入池。
因此,我们一般会采取第一种方式即直接赋值
String类的其中一种构造方法如下: public String(String str) ;

2, 字符串相等比较

观察以下代码的输出

int x = 10 ;
int y = 10 ;
System.out.println(x==y); //true
String str1 = "Hello" ;
String str = new String("Hello") ;
System.out.println(str1==str); // false

为什么两个字符串内容相同,而使用 == 得到的结果不同。

来看内存图分析:

javancss例外 java例外三大类_字符串

可知:== 本身是进行数值比较的,若用于对象比较,则比较的是两个对象所保存的内存地址是否相等,而并没有比较对象的内容。

若想要进行内容比较,则必须采用String类提供的equals方法:

String str1 = "Hello" ;
 String str = new String("Hello") ;
 System.out.println(str1.equals(str));

由此可知:
==比较与equals比较的区别是:
(1) ==:进行数值比较,比较的是两个字符串对象的内存地址数值。
(2) “equals()”:可以进行字符串内容的比较

3,字符串不可变更

字符串一旦定义不可改变。
判断如下代码共开辟了多少块内存空间:

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

一起来看看这段代码内存模型:

javancss例外 java例外三大类_javancss例外_02

可以发现字符串上没有发生任何变化,但是字符串对象的引用一直在改变,而且会形成大量的垃圾空间。因此我们应该尽量避免在代码中用循环对字符变量的引用不断赋值。

关于字符串的一些方法:

方法名称

类型

描述

public boolean equals(Object anobject)

普通

区分大小写的比较

public boolean equalsIgnoreCase(String anotherString)

普通

不区分大小写的比较

public int compareTo(String anotherString)

普通

比较两个字符串大小关系

public boolean contains(CharSequence s)

普通

判断一个子字符串是否存在

public int indexOf(String str)

普通

从头开始查找指定字符串的位置,查到了返回位置的开始索引,查不到返回-1

public int indexOf(String str,int fromIndex)

普通

从指定位置开始查找子字符串位置

public int LastIndexof(String str)

普通

由后向前查找子字符串位置

public int LastIndexof(String str,int fromIndex)

普通

从指定位置由后向前查找

public boolean startsWith(String prefix)

普通

判断是否由指定字符串开头

public boolean startsWith(String prefix,int toffset)

普通

从指定位置开始判断是否以指定字符串开头

public boolean endsWith(String suffix)

普通

判断是否以指定字符串结尾

public String(byte bytes[])

构造

将字节数组变为字符串

public String(byte bytes[],int offset,int Length)

构造

将部分字节数组中的内容变为字符串

public byte[] getBytes()

普通

将字符串以字节数组的形式返回

public String(char value[])

构造

将字符数组中的所有内容变为字符串

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

构造

将部分字符数组中的内容变为字符串

public char charAt(int index)

普通

取得指定索引位置的字符,索引从0开始

public char[] toCharArray()

普通

将字符串变为字符数组返回

public String replaceAll(String regex,String replacement)

普通

替换所有指定内容

public String replaceFirst(String regex,String replacement)

普通

替换首个内容

public String[] split(String regex)

普通

将字符串全部拆分

public String[] split(String regex,int limit)

普通

将字符串部分拆分,该数组长度就是limit极限

public String substring(int beginIndex)

普通

从指定索引截取到结尾

public String substring(int beginIndex,int endIndex)

普通

截取部分内容

public String trim()

普通

去掉字符串中的左右空格,保留中间空格

public String toUpperCase()

普通

字符串转大写

public String toLowerCase()

普通

字符串转小写

public native String intern()

普通

字符串入池操作

public String concat(String str)

普通

字符串连接,等同于“+”,不入池

public int Length()

普通

取得字符串长度

public boolean isEmpty()

普通

判断是否为空字符串,但不是null,而是长度为0

4, StringBuffer类
String类的特点:任何的字符串常量都是String对象,而且String的常量一旦声明不可改变,如果改变对象内容,改变的是其引用的指向而已。
由于String的不可更改特性,为了方便字符串的修改,提供StringBuffer类。 在String中使用"+"来进行字符串连接,但在StringBuffer类中需要更改为append()方法:

public synchronized StringBuffer append(各种数据类型 b)

来看看StringBuffer的使用:

public class Stringbuffer {

        public static void main(String[] args) {
            StringBuffer sb = new StringBuffer();
            sb.append("Hello").append("World");
            fun(sb);
            System.out.println(sb);
        }    
        public static void fun(StringBuffer temp) {
            temp.append("\n").append("welcome to china");
        }
}

输出结果如下:

"C:\Program Files\Java\jdk1.8.0_131\bin\java" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2018.1\lib\idea_rt.jar=28563:C:\Program Files\JetBrains\IntelliJ IDEA 2018.1\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_131\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar;D:\code\java\Base\target\classes" String.Stringbuffer
HelloWorld
welcome to china

Process finished with exit code 0

String和StringBuffer大的区别在于:String的内容无法修改,而StringBuffer的内容可以修改。频繁修改字符串 的情况考虑使用StingBuffer。
两个类都是"CharSequence"接口的子类。
注意:String和StringBuffer类不能直接转换。
如果要想互相转换,可以采用如下原则:
●String变为StringBuffer:利用StringBuffer的构造方法或append()方法
● StringBuffer变为String:调用toString()方法。
除了append()方法外,StringBuffer也有一些String类没有的方法:
★字符串反转:

public synchronized StringBuffer reverse()

★删除指定范围的数据:

public synchronized StringBuffer delete(int start, int end)

★插入数据:

public synchronized StringBuffer insert(int offset, 各种数据类型 b)

二,Object类
Java里面除了Object类,所有的类都是存在继承关系的。默认会继承Object父 类。即,所有类的对象都可以使用Object进行接收。

方法名称

类型

描述

public Object()

构造

取得无参构造为子类服务

public String toString()

普通

取得对象信息

public boolean equals(Object obj)

普通

进行对相比较

在使用对象直接输出的时候,默认输出的是一个地址编码。如果现在使用的是String类,该类对象直接输出的是内容,主要原因就是toString()方法的问题。默认Object类提供的toString()方法只能够得到一个对象的地址(而这是所有对象都共同具备 的特征)。
toString()的核心目的在于取得对象信息。 String作为信息输出的重要数据类型,在Java中所有的数据类型只要遇见了String并且执行了 + ,那么都要求将其变 为字符串后连接,而所有对象要想变为字符串就默认使用 toString() 方法。
2. 对象比较
String类对象的比较使用的是equals()方法,实际上String类的equals()方法就是覆写的Object类中的equals()方法。
3. 接收引用数据类型
现在知道Object可以接收任意的对象,因为Object是所有类的父类,但是Obejct并不局限于此,它可以接收所有数据类型,包括:类、数组、接口。Object可以接收接口是Java中的强制要求,因为接口本身不能继承任何类。
来看一个Object类接受接口的例子:

interface IMessage {  
  public void getMessage() ;
 } 
   
 class MessageImpl implements IMessage {  
 
    @Override  
     public String toString() {   
            return "I am small girl" ;  
     }   
     public void getMessage() {    
            System.out.println("中国欢迎你");   
         } 
} 

public class Test {   
    public static void main(String[] args) {    
           IMessage msg  = new MessageImpl() ; // 子类向父接口转型     
           Object obj = msg ; // 接口向Obejct转型   
           System.out.println(obj);     
           IMessage tem = (IMessage) obj ; // 强制类型转换  
           temp.getMessage();  
      }
  }

Object真正达到了参数的统一,如果一个类希望接收所有的数据类型,就是用Object完成。
三 ,包装类
在Java中,数据类型分为基本数据类型和引用数据类型,Object类可以接收所有引用数据类型。那么基本数据类型如何处理呢?
1, 基本原理
包装类就是将基本数据类型封装到类中。
利用IntValue就可以实现基本数据类型变为对象的需求。将基本数据类型包装为一个类对象的本质就是使用Object进行接收处理。

●数值型(Number的子类):Byte,Short,Integer(int),Long,Float,Double
● 对象型(Object的子类):Boolean,Character(char)

2, 装箱与拆箱
在包装类与基本数据类型处理之中存在有两个概念:
●装箱:将基本数据类型变为包装类对象,通过每个包装类的构造方法实现装箱处理。
●拆箱:将包装类中包装的基本数据类型取出,利用包装类提供的XxValue()方法。
例如:

public class Test {
    public static void main(String[] args){
        //装箱
        Integer integer=new Integer(10);
        //拆箱
        int data=integer.intValue();
        System.out.println(data+10);
    }
}

Java在JDK1.5之后就提供了自动拆装箱机制,使用包装类与使用基本类型在用法上基本一致。
使用基本类还是包装类?
1)【强制】所有POJO类(类中只有属性与getter/setter,构造方法)使用包装类。
2)局部变量推荐使用基本类。包装类进行数值比较使用equals方法。
对于 Integer var = ? 在-128 至 127 范围内的赋值,Integer 对象是在IntegerCache.cache 产生,会复用 已有对象,这个区间内的 Integer 值可以直接使用==进行判断,但是这个区间之外的所有数据,都会在堆上产 生,并不会复用已有对象,这是一个大坑,推荐使用 equals 方法进行判断。

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

如何将字符串变为各个数据类型,这个时候就需要包装类支持。
字符串---->基本数据类型
★ String变为int 类型(Integer类):public static int parseInt(String s) throws NumberFormatException
★ String变为double类型(Double类):public static double parseDouble(String s) throws NumberFormatException
★ String变为Boolean类型(Boolean类):public static boolean parseBoolean(String s)
eg:将字符串变为int 型

String str = "123" ; // String类型
 int num = Integer.parseInt(str) ; 
 System.out.println(num);

注意:将字符串转为数字的时候,字符串的组成有非数字,那么转换就会出现错误 (NumberFormatException)
基本数据类型---->字符串:
★任何数据类型使用了"+"连接空白字符串就变为了字符串类型。
★使用String类中提供的valueOf()方法,此方法不产生垃圾。
eg:

String str = String.valueOf(100) ;  
 System.out.println(str);