我有以下代码。接下来是两个问题:
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
答案 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
。如果您要调用这样的重写方法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
和x2
都具有编译时类型
x3
。这意味着所有三个变量都可以引用一个实例
Parent
的{{1}}或Parent
或Child
或其他任何实例
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)
,而不是Parent
。 Grandchild
未定义
为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没有做的是它没有覆盖任何父方法。
修改强>
测试方法在父类中是私有的,因此它不是正确的继承
它可用,因为您的代码似乎在同一个文件中。尝试将您的类放在他们自己的文件中,看看会发生什么(看看代码是否会编译)。