基础:引用变量和引用对象有什么区别呢?

时间:2022-06-29 16:15:16
我现在看java
看到了"动态方法调度",有这两个概念弄不明白,能给我说一下吗?

17 个解决方案

#1


这种问题还是好好去看书的好,三言两语也说不清楚

#2


我自认为这涉及到实参和形参的问题

引用变量实际就是使用形式参数,是一个参数传递过程

引用对象实际是使用实际参数,是不用传值而直接使用

这是我写程序体会出来的,不知正步正确,自己体会体会

#3


引用变量(主类型)就是值传递, 无论怎么变都不影响实参。
应用对象是直接使用,你就当它是指针。

#4


大家能举个例子吗?

书上有句话是这样说的:
"理解是引用变量的类型--而不是引用对象的类型--决定了什么成员可以被访问.也就是说,当一个子类对象的引用被赋给一个超类引用变量时,你只能访问超类定义的对象的那一部分.这是为什么plainbox不能访问weight的原因,甚至是它引用了一个BoxWeight对象也不行."

超类Box
子类BoxWeight

BoxWeight weightbox = new BoxWeight();
Box plainbox = new Box();

plainbox = weightbox;

weight是子类BoxWeight的一个变量...

#5


plainbox是超类Box的引用变量吗?

#6


不是引用变量
是一个实例

#7


那书上怎么这么讲呢?

"当一个子类对象的引用被赋给一个超类引用变量时,你只能访问超类定义的对象的那一部分."

plainbox = weightbox;

#8


大侠,能告诉我吗?

#9


当plainbox = weightbox;以后有以下特点:
1、plainbox的类型是Box(即上述的各“引用变量类型”,这是变量声明时定义的);
2、plainbox变量所指向的具体对象是BoxWeight类型的;(即上述的“引用对象类型”);
此时假设Box定义的成员有A、B;BoxWeight则包括继承而来的A、B以及自己定义的C。因为plainbox变量所指向的具体对象是BoxWeight类型的,所以实际上他有A、B、C三个成员。但是其中只有A、B可访问(因为plainbox的类型是Box,而对于Box类型来说公开可知的成员只有A、B,子类定义的C是不可知的),这就是所谓的“引用变量的类型(而不是引用对象的类型)决定了什么成员可以被访问”。

#10


那为什么以下程序会输出这样的结果呢?

class A{
  void Callme()
  {
    System.out.println("Inside A's Callme method");
  }
}
class B extends A{
  void Callme()
  {
    System.out.println("Inside B's Callme method");
  }
}
class C extends A{
  void Callme()
  {
    System.out.println("Inside C's Callme method");
  }
}

class Dispatch
{
  public static void main(String[] args)
  {
  A a = new A();
  B b = new B();
  C c = new C();
  A r;

  r = a;
  r.callme();
  
  r = b;
  r.callme();

  r = c;
  r.callme();
  }
}

结果:
Inside A's callme method
Inside B's callme method
Inside C's callme method

#11


记住<thinking in java>的作者Bruce Eckel的一句经典的话吧,对象就是神奇的变量。

#12


你能给我解释一下,我上面提的两种情况,为什么不一样吗?
第1个:
"当一个子类对象的引用被赋给一个超类引用变量时,你只能访问超类定义的对象的那一部分"

第2个:
r = b;后,r.callme();显示子类b的方法callme()

#13


两种情况并不冲突啊:
1、当r = b;后,根据A类型定义你对r能访问的依然是callme()成员。
2、而此时的r所指向的对象虽然是B型的,其中callme()虽然重载了其超类方法,但编译器依然知道该对象里有一个名为callme的方法可以访问。假设该对象里还包括了其他的在子类中定义的成员方法,那么在此这些子类里定义的方法就不可用了。
3、你的程序里之所以对每各对象调用相同方法而得出了不同结果,其实就是因为对编译器而言,它只知道每个对象里都有一个名为callme的方法可以访问,至于具体每个对象里的callme()执行什么动作是在运行时动态绑定的,这也是多态的一个体现。

#14


也就是,只能方法重载的时候,超类对象才可以访问子类对象,是吗?

#15


子类对象赋值给超类的变量时,只可以访问该对象里符合超类定义(范围)的成员。跟重载方法无关,即便不重载,因为子类是继承自超类的,所以他本就有对应方法。关键问题是对象里有这个方法(其内部动作可不关心);而且根据引用该对象的变量声明编译器可以知道这个方法可用。

#16


是对象(实例)决定调用哪个函数,而非引用。
所以不可能用超类的引用调用到被覆盖的函数版本。
这也是必然的,否则类的继承结构就没意义了。
就好像C++中的虚拟函数,即使用父类的指针指向子类的对象,调用函数也会自动调用子类的函数版本,一个道理。

