【JavaSE】三个特殊的类,String类,Object类,包装类。
一、String类
1.String类的两种实例化方式
直接赋值
String str = "Hello";
- 直接赋值在堆上分配空间,形成一个对象池(类似数组),再次直接赋值字符串,如果对象池中有和此次赋值相等的字符串,就让新的引用也指向对象池中本来存在的堆地址。
传统方法
String str = new String("Hello");
- 每次new一个实例化对象,都新开辟一个堆空间,然后让对象引用指向这个堆空间。不论是否对象池中有没有相等的字符串。
- 第一种方式的实现原理在java中称为共享设计。这种设计的思路是,在java中形成一个对象池,在这个对象池中保存多个对象,新实例化的对象如果已经在池中定义了,则不再重新定义,而从池中直接取出继续使用。String就是因为采用了这样的设计,所以当内容重复时,会将对象指向已存在的实例空间。
2.字符串的相等比较
- 先看如下代码:
public class Test{
public static void main(String[] args){
String str1 = "123";
String str2 = "123";
String str3 = new String("123");
String str4 = new String("123");
System.out.println("123" == "123"); //true
System.out.println(str1==str2); //true
System.out.println(str3==str4); //false
System.out.println(str1=="123"); //true
System.out.println(str3=="123"); //false
}
}
- 由于字符串不是基本数据类型,用“==”判断它是否相等的时候,比较的不是字符串的值,而是它的堆地址。
- 根据上面所说的,如果赋值相等,字符串只有new的时候才会创建新的堆空间,否则会去对象池里面找值相同的,然后得到相同的堆地址。
- 所以只有str1和str2是相同的地址,str3和str4有各自新new出来的堆地址。
equals方法
- 一般比较字符串用的是equals方法,它比较的是真正的字符串的值,而不是堆地址。
System.out.println("123".equals(str3)); //true
- 给上面的代码再加一条,输出true。
- 注意:一般将匿名字符串放在前面去调用equals方法,因为将str3放在前面,有可能出现空指针异常的错误。
native String intern()方法 手工入池
- 这个方法是一个 native 的方法。“如果常量池中存在当前字符串, 就会直接返回当前字符串. 如果常量池中没有此字符串, 会将此字符串放入常量池中后, 再返回”。
- 什么是native?
- 简单地讲,一个Native Method就是一个java调用非java代码的接口。一个Native Method是这样一个java的方法:该方法的实现由非java语言实现,比如C。这个特征并非java所特有,很多其它的编程语言都有这一机制,比如在C++中,你可以用extern "C"告知C++编译器去调用一个C的函数。
public class Test{
public static void main(String[] args){
String str3 = new String("123").intern();
String str1 = "123";
System.out.println(str3==str1); //true
}
}
- 如果使用手工入池的话,new出来的字符串,也会被加入到对象池里面去。
- 字符串常量一旦定义,就无法更改。
二、Object类
1.特点
- Object类是java中最*的父类。
- Java中除了Object类,所有的类都存在继承关系,默认会继承Object父类。所有类对象都可以通过Object类进行接收
2.取得对象信息—toString()方法
- 直接输出对象,默认调用对象的toString()方法,打印一个地址信息
Person p1 = new Person(); //假设Person是一个类名
system.out.println(p1);
- 如果输出的是String类的对象,那么打印的就是字符串。因为String类覆写了toString()的方法。
- 如果默认给出的toString()功能不足(不想输出地址而是输出本类信息),需要在子类中覆写toString()方法。
3.对象的比较—equals()方法
- obj instanceof Person 判断obj是否是Peron的实例
public boolean equals(Object obj){
if(!(obj instanceof Person)){
return false;
}
if(obj == this){
return true;
}
//需要向下转型,因为Object的引用没有Person对象的属性
Person per = (Person)obj;
return per.name.equals(this.name) && (per.age == this.age);
}
3.接受引用数据类型
- Object可以接受所有引用类型,包括:类、数组、接口
三、包装类
- 定义:包装类就是将基本数据类型封装到类中
1.分类
对象包装类(Object的直接子类):
- Boolean(boolean)
- Character(char)
数值型包装类(Number的直接类):
- 存在数值转换异常
- Byte(byte)
- Short(short)
- Long(long)
- Double(double)
- Float(float)
- Integer(int)
2.装箱与拆箱—基本数据类型与相应包装类的数据处理
- 装箱:将基本数据类型变为包装类对象,利用每个包装类提供的构造方法实现装箱
- 拆箱:将包装类中包装的基本类型值取出,利用Number类提供的xxValue()实现拆箱处理
//手工装箱
Integer i = new Integer(20);
//手工拆箱
int result = i.intValue();
//JDK 1.5之后:
//自动装箱
Integer i2 = 20;
//自动拆箱
int result2 = i2+10;
- 说明:对于Integer var = ? 在-128到127之间的赋值,Integer对象在Integer常量池产生,会复用已有对象,这个区间内的Integer值可以直接使用==判断.除此之外的所有数据,都会在堆上产生,并不会复用已有对象.
使用int还是Integer有以下几个场景
- [强制]所有POJO类(简单Java类,Bean它里面只有基本属性,get和set,还有构造方法)属性必须使用包装类型
- [强制]RPC方法的返回值和参数必须使用包装类型
- [推荐]所有的局部变量使用基本类型
3.字符串与基本类型的转换
①.将字符串转为基本类型(静态方法):
-
调用各个包装类.parseXX(String str)
-
Integer.parseInt(String str);
②.基本类型—>字符串 -
“”+基本类型
-
使用String类的valueOf(基本类型) 它是静态方法,此方法不产生垃圾空间