【问题标题】:how to get type of variable referenced in Java?如何获取Java中引用的变量类型?
【发布时间】:2013-09-17 12:55:13
【问题描述】:

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

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。那么我将如何获得ptype

这里的第二个问题是私有方法是否被继承。虽然包括this、cmets 在内的许多文章都认为私有方法没有被继承,但我在下面的示例中看到它是被继承的。可能是下面的一些类型转换问题。

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!

在这里,我在 Child1 类型为 Parent1 的对象上调用 test 方法。 Child1 没有 test 方法,因为它不是继承的。但我仍然得到输出,这表明私有方法是继承的!如果test 是一个受保护的方法,并且我在子类中重写,那么尽管调用它的对象类型是parent(parent p1 = new child1());,但仍会执行被重写的方法。

编辑:经过几次 cmets,我将 Parent1 类和 Child1 类分开,并创建了一个名为 App 的新类,它构造了一个父对象和子对象。现在我不能在下面的代码中调用p.test

class Child1 extends Parent1  
    {  


    }  


     class Parent1 {  

        private void test()  
        {  
            System.out.print("test executed!");  
        } }

    public class App1{

        public static void main(String[] args)  
        {  
            Parent1 p = new Child1();  
            p.test();//The method test from parent is not visible
            Child1 c = new Child1();
            //c.test(); //The method test from parent1 is not visible

        }     
    }  

【问题讨论】:

    标签: java inheritance private classname


    【解决方案1】:

    解决第二个问题:将“继承”和“可见性”的概念区分开来可能会有所帮助。 private 方法 m 仅在声明该方法的类 C可见。所以你根本不能从外部C 使用m。此外,即使在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 内部,您仍然可以调用ctest 方法,即使c 的类型为Class2。但是,您只能这样做,因为代码位于声明 test() 方法的类 Class1 中(这就是 [2] 无法编译的原因);您只能通过将c 转换为Class1 类型的对象来做到这一点(这就是[1] 无法编译的原因)。然而,即使在你转换它以使编译器将其视为Class1 类型的表达式之后,实际对象仍然具有Class2 类型。如果你像这样调用polymorphic 的重写方法:((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();
    

    变量x1x2x3都有一个编译时类型 Parent。这意味着所有三个变量都可以引用一个实例 ParentChildGrandchild 或任何其他实例 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。编译器不知道哪个类 变量或函数调用实际上是指您运行程序时。 所以如果你在Grandchild 中声明一个方法play(),这些是 仍然是非法的:

    x3.play ();             // ERROR
    x6.play ();             // ERROR
    getAParent(2).play ();  // ERROR
    

    因为编译器会想到两个变量和getAParent(2) 具有类型Parent,而不是Grandchild。并且 play 没有定义 为Parent。要查看这些变量是否具有 run-time 类型 有一个play 方法需要编译器生成代码 在运行时检查,编译器不会这样做。

    这就是p.test() 在您的第二个示例中起作用的原因。尽管pChild1的一个实例,p的编译时类型是 Parent1,因为您将其声明为具有 Parent1 类型。和 编译器看到Parent1 有一个test 方法;并且由于代码 在Parent1 内部,test 方法是可见的,即使它是 私人的。这就是它起作用的原因。编译器不会生成代码 检查运行时类型 p 实际指的是什么。希望这可以帮助 解释事情。

    【讨论】:

    • If you have a function f whose return type is Parent, then an expression like obj.f(arg,arg2) will have type Parent. But at run-time, if a variable or expression has compile-time type Parent, the actual type at run-time can be Parent or any of its subclasses. The run-time type will be based on how the object was constructed. -- 这很令人困惑。你能举个例子吗?
    • @user2708477 编辑了我的答案以包含一个示例。希望这会有所帮助,但我觉得这是我能做的最多的事情了。
    【解决方案2】:

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

    类名将反映实例的类型,而不是变量的类型。

    这里我正在调用 Parent1 类型的 Child1 对象的测试方法。 Child1 没有测试方法,因为它不是继承的。

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


    编辑

    测试方法在父类中是私有的,所以继承不正确

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

    【讨论】:

    • 测试方法在父类中是私有的,所以它没有被继承对吗?有没有办法获取变量的类型。即虽然 p 是一个子对象,但它在声明时的类型是父对象。所以我在想是否可以检索有关 p 类型的信息。
    • @HovercraftFullOfEels:“看看代码是否会编译”(在他们自己的文件中使用类):我试过了。确实如此。
    • @ajb:不是上面的 OP 代码。或者你是在告诉我,当子类在不同的文件中时,他们可以通过调用父类的私有方法来逃避??
    • @HovercraftFullOfEels:实际上并不是 child 类调用了父类的私有方法。对p.test() 的调用在父类的主体中,对象的(静态)类型是父类,即使p 在运行时的实际类型是子类。 (如果你说的是c.test(),它被注释掉了,我没有取消注释。)
    • @ajb:我对代码进行了一些编辑。现在代码甚至无法编译。我认为您是正确的,因为父类正文中的p.test() 有所不同。所以如果我被问到私有方法是否在子类中被继承,我的回答应该是它们被继承但不可见,对吧..?
    猜你喜欢
    • 1970-01-01
    • 2018-07-30
    • 2012-07-03
    • 2016-12-03
    • 2011-12-23
    • 1970-01-01
    • 2017-08-12
    相关资源
    最近更新 更多