1、基本数据类型存放在哪?

基本类型的变量存在栈里或者堆里不是由"大小可知,生存期可知"就能确定了。

关键是上下文。

比如:

1
2
3
void method(){
    int a = 3;
}

这自然是存在栈里的。局部方法嘛。

而:

1
2
3
class Test {
    int a = 3;
}

这就肯定是随对象放到堆里的。

**因此,不要孤立的看到基本类型就说放到栈里,看到引用类型就说放到堆里。

**从更深层次去理解它们会更好,例如为什么是在基本类型的实例变量在堆上创建,局部变量在栈上创建,这样做有什么好处

2、思考

如果你熟悉java的内存结构的话就会知道,堆 是所有线程共享的内存区域,栈 是每个线程独享的,如果你将一个实例变量放在栈内,那么就不存在多个线程访问同一个对象资源了,这显然是不对的,所以实例变量要在堆上创建,也不是线程安全的。

但是对于局部变量,是在栈上创建的,每一次方法调用创建一个帧,独享一份内存区域,其他的线程是不会访问到该线程的资源,在 栈上创建也会减轻GC的压力,随着该方法的结束,帧出栈,相对应的内存消除,这种局部变量占用的内存自然就消失了,因此局部变量是线程安全的。

3、注

基本数据类型是放在栈中还是放在堆中,这取决于基本类型声明的位置。

一:在方法中声明的变量

即使变量是局部变量,每当程序调用方法时,系统都会为该方法建立一个方法栈,其所在方法中声明的变量就放在方法栈中,当方法结束系统会释放方法栈,其对应在该方法中声明的变量随着栈的销毁而结束,这就局部变量只能在方法中有效的原因。

在方法中声明的变量可以是基本类型的变量,也可以是引用类型的变量。

(1)当声明是基本类型的变量的时,其变量名及值(变量名及值是两个概念)是放在方法栈中

(2)当声明的是引用变量时,所声明的变量(该变量实际上是在方法中存储的是内存地址值)是放在方法的栈中,该变量所指向的对象是放在堆类存中的。

二:在类中声明的变量是成员变量

也叫全局变量,放在堆中的(因为全局变量不会随着某个方法执行结束而销毁)。

同样在类中声明的变量即可是基本类型的变量 也可是引用类型的变量

(1)当声明的是基本类型的变量其变量名及其值放在堆内存中的

(2)引用类型时,其声明的变量仍然会存储一个内存地址值,该内存地址值指向所引用的对象。引用变量名和对应的对象仍然存储在相应的堆中.

总结:

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

众所周知Java是一种强类型语言,在Java语言中,Java的数据类型一共分为两大类,分别为基本数据类型和引用数据类型,其中基本数据类型细分小类可分为整数类型、浮点类型、字符类型、布尔类型这四小类。

基本数据类型和引用数据类型

1. 基本数据类型

只有8种,可按照如下分类 :

  • 整数类型: long、int、short、byte
  • 浮点类型: float、double
  • 字符类型: char
  • 布尔类型: boolean
No.数据类型大小/位可表示数据范围默认值
1 byte(字节型) 8 -128~127 0
2 short(短整型) 16 -32768~32767 0
3 int(整型) 32 -2147483648~2147483647 0
4 long(长整型) 64 -9223372036854775808~9223372036854775807 0
5 float(单精度) 32 -3.4E38~3.4E38 0.0
6 double(双精度) 64 -1.7E308~1.7E308 0.0
7 char(字符) 16 0~255 ‘\u0000’ (其实就是一个空格)
8 boolean(布尔) - true或false false

2. 引用数据类型

引用数据类型非常多,大致包括:类Class、 接口类型Inteface、 数组类型Array、 枚举类型Enum、 注解类型、 字符串型

例如,String类型就是引用类型。简单来说,所有的非基本数据类型都是引用数据类型。

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

1. 存储位置区别

a). 基本变量类型

在方法中定义的非全局基本数据类型变量的具体内容是存储在栈中的,基本数据类型在被创建时,在栈上给其划分一块内存,将数值直接存储在栈上的。

b). 引用变量类型

只要是引用数据类型变量(类class、接口interface、数组array),其变量或者对象的具体内容信息都是存放在堆中的,而栈中存放的是其具体内容所在内存的引用地址

Tips : 通过变量地址可以找到变量的具体内容,就如同通过房间号可以找到房间一般

1
2
3
4
5
6
7
8
9
public class Main{
   public static void main(String[] args){
       //基本数据类型
       int i=1;
       double d=1.2;
       //引用数据类型
       String str="helloworld";
   }
}

c)内存划分:

 

2. 传递方式区别

a. 基本变量类型

方法中定义的非全局基本数据类型变量,调用方法时作为参数是按数值传递的

1
2
3
4
5
6
7
8
9
10
11
12
//基本数据类型作为方法参数被调用
public class Main{
   public static void main(String[] args){
       int msg = 100;
       System.out.println("调用方法前msg的值:\n"+ msg);    //100
       fun(msg);
       System.out.println("调用方法后msg的值:\n"+ msg);    //100
   }
   public static void fun(int temp){
       temp = 0;
   }
}

内存空间

 

b. 引用变量类型

引用数据类型变量,调用方法时作为参数是按引用传递的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//引用数据类型作为方法参数被调用
class Book{
    String name;
    double price;
    public Book(String name,double price){
        this.name = name;
        this.price = price;
    }
    public void getInfo(){
        System.out.println("图书名称:"+ name + ",价格:" + price);
    }
    public void setPrice(double price){
        this.price = price;
    }
}
public class Main{
   public static void main(String[] args){
       Book book = new Book("Java开发指南",66.6);
       book.getInfo();  //图书名称:Java开发指南,价格:66.6
       fun(book);
       book.getInfo();  //图书名称:Java开发指南,价格:99.9
   }
   public static void fun(Book temp){
       temp.setPrice(99.9);
   }
}

调用时为temp在栈中开辟新空间,并指向book的具体内容,方法执行完毕后temp在栈中的内存被释放掉

内存空间