2013-07-25 72 views
2

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

这里Num是一个接口

public interface Num { 
    void sum(); 
} 

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(); 

在这里,我知道Ñ是对象的基准Num2和n是一个指向对象Num2的指针。 NUM2既包含了方法总和getRandom。但是,当我们试图通过ň引用来访问方法,我们只能得到总和方法。我的问题是,指针如何知道Num中包含哪种方法。在对象初始化过程中,如何以及在堆栈中存储哪些信息以供参考。如果我有任何误解纠正了我。

回答

1

我认为下面那张背后(纠正我,如果我错了):

当你创建一个参考Num n,然后在某处这是通过其属性创建的内存。

所以它必须定义方法和可以通过这个引用访问的东西。

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

+0

对于阿布......正确的+1。 –

+0

@Abu创建和获取引用的属性是否在编译时发生?你能否详细说明这些分配是如何在编译和运行时发生的。 –

1

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

2

编译器(而不是在运行时)负责验证的,你把你的物体,像Num而非Num2

3

您所定义的变量nNum类型的接口,因此你只能在调用方法在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(); 
    } 
} 
+0

如何编译器实际上看到它的视角的参考?@The新白痴 –

+0

@DiptopolDam正如我已经强调上述JLS,编译器检查的参考变量的类型,并确定哪些方法可以使用引用变量调用。 – NINCOMPOOP

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

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

另外,您提到的引用指针在堆栈中,而实际对象在堆中。和对象有它的类information.Let我举一个例子 -

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

将打印class Dogclass Animal

0

在java中,当Child extends Parent(或implements)和你写Parent object = new Child(),已创建了Parent参照存储器中的Child对象。

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

但是在那之前,你必须处理编译器。该编译只关心参考,在这种情况下是Parent的类型(或你的情况Num),这样只会让你取消它的方法,这些方法在Parent声明(Num)类。得到这个各地

一种方法是做一个演员,就像这样:

((Num2) n).getRandom();

确保只有做到这一点,如果你肯定知道n是(或将要)实际上指向一个内存中的对象Num2!否则,您将获得ClassCastException
在这里,你告诉编译器:“相信我,我知道这是一个Num2,所以把它当作一个。”

综上所述:

  • Num n = new Num2()声明一个参考变量,并创建一个对象在内存
  • 该变量是Num型的,这就是所有的编译器知道
  • 在存储器中创建的对象是键入Num2,并且JVM将知道这个
  • 要运行JVM,您必须满足编译器
  • 在这种情况下,您可以通过强制转换来满足编译器。