重新理解Java -- 类型、值、对象、参数传递

来源:互联网 发布:淘宝cpu鞋旗舰店真假 编辑:程序博客网 时间:2024/06/06 08:45

Java的类型、值、对象以及值传递,常常是众多面试官喜欢混淆的概念之一。自以为有清晰了解的童鞋们,也常常在面试官的妖言之下就迷失方向,而笔者就是其中一个。为此,笔者翻看了The Java Language Specification (Third Edition),看看Java之父是怎么解释的。


这篇文章介绍了Java的类型与值,简单介绍了对象。在这些的基础之上,最后描述了Java的参数传递机制


众所皆知,Java是个强类型语言(Strongly Typed Language)。在编译时刻,每一个值都有清晰的类型。这点是与许多弱类型语言(如Python)所不同的,而与C/C++则是一致的。这些类型的确定,也同时确定了与之相关的操作与操作符的定义


类型与值:

首先从值与变量开始说起:

Java的类型(Type)分为2个类别:基本类型(primitive types)、引用类型(reference types)。


基本类型有:boolean, byte, short, int, long, char, float, double,即boolean以及各种数值类型

在JLS中,对基本值的描述不多,也没有太多的分析价值,不过与对象做对比的话还是能看出一些东西的:

基本值,不与其他的基本值共享状态。基本类型的变量保持着与其基本值一致的类型。基本类型变量的值只能由赋值操作来改变(包括自增"++"和自减"--"操作符)。
原文:Primitive values do not share state with other primitive values. A variable whose type is a primitive type always holds a primitive value of that same type. The value of a variable of primitive type can be changed only by assignment operations on that variable (including increment and decrement operators).


引用类型分为:类类型(class types)、接口类型(interface types)、数组类型(array types)、空类型(null type)

引用值 (reference values),是指向对象的指针(或是不指向任何对象的空指针)


是的,Java中的引用值,也只是对指针的一种封装,并没有从根本上消除指针的概念。这种封装,杜绝了野指针(wild pointer),但并没有杜绝空值,所以才存在java.lang.NullPointerException例外。


对象:

相应的,看看类型所指向的“对象”

一个对象(Object),是一个类实现或一个数组


类实现、数组分别由其产生式(creation expression)显式生成。只有下面这些情况下,他们会隐式生成:

1.在"非常量的字符串表达式"中使用+操作符,这会产生String类型的对象

2.在数组初始化表达式中

3.Boolean, Byte, Short, Character, Integer, Long, Float, Double的装箱转换中。


同一个对象可能有多个引用。多个当一个对象被修改时,他的所有的引用都会被影响。


java.lang.Object是所有其他类的超类,事实上,数组也继承Object,也就是说:

所有的对象(object)都实现Object或其衍生类。


特别的,有一些类被设计成"不变的"(constant)。这意味的这个类的实现对象一旦被生成,它的内容就不再发生变化。String就是一个经典的例子。


参数传递机制

有了上面这些基础,是时候切入正题了:Java的(方法中的)参数传递机制


首先先介绍一下常用的传递机制:(参考自《编译原理》第二版 1.6.6)


值调用(按值传递 call-by-value):

调用时,先对参数进行求值(如果它是表达式)或拷贝(如果它是变量)。... 值调用的效果,被调用过程所做的所有有关形式参数的计算都局限于这个过程,相应的实在参数本身不会改变。

引用调用 (按引用传递 call-by-reference):

调用时,把实在参数的地址作为相应的形式参数传递给被调用者。在被调用者的代码中使用形式参数时,实现方法是沿着这个指针找到调用者指明的内存位置。因此,改变形式参数看起来就像是改变了实在参数一样。


另外还有一种“名调用”,在今天已经被忽略了,于是就不描述了。从上面的描述文字中,可以看到,对于基本值,Java表现出按值传递的特性,而对于引用值,Java表现出引用调用的特性,那么,Java是值调用?引用调用?还是两者的混合?


Java是参数传递机制是:值调用。对于原生值,Java拷贝了这个原生值;而对于引用值,Java同样拷贝了这个引用值。如前面所说,引用值是指向对象的指针,所以,传递引用值时,Java拷贝了所引用对象的指针,而被调用方法的形式参数就是这个指针。

所以,在Java的方法中,对引用值的形式参数的内部操作可以直接操作到这个对象,而当你修改引用值本身时,你修改的只是指针,这个引用值就不再指向实际参数所指向的对象,对它的修改就无效了。


简单的举个小例子:

//Test.javaclass Test{  public int i;  public Test(int num){i=num;}  public static void fun1(Test t){t=new Test(1);}  public static void fun2(Test t){t.i=2;}}


与之等效的C++代码(C++默认使用值调用的参数传递方式):

//test.cppclass Test{public:  int i;  Test(int num){i=num;}  static void fun1(Test* t) {t=new Test(1);}  static void fun2(Test* t) {t->i=2;} };

两例中,fun1都不修改传入的参数所指的实例t的属性,而fun2都修改了它。在Java中,fun1结束后新对象会被gc回收,而C++中,fun1则产生了内存泄漏。


小结:

Java的类型(Type)分为2个类别:基本类型(primitive types)、引用类型(reference types)。

基本类型即boolean以及各种数值类型。

引用类型分为:类类型(class types)、接口类型(interface types)、数组类型(array types)、空类型(null type)

引用值 (reference values),是指向对象的指针(或是不指向任何对象的空指针)

一个对象(Object),是一个类实现或一个数组。


Java是参数传递机制是:值调用。引用值的传递,实际上拷贝和传递了一个指针。

1 0
原创粉丝点击