今天又被人问道,java里面是否有指针的问题。如果一定要在是或否里选择一个,那么答案是否定的,java中没有指针。但是,java中的引用(reference)和c/c++中的指针(pointer)又有什么关系呢?

一、指针

  在计算机科学中,指针是编程语言中的一个对象,利用地址,它的值直接指向存在电脑存储器中另一个地方的值。由于通过地址能找到所需的变量单元,可以说,地址指向该变量单元。因此,将地址形象化的称为“指针”。意思是通过它能找到以它为地址的内存单元。

  C++标准中规定,“指针”概念不适用于成员指针(不包含指向静态成员的指针)。C++标准规定,参见维基百科,指针分为两类:
    object pointer type:指向void或对象类型,表示对象在内存中的字节地址或空指针
    function pointer type:指代一个函数

二、C/C++中的指针与引用

1、指针和引用的相同点和不同点

★相同点:
  ●都是地址的概念;
    指针指向一块内存,它的内容是所指内存的地址;而引用则是某块内存的别名。
    
★不同点:
  ●指针是一个实体,而引用仅是个别名;
  ●引用只能在定义时被初始化一次,之后不可变;指针可变;引用“从一而终”,指针可以“见异思迁”;
  ●引用没有const,指针有const,const的指针不可变;(具体指没有int& const a这种形式,而const int& a是有 的, 前者指引用本身即别名不可以改变,这是当然的,所以不需要这种形式,后者指引用所指的值不可以改变)
  ●引用不能为空,指针可以为空;
  ●“sizeof 引用”得到的是所指向的变量(对象)的大小,而“sizeof 指针”得到的是指针本身的大小;
  ●指针和引用的自增(++)运算意义不一样;
  ●引用是类型安全的,而指针不是(引用比指针多了类型检查)

2、 C++类的对象和类的指针的区别

如下程序:

#include <iostream> 
#include <string> 
using namespace std; 

class Student 
{ 
    public: 
    static int number;  
    string name; 
    void set(string str) 
    { 
        name = str; 
        number++;    // 调用静态数据成员 
    } 
    void print()  // 态成员函数 print() 
    { 
        std::cout < < name < <" : The number of the students is " < < number < < " numbers." < < std::endl; // 调用静态数据成员 
    } 
}; 

int Student::number = 0;  // 静态数据成员初始化 

int main(int argc, char** argv) 
{ 
    Student* s1; 
    s1 = new Student(); 
    s1->set("111"); 
    Student s2; 
    s2.set("222"); 

    s1->print(); 
    s2.print(); 

    return 0; 
}

对于类student ,定义了一个对象 和一个指针。

类的指针:是一个内存地址值,他指向内存中存放的类对象(包括一些成员变量所赋的值).
类的对象,是利用类的构造函数在内存中分配一块内存(包括一些成员变量所赋的值).

定义对象实例时,分配了内存。指针变量则未分配类对象所需内存
指针变量是间接访问,但可实现多态(通过父类指针可调用子类对象),并且没有调用构造函数。

至于那个效率高要看程序调用过程而定。

三、Java中的引用

  在Java中的引用类型,是指除了基本的变量类型之外的所有类型,所有的类型在内存中都会分配一定的存储空间(形参在使用的时候也会分配存储空间,方法调用完成之后,这块存储空间自动消失), 基本的变量类型只有一块存储空间(分配在stack中), 而引用类型有两块存储空间(一块在stack中,一块在heap中), 方法形参的值传递(引用)是指形参和传进来的参数指向同一个值的内存(heap)中。

实际上java语言并不是没有指针,而是对指针进行了伪装:使用上泛化、强化和简单化,概念上淡化和弱化。

  C++中可以有对象类型的变量和对象指针类型,两者的区别如下: Object oo = Object(); Object * oop = new Object(); 也就是说当使用new方式时,是动态为对象分配内在并将地址赋给oop这个指针变量。
  JAVA中只有一种相关类型:对象类型,可是它的表现形式却是这样的: Object oo = new Object(); 比较一下,原来它就是使用了C++的动态内在分配方式创建了一个对象,并把地址返回给了oo变量,也就是说oo本质上就是一个指针变量。

引申一下:JAVA中的对象类型本质上应该叫做 对象指针 类型。那么传统的对象类型呢?在JAVA里已经不见了踪影!既然没有了传统的对象类型,那么 对象指针变量 前面的*也就可以不要了。对象指针变量也就可以简称为对象变量了,反正也不会和其它概念混淆! 所有的对象变量都是指针,没有非指针的对象变量,想不用指针都不行,这就是指针的泛化和强化。 不叫指针了,就叫对象变量,这就是概念上的淡化和弱化。 没有了指针的加减运算,也没有了*、->等运算符,这是对指针的简单化

1.JAVA强调所有的对象赋值和传递都是引用,解释如下:
  Object a=new Object(); 并不是将新生成的对象赋给a,a是对新生成对象的引用。
  Object a=new Object(); Object b; b=a; b并不是一个新对象,它是对a对象的引用。
其实,a是指针,b也是指针,将a的值赋给b,也就是将a所存储的地址赋给b,b自然指向了a所指向的对象。

2.而两个对象的相等比较不是比较两个对象的值是否相同,是比较两个对象是不是相同的引用。解释如下:
  Object a=new Object(); Object b=a; a==b为真,两个对象引用相同。
  String a=new String(“abc”); String b=new String(“abc”); a==b为假,两个对象引用不同。
其实,==的意义并没有变。a是指针,b也是指针,a、b存储的都是地址,当两个变量存储了同一个对象的地址时,这两个地址当然相等,a==b自然是真。当两个变量存储了不同对象的地址,这两个地址值当然不同,a==b自然为假。

最后的一个例子用java里面用引用实现指针的功能:

public class Foo1 {
public static void main(String[] args) {
   FakeInt a = new FakeInt(10);
   FakeInt b = new FakeInt(20);
   Foo1.exchange(a, b);
   System.out.println("结果为:\n"+a.getValue());
   System.out.println(b.getValue());
}
public static void exchange(FakeInt a, FakeInt b) {
   FakeInt t = new FakeInt(a.getValue());
   a.setValue(b.getValue());
   b.setValue(t.getValue());
}
}
class FakeInt {
private int value;
public FakeInt(int i) {
   this.value = i;
}
public void setValue(int i) {
   this.value = i;
}
public int getValue() {
   int v = this.value;
   return v;
}
}