java

java数据类型

java-谈谈数据类型

JAVA中分为基本数据类型及引用数据类型

基本类型

八种基本数据类型: byte、short、int、long、float、double、boolean、char。

  • byte:Java中最小的数据类型,在内存中占8位(bit),即1个字节,取值范围-128~127,默认值0
  • short:短整型,在内存中占16位,即2个字节,取值范围-32768~32717,默认值0
  • int:整型,用于存储整数,在内在中占32位,即4个字节,取值范围-2147483648~2147483647,默认值0
  • long:长整型,在内存中占64位,即8个字节-2^63~2^63-1,默认值0L
  • float:浮点型,在内存中占32位,即4个字节,用于存储带小数点的数字(与double的区别在于float类型有效小数点只有6~7位),默认值0
  • double:双精度浮点型,用于存储带有小数点的数字,在内存中占64位,即8个字节,默认值0
  • char:字符型,用于存储单个字符,占16位,即2个字节,取值范围0~65535,默认值为空
  • boolean:布尔类型,占1个字节,用于判断真或假(仅有两个值,即true、false),默认值false
  • 实际上,Java中还存在另外一种基本类型void,它也有对应的包装类 java.lang.Void,不过我们无法直接对它们进行操作。

在Java语言中, new 一个对象是存储在里的,我们通过栈中的引用来使用这些对象;所以,对象本身来说是比较消耗资源的。

对于经常用到的类型,如int等,如果我们每次使用这种变量的时候都需要new一个Java对象的话,就会比较笨重。所以,Java提供了基本数据类型,这种数据的变量不需要使用new创建,他们不会在堆上创建,而是直接在 栈内存 中存储,因此会更加高效。

每个基本类型都有自己的包装类, 除了IntegerCharacter类以后,其它六个类的类名和基本数据类型一致,只是类名的第一个字母大写即可。

为什么需要包装类 :

很多人会有疑问,既然Java中为了提高效率,提供了八种基本数据类型,为什么还要提供包装类呢?

这个问题,其实前面已经有了答案,因为Java是一种面向对象语言,很多地方都需要使用对象而不是基本数据类型。比如,在集合类中,我们是无法将int 、double等类型放进去的。因为集合的容器要求元素是Object类型。

为了让基本类型也具有对象的特征,就出现了包装类型,它相当于将基本类型“包装起来”,使得它具有了对象的性质,并且为其添加了属性和方法,丰富了基本类型的操作。

我相信, 这足能解释 Java中,一切皆是对象!

谈到包装类 , 其实应该说一下基本类型的拆装箱, 场景: 将基本数据类型放入集合类 、 包装类型和基本类型的大小比较、包装类型的运算、三目运算符的使用、函数参数与返回值。。。

拆箱与装箱

那么,有了基本数据类型和包装类,肯定有些时候要在他们之间进行转换。比如把一个基本数据类型的int转换成一个包装类型的Integer对象。

我们认为包装类是对基本类型的包装,所以,把基本数据类型转换成包装类的过程就是打包装,英文对应于boxing,中文翻译为装箱。

反之,把包装类转换成基本数据类型的过程就是拆包装,英文对应于unboxing,中文翻译为拆箱。

自动装箱: 就是将基本数据类型自动转换成对应的包装类。

自动拆箱:就是将包装类自动转换成对应的基本数据类型。

自动装箱与自动拆箱的实现原理

有一下代码 :

public static  void main(String[]args){
    Integer integer = 1; //装箱
    int i = integer; //拆箱
}

反编译 :

public static  void main(String[]args){
    Integer integer = Integer.valueOf(1); 
    int i = integer.intValue(); 
}

自动拆装箱带来的问题

当然,自动拆装箱是一个很好的功能,大大节省了开发人员的精力,不再需要关心到底什么时候需要拆装箱。但是,他也会引入一些问题。

包装对象的数值比较,不能简单的使用==,虽然-128到127之间的数字可以,但是这个范围之外还是需要使用equals比较。

前面提到,有些场景会进行自动拆装箱,同时也说过,由于自动拆箱,如果包装类对象为null,那么自动拆箱时就有可能抛出NPE。

如果一个for循环中有大量拆装箱操作,会浪费很多资源。

引用类型

基本的变量类型只有一块存储空间(分配在stack中), 而引用类型有两块存储空间(一块在stack中,一块在heap中), 在函数调用时Java是传值还是传引用,这个估计很多人至今都很糊涂,可见此图理解:

什么是引用:

Java 是传值还是传引用,问题主要出在对象的传递上,因为 Java 中简单类型没有引用。既然争论中提到了引用这个东西,为了搞清楚这个问题,我们必须要知道引用是什么。

简单的说, 引用其实就像是一个对象的名字或者别名 (alias),一个对象在内存中会请求一块空间来保存数据,根据对象的大小,它可能需要占用的空间大小也不等。访问对象的时候,我们不会直接是访问对象在内存中的数据,而是通过引用去访问。引用也是一种数据类型,我们可以把它想象为类似 C++ 语言中指针的东西,它指示了对象在内存中的地址——只不过我们不能够观察到这个地址究竟是什么。
  
如果我们定义了不止一个引用指向同一个对象,那么这些引用是不相同的,因为引用也是一种数据类型,需要一定的内存空间(stack,栈空间)来保存。但是它们的值是相同的,都指示同一个对象在内存(heap,堆空间)的中位置。

值传递与引用传递

值传递:(形式参数类型是基本数据类型):方法调用时,实际参数把它的值传递给对应的形式参数,形式参数只是用实际参数的值初始化自己的存储单元内容,是两个不同的存储单元,所以方法执行中形式参数值的改变不影响实际参数的值。

引用传递:(形式参数类型是引用数据类型参数):也称为传地址。方法调用时,实际参数是对象(或数组),这时实际参数与形式参数指向同一个地址,在方法执行中,对形式参数的操作实际上就是对实际参数的操作,这个结果在方法结束后被保留了下来,所以方法执行中形式参数的改变将会影响实际参

问几个问题;

Q1:String s = new String("hollis");定义了几个对象。
A1:若常量池中已经存在”hollis”,则直接引用,也就是此时只会创建一个对象,如果常量池中不存在”hollis”,则先创建后引用,也就是有两个。

Q2: String a = "123"; String b = "123"; a==b?
A2 : 结果为True,这就说明了str1和str2其实指向的是同一个值。明白了A1, 应该就理解了Q2, 无论a还是b都是在栈的常量池中,a与b的引用地址一样, 所以位true

String唯一不需要new 就可以产生对象的途径, 为了减少在JVM中创建的字符串的数量,字符串类维护了一个字符串池,每当代码创建字符串常量时,JVM会首先检查字符串常量池。如果字符串已经存在池中,就返回池中的实例引用。如果字符串不在池中,就会实例化一个字符串并放到池中。

Q3: String s1 = new String("Hollis");String s2 = new String("Hollis");s1==s2?
A3: 结果flase,因为,== 比较的是变量(栈)内存中存放的对象的(堆)内存地址,用来判断两个对象的地址是否相同,即是否是指相同一个对象。比较的是真正意义上的指针操作。
可看图:

hope can help you!


本博客所有文章除特别声明外,均采用 CC BY-NC-SA 3.0 CN 许可协议。转载请注明出处!
文章若有侵权请立即与我联系, 我将及时处理
微信扫一扫,向我赞赏

微信扫一扫,向我赞赏

微信扫一扫,向我赞赏

支付宝扫一扫,向我赞赏

回复

This is just a placeholder img.
Title - Artist
0:00