1

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

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获得p.

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

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方法。没有方法,因为它不是继承的。但我仍然得到输出,这表明私有方法是继承的!如果是受保护的方法,并且我在子类中重写,则尽管调用它的对象类型是父类,但仍会执行被重写的方法Child1Parent1Child1testtest(parent p1 = new child1());

编辑:经过几条评论,我将 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

        }     
    }  
4

2 回答 2

1

为了解决第二个问题:保持“继承”和“可见性”的概念不同可能会有所帮助。方法仅在声明该private方法的类内部可见。所以你根本不能从外面使用。此外,即使在内部,您也不能使用,除非该对象被声明为 type 。但是子类的对象仍然有方法,并且可以调用该方法,但只能在内部调用。此示例将编译(即使两个类位于不同的文件中):mCmCCx.m()xCmC

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方法c,即使c有类型Class2。但是,您只能这样做,因为代码位于Class1声明该test()方法的类中(这就是 [2] 无法编译的原因);并且您只能通过转换c为类型的对象来做到这一点Class1(这就是 [1] 无法编译的原因)。然而,即使在你转换它以使编译器将其视为 type 的表达式之后Class1,实际对象仍然具有 type 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();

变量x1,x2x3都具有编译时类型 Parent. 这意味着所有三个变量都可以引用 的实例Parent、或的实例Child或的Grandchild任何其他子类Parent。这就是上面发生的情况:x2将引用 的实例Childx3并将引用 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) 具有类型Parent,而不是类型Grandchild。并且play没有为Parent. 要查看这些变量是否具有具有方法的运行时类型,则play需要编译器生成代码以在运行时进行检查,而编译器不会这样做。

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

于 2013-09-13T00:33:41.153 回答
0

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

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

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

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


编辑

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

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

于 2013-09-12T23:59:58.440 回答