#17


HERE

#1


这种问题还是好好去看书的好,三言两语也说不清楚

#2


我自认为这涉及到实参和形参的问题

引用变量实际就是使用形式参数,是一个参数传递过程

引用对象实际是使用实际参数,是不用传值而直接使用

这是我写程序体会出来的,不知正步正确,自己体会体会

#3


引用变量(主类型)就是值传递, 无论怎么变都不影响实参。
应用对象是直接使用,你就当它是指针。

#4


大家能举个例子吗?

书上有句话是这样说的:
"理解是引用变量的类型--而不是引用对象的类型--决定了什么成员可以被访问.也就是说,当一个子类对象的引用被赋给一个超类引用变量时,你只能访问超类定义的对象的那一部分.这是为什么plainbox不能访问weight的原因,甚至是它引用了一个BoxWeight对象也不行."

超类Box
子类BoxWeight

BoxWeight weightbox = new BoxWeight();
Box plainbox = new Box();

plainbox = weightbox;

weight是子类BoxWeight的一个变量...

#5


plainbox是超类Box的引用变量吗?

#6


不是引用变量
是一个实例

#7


那书上怎么这么讲呢?

"当一个子类对象的引用被赋给一个超类引用变量时,你只能访问超类定义的对象的那一部分."

plainbox = weightbox;

#8


大侠,能告诉我吗?

#9


当plainbox = weightbox;以后有以下特点:
1、plainbox的类型是Box(即上述的各“引用变量类型”,这是变量声明时定义的);
2、plainbox变量所指向的具体对象是BoxWeight类型的;(即上述的“引用对象类型”);
此时假设Box定义的成员有A、B;BoxWeight则包括继承而来的A、B以及自己定义的C。因为plainbox变量所指向的具体对象是BoxWeight类型的,所以实际上他有A、B、C三个成员。但是其中只有A、B可访问(因为plainbox的类型是Box,而对于Box类型来说公开可知的成员只有A、B,子类定义的C是不可知的),这就是所谓的“引用变量的类型(而不是引用对象的类型)决定了什么成员可以被访问”。

#10


那为什么以下程序会输出这样的结果呢?

class A{
  void Callme()
  {
    System.out.println("Inside A's Callme method");
  }
}
class B extends A{
  void Callme()
  {
    System.out.println("Inside B's Callme method");
  }
}
class C extends A{
  void Callme()
  {
    System.out.println("Inside C's Callme method");
  }
}

class Dispatch
{
  public static void main(String[] args)
  {
  A a = new A();
  B b = new B();
  C c = new C();
  A r;

  r = a;
  r.callme();
  
  r = b;
  r.callme();

  r = c;
  r.callme();
  }
}

结果:
Inside A's callme method
Inside B's callme method
Inside C's callme method

#11


记住<thinking in java>的作者Bruce Eckel的一句经典的话吧,对象就是神奇的变量。

#12


你能给我解释一下,我上面提的两种情况,为什么不一样吗?
第1个:
"当一个子类对象的引用被赋给一个超类引用变量时,你只能访问超类定义的对象的那一部分"

第2个:
r = b;后,r.callme();显示子类b的方法callme()

#13


两种情况并不冲突啊:
1、当r = b;后,根据A类型定义你对r能访问的依然是callme()成员。
2、而此时的r所指向的对象虽然是B型的,其中callme()虽然重载了其超类方法,但编译器依然知道该对象里有一个名为callme的方法可以访问。假设该对象里还包括了其他的在子类中定义的成员方法,那么在此这些子类里定义的方法就不可用了。
3、你的程序里之所以对每各对象调用相同方法而得出了不同结果,其实就是因为对编译器而言,它只知道每个对象里都有一个名为callme的方法可以访问,至于具体每个对象里的callme()执行什么动作是在运行时动态绑定的,这也是多态的一个体现。

#14


也就是,只能方法重载的时候,超类对象才可以访问子类对象,是吗?

#15


子类对象赋值给超类的变量时,只可以访问该对象里符合超类定义(范围)的成员。跟重载方法无关,即便不重载,因为子类是继承自超类的,所以他本就有对应方法。关键问题是对象里有这个方法(其内部动作可不关心);而且根据引用该对象的变量声明编译器可以知道这个方法可用。

#16


是对象(实例)决定调用哪个函数,而非引用。
所以不可能用超类的引用调用到被覆盖的函数版本。
这也是必然的,否则类的继承结构就没意义了。
就好像C++中的虚拟函数,即使用父类的指针指向子类的对象,调用函数也会自动调用子类的函数版本,一个道理。

#17


HERE