10分钟彻底掌握数据类型

数据类型概览

在这里插入图片描述

基本数据类型和引用数据类型的区别

  • 基本数据类型在被创建的时候,是在栈如给其划分一个内存,将数值直接存储在栈上
  • 引用数据类型,是需要给引用在栈上分配一块内存,而对象的具体信息分配在堆上,利用在栈上对堆的指向来进行对对象进行访问

为什么要设计基本数据类型

因为程序在编写的过程中要经常使用他们,尤其是小而简单的变量,使用new创建对象的方法不是非常有效,因为new将对象置于堆里,需要通过句柄(引用)访问他们。如果直接将置于栈中的便利用来容纳具体的值,效率会更高。

是否所有的基本数据类型都存在于栈中?

答案自然是否定的,比如:

class test{
	public int i=10;
} 

存在于test的实例对象中的i就属于基本数据类型,但是他会随着test对象存储在堆上,而不栈上。

基本数据类型的大小范围

类型名称字节大小默认值取值范围
boolean1bitfalse/truefalse
byte1byte(8bit)0-128~127
short2byte0-32768~32767
char2byte\u0000可指定,动态分配
int4byte0-2^31 ~ 2^31-1
float4byte0.0-3.403E38~3.403E38
long8byte0-2^63 ~ 2^63-1
double8byte0.0-1.798E308~1.798E308

基本数据类型对应的包装类

Java中的基本数据类型没有方法和属性,于是开发人员将这些基本数据类型包装起来,形成包装类,拥有了属性和方法,实现对象化交互。

装箱:基本数据转化为包装类的过程,通过valueof()方法

//使用Integer(整形的包装类)作为例子
Integer.valueof(str) 
//返回Integer对象

拆箱:包装类转化为基本数据的过程,通过parseXxx()方法

//使用Integer(整形的包装类)作为例子
Integer.parseInt(str) 
//返回是int型数据

现在Java装箱拆箱都是自动的,虚拟机会自动调用valueof()或者parseXxx(),可以提高不少开发的效率

包装类格式

  • 包装类将首字母大写
基本数据类型包装类缓存区间
booleanBooleanfalse
byteByte-128-127
shortShort-128-127
longLong-128-127
floatFloat
doubleDouble
  • 包装类进行变形
基本数据类型包装类缓存区间
intInteger-128-127
charCharacter0-127

包装类缓存机制

缓存处理的原理:如果数据在相应数据包装类的缓存区间内,那么类在加载时就已经为该区间的每个数值创建了对象,并将这256个对象放在一个名为cache的数组中。

每当我进行自动装箱过程时,JVM会调用valueof方法,就会判断数据是否存在对应缓存区间,如果在,直接获取对应的包装类对象的引用,如果不在该区间,才通过new调用包装类的构造对象。

缓存处理的作用:提高效率,对于缓存区间内部的对象不需要重复开辟空间,实例化对象。

比如说Integer具体源码

public static Integer valueOf(int i) {
		//IntegerCache.low=-128;
		//IntegerCache.high=127;
		//IntegerCache为Integer的一个静态内部类

		//判断是否在[-128,127]的缓存区间
        if (i >= IntegerCache.low && i <= IntegerCache.high)
        	//如果在,返回cache缓存的包装类对象
            return IntegerCache.cache[i + (-IntegerCache.low)];
            //如果不在,新建一个包装对象。
        return new Integer(i);
    }

Integer是唯一能对cache(缓存数组)进行扩容的包装类,但是只能向上扩容,不能变小。

IntegerCache源码

  private static class IntegerCache {
        static final int low = -128;
        static final int high;
        static final Integer cache[];
 
        static {
            // high value may be configured by property
            int h = 127;
            String integerCacheHighPropValue =
                sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
            if (integerCacheHighPropValue != null) {
                try {
                    int i = parseInt(integerCacheHighPropValue);
                    //这里说明 i最小为127;
                    i = Math.max(i, 127);
                    // Maximum array size is Integer.MAX_VALUE
                    h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
                } catch( NumberFormatException nfe) {
                    // If the property cannot be parsed into an int, ignore it.
                }
            }
            high = h;
 
            cache = new Integer[(high - low) + 1];
            int j = low;
            for(int k = 0; k < cache.length; k++)
                cache[k] = new Integer(j++);
 
            // range [-128, 127] must be interned (JLS7 5.1.7)
            assert IntegerCache.high >= 127;
        }
 
        private IntegerCache() {}
    }

