Java教程

java对象引用发生改变和String、Integer和int理解与解释

本文主要是介绍java对象引用发生改变和String、Integer和int理解与解释,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

      俺又来了,今天给大家分享的东西比较杂,本来打算只分享java中new出来对象当作一个参数传递给其他对象后,被改变后,那么这个对象也会改变(具体怎么表达我也不太知道如何表达,等下用具体例子来给大家演示),然后在找资料的时候,发现了很多讲String、Integer和int中三者比较的是关系;然后索性今天这篇文章把这也给大家分享下吧,好了,废话少说,直接上干货。

1、java中new出来对象详解

      周四见项目代码中有一段代码表示在A方法中new出来一个对象,这个对象当作一个参数传递给B方法,然后在B方法中将该参数对象进行修改,注意哈:修改后该对象并没有返回给A方法,B方法返回的是void,然后在A方法中将该参数打印出来,惊奇发现该对象值发生改变,对象值打印是B方法中修改后对象值。当时就一脸懵,然后自己又重新写了下测试例子,还真是发生了改变,下面我分析出如下结果:

      先说下代码例子:

      A方法代码如下:

@GetMapping("/testA")
private void testA() {
    People people = new People();
    people.setName("ygl");
    people.setAge(18);
    //将people对象传递给B方法
    testService.testB(people);
    //打印people对象值
    System.out.println("People:" + people.toString());
}

      B方法代码如下所示:

public void testB(People people){
    people.setName("ly");
    people.setAge(99);
}

      打印结果为:

People:People(name=ly, age=99, address=null);

      java中A方法new出来对象后,将该对象存放进java堆中,然后该对象名存放在栈中,栈中该对象名指向堆中地址;然后将该对象当作参数传递给B方法,然后B中该参数名指向堆中地址,然后B方法中对其对象修改,则是修改堆中对象,因此所有指向该对象的对象名都会修改,也就是出现了以上B方法中未返回给A方法该对象,但是A中对象却发生更改。

      下面图片更容易理解:

image-20210515205018482

      通过上面解释,大家应该很容易理解上面出现的问题了。

2、String引用类型详解

      String是java中引用类型,它可不属于java中八大基本类型,这一点大家千万要注意。

      刚刚在上一个段落中分析的是new出来实体的对象出现的上面结果,我就想到测试下String类型来试试看会出现那种结果呢,测试代码如下所示:

      A方法:

@GetMapping("/testA")
private void testA() {
    String str = "ygl";
    //将people对象传递给B方法
    testService.testB(str);
    //打印people对象值
    System.out.println("Str:" + str);
}

      B方法:

public void testB(String str){
   str = "ly";
}

      打印结果如下所示:

Str:ygl

      大家可以很明显的看出,没有出现和上面new对象一样结果呀,String也是引用类型,这是为什么呢?大家不要急,我接下来给大家分析下(大家先等下我哦,我先下楼去买点水果,嘻嘻,等我哦,很快的)。

      String有两种情况,一种是String str = new String(“abc”);另外一种为String str = “abc”。

      第一种String str = new String(“abc”);这种都是在堆中创建字符串对象,然后变量名str是指向堆中该变量地址;

      第二种String str = “abc”;这种通过字面量赋值创建字符串,会先在常量池中查找是否有相同的字符串,如果存在,则将栈中的引用直接指向该字符串;如果不存在,则在常量池中生成该字符串,然后栈中引用再指向该字符串。

      注意:String是不可变对象,因此在每次改变String的时候,都是生成一个新的String对象,然后再将栈指向新的堆内存或者常量池。因为String源代码中修饰符为final,因此会出现这种结果。

      源代码如图所示:

image-20210515225403994

      接下来我给大家解释下在上面例子中为什么出现那种结果,直接用图给大家解释下:

image-20210515230421014

      谈到String都到这种地步了,这个时候如果我不给大家聊聊String类型的各种比较的话,那么我就太不够意思了,那接下来来和大家聊聊,先上代码:

