我遇到了关于对象类型以及可以调用哪种方法的问题。
我只是在测试继承的用法,我定义了两个类:superclass Person和subclass Student。代码如下。
public class Person{
private String name;
private int birthday;
public Person(){
}
public Person(String name, int birthday){
this.name=name;
this.birthday=birthday;
}
public void setName(String name){
this.name=name;
}
public void setBirth(int birthday){
this.birthday=birthday;
}
public String getName(){
return name;
}
public int getBirth(){
return birthday;
}
public String toString(){
return "Name: "+name+"\n"+"Birthday: "+birthday;
}
public void print(Person a){
System.out.println(toString());
}
}
学生班:
public class Student extends Person{
private String major;
public Student(){}
public Student(String major,String name,int birthday){
super(name,birthday);
this.major = major;
}
public void setMajor(String major){
this.major=major;
}
public String getMajor(){
return major;
}
public String toString(){
return "Name: "+getName()+" BOD: "+getBirth()+" Major: "+getMajor();
}
public void print(){
System.out.println(toString());
}
}
测试仪。
public class persontest{
public static void main(String[] args){
//Part 1
Person p2 = new Person("p2 Ryan", 19920604);
p2.print(p2);
//Test 1 p2-->Student
p2=new Student();// what does it mean??
p2.print(p2); //which 'toString' should be called??
//1.If p2 is now a Student Why can't invoke Student's print()? (Uncomment 'p2.print()')
// p2.print();
//2. If p2 isn't a Studnet, why is it able to call Student's toString()? (Uncomment toString in Student)
}
}
我宣布' toString()'方法和' print()'人和学生班的方法。
作为方法' print()'在Person类中有参数,而在Student类中没有参数,我认为这个方法是重载而不是被覆盖。
'的toString'方法已在Student class中重写。
在第1部分中,我创建了一个对象p2,其中包含名称和生日的初始化,并且输出得到满足(姓名:p2 Ryan生日:19920604)。 )
然后我尝试了#p2 =新学生()',这是什么意思?将p2的类型从Person更改为Student?
然后我做了&#p ;print(p2)'我认为所谓的方法'打印()'在Person类中,但是' toString'已被调用并用作参数?打印输出是(姓名:null BOD:0 Major:null),我认为这表明学生的#String'方法已被调用和处理。并且它可能证明p2现在是一种人物?
然而,当我试图获得p2电话' print()'在Student方法中,出现了错误'类型为Person的方法print(Person)不适用于arguments()',这似乎表示p2仍然是Person,因此无法调用方法' print()'在学生班中定义。
所以我很困惑p2是什么类型的?
答案 0 :(得分:0)
bootstrap(AppComponent, [
HTTP_PROVIDERS,
provide(RequestOptions, {useClass: CustomRequestOptions})
]);
// p2.print();
// 2。如果p2不是Studnet,为什么它能够调用Student's toString()? (在学生中取消注释toString)
} }
答案 1 :(得分:0)
使用Person p2 = new Student()
,您已声明了一个类型为Person的新变量,但为其分配了一个学生对象。
变量类型仍然是人,因此您无法直接从学生上调用方法。
要做到这一点,你必须先把它投给学生
((student) p2).print()
这将从学生班级调用print()
方法。
但是,如果要覆盖方法,则始终从对象调用方法,因为编译器会检查对象所属类型的运行时间并在此对象上调用方法。这称为动态绑定。
从学生对象中的人访问覆盖方法的唯一方法是使用super
调用方法,所以:
super.toString();
但这只能在学生班内完成。
答案 2 :(得分:0)
可以看出每个不是基元的变量都具有弱类型和强类型。弱类型用于重载解析,并且编译器可以查看对象具有的接口。但实际调用对象上的方法时会使用强类型。注意:强类型始终与弱类型的直接或间接子类型相同。我们来看看:
A obj = new A();
弱类型和强类型都是A
。
A obj = new B();
弱类型为A
,但强类型为B
。
编译器使用weak类型来检查对象具有哪个接口(方法集合)。因此,我们只能在A
上obj
而非B
调用方法。所以如果这些类看起来像这样:
class A { }
class B extends A {
public void bMehtod(){
...
}
}
我们无法在bMethod
上致电obj
,因为bMethod
不属于A
界面。
为了覆盖,当实际调用方法时使用强类型。就像JVM从强类型开始一样,向上移动继承链,直到找到被调用方法的出现。所以如果我们的课程看起来像这样:
class A {
public String toString() {
return "A";
}
}
class B extends A {
public String toString() {
return "B";
}
}
我们创建一个对象并调用toString
:
A obj = new B();
System.out.println(obj); // this will call 'obj.toString()'
JVM将从强类型(B
)开始,并查找toString
方法。如果它找不到任何东西,它将向上移动继承链。但是,B
会覆盖toString
,因此B
toString
会被调用。当添加第三个类时,这变得更加明显:
class C extends B { }
如果我们现在创建一个对象并调用toString
:
A obj = new C();
System.out.println(obj);
JVM将从C
开始寻找toString
方法,它找不到任何方法并向上移动到B
,在那里找到toString
方法。因此,B
toString
方法将被调用。
就像其他变量一样,this
具有弱而强的类型。弱类型是写入this
关键字的类。强类型是创建对象的实际类型。
在print
方法中:
public void print(Person a){
System.out.println(toString());
}
toString()
被隐式翻译为this.toString()
。 this
的弱类型是Person
,因此可以在其上调用toString
,它是Person
的一部分&#39}。接口。但强类型是您实际用于创建对象的类型:
p2 = new Student();
this
的强类型为Student
,因此在查找Student
方法时,JVM将从toString
开始,并在Student
中找到它}。因此调用Student
' toString
方法。
就像我说这只是一种表示,它实现的实际方式可能因JVM而异。但它仍然会表现得一样。
另请参阅Live Demo