关于java:覆盖(非)静态类中的私有方法

Overriding private methods in (non-)static classes

我有这个测试代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
public class Test {

    private static class Test3 {

        private void print1() {
            System.out.println("1");
        }
    }
    private static class Test4 extends Test3 {

        private void print1() {
            System.out.println("2");
        }
    }

    public static void main(String[] args) {
        System.out.println("Overriden call to private method ----------------");
        OuterTest.Test1 test1 = new OuterTest.Test1();
        OuterTest.Test2 test2 = new OuterTest.Test2();
        OuterTest.Test1 test12 = new OuterTest.Test2();

        test1.invokeOverriden();
        test2.invokeOverriden();
        test12.invokeOverriden();

        System.out.println("Call to private method from parent class ----------------");

        test1.invokeNotOverriden();
        test2.invokeNotOverriden();
        test12.invokeNotOverriden();

        System.out.println(" Some magic ----------------");

        Test3 test3 = new Test3();
        Test4 test4 = new Test4();
        Test3 test34 = new Test4();

        test3.print1();
        test4.print1();
        test34.print1();
    }
}

class OuterTest {

    public static class Test1 {
        public void invokeOverriden() {
            print1();
        }
        public void invokeNotOverriden() {
            print1();
        }

        private void print1() {
            System.out.println("1");
        }
    }

    public static class Test2 extends Test1 {

        @Override
        public void invokeOverriden() {
            print1();
        }
        private void print1() {
            System.out.println("2");
        }
    }
}

首先,我认为一切都是可行的:

1
2
3
4
Overriden call to private method ----------------
1
2
2

然后,如果我调用了未实现的父方法,继承类的私有方法将不起作用。可以解释为"所有私有方法都是最终的,并且隐藏在派生类中",所以invokeNotOverriden()对test2类中的方法一无所知:

1
2
3
4
Call to private method from parent class ----------------
1
1
1

最后,在静态类中,当我调用非静态私有方法时,突然出现了一些魔力:

1
2
3
4
Some magic ----------------
1
2
1

我原以为埃多克斯在这儿。为什么我错了?


some magic部分中有1 2 1,因为私有方法是通过w/o多态性来解决的,所以编译器创建对类型变量中包含的方法的调用,在您的情况下是Test3。在Test3中将print1声明为非私有(因此,在Test4中,由于禁止收紧方法的访问修饰符),并看到多态性在起作用,因此您将得到预期的1 2 2

考虑简短的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class Test {

    private static class Test3 {
        private void print1() {
            System.out.println("non-polymorphic 1");
        }

        void polymorphic() {
            System.out.println("polymorphic 1");
        }
    }

    private static class Test4 extends Test3 {
        private void print1() {
            System.out.println("non-polymorphic 2");
        }

        void polymorphic() {
            System.out.println("polymorphic 2");
        }
    }

    public static void main(String[] args) {
        Test4 t4 = new Test4();
        t4.print1();
        t4.polymorphic();

        System.out.println("======");

        Test3 t34 = new Test4();
        t34.print1();
        t34.polymorphic();
    }
}

澄清。。。在我对这个答案的评论中:多态性对于访问数据字段无效,只对方法有效。考虑:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private static class Test3 {
    int i = 1;
}

private static class Test4 extends Test3 {
    int i = 2;
}

public static void main(String[] args) {
    Test4 t4 = new Test4();
    System.out.println(t4.i);

    System.out.println("======");

    Test3 t34 = new Test4();
    System.out.println(t34.i);
}

尽管i宣布为非私有,但t34.i的价值为1


私有方法仅对声明它们的类可用,而不是该类的子级。

如果要在子类中使用父类中的方法,则必须将其设置为protected

在上一个例子中,您强制转换为test3,因此出于所有的意图和目的,该类认为它是test3,并调用test3的print方法。静态实例不是强制转换的(您总是用其限定名调用它们),因此它们总是调用自己的私有方法。


就像你说的,你不能重写一个private方法,使它成为protected