创建对象的引用

时间:2013-07-25 04:43:32

标签: java

我有一个关于java中对象引用的概念性问题。

这里Num是一个界面

public interface Num {
    void sum();
}

实现Num的Num2

public class Num2 implements Num{
    @Override
    public void sum() {
        System.out.println(getRandom()+getRandom());
    }

    public int getRandom() {
        Random randomNumber = new Random();
        int number = randomNumber.nextInt(30);
        return number;
    }
}

主要功能

Num n = new Num2();
n.sum();

我知道 n 是对象Num2的引用, n 是指向对象Num2的指针。 Num2包含方法 sum getRandom 。但是当我们尝试通过 n 引用访问方法时,我们只能得到 sum 方法。我的问题是指针如何知道Num中包含哪个方法。在对象初始化期间如何以及哪些信息存储在堆栈中以供参考。如果我有任何误解纠正我。

6 个答案:

答案 0 :(得分:3)

您正在定义类型n接口的变量Num,因此您只能调用Num中声明的方法。我相信这个解决方案是在编译时自己完成的。编译器根据类型使用引用变量来确定可访问哪些字段或方法。

但请记住,运行时将调用实际对象类型的方法,即实现接口的类。

  

类类型T的变量可以包含空引用或对类T的实例或作为T的子类的任何类的引用。

请看以下代码:

interface A {
  void method1();
}
class B implements A {
  public void method1() {
  }
  public void methodB(){
  }
}
class C implements A {
  public void method1() {
  }
  public void methodC(){
  }
}
public class InterfaceTest {
   public void testMethod(A a){
       // this is safe because whatever may be the run time type of actual
       // object `a` is referring to , that object will always implement
       // method1.
      a.method1();
      // this cannot be allowed because compiler doesn't know 
      // what will be the actual run time object `a` will refer to
       // It may or may not be an object of B.
      a.methodB(); 
   }
}

答案 1 :(得分:2)

编译器(不在运行时)负责验证您将对象视为Num而不是Num2

答案 2 :(得分:1)

您只能在编译时访问为变量定义的类型的方法。由于您的n变量来自Num类型,因此您只能使用Num接口中定义的方法。请注意,这些方法的行为将由实际对象引用类型定义,在本例中为Num2

答案 3 :(得分:1)

我认为以下内容落后于它(如果我错了,请纠正我):

当你创建一个引用Num n时,就会在内存中的某个地方创建它的属性。

因此必须定义方法以及可以使用此引用访问的内容。

现在,当您将其引用到对象时,该对象是内存中的单独实体。当您尝试使用引用进行访问时,编译器必须使用引用元数据来确定可以使用该引用调用哪个方法,依此类推。

答案 4 :(得分:1)

My question is that how can a pointer know which method are contained in Num?

在编译时,它只会检查引用指针调用的函数或方法是否在引用指针类中声明(不一定定义)。在运行时,整个继承树以自上而下的方式进行解析,并选择正确的函数实现。

此外,您提到的引用指针位于堆栈中,而实际对象位于堆中。对象有它的类信息。让我举一个例子 -

    Animal animal = new Dog();
    System.out.println(animal.getClass());

将打印class Dog class Animal

答案 5 :(得分:0)

在java中,当Child extends Parent(或implements)并且您编写Parent object = new Child()时,您已在内存中创建了对Parent对象的Child引用。

一旦你的代码被编译, JVM 将处理内存中的对象,它将知道引用变量object实际上是指一个类型的对象内存中Child(在您的情况下,n类型为Num2)。

但在此之前,您必须处理编译器编译器只关心引用的类型,在本例中为Parent(或在您的情况下为Num),因此只会让您调用ParentNum)类中声明的方法。

绕过这个的一种方法是进行演员表,如下:

((Num2) n).getRandom();

如果您确定n确实(或将会)实际指向内存中Num2类型的对象,请务必执行此操作!否则,您将获得ClassCastException 在这里,你告诉编译器,“相信我。我知道这是一个Num2,所以请把它当成一个。”

总结一下:

  • Num n = new Num2()声明一个引用变量并在内存中创建一个Object
  • 变量的类型为Num,而且编译器都知道
  • 在内存中创建的对象的类型为Num2,JVM将知道此
  • 要运行JVM,您必须满足编译器
  • 在这种情况下,您可以通过强制转换来满足编译器。