引言

  什么是数据类型?在计算机科学和计算机编程中,数据类型或简单的类型是数据的一个属性,它告诉编译器或解释器程序员打算如何使用数据。

  每一种编程语言都有属于自己的数据类型,可能不尽相同,但万变不离其宗。Java中当然也有一套属于自己的数据类型,分为两大类:基础数据类型和引用数据类型,它们各自又有不同的分类。

  在程序设计的C语言中,关于函数的参数传递有两个专业术语:按值调用(call by value)和按引用调用(call by reference),它们和数据类型关系密切,但是,Java中只有按值调用。小编楼兰胡杨的这篇文章就和老铁们探索一下Java中的各种数据类型的分类、用途以及之间的关系等,探索java热门基础面试题按值调用(值传递)

数据类型分类

  在Java里面,整体上把数据类型分为两大类——8个基础类型(primitive types) 和 3个引用类型(reference types) ,分类图如下图所示:

数据类型分类

  接下来,分别介绍基本类型和引用类型。

基本类型

  基本类型是Java中预定义的类型,用相应的保留关键字来表示,具有明确的取值范围和数学行为,表示了真实的数字、字符和整数。基本类型的数据都是单个值,而不是复杂的对象,所以基本类型并不是面向对象的,这主要是出于效率方面的考虑。

  基本类型包括布尔类型和数值类型,数值类型又分为整型和浮点型。八种基本数据类型分类如下:

1、整型:byte、short、int、long

2、字符型:char(本质上是一种特殊的int)

3、浮点型:float、double

4、布尔型:boolean

  与此同时,Java语言也为基本类型提供了对应的对象版本,即基本类型的包装类(wrapper),具体信息如下表所示:

图片占用字节

  如果类的成员变量(字段)是基本类型,那么在类初始化时,每个成员变量将会被赋予一个如上表中默认值列所述的默认值。若为了防止因默认值引起不必要的麻烦,推荐用基本类型的包装类型。

引用类型

  引用类型(The value of reference types are references to objects)中的引用,一般是指某个对象的内存地址,其中对象是动态创建的类实例或者数组等。简单的说,引用其实就像是一个对象的名字或者别名 (alias),一个对象在内存中会请求一块空间来保存数据,根据对象的大小,它可能需要占用不相等的空间大小。

  另外,Java语言本身不支持C++中的结构体(struct) 或联合体(union) 等数据类型,这种复合数据类型一般都是通过类或接口进行构造。除了基础类型外,其余的都是引用类型,诸如Java自带的StringBigDecimalBigInteger以及自定义的业务类等,如下所示:

User user;             //类引用类型
List<Object> list;     //接口引用类型
Integer[] array;       //数组引用类型

和基础数据类型不同的一点是,引用数据类型可以赋值为null,也就是空的意思,如下所示:

User user = null;             //类引用类型
List<Object> list = null;     //接口引用类型
Integer[] array = null;       //数组引用类型

  Java是一门面向对象的编程语言,除了基本数据类型以外,Java要求每一个数据类型必须都是一个类。面向对象的编程思想力图使在计算机语言中对事物的描述与现实世界中该事物的本来面目尽可能地一致,类(class)和对象(object)就是面向对象方法的核心概念。

  类是对某一类事物的描述,是抽象的、概念上的定义;对象是实际存在的该类事物的个体,因而也称为实例(Instance)。类和对象就如同概念和实物之间的关系一样,类就好比是一个模板,而对象就是该模板下的一个实例。

引用分类

  引用有哪些分类?【划重点】在Java中引用包括Final reference 强引用、Soft reference 软引用、Weak reference 弱引用 和 Phantom reference 虚引用。那么,为什么会提供这四种引用?主要原因如下:

  • 方便 JVM 进行垃圾回收;

  • 方便开发人员灵活的决定某些对象的生命周期。

  如果我们定义了不止一个引用指向同一个对象,那么这些引用是不相同的,因为引用也是一种数据类型,需要一定的内存空间(stack,栈空间)来保存。但是它们的值是相同的,都指向同一个对象在堆内存(heap,堆空间)中的位置。比如:

String a="Word";
String b="Word Two";
String b=a;

  如图,b = "Word Two"; b = a; 不是改变了 “Word” 这一对象的值,初始化时,b 的值为绿线所指向的“Word Two”,然后 b=a使 b 的引用变更为红线所指向的”Word“。但要注意,String 对象的值本身是不可更改的

