这次主要记录的是基本数据类型的封装和String的基本使用。
基本数据类型的封装
在java中,八种数据类型也可以封装成对象。所以java相较于C++,面向对象更彻底,而相对于只有面向对象的语言,又有容易操作的面向过程的处理。
基本数据类型 | 封装数据类型 |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
而封装的数据类型,保证了数据的安全性,也为我们提供一些方法,比如把字符串转换成整数,小数之类的,重写的equals()方法来比较是否相等。
基本使用
1 | public static void main(String[] args) { |
既然是封装,那也就是对象,需要实例化,看样子和平时int a = 10;没啥区别。
1 | public static void main(String[] args) { |
还是 == 的注意,只比较基本变量的值是否相等和对象是否相等,对象相等的条件是引用的地址是否同一个。所以这里不出意外, false。
而equals()方法在Object也是比较值或地址是否相等,当在这重写了equals()方法,看下面的代码。
1 | public boolean equals(Object obj) { |
下面则是把字符串变为整型各种方法,虽然最后值都是一样。但,运算不一样,parseInt()把它默认当做十进制的1000表示。
1 | public static void main(String[] args) { |
但是,如果出现其他字符字母,则运行会报错,下面的代码,我们都知道是11.1,整数为11,但编译器不会把小数点后面的去掉。当然,里面只填11.1,编译器也会直接报错。你可以改为Double类使用浮点数。
1 | public static void main(String[] args) { |
装箱与拆箱
1 | public static void main(String[] args) { |
装箱与拆箱也改变了一点变化。我们来看看。
1 | public static void main(String[] args) { |
这两个答案是什么呢?因为是对象,你可以回答都是false。但是,我们先看看它的源代码。
1 | /** |
1 | /** |
1 | /** |
虽然看着还挺长的,但很多都是注释,注释都是帮助理解的。先看中间的这段代码,看得出来,如果这个数在默认的[low(-128),high(127)]范围外,是直接返回一个数组的值,而这个数组是怎么来的呢?看第一段里从第32行做分水岭,上面操作都在确定数组的范围,下面给cache赋值范围并新建Interger对象赋值。否则在[low,high]范围内呢,返回一个value,而这个value就是它本身。
所以,在装箱中,如果范围在[-128,127]之间,得到的是一个值,不在范围内才是对象。
既然你可以自动装箱和拆箱,那么下面的写法也就是ok的。
1 | public static void main(String[] args) { |
写东西总是会发现有意思的事,对象和值用 == 是什么比较?没想到是值,以前都没发现,都是对象.equals(对象),值==值。
1 | public class test01 { |
打印的两个都是true。
以上是关于Int型的封装Integer的使用,八种基本数据类型,封装都差不多,但也还是有不同,可以试试其他,比如integer的加法比较,Double的大小比较,Boolean的返回的true和false是不是对象等等。
String
八种基本数据类型之外的都是引用数据类型,比如数组,String,类,接口。而引用数据类型也就意味着它是对象。
1 | public static void main(String[] args) { |
看,String是类,却没有new,很多人初学可能都以为它是特殊的基本数据类型。但它是类,所以它也可以new。
1 | public static void main(String[] args) { |
那第一个打印啥,是false,为啥?在内存中,常量是一开始加载到方法区的常量池,比如我们定义的Final,或字符串都在常量池,而str2是先在常量池找有没有该常量,有的话直接在堆新建一个对象,没有的话,会在常量池存入该常量,接着在堆里新建对象。一个指向常量池,一个指向堆,所以打印false。
1 | public static void main(String[] args) { |
这个代码也能说明问题,当我给str赋值时,会去常量池找”Hello,World”这个常量,str2赋值,也会先去常量池找,同时指向同一个地址,那么它们的对象、值也就相等。
String也被称为不可变的字符串,在java中定义如下。
1 | public final class String |
可是,我们在使用中,往往可以加字符串,但是会产生多个对象
1 | public static void main(String[] args) { |
这里新建了一次str对象。而对象呢,也就创建了一个,因为”Hello,World”和”! java”一开始就加载到了常量池,使用的时候直接指向在常量池的对象就行。
1 | public static void main(String[] args) { |
每次地址都不一样,也就说明对象也不一样,一开始str新建String对象,而常量池没有”Hello”,于是先在常量池新建”Hello”对象,接着给str新建对象,所以第5行代码新建了两个对象,我们也看到str和”Hello”地址不一样。
而str2也新建”Hello”对象,但是常量池有”Hello”的对象,所以直接在堆里新建一个对象,所以这里只新建str2对象。看得出”Hello”地址没变。
而str3是把”He”和”llo”合在一起,构成一个字符串,去常量池找,所以直接指向常量池的对象地址。没有创建对象。
最后str把str+str,因为字符串不可变,而常量池没有”HelloHello”,所以先在常量池创建新对象”HelloHello”,str也更改对象,获取“helloHello”。创建了两个对象。
所以上面的代码最少创建5个对象,
1 | public static void main(String[] args) { |
String自然也可以用装箱和拆箱使用一些方法。
String常用方法
方法 | 解释 |
---|---|
isEmpty() | 是否为空,如果空返回true,否则返回flag |
charAt(int) | 返回字符串下标为int的值 |
length() | 返回字符串的长度,从0开始计算,但字符串末尾默认以\0结束 |
indexOf(String||char) | 返回字符或子字符串的最开的出现的下标 |
lastIndexOf(String||char) | 返回最后字符或子字符串的出现的下标 |
startsWith(String) | 是否以当前字符串开头 |
endsWith(String) | 是否以当前字符串结尾 |
replace(String||char,String||char) | 替换字符 |
toUpperCase() | 字符串全变为大写字母 |
toLowerCase() | 字符串全变为小写字母 |
split(String) | 切割字符串 |
toCharArray() | 变为字符数组 |
1 | public static void main(String[] args) { |
当然,String方法还有重写的equals()、hashCode()等等方法….