精华内容
下载资源
问答
  • 面试官:兄弟,说说基本类型和包装类型的区别吧

    万次阅读 多人点赞 2019-09-29 08:36:07
    Java 的每个基本类型都对应了一个包装类型,比如说 int 的包装类型为 Integer,double 的包装类型为 Double。基本类型和包装类型的区别主要有以下 4 点。

    六年前,我从苏州回到洛阳,抱着一幅“海归”的心态,投了不少简历,也“约谈”了不少面试官,但仅有两三个令我感到满意。其中有一位叫老马,至今还活在我的手机通讯录里。他当时扔了一个面试题把我砸懵了:说说基本类型和包装类型的区别吧。

    我当时二十三岁,正值青春年华,从事 Java 编程已有 N 年经验(N < 4),自认为所有的面试题都能对答如流,结果没想到啊,被“刁难”了——原来洛阳这块互联网的荒漠也有技术专家啊。现在回想起来,脸上不自觉地泛起了羞愧的红晕:主要是自己当时太菜了。不管怎么说,是时候写篇文章剖析一下基本类型和包装类型的区别了。

    Java 的每个基本类型都对应了一个包装类型,比如说 int 的包装类型为 Integer,double 的包装类型为 Double。基本类型和包装类型的区别主要有以下 4 点。

    01、包装类型可以为 null,而基本类型不可以

    别小看这一点区别,它使得包装类型可以应用于 POJO 中,而基本类型则不行。

    POJO 是什么呢?这里稍微说明一下。

    POJO 的英文全称是 Plain Ordinary Java Object,翻译一下就是,简单无规则的 Java 对象,只有属性字段以及 setter 和 getter 方法,示例如下。

    class Writer {
    	private Integer age;
    	private String name;
    
    	public Integer getAge() {
    		return age;
    	}
    
    	public void setAge(Integer age) {
    		this.age = age;
    	}
    
    	public String getName() {
    		return name;
    	}
    
    	public void setName(String name) {
    		this.name = name;
    	}
    }
    

    和 POJO 类似的,还有数据传输对象 DTO(Data Transfer Object,泛指用于展示层与服务层之间的数据传输对象)、视图对象 VO(View Object,把某个页面的数据封装起来)、持久化对象 PO(Persistant Object,可以看成是与数据库中的表映射的 Java 对象)。

    那为什么 POJO 的属性必须要用包装类型呢?

    《阿里巴巴 Java 开发手册》上有详细的说明,我们来大声朗读一下(预备,起)。

    数据库的查询结果可能是 null,如果使用基本类型的话,因为要自动拆箱(将包装类型转为基本类型,比如说把 Integer 对象转换成 int 值),就会抛出 NullPointerException 的异常。

    02、包装类型可用于泛型,而基本类型不可以

    泛型不能使用基本类型,因为使用基本类型时会编译出错。

    List<int> list = new ArrayList<>(); // 提示 Syntax error, insert "Dimensions" to complete ReferenceType
    List<Integer> list = new ArrayList<>();
    

    为什么呢?因为泛型在编译时会进行类型擦除,最后只保留原始类型,而原始类型只能是 Object 类及其子类——基本类型是个特例。

    03、基本类型比包装类型更高效

    基本类型在栈中直接存储的具体数值,而包装类型则存储的是堆中的引用。

    很显然,相比较于基本类型而言,包装类型需要占用更多的内存空间。假如没有基本类型的话,对于数值这类经常使用到的数据来说,每次都要通过 new 一个包装类型就显得非常笨重。

    03、两个包装类型的值可以相同,但却不相等

    两个包装类型的值可以相同,但却不相等——这句话怎么理解呢?来看一段代码就明明白白了。

    Integer chenmo = new Integer(10);
    Integer wanger = new Integer(10);
    
    System.out.println(chenmo == wanger); // false
    System.out.println(chenmo.equals(wanger )); // true
    

    两个包装类型在使用“”进行判断的时候,判断的是其指向的地址是否相等。chenmo 和 wanger 两个变量使用了 new 关键字,导致它们在“”的时候输出了 false。

    chenmo.equals(wanger) 的输出结果为 true,是因为 equals 方法内部比较的是两个 int 值是否相等。源码如下。

    private final int value;
    
    public int intValue() {
        return value;
    }
    public boolean equals(Object obj) {
        if (obj instanceof Integer) {
            return value == ((Integer)obj).intValue();
        }
        return false;
    }
    

    瞧,虽然 chenmo 和 wanger 的值都是 10,但他们并不相等。换句话说就是:将“==”操作符应用于包装类型比较的时候,其结果很可能会和预期的不符

    04、自动装箱和自动拆箱

    既然有了基本类型和包装类型,肯定有些时候要在它们之间进行转换。把基本类型转换成包装类型的过程叫做装箱(boxing)。反之,把包装类型转换成基本类型的过程叫做拆箱(unboxing)。

    在 Java SE5 之前,开发人员要手动进行装拆箱,比如说:

    Integer chenmo = new Integer(10);  // 手动装箱
    int wanger = chenmo.intValue();  // 手动拆箱
    

    Java SE5 为了减少开发人员的工作,提供了自动装箱与自动拆箱的功能。

    Integer chenmo  = 10;  // 自动装箱
    int wanger = chenmo;     // 自动拆箱
    

    上面这段代码使用 JAD 反编译后的结果如下所示:

    Integer chenmo = Integer.valueOf(10);
    int wanger = chenmo.intValue();
    

    也就是说,自动装箱是通过 Integer.valueOf() 完成的;自动拆箱是通过 Integer.intValue() 完成的。理解了原理之后,我们再来看一道老马当年给我出的面试题。

    // 1)基本类型和包装类型
    int a = 100;
    Integer b = 100;
    System.out.println(a == b);
    
    // 2)两个包装类型
    Integer c = 100;
    Integer d = 100;
    System.out.println(c == d);
    
    // 3)
    c = 200;
    d = 200;
    System.out.println(c == d);
    

    答案是什么呢?有举手要回答的吗?答对的奖励一朵小红花哦。

    第一段代码,基本类型和包装类型进行 == 比较,这时候 b 会自动拆箱,直接和 a 比较值,所以结果为 true。

    第二段代码,两个包装类型都被赋值为了 100,这时候会进行自动装箱,那 == 的结果会是什么呢?

    我们之前的结论是:将“==”操作符应用于包装类型比较的时候,其结果很可能会和预期的不符。那结果是 false?但这次的结果却是 true,是不是感觉很意外?

    第三段代码,两个包装类型重新被赋值为了 200,这时候仍然会进行自动装箱,那 == 的结果会是什么呢?

    吃了第二段代码的亏后,是不是有点怀疑人生了,这次结果是 true 还是 false 呢?扔个硬币吧,哈哈。我先告诉你结果吧,false。

    为什么?为什么?为什么呢?

    事情到了这一步,必须使出杀手锏了——分析源码吧。

    之前我们已经知道了,自动装箱是通过 Integer.valueOf() 完成的,那我们就来看看这个方法的源码吧。

    public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }
    

    难不成是 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;
            int i = parseInt(integerCacheHighPropValue);
            i = Math.max(i, 127);
            h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
            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;
        }
    }
    

    大致瞟一下这段代码你就全明白了。-128 到 127 之间的数会从 IntegerCache 中取,然后比较,所以第二段代码(100 在这个范围之内)的结果是 true,而第三段代码(200 不在这个范围之内,所以 new 出来了两个 Integer 对象)的结果是 false。

    看完上面的分析之后,我希望大家记住一点:当需要进行自动装箱时,如果数字在 -128 至 127 之间时,会直接使用缓存中的对象,而不是重新创建一个对象

    自动装拆箱是一个很好的功能,大大节省了我们开发人员的精力,但也会引发一些麻烦,比如下面这段代码,性能就很差。

    long t1 = System.currentTimeMillis();
    Long sum = 0L;
    for (int i = 0; i < Integer.MAX_VALUE;i++) {
        sum += i;
    }
    long t2 = System.currentTimeMillis();        
    System.out.println(t2-t1);
    

    sum 由于被声明成了包装类型 Long 而不是基本类型 long,所以 sum += i 进行了大量的拆装箱操作(sum 先拆箱和 i 相加,然后再装箱赋值给 sum),导致这段代码运行完花费的时间足足有 2986 毫秒;如果把 sum 换成基本类型 long,时间就仅有 554 毫秒,完全不一个等量级啊。

    05、最后

    谢谢大家的阅读,原创不易,喜欢就点个赞,这将是我最强的写作动力。如果你觉得文章对你有所帮助,也蛮有趣的,就关注一下我的公众号,谢谢。

    展开全文
  • 包装类型

    2018-09-30 16:23:10
    这节课我们来讲讲包装类型   什么是包装类型? JDK为我们提供了一些与基本数据类型对应的类,这些类的对象可以和基本数据类型的变量直接互相赋值,并且这些类对比基本数据类型而言具有更为强大的功能。这些类就...

    这节课我们来讲讲包装类型

     

    什么是包装类型?

    JDK为我们提供了一些与基本数据类型对应的类,这些类的对象可以和基本数据类型的变量直接互相赋值,并且这些类对比基本数据类型而言具有更为强大的功能。这些类就被称为包装类型。

     

    基本数据类型与包装类型的对应关系:

    Integer === int

    Float === float

    Short === short

    Double === double

    Character === char

    Boolean === boolean

    Byte === byte

    Long === long

     

    Demo:

     

    public static void main(String[] args) {
        //包装类型和基本数据类型可以互相直接赋值
        Integer i1 = 12;
        System.out.println(i1);

        int i = i1;
        System.out.println(i);

        //包装类型能提供更为强大的功能
        int max = Integer.max(2,1);
        System.out.println(max);
    }

     

     

    Integer 源码分析:

    public final class Integer extends Number implements Comparable<Integer>

     

    可以看到Integer类是继承了一个Number类然后实现了一个Comparable接口

     

    首先来看Comparable接口

    public interface Comparable<T> {

     

        public int compareTo(T o);

    }

     

    可以看到Comparable源码中只有一个方法叫compareTo,T是泛型,这个以后讲

     

    然后来看看compareTo在Integer中的实现

    public int compareTo(Integer anotherInteger) {

        return compare(this.value, anotherInteger.value);

    }

     

    可以看到是调用了自己类的compare方法并返回

     

    public static int compare(int x, int y) {

        return (x < y) ? -1 : ((x == y) ? 0 : 1);

    }

    这里解释一下? :,这个叫三目运算符,语法是

    表达式?语句1:语句2;

    相当于:

    if(表达式)

    语句1

    else

    语句2

     

    那么这就很简单了,

    这个compare方法就相当于

    If(x < y)

    return -1;

    else if(x == y)

    return 0;

    else

    return 1;

     

    这就是compareTo的功能,比较自己和另一个Integer的大小,如果自己更小,则返回-1,如果相等,返回0,如果自己更大,返回1

     

    接下来看看API文档

    int Integer.compareTo(Integer anotherInteger)

     

    如果该 Integer 等于 Integer 参数,则返回 0 值;如果该 Integer 在数字上小于 Integer 参数,则返回小于 0 的值;如果 Integer 在数字上大于 Integer 参数,则返回大于 0 的值(有符号的比较)。

     

    Jdk1.6里好像没有compare方法,来看看1.8的

    1.8的翻译不是很好,有机会带你们看英文版,总之compare的具体实现我们分析完成了。接下来看看Number类是个啥。

     

     

    public abstract class Number implements java.io.Serializable

    可以看到Number是一个抽象类,这个类实现了Serializable接口,这个接口是实现序列化的,凡是实现Serializable接口的类都要实现序列化,序列化以后再讲,先看看Number有哪些方法。

     

    可以看到Numebr里的方法就是xxxValue(),返回值类型就是xxx

     

    最后我们来看看Integer类。

     

    @Native public static final int   MIN_VALUE = 0x80000000;

    /**

     * A constant holding the maximum value an {@code int} can

     * have, 2<sup>31</sup>-1.

     */

    @Native public static final int   MAX_VALUE = 0x7fffffff;

    最大值最小值,用的16进制表示,我们可以来输出一下

     

    接下来需要你们了解一个东西:

     

    System.out.println(Integer.MAX_VALUE + 1);

    System.out.println(Integer.MIN_VALUE - 1);

     

    -2147483648

    2147483647

     

    可以看到Integer.MIN_VALUE就是Integer.MAX_VALUE + 1,这个了解一下就行,有机会会讲原理。

     

     

    public Integer(int value) {

        this.value = value;

    }

     

    这个就是Integer的构造器。

    搞错了,value还是在Integer里。

     

    只不过声明的地方已经是840行了

     

    可以看到value这个属性是一个int类型的常量,这说明什么?

     

    这说明每当Integer的值改变的时候,其实是new出了一个新的Integer对象,然后原引用变量再指向这个新的new出来的对象。

     

    OK,Integer的源码就看到这里,以后有机会再深入研究。

     

     

    展开全文
  • 包装类型和非包装类型问题 在公司开发中遇到一个就是非包装类型包装类型的空指针异常问题: 大概如下: package com.itstyle.mail.repository; /*** * @ClassName: Demo2 * @Description...

    包装类型和非包装类型问题

    在公司开发中遇到一个就是非包装类型和包装类型的空指针异常问题:

    大概如下:

    package com.itstyle.mail.repository;
    
    /***
     * @ClassName: Demo2
     * @Description:
     * @Auther: cxy
     * @Date: 2017/5/19:14:57
     * @version : V1.0
     */
    public class Demo2 {
        public static void main(String[] args) {
            Long s=null;
            long s2 =0L;
            //long s3=null;
            Long s4=0L;
            System.out.println(s == s4);
        }
    }

    当s == s2时候就会报空指针异常,

    s == s4 时候是不会报空指针的,在包装类型里面是可以为空的

    可以打开注释模块,编译器会报错的,

    那么在开发者一般使用

    posted @ 2019-05-19 15:20 动手的程序员 阅读(...) 评论(...) 编辑 收藏
    展开全文
  • 包装类型和基本类型

    2020-01-28 23:35:17
    包装类型和基本类型 Java中有八种基本数据类型,分别对应着八大包装类型,因为包装类型的实例都存在于堆中,所以包装类型也称为引用类型。 基本类型属于原始数据类型,变量中存储的就是原始值。包装类型属于...

    包装类型和基本类型

    1. Java中有八种基本数据类型,分别对应着八大包装类型,因为包装类型的实例都存在于堆中,所以包装类型也称为引用类型。
      在这里插入图片描述

    2. 基本类型属于原始数据类型,变量中存储的就是原始值。包装类型属于引用数据类型,变量中存储的是存储原始值的地址的引用。

      • 基本类型中,局部变量存在方法虚拟机栈的局部变量表中,而类中声明的的变量存在堆里。
      • 包装类型中,无论局部变量还是类中声明的变量均存在堆中,而方法内的局部包装类型变量,其也存在局部变量表中,不过期值为该变量在堆中的地址。
    3. 手动装箱 / 手动拆箱

     	Integer b = valueOf(1);
        int a = b.intValue();
    
    1. 自动装箱 / 自动拆箱
       Integer b = 1;
       int a = b;
    

    Java SE5 为了减少开发人员的工作,提供了自动装箱与自动拆箱的功能,3等价4。
    5. == and equals

    • == 比较的是内存地址
    • equals 比较的是值
    1. 代码实例
     int a=0;
     int b=0;
     System.out.println(a==b);
    

    按照==的分析,此处应该输出false,然而结果是true,原因在于:

    当定义b时,JVM会先检查局部变量表中是否已经有了0这个值,如果没有,则创建,如果有(如之前已经执行过int a= 0),则不会再创建,而是直接将变量b指向变量a所在的局部变量表的地址,就好像执行的语句是int b = a。换句话说,a和b最终指向的内存空间,其实还是一致的

       int a = 0;
       int b = 0;
       b = b + 1;
       System.out.printlt(a == 1)
    

    首先jvm会先创建一个常量 0,然后把a的引用指向0,再把b的引用指向0,当执行b=b+1的时候,运算出结果为1,jvm先不创建1这个量,而是在局部变量表中去查找是否有这个值,有就返回,无就创建,此时b的值就被指向了1,所以输出结果自然是false,当我们看下面代码

      	int a = 0;
        int b = 0;
        int c=1;
        b = b + 1;
        System.out.println(b==c);
    

    我们已经声明了1,并把c指向这个地址,然后运行b=b+1时,jvm查找有1这个值,就把这个值的局部变量表地址赋值给了b,所以这里判断b==c应该是true;

    1. 装箱拆箱详解
      • 装箱:装箱是通过 valueOf()方法来实现自动装箱的,我们来看看源码:
    public static Integer valueOf(int i) {
               if (i >= IntegerCache.low && i <= IntegerCache.high)
                   return IntegerCache.cache[i + (-IntegerCache.low)];
               return new Integer(i);
           }
    

    这里面有个IntegerChche即Integer类型的缓存,来看看内部类IntegerCache:

    private static class IntegerCache {
               static final int low = -128;
               static final int high;
               static final Integer cache[];
       
               static {
                  ...
                   
                   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() {}
           }
    

    这里省略了部分内容,这个类存在的意义是将较为常用的数字存到缓存中,int类型的是 -128 - +127,我们可以看到有一个final类型、Integer类型的cache数组,然后在static块中分别对这个数组赋值,即把-128 - +127这256个数据存到cache数组里,且索引是0-255,注意,这里的cache数组是在类加载过程的初始化阶段确定的,因为在static块中,并且由于是常量,会存在元空间内 ,又由于cache这实际上是一个对象数组,所以常量池中有cache这一项引用,其指向了再堆中的数组,但是又因为是对象数组,其每一项都指向了堆中的具体的Integer对象.

    然后再看valueOf,如果要装箱的值不在-128-+127之间,那么它会返回一个新的对象,这个对象是存在堆里,如果是方法内调用,那么对象的引用会存在方法的局部变量表内。

    即:当我们开始运行程序的时候,-128-+127这256个数字就已经存在了堆中,用cache进行管理,如果新建一个Integer对象,其值是在此范围内,就会直接返回cache中的相对于的信息即堆中的信息,如果不在此范围内,就会新建立一个Integer对象,放在堆中,然后将其引用存在局部变量表里。

    • 拆箱:拆箱是通过intValue来实现的
      	  Integer a = 0;
          int b = a.intValue();
    

    其中intValue:

       public int intValue() {
                 return value;
             }
    

    从JVM来看,先创建了一个Integer类型的变量a,其引用指向堆,当我们实现拆箱的时候,JVM会先判断
    在局部变量表中是否有这个值,如果有,直接放回在局部变量表中的引用,如果没有则新建再返回。

    1. 包装类型代码详解:
       Integer a = 1;
            Integer b = 1;
            System.out.println(a==b);
    

    由于 == 是比较地址,而Integer属于引用类型,分别建立了两个实例分别存在了堆中,所以直觉来看应该两个地址应该不同,但是结果是true,原因是cache的存在,再代码正式运行前,堆中就已经存有缓存,这里的1属于-128-+127之间,所以直接返回缓存中的值也就是说,在赋值a的时候,其实它指向了缓存中的1的引用,也就是指向了堆中,而赋值b的时候也是直接指向了缓存,所以他们两个地址是一致的。
    给一个草图
    在这里插入图片描述

     Integer a = 128;
          Integer b = 128;
          System.out.println(a==b);
    

    这里由于128不属于缓存范围,所以两个语句分别建立了两个不同的对象,所以他们的内存地址也是不一样的,所以返回false,同样也给出一个草图

    在这里插入图片描述

     public class test2 {
          Integer b=0;
          public static void main(String[] args) {
              test2 test2 = new test2();
              Integer a = 0;
              System.out.println(test2.b==a);
          }
      }
    

    我们来看这个代码,我们再类中定义了一个Integer对象b,赋值为0,在main方法中也定义了一个Integer对象,也赋值为0,比较这两个地址,会输出什么?答案是true,原因很简单:
    在我们在类中定义b时,实际上这个b存于堆中,然后指向常量池中的cache,然后cache又指向在堆中的数组,而数组的每一项均指向了堆中的Integer对象,所以可以直接说是b直接指向了0这个Integer对象,在类中定义的a,其引用存在于局部变量表中,引用指向了Integer的cache,cache指向了堆,所以它们两个的实际地址引用是一致的,都是cache在堆中的缓存.

    所以我们得出了这个结论:在一个程序运行期间,无论是方法内还是方法外,其所定义的Integer,且其值是在-128-+127之间,那么他们的引用是一致的。

      int a = 1;
      Integer b = 1;
      System.out.println(a==b);
    

    但是如果我们来比较包装类型和基本类型的地址的时候会输出什么?这里输出了true,为什么呢?
    单看代码看不出来啥,我们来看看字节码:

     public static void main(java.lang.String[]);
              descriptor: ([Ljava/lang/String;)V
              flags: ACC_PUBLIC, ACC_STATIC
              Code:
                stack=3, locals=3, args_size=1
                   0: iconst_1
                   1: istore_1
                   2: iconst_1
                   3: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
                   6: astore_2
                   7: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
                  10: iload_1
                  11: aload_2
                  12: invokevirtual #4                  // Method java/lang/Integer.intValue:()I
                  15: if_icmpne     22
                  18: iconst_1
                  19: goto          23
                  22: iconst_0
                  23: invokevirtual #5                  // Method java/io/PrintStream.println:(Z)V
                  26: return
               
          }
    

    这里是main方法的主要字节码,省略了部分,我们不做细讲,主要讲跟问题相关的,我们通过行号指示器来看,
    首先第3行,invokestatic 表示调用了一个static方法,后面是注释,表示调用了Integer.valueOf,这里对应着代码里的定义包装类,因为定义包装类就必须进行装箱,而Java5后直接支持自动拆装箱,自动不代表不用,所以这里需要调用静态方法Integer.valueOF进行装箱,

    看第7行,调用了输出流的PrintSteam方法,再来看第12行,看后面的注释,表示调用了Integer.intValue方法,这是拆箱的方法,但是我们代码中并没有拆箱,那么这段代码是怎么来的呢?

    如果要使用拆箱,就必须有包装类,看代码,输出流里面只有一个包装类即b,那就说明了b调用了拆箱的方法,其主要过程是,把b的值取出,判断局部变量表中是否存在,如果存在,则返回局部变量表中的地址,如果不存在则创建再返回。

    所以我们能很好的解释为什么上面的输出是true,因为,当我们使用==来比较基本类型和包装类型时,包装类型自动进行拆箱,并返回局部变量表中的引用,由于之前局部变量表中已经存在0这个值,并把a的引用执行它,当进行拆箱的时候,b的引用也指向它,如此一比较,他们的地址当然相等。

    1. equals 详解
     Integer a=128;
            Integer b=128;
            System.out.println(a.equals(b));
    

    为什么用equals能比较值呢?来看看equals源码:

      public boolean equals(Object obj) {
                  if (obj instanceof Integer) {
                      return value == ((Integer)obj).intValue();
                  }
                  return false;
              }
    

    非常简单粗暴,先判断是否属于Integer,如果是转换再进行拆箱直接判断值是否相等即可。
    这个equals方法属于Object类,如果要分别实现比较不同的值就必须进行重写,所以上面的equals是Integer类重写的equals,其实现会根据不同的引用类型给予不同实现。例如 Character-char类型包装类,其equals是这样的:

      public boolean equals(Object obj) {
                  if (obj instanceof Character) {
                      return value == ((Character)obj).charValue();
                  }
                  return false;
              }
    

    和Integer的equals是不一样的。


    几个问题:

    1. b=b+1;1存在哪?
      当我们执行b=b+1时,b的值和1均存在于局部变量表中,不过b是以变量形式存在,即b的引用可以根据需要指向不同的值,而1是常量,直接存在局部变量表中,当我们执行加法操作时,JVM会先把b这个变量所代表的数(有可能是1、2、3等)压入操作数栈,然后再把1压入操作数栈,然后一个个出栈进行加法操作,再把结果入栈,这就完成了一个加法操作,看下面的实例:
    public class test6 {
           public static void main(String[] args) {
               int a=1;
               a = a+1;
           }
       }
    

    很简单一个例子,要分析就要通过字节码进行分析,字节码如下:

    public static void main(java.lang.String[]);
           descriptor: ([Ljava/lang/String;)V
           flags: ACC_PUBLIC, ACC_STATIC
           Code:
             stack=2, locals=2, args_size=1
                0: iconst_1
                1: istore_1
                2: iload_1
                3: iconst_1
                4: iadd
                5: istore_1
                6: return
    

    省略了部分,我们来分析这个字节码的内容

    第一行代表这个字节码是main方法的字节码

    第二行是这个方法的描述信息,说明这个方法的参数是String类型的一维数组,其返回值是void

    第三行表示控制修饰符:说明这个方法的控制描述符(AccessFlag)是public、static

    第五行表示,操作数栈深度为2,局部变量表数为2,参数大小是1

    剩下的就是这个main方法的具体实现过程

    • 0:iconst_1:把int类型的常量1压入到操作数栈中,对应着是代码中的 int a=1;
    • 1:istore_1:把int类型的值从操作数栈中弹出,将其放到位置为1的局部变量中;
    • 2: iload_1:将位置为1的int类型的局部变量压入栈;
    • 3: iconst_1:把int类型的常量1压入到操作数栈中,对应着是代码中的 a+1的1;
    • 4:iadd: 从操作数栈栈顶弹出两个元素然后做加法,把结果压入栈。对应着代码中的a=a+1;
    • 5:istore_1:把int类型的值从操作数栈中弹出,将其放到位置为1的局部变量中;
    • 6:return表示结束。

    很容易看出:一个简单的Java程序,其原理无非就是数据再内存中入栈出栈并进行计算的过程,其常量在编译期均已经确定并存于局部变量表中,因为字节码是根据class文件反编译而成,

    1. 基本类型的内存模型是什么
      在这里插入图片描述
      方法中的基本类型如int、float等类型是直接存在局部变量表中的,类中的基本类型数据是存在堆中的。

    参考资料
    java中的基本数据类型和引用类型在JVM中存储在哪?
    包装类和基本类型
    操作数详解一
    操作数详解二
    自动拆箱装箱
    Java基本类型详解
    基本类型和包装类型的区别

    展开全文
  • java基本类型和包装类型

    千次阅读 2018-10-08 11:20:21
    java是面向对象的语言为什么还要有基本类型,只有包装类型完全面向对象不行吗? java语言可以只有基本类型吗,为什么还有要包装类型? java中的基本类型和包装类型:  基本类型  包装器类型 boolean ...
  • Java 的每个基本类型都对应了一个包装类型,比如说 int 的包装类型为 Integer,double 的包装类型为 Double。基本类型和包装类型的区别主要有以下 4 点 1.包装类型可以为 null,而基本类型不可以 它使得包装类型可以...
  • java包装类型

    2018-08-26 10:31:57
    java中基本数据类型与包装类型有: 基本类型  包装器类型 boolean Boolean char Character int Integer byte Byte short Short long Long float Float double ...
  • JAVA中的基本类型与包装类型

    千次阅读 2021-03-14 19:54:46
    JAVA中的基本类型与包装类型 一:基本类型与包装类型简介 1.由于基本类型没有面向对象的特征,为了他们参加到面向对象的开发中, java为八个基本类型提供了对应的包装类。 2.六个和包装类继承java.lang.Number,...
  • Java包装类型

    2017-06-11 19:04:06
    部分内容引用自网络数据类型java的数据类型: 基本类型: int,boolean,float ...可以把integer视为int的包装类型(wrapper) 包装类型是引用类型, 只不过内部只有一个基本类型的变量。JDK为每种基本类型都创建了对应
  • 一、基本类型 Java一种静态编程语言,所有变量和表达式是在编译时就确定的。同时,Java又是一种强类型语言,所有的变量和表达式都有具体...最简单的理解,基本类型有默认值,而包装类型初始为null。然后再根据这两...
  • 基本包装类型和引用类型 一、相关概念 1.定义 为了便于操作基本类型值,JavaScript提供了三个特殊的引用类型:Boolean、Number和String。这些类型与其他引用类型相似,但同时也具有与各自基本类型...
  • JavaScript基本包装类型

    2021-01-29 13:30:27
    实际上,每当读取一个基本类型的时候,js内部会自动创建一个基本包装类型对象,可以让我们调用一些方法来操作。 let str = 'hello 蛙人' let str1 = str.substring(2) 上面example中,str是一个字符串类型,然而它...
  • 在java中有八种基本数据类型对应每种基本类型又有八种包装类型: 基本类型:boolean, char, int, byte,short,long, float,double 包装器类型:Boolean,Character,Integer,Byte,Short,Long,Float,...
  • JS 基本包装类型

    2019-01-11 10:14:23
    基本包装类型:本身是基本类型,但是在执行代码的过程中,如果这种类型的变量调用了属性或者方法,那么这种类型就不在是基本类型了,而是基本包装类型,这个变量也不是普通的变量,而是基本包装类型对象。...
  • JAVA包装类型

    2016-10-07 10:44:10
    关于JAVA包装类型你需要知道如下几点: 1.不可变的,同String 2.是对象 3.又的包装类型存在Cache缓存,这个见如下例子:在此处涉及自动打包操作,将int类型自动打包成Integer类型。而自动打包规范要求boolean,...
  • 基本包装类型即基本类型地包装类型。 为了便于操作基本类型,提供了三个特殊地引用类型:String,Number和Boolean。 每当读取一个基本类型值的时候,后台就会创建一个对应的基本包装类型的对象,从而能够调用一些...
  • java基本类型和包装类型的区别

    千次阅读 2019-02-24 14:01:29
    2、有了基本类型,为什么还会产生包装类型: (1)什么是包装类:  包装类型相当于将基本类型包装起来,使其具有对象的性质,并且可以添加属性和方法,丰富了基本类型的操作。 (2)包装类型具有哪些好处:  ...
  • Java基本类型 Java语言提供了八种基本类型。其中,六种数据类型(四个整数型,两个浮点型),一个字符类型,还有...包装类型把基本类型转换为对象,每个基本类型在java.lang包中都有一个相应的包装类型 包装类型: Int
  • 说明:最简单的理解,基本类型有默认值,而包装类型初始为null。然后再根据这两个特性进行分业务使用,在阿里巴巴的规范里所有的POJO类必须使用包装类型,而在本地变量推荐使用基本类型。 Java语言提供了八种基本...
  • java基本类型与包装类型

    千次阅读 2016-05-25 11:11:17
    java基本类型与包装类型 基本数据类型:byte,int, short, long, boolean,char, float,double等 包装类型 : Byte,Integer,Short,Long,Boolean,Character,Float,Double等 基本类型(primitive type)...
  • 当 Number、String、Boolean使用new操作符时,它们就不仅仅是基本类型了,变成了基本的包装类型,即引用类型。Boolean类型应该算是这三种类型中最简单的类型,这篇文章将介绍Boolean类型。 定义 Boolean类型只有两个...
  • Java基本类型与包装类型的对应关系、产生原因及两者之间的区别 基本类型 包装类性 byte Byte  short Short
  • js 基本包装类型

    2018-07-13 21:29:09
    所谓的基本包装类型,就是即是基本类型,也是引用类型。基本包装类型还可以想引用类型一样通过对象的方法访问它自带的一些方法,但是不能想引用类型那样自定义方法。我之前对与引用类型是懵的,但一段时间后就突然...
  • 八大基础类型(都有对应的包装类型): 整数:byte、short、int、long 浮点数:float、double 字符型:char 布尔型:boolean 基本类型 byte short int long 位数 8位 16位 32位 64位 ...
  • 浅析八种基本类型和包装类型
  • java包装类型作用,和基本类型区别

    千次阅读 2018-09-18 14:27:00
    Java中的8种基本数据类型都有对应的对象类型,但是既然有了基本数据类型,包装类型有什么作用呢?它们有什么区别呢? 答案是包装类型的出现是为了方便对基本类型进行操作。包装类型可以解决一些基本类型解决不了的...
  • 基本类型不是2、包装类型是引用的传递;基本类型是值的传递3、声明方式不同: 基本数据类型不需要new关键字; 包装类型需要new在堆内存中进行new来分配内存空间4、存储位置不同: 基本数据类型直接将值保存在值栈中...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 28,424
精华内容 11,369
关键字:

包装类型