正因他的缓存机制的效率较高,推荐同学们创建一个包装类对象时,使用

Integer i=Integer.valueof(a);

你不得不知道的小细节

  • 输入整数时,默认为int型,输入浮点数时,默认为double型
  • byte,short,char进行数的运算时,会自动转化为int型
  • 通过包装类.MAX_VALUE 可以获得相应数据的最大值包装类.MIN_VALUE,可以获得相应数据的最小值
  • float和double存在精度丢失的问题,他们只是无限接近于某个数,而不能达到它,不建议直接比较判断相等,如果需要直接判断相等建议使用**“<>”**

或者

//根据他们的差的绝对值是否大于0来进行判断
Math.abs(a-b)==0;
//考虑到实际应用,一般如果两个浮点数之差的绝对值小于或等于某一个可接受的误差(即精度,比如0.00000001即可),就认为它们是相等的。
Math.abs(a-b)<0.0000000000001;
  • 但是在科学或者商业要进行十分精确的数字进行运算,我们就需要BigDecimal类
构造方法

BigDecimal(int)        创建一个具有参数所指定整数值的对象。
BigDecimal(double)     创建一个具有参数所指定双精度值的对象。
BigDecimal(long)       创建一个具有参数所指定长整数值的对象。
BigDecimal(String)     创建一个具有参数所指定以字符串表示的数值的对象。

使用BigDecimal(double val)构造函数时仍会存在精度丢失问题,建议使用BigDecimal(String val)。

我们进行运算的时候,只能通过调用BigDecimal的方法来完成。

add(BigDecimal)          BigDecimal对象中的值相加,然后返回这个对象。
subtract(BigDecimal)     BigDecimal对象中的值相减,然后返回这个对象。
multiply(BigDecimal)     BigDecimal对象中的值相乘,然后返回这个对象。
divide(BigDecimal)       BigDecimal对象中的值相除,然后返回这个对象。
toString()               将BigDecimal对象的数值转换成字符串。
doubleValue()            将BigDecimal对象中的值以双精度数返回。
floatValue()             将BigDecimal对象中的值以单精度数返回。
longValue()              将BigDecimal对象中的值以长整数返回。
intValue()               将BigDecimal对象中的值以整数返回。
compareTo(BigDecimal)	 比较大小,返回-1,0,1

也不是说明任何情况都是BigDecimal比float或者double表现优秀,因为float或者double都是内置数据类型,他们的开销肯定要比创建一个对象小,尤其在处理数据十分大的时候,性能表现得越差。

  • 类型转换(boolean没有类型转化

自动类型转换条件:目标类型大于原来数据类型
强制类型转化条件:目标类型小于原来数据类型(浮点数数转化为整数直接被斩断小数部分

String(字符串)

细心的你肯定发现了,字符串并不是一个基本数据类型出现在我们的概览图中,这是因为Java中字符串是一个引用数据类型,Java将其封装成了一个类

创建字符串对象的两种方法

String s1="Hello";
String s2=new String("Hello");

这两种其实的创建过程不一样

System.out.println("s1和s2 引用地址是否相同:"+(s1 == s2));
//return false
System.out.println("s1和s2 值是否相同:"+s1.equals(s2));
//return true

s1其实是在堆中字符串常量池中存储了“Hello”,而s2是在堆上创建了“Hello”的实例化对象

当我们使用s1的方法再创建一个hello,比如s3,JVM首先会去常量池中寻找是否已经存在“Hello”,发现已经存在,那么s3直接指向“Hello”,若没有发现,那么就自己创建“Hello”(这就是s1在常量池中完成的部分,因为之前没有“Hello”)

当我们使用s2的处理方式创建一个“Hello”对象时候,也需要先去字符串常量池中去寻找存不存在Hello,如果存在了,那么直接在堆上进行对象实例化,如果没有找到则需,先在常量池中创建Hello,然后再进行“Hello”的实例化操作,这样其实意味着方法二其实花费了更多的空间

参考链接:
https://www.cnblogs.com/linjiqin/p/3413894.html

https://blog.csdn.net/weixin_33720078/article/details/93194508?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值