private void testNew() {
    
    String str1 = "str";
    String str2 = "str";
    System.out.println(str1 == str2); //true
    
    String str3 = new String("str");
    String str4 = new String("str");
    System.out.println(str3 == str4); //false
    
    System.out.println(str1 == str3); //false
    
}

      打印结果都在后面注释中写着的,在这里我就不单独给大家再写了。

      分析结果:

      str1与str2结果比较:创建str1属性时,会先在常量池中查找是否有相同属性值,这时发现常量池中没有该常量,则会在常量池中创建str1的属性值str,然后将str1属性指向常量池中值str的地址;创建str2属性时,同样先在常量池中查找是否有str的值,这时发现拥有该值,那么不再重新创建str值,直接将str2属性指向常量池中str值。因此str1在与str2的双等号比较其地址时,两个属性指向的是同一个属性值地址,因此两者比较结果为true

image-20210516174724223

      str3与str4结果比较:创建str3时,在堆内存中创建new String("str"),然后str3变量名存放在栈中,栈中str3指向堆内存的str3刚刚创建的地址;创建str4时,在堆内存中又创建一个new String("str"),然后str4变量名存放在栈中,栈中str4指向堆内存中刚刚创建的地址;一次两个变量指向地址是不一样的,因此两个变量在比较时,结果为false。含义如下图所示:

image-20210516175746511

      str1与str3结果比较:str1变量指向的是常量池中(常量池在堆内存中,独立开辟出个内存空间),str3变量指向堆内存中的地址,因此两者在比较地址的时候会出现false结果。

image-20210516180500381

3、Integer和int类型详解

      int是基本类型,Integer是int的包装类型,可以自动拆箱和装箱,这里我就不做过多解释这方面内容,大家可以自行百度哦,我这里就写如下代码来进行分析与研究。

a:分析下面一段代码:

private void testNew() {
    
    //-128 ~ 127之间结果比较为true;不在这个范围内则为false
    
   Integer i1 = 127;
   Integer i2 = 127;
   System.out.println("1:" + (i1 == i2)); //true
    
   Integer i3 = 999; 
   Integer i4 = 999;
   System.out.println("2:" + (i3 == i4)); //false
    
}

      代码中打印结果我在后面注释中已经标注。

Integer直接进行赋值时,如果数值在-128 ~ 127范围内的话,则会自动拆箱为int类型,数值存放在常量池中,因此i1 和 i2的结果在比较中结果为true;当数值超过这个范围时,它会自动装箱,例如:Integer = 999时,内部实际运行代码和new Integer(999)一样,在堆内存中存放,因此i3和i4结果为false

      b:分析下面一段代码:

private void testNew() {
    
   Integer i5 = new Integer(12);
   Integer i6 = new Integer(12);
   System.out.println("1:" + (i5 == i6)); //false
    
}

      这里采用的new Integer(12),其运行原理是在每new一次,那么就会在堆内存中创建其对象,栈中变量名指向其堆内存地址,因此上面代码段中i5与i6指向堆内存地址是不一样的,所以其比较结果为false。注意哈,这里不论其数值,也就是数值无论在不在-128 ~ 127之间,其原理都会在堆内存中创建对象,因此不论其数值,比较结果都为false。

      c:分析下面一段代码:

private void testNew() {
    
  int int1 = 990;
  int int2 = 990;
  System.out.println("1:" + (int1 == int2)); //true
  
}

      上面代码采用是int直接进行赋值,也就是变量名存放在栈中,值存放在常量池中,每创建一个变量是,先去常量池中去查找该值是否存在,如果存在则直接指向,如果不存在则会在常量池中进行创建。因此上述代码中两个指向的是同一个地址,比较结果为true

      好了,上面就是给大家分享的知识点了,如果有那些不对的地方还恳请大家指出,我进行改正。

      大家记得转发、点赞和评论哦。拜拜,这周末又过完了,明天要上班喽,加油干饭人。

这篇关于java对象引用发生改变和String、Integer和int理解与解释的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!