Java 在toString()方法中使用getClass().getName()

Java 在toString()方法中使用getClass().getName(),java,polymorphism,Java,Polymorphism,我定义了以下类: class BaseClass { public String toString() { return "I am a: " + getClass().getName(); } } class DerivedClass { public String toString() { return super.toString(); } } 在main()函数中,我有以下代码: BaseClass b

我定义了以下类:

class BaseClass {
    public String toString()
    {
        return "I am a: " + getClass().getName();
    }
}

class DerivedClass {
    public String toString()
    {
        return super.toString();
    }
}
在main()函数中,我有以下代码:

BaseClass b = new BaseClass();
DerivedClass d = new DerivedClass();

System.out.println(b);
System.out.println(d);  // not sure why/how this works!
正如所料,在运行此代码时,我确实获得了正确的运行时类类型:

I am a: BaseClass
I am a: DerivedClass
我的问题是,在我的DerivedClass中调用
toString()
到底是如何工作的?在我对
toString()
的DerivedClass重写中,我调用了
super.toString()
,它似乎应该实际返回“我是:基类”,因为我们正在父类上调用
toString()

我怀疑这可能与我的基类
toString()
利用了
getClass().getName()
有关,因此当我通过子类对象调用它时,Java一定在检测我的实际对象类型-但我不知道它如何知道如何做到这一点

如果这听起来像是一个noob问题,很抱歉,但我仍然在思考多态性的概念。如果有人能解释为什么它是这样工作的,我将非常感谢您的见解。

getClass()
是一种多态方法。它返回调用它的对象的实际具体类。由于
d
id类型为
DerivedClass
,其
getClass()
方法返回
DerivedClass.class

如果方法实现是正确的,您将得到预期的结果

return "I am a: " + BaseClass.class.getName();
getClass()
是一种多态方法。它返回调用它的对象的实际具体类。由于
d
id类型为
DerivedClass
,其
getClass()
方法返回
DerivedClass.class

如果方法实现是正确的,您将得到预期的结果

return "I am a: " + BaseClass.class.getName();

想象一下你的课程是这样的:

class BaseClass {
    @Override
    public String toString() {
        return "I am a: " + getClass().getName();
    }

    public Class<?> getClass() {
        return BaseClass.class;
    }
}

class DerivedClass extends BaseClass {
    @Override
    public Class<?> getClass() {
        return DerivedClass.class;
    }
}
类基类{
@凌驾
公共字符串toString(){
返回“我是一个:”+getClass().getName();
}
公共类getClass(){
返回BaseClass.class;
}
}
类DerivedClass扩展了基类{
@凌驾
公共类getClass(){
返回DerivedClass.class;
}
}
由于重写的工作方式,
getClass()
DerivedClass
的实例上调用时,即使从超类
基类
调用,也将始终返回
DerivedClass.class
。调用
super.toString()
不会改变这一点,实际上完全没有必要,因为超类实现是默认继承的


请注意,这只是调用
getClass()
时可以预期的演示。在现实生活中,
getClass()
实际上是一种
最终本机方法。重写它是不可能或不必要的。

想象一下您的类是这样的:

class BaseClass {
    @Override
    public String toString() {
        return "I am a: " + getClass().getName();
    }

    public Class<?> getClass() {
        return BaseClass.class;
    }
}

class DerivedClass extends BaseClass {
    @Override
    public Class<?> getClass() {
        return DerivedClass.class;
    }
}
类基类{
@凌驾
公共字符串toString(){
返回“我是一个:”+getClass().getName();
}
公共类getClass(){
返回BaseClass.class;
}
}
类DerivedClass扩展了基类{
@凌驾
公共类getClass(){
返回DerivedClass.class;
}
}
由于重写的工作方式,
getClass()
DerivedClass
的实例上调用时,即使从超类
基类
调用,也将始终返回
DerivedClass.class
。调用
super.toString()
不会改变这一点,实际上完全没有必要,因为超类实现是默认继承的


请注意,这只是调用
getClass()
时可以预期的演示。在现实生活中,
getClass()
实际上是一种
最终本机方法。覆盖它是不可能或不必要的。

您的第一个问题是:

系统输出打印Ln(d);//不知道为什么/如何工作

这是一个好问题!毕竟,您正在将
println
方法的引用
d
传递给
DerivedClass
的一个实例。为什么这会导致实际调用名为
toString()
的方法

这个问题的答案在Javadoc中找到了相应的
println
方法。编译器(
javac
)正确编译您的代码,表示您有兴趣调用接受
对象的
println
方法。请注意,println是一个重载方法,编译器必须根据传递的参数解析正确的方法。在这种情况下,该方法将解析为以下状态:

打印一个对象,然后终止该行。此方法首先调用String.valueOf(x)以获取打印对象的字符串值,然后调用print(String)和println()

然后访问
String.valueOf()
方法并查看:

public static String valueOf(Object obj) {
    return (obj == null) ? "null" : obj.toString();
}
宾果!这将关闭第一个循环,要么调用
基类
toString()
,要么调用
派生类


调用
d
getClass()
的实际原因与
引用的值有关。您可能知道,Java中的每个实例方法(如
toString()
one)除了声明的参数外,还接收一个名为
this
引用的不可见参数。在这种特殊情况下,由于
this
引用指向
d
,因此所有方法都在该引用上调用。
d
的类别显然是
DerivedClass

您的第一个问题是:

系统输出打印Ln(d);//不知道为什么/如何工作

这是一个好问题!毕竟,您正在将
println
方法的引用
d
传递给
DerivedClass
的一个实例。为什么这会导致实际调用名为
toString()
的方法

这个问题的答案在Javadoc中找到了相应的
println
方法。汇编