如何获取Java中引用的变量类型?

时间:2013-09-12 23:58:07

标签: java inheritance private classname

我有以下代码。接下来是两个问题:

class Parent {  

        private void test()  
        {  
            System.out.print("test executed!");  
        }
        static void print(){
            System.out.println("my class is parent");
        }
}

class Child extends Parent  
    {  
    static void print(){
        System.out.println("my class is Child");
    }

    }  


   public class Inheritence {

        public static void main(String[] args)  
        {  
            Child p1 = new Child();
            Parent p = new Child();  
            System.out.println("The class name of p is "+p.getClass());
            System.out.println("The class name of p1 is "+p1.getClass());
            System.out.println("p instance of child "+ (p instanceof Child));
            System.out.println("p1 instance of child "+ (p1 instanceof Child));
            //p.test(); 
            p.print();
        }     
    }  

输出结果为:

The class name of p is class Child
The class name of p1 is class Child
p instance of child true
p1 instance of child true
my class is parent

我认为p的类名称为Parent,因为它的类型为Parent。但是,它打印为Child。那么我如何获得type的{​​{1}}。

这里的第二个问题是私有方法是否被继承。虽然许多文章包括this,但私有方法没有被继承的注释,我在下面的例子中看到它是继承的。它可能是下面的一些类型铸造问题。

p

这里我在class Child1 extends Parent1 { } public class Parent1 { private void test() { System.out.print("test executed!"); } public static void main(String[] args) { Parent1 p = new Child1(); p.test(); Child1 c = new Child1(); //c.test(); The method test from parent1 is not visible } } Output is : test executed! 对象test上调用Child1方法。 Parent1没有Child1方法,因为它没有被继承。但我仍然得到输出,这表明私有方法是继承的!如果test是受保护的方法,并且我在子类中重写,那么通过调用它的对象类型是父test

,它是被重写的方法。

编辑:在几条评论之后,我将类Parent1和类Child1分开,并创建了一个名为App的新类,用于构造父对象和子对象。现在我无法在下面的代码中调用(parent p1 = new child1());

p.test

2 个答案:

答案 0 :(得分:1)

要解决第二个问题:保持“继承”和“可见性”的概念不同可能会有所帮助。 private方法m仅在声明方法的类C可见。因此,您无法在m之外使用C。此外,即使在C内,也不能使用x.m(),除非声明对象x属于C类型。但是子类的对象仍然具有方法m,并且可以调用该方法,但仅在C内。这个例子将编译(即使这两个类在不同的文件中):

public class Class1 {
    private void test () { System.out.println ("test"); }
    public void doThis (Class2 c) {
        // c.test();  -- does not compile [1]
        ((Class1)c).test();
    }
}

public class Class2 extends Class1 {
    public void doSomething () {
        doThis (this);
        // ((Class1)this).test();  -- does not compile [2]
    }
}

请注意,在doThis内,您仍然可以调用test的{​​{1}}方法,即使c的类型为c。但是,您只能这样做,因为代码位于声明Class2方法的类Class1内(这就是为什么[2]不能编译);并且只能通过将test()强制转换为c类型的对象(这就是[1]无法编译的原因)来实现。但是,即使在将其强制转换为编译器将其视为类型Class1的表达式之后,实际对象仍然具有类型Class1。如果您要调用这样的重写方法Class2polymorphic,它会调用((Class1)c).polymorphic()中定义的方法,而不是Class2,因为该对象实际上仍然是Class1对象。

所以我认为在某种意义上,Class2 继承的,即使它是私有的;它只是在test中看不到。

更多:我认为理解编译时类型和运行时类型(或实例类型)之间存在差异也很有帮助。如果声明变量Class2,则Parent x;的编译时类型为x。如果您的函数Parent的返回类型为f,则Parent之类的表达式将具有类型obj.f(arg,arg2)。但是在运行时,如果变量或表达式具有编译时类型Parent,则运行时的实际类型可以是Parent 或其任何子类。运行时类型将基于对象的构造方式。因此,变量可以具有编译时类型Parent和运行时类型Parent。然后你只需要知道使用哪种类型以及何时使用。为了检查方法是否可见(Child在哪里发挥作用),使用编译时类型。为了在子子类重写方法时决定调用哪个方法,使用运行时类型(这就是多态性)。对于private,使用运行时类型。无论如何,这就是我对事情的看法,这样我就不会太困惑了。

示例:假设我们有:

.getClass()

在其他一些课程中,我们有

class Parent { }
class Child extends Parent { }
class Grandchild extens Child { }

变量Parent x1 = new Parent(); Parent x2 = new Child(); Parent x3 = new Grandchild(); x1x2都具有编译时类型 x3。这意味着所有三个变量都可以引用一个实例 Parent的{​​{1}}或ParentChild或其他任何实例 Grandchild的子类。这就是上面发生的事情:Parent将引用 到x2的实例,Child将引用一个实例 x3

类似地:

Grandchild

private Parent getAParent(int n) { if (n == 0) return new Parent(); if (n == 1) return new Child(); if (n == 2) return new Grandchild(); throw new IllegalArgumentException(); } Parent x4 = getAParent (0); Parent x5 = getAParent (1); Parent x6 = getAParent (2); 表示x5的实例,Child表示实例 x6

但所有变量的编译时类型和Grandchild 来电仍然是getAParent。编译器不知道是哪个类 变量或函数调用实际上是指运行程序时。 因此,如果您在Parent中声明方法play(),则可以使用这些方法 还是非法的:

Grandchild

因为编译器会考虑两个变量而x3.play (); // ERROR x6.play (); // ERROR getAParent(2).play (); // ERROR 类型getAParent(2),而不是ParentGrandchild未定义 为play。要查看这些变量是否具有运行时类型 有一个Parent方法需要编译器生成代码 在运行时检查,编译器不这样做。

这就是为什么play适用于你的第二个例子。即使p.test() 是指p的实例,Child1的编译时类型是 p,因为您声明它的类型为Parent1。而且 编译器看到Parent1有一个Parent1方法;自从代码 在test内,Parent1方法即使可见也是可见的 私人的。这就是它的原因。编译器不会生成代码 检查实际引用的运行时类型test。希望这可以帮助 解释事情。

答案 1 :(得分:0)

  

我认为p的classname将是Parent,因为它的类型为Parent。但是,它打印为Child。

班级名称将反映 实例 的类型而非变量。

  

这里我在Child1对象上调用了测试方法,类型为Parent1。 Child1没有测试方法,因为它没有被继承。

但是继承测试方法 可能是因为你的两个类在同一个文件中,因此每个类都可以看到私有方法,因此Child1将继承并因此具有可用其父母的所有非私人方法。这就是继承的全部意义 - 重新使用父级的行为(方法)和状态(字段)。 Child1没有做的是它没有覆盖任何父方法。


修改

  

测试方法在父类中是私有的,因此它不是正确的继承

它可用,因为您的代码似乎在同一个文件中。尝试将您的类放在他们自己的文件中,看看会发生什么(看看代码是否会编译)。