数据存在哪

  Java是面向对象语言,其概念为一切皆为对象,但基本数据类型算是个例外哦。基本数据类型大多是面向机器底层的类型,它是 “值” 而不是一个对象,它存放于“栈”中而非“堆”中,但Java一切皆为对象的概念绝非说说而已,它为每一个基本数据类型都提供了相应的包装类(封装器类)。包装类就是一个对象,它存放于“堆”中,下面介绍一下栈内存和堆内存的区别。

  程序是运行在内存中的,也就是我们常说的电脑16g还是8g的内存。而内存空间又划分为栈内存堆内存

  • 栈内存分配速度快,内存空间小。Java的基本类型和引用类型的对象引用存在栈内存中。
  • 堆内存分配速度稍慢,内存空间大。Java的引用类型指向的具体对象存在堆内存中。

  基本类型使用频繁而且占用空间小,放在栈内存中。引用类型的对象引用就是堆内存中对象存放的地址。打个比喻:藏宝图里面记录着宝藏的位置,可以根据藏宝图上面标记的位置找到这些宝藏,这里藏宝图就是栈内存,存放着对象引用,而具体埋放宝藏的地方就是堆内存

基本类型与引用类型的区别

  不论是基本类型还是引用类型,都会先在栈中分配一块内存。对于基本类型来说,这块内存区域中包含的是基本类型的具体数据内容;对于引用类型来说,这块内存区域中包含的是指向真正内容的引用,而真正的内容则被分配在堆上。

  所有的类型在内存中都会分配一定的存储空间,基本类型只有一块存储空间(分配在stack中), 而引用类型有两块存储空间(一块在stack中,一块在heap中);形参在使用的时候也会分配存储空间,方法调用完成之后进行垃圾回收。

值传递

  首先要说明的是java中只存在值传递,只存在值传递!!! 然而我们经常看到对于对象(数组,类,接口)的传递似乎有点像引用传递,可以改变对象中某个属性的值。但是不要被这个假象所蒙蔽,实际上传入函数的值是对象引用的拷贝,即传递的是引用的地址值,故依然是按值传递。

  函数的形参类型如果是引用类型,则调用函数时传过来的就是实参的副本,这个副本存放的是实参的引用地址。如果是基本类型,那么传过来的也是实参的副本,但此时副本存放的是实参的值,如果在函数中改变了副本的值不会改变原始的值。

  为什么Java中只有按值调用,没有按引用调用?Java不支持指针,所以Java不支持引用调用。但是C/C++支持指针,故这些语言支持引用调用。

  Java 方法的参数是简单类型的时候,是值传递的 。这一点我们可以通过一个简单的例子来说明:

package test;
 
public class Test {
   //交换两个形参的值
  public static void swap(int a,int b){
  int c=a;
      a=b;
      b=c;
      System.out.println("a: "+a);
      System.out.println("b: "+b);
   }
 
  public static void main(String[] args){
      int c=10; // 实参
      int d=20; // 实参
      swap(c,d);
      System.out.println("After swap:");
      System.out.println("c: "+d);
      System.out.println("d: "+c);
   }
}
运行结果:
a: 20
b: 10
After swap:
c: 20
d: 10

  不难看出,虽然在 swap (a,b) 方法中改变了形参的值,但对实参本身并没有影响,即对 main(String[]) 方法里的 a,b 变量没有影响。故参数类型是基本类型的时候,是按值传递的,实际上是将参数的值作了一个拷贝传进函数的,无论在函数里怎么改变其值,其结果都是只改变了拷贝的值,而不影响源值。

引用对象传递之例外null

  众所周知,java中除基本类型外,参数传递的都是引用的地址。但是,有一个例外,就是当为引用类型的实参赋值null时,它依然是值传递。也就是说,传参为null的时候退化为值传递,不管函数体内用这个参数做了什么,跳出函数体后该参数依然是null。

  再进一步剖析,其实是基本类型和指向null的非基本类型的引用都存在栈而非堆中,而引用类型传递的是堆内存地址。还有一种常见的、引用失效的场景是引用被改变,示例如下:

User wiener = new User();
wiener.setUserName("Wiener");
wiener.setAge(19);
wiener = new User(); // 覆盖了原来的引用
wiener.setAge(18);
log.info(wiener); // 此时打印出来时,控制台没有姓名只有年龄为18

Reference

原文地址:http://www.cnblogs.com/east7/p/16905767.html

1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长! 2. 分享目的仅供大家学习和交流,请务用于商业用途! 3. 如果你也有好源码或者教程,可以到用户中心发布,分享有积分奖励和额外收入! 4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解! 5. 如有链接无法下载、失效或广告,请联系管理员处理! 6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需! 7. 如遇到加密压缩包,默认解压密码为"gltf",如遇到无法解压的请联系管理员! 8. 因为资源和程序源码均为可复制品,所以不支持任何理由的退款兑现,请斟酌后支付下载 声明:如果标题没有注明"已测试"或者"测试可用"等字样的资源源码均未经过站长测试.特别注意没有标注的源码不保证任何可用性