1. 包装类API
package javase.demo08.baozhaunglei;
import org.junit.Test;
// 8大基本数据类型的包装类。
// 包装和解包装/装箱和拆箱。
public class Demo01Integer {
Integer a;
@Test
public void testByte() {
byte byteNumber = 10;// byte类型的数字
System.out.println("输出 byte 基本类型的变量:" + byteNumber);
Byte byteNumberByte = new Byte(byteNumber);// 包装基本类型为Byte对象/装箱
System.out.println("输出包装后的对象 byteNumberByte:" + byteNumberByte);//包装类中覆盖了toString()方法,直接输出包装类对象输出的是具体的值。
byte byteNumberAfter = byteNumberByte.byteValue();// 解包装/拆箱
System.out.println("输出解包装后的对象:" + byteNumberAfter);
}
@Test
public void testInteger() {
int number = 100;
System.out.println("输出 int 基本类型变量:" + number);
Integer numberInteger = new Integer(number);// 通过构造方法包装成Integer对象/装箱
Integer valueofInteger = Integer.valueOf(1234);//通过valueOf()方法装箱
System.out.println("输出包装后的对象numberInteger:" + numberInteger);
System.out.println("输出包装后的对象valueofInteger:" + valueofInteger);
int numberAfter = numberInteger.intValue();// 解包装成基本类型/拆箱
System.out.println("输出解包装后的对象 numberAfter:" + numberAfter);
}
@Test
public void testBoolean() {
boolean bool = true;
System.out.println("输出 boolean 基本类型变量:" + bool);
Boolean boolBoolean = new Boolean(bool);
Boolean valueBollean = Boolean.valueOf(false);
System.out.println("输出 boolBoolean 包装后的变量:" + boolBoolean);
System.out.println("输出 valueBollean 包装后的变量:" + valueBollean);
boolean boolBooleanAfter = boolBoolean.booleanValue();
System.out.println("输出解包装后的对象 boolBooleanAfter:" + boolBooleanAfter);
}
@Test
public void testChar() {
char c = 'f';
System.out.println("输出char 基本类型变量:" + c);
Character cChar = new Character(c);// 将基本char类型包装成Character类型
Character vChar = Character.valueOf('J');
System.out.println("输出 Character 包装后的对象:" + cChar);
System.out.println("输出 Character 包装后的对象:" + vChar);
char cCharAfter = cChar.charValue();// 解包装
System.out.println("输出解包装后的对象 cCharAfter:" + cCharAfter);
}
@Test
public void testDefaultValue() {
//测试包装类型的默认值
//包装类型默认值是null值啊哈哈哈哈
System.out.println("包装类型的默认值:" + a);
}
}
2. 自动装箱和自动拆箱
JDK1.5之后实现了自动装箱和自动拆箱。
package javase.demo08.baozhaunglei;
import org.junit.Test;
// jdk1.5之后自动装箱和拆箱了,验证自动装箱操作和自动拆箱操作。
// 实际上对于基本类型的包装类,java基于一切皆对象的原则实现了包装类型,而为了方便的进行装箱和拆箱,jdk1.5之后实现了自动装箱和自动拆箱。
// 8大包装类型就是引用类型,是Object类的子类,而基本类型不是。所以基本类型无法调用方法。
public class Demo02Integer {
@Test
public void testInteger() {
Integer a = 1;// 自动装箱
Integer b = new Integer(2);// 手动装箱
int aa = a;// 自动拆箱为int型
int bb = b;// 自动拆箱为int型
System.out.println(aa);
System.out.println(bb);
System.out.println(aa);
System.out.println(b.toString());
System.out.println(new Object().toString());
System.out.println(new Person("zhaoerhu"));
System.out.println(new Person("zhaoerhu").toString());
}
class Person {
private String name;
public Person(String name) {
this.setName(name);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "name = " + this.name;
}
}
}
3. 探究String和8大基本包装类不可变的本质
package javase.demo09.init;
import org.junit.Test;
// 探究String和8大基本包装类不可变的本质(Java中不可变的本质来源就是常量,即通过final修饰导致的对象的不可变性):
// 8大基本数据类型的包装类和String有相似点,他们的类和成员的声明都是final的,所以,8大包装类和String的内容一旦声明都不能修改,看似的修改实际上每次都会实例化一个新的对象来存储。
// java中对于引用类型,某些类设计成了不可变类(所谓不可变类指的是当前类的成员被设计成final类型的),不可变类的对象就是不可变对象。
// 最著名的:String类和8大基本包装类型是不可变的。
// 不可变性是由于JDK团队设计的,并不是语法限制;语法上来说,只要是变量,它的内容就可以被修改;只要是常量,它的内容就不可以被修改。
// 实际上String和基本类型包装类就是使用的final实现的不可变,即这些类中的成员就是final修饰的常量。
// 注意:不可变性指的是对象中保存的实体内容,即我们常说的不可变性指的是引用类型的对象实体,而不是指引用地址本身。
public class Demo05KeBian {
// 测试基本类型的可变性:任何变量都可以被重置,注意此时的可变指的是重置变量本身,如果是基本类型指的是重置基本类型本身,如果是引用类型指的是重置引用本身;而不是对象实体。
@Test
public void testJiBenLeiXing() {
// 为a变量分配空间,并初始化为10
int a = 10;
System.out.println("a重置之前的值:" + a);
// 改变a空间的值为100,即重置a的值,之前的10等待被回收
a = 100;
System.out.println("a重置之后的值:" + a);
// 结论,所有基本类型的值都是可以改变的。
}
// 测试引用类型的可变性
@Test
public void testYinYongLeiXing() {
// 初始化per变量的值,为new Person11()返回的内存地址。
Person05 per = new Person05();
// 设置堆里面对象实体的内容
per.setName("ZHAOERHU");
per.setAge(22);
System.out.println("per重置前:" + per);
// 改变per空间的值,让它执指向新的内存地址
per = new Person05();
System.out.println("per重置后:" + per);
// 结论:引用类型的值(地址)是可变的。
}
// 引出对象的可变性
// 结论:这里正式开始了面向对象,new操作实际上就是实例化操作,new操作是在堆内存开辟空间保存对象实体的;
// 而对象名实际上保存的是指向对象实体的堆内存地址。注意java中所有对象实体都保存在堆内存,引用地址可能保存在栈中/方法区中/和堆中。
// Person per = new Person();per和所有基本类型没有任何区别,保存的就是地址值;当认识new之后,就有区别了,new Person();才是对象实体。
// 所以,我们常说的对象不可变,一定指的是对象本身,即对象实体,而不是引用变量。即不可变指的是new Person();而不是per。
@Test
public void testBuKeBianXing() {
// 初始化per变量的值-为new Person11()返回的内存地址。
Person05 per = new Person05();
// 设置堆里面对象实体的内容
per.setName("ZHAOERHU");
per.setAge(22);
System.out.println("per内容重置前:" + per);
// 如果说Person05被设计称不可变类,则要想改变上面堆内存中的成员,只能重新开辟一个新的对象来保存这个新值。
// 现在因为引用类型其内容本身就是可变的,所以直接修改其内容的值。
// 总结:对于普通的引用类型其对象实体是可以被重置的(除非这个类是不可变类)。
per.setName("Daisy");
per.setAge(18);
System.out.println("per内容重置后:" + per);
}
// 测试8大包装类和String的不可变性
// 总结:不可变性永远是对对象实体而言的,变量本身的可变和对象实体的可变不是一回事。
// 变量本身的可变是变量本身存储的值或者地址可变不可变, 对象的可变指的是对象里面的内容可变不可变。
// 我们常说的可变指的就是对象实体中的内容可变不可变。
@Test
public void testInteger() {
// 在堆内存创建一个Integer对象,并初始化其里面的值为8
Integer integer = new Integer(8);
System.out.println("包装类型b重置之前的值:" + integer);
System.out.println("integer对象的地址:" + System.identityHashCode(integer));
// 很明显,对于包装类型,是不能直接更改它原来空间的值的,一个是因为Integer中的value是final的,二一个是因为Integer没有提供setter方法。
// 包装类和String一样,所谓的重置和基本类型一样,真的是重置了一个新的内存空间,指向了新的对象,重新开辟了堆空间,而不像普通引用可以修改堆内容。
integer = new Integer(198);
System.out.println("包装类型b重置之后的值:" + integer);
System.out.println("integer对象的地址:" + System.identityHashCode(integer));
// 结论:包装类型和String被JVM设计成不可变的,每次的改变都是断开-连接的反复过程以求重新开辟空间,可以看出integer变量本身被重置为新的内存地址了。
}
}
class Person05 {
private String name;
private int 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;
}
public String toString() {
return "name = " + this.getName() + ";age = " + this.getAge();
}
}
文档信息
- 本文作者:Marshall