Java多态之向上转型、同名变量以及方法覆盖
来源:blog.csdn.net 更新时间:2023-05-25 21:55
首先,我们先要简单理解两个概念:
1、向上转型:父类类型的引用指向子类类型的对象。例如:
class Parent {
}
class Child extends Parent {
}
public class MainClass {
public static void main(String[] args) {
Parent parent = new Child();//向上转型
}
}
2、向上转型中的多态体现,先看例子:
class Parent {
void myType() {
System.out.println("I`m Parent.");
}
}
class Son extends Parent {
void myType() {
System.out.println("I`m Son.");
}
}
class Daughter extends Parent {
void myType() {
System.out.println("I`m Daughter.");
}
}
public class MainClass {
public static void main(String[] args) {
Parent parent_Parent = new Parent();
Parent parent_Son = new Son();
Parent parent_Daughter = new Daughter();
System.out.print("parent_Parent:");
parent_Parent.myType();
System.out.print("parent_Son:");
parent_Son.myType();
System.out.print("parent_Daughter:");
parent_Daughter.myType();
}
}
输出结果:
parent_Parent:I`m Parent.
parent_Son:I`m Son.
parent_Daughter:I`m Daughter.
可以看到,Parent类型引用了不同的对象,调用了相同的方法,输出了不一样的结果。向上转型中的多态体现可以用在函数传递方面,如果函数参数的类型为Parent,我们可以传递给它Parent,Son,Dauther类型的对象。
在学习下面关于Java向上转型的同名变量以及方法覆盖前,希望您能了解Java程序初始化顺序,您先看看这篇博文:点击打开链接 的例子,将非常有助于您对一下例子的理解。
我们先记住这几个知识点:
一、如果使用父类类型的引用指向子类的对象,该引用只能调用父类中定义的方法和变量;
二、如果子类中重写了父类中的一个方法,那么在调用这个方法的时候,将会调用子类中的这个方法;
三、变量不能被重写(覆盖),”重写“的概念只针对方法。
接下来,我们逐点分析:
一、如果使用父类类型的引用指向子类的对象,该引用只能调用父类中定义的方法和变量;
对于第一点,可以在编写程序的时候发现,对于一个父类类型引用了一个子类的对象,在编译器,比如eclipse,不会提示父类没有而子类有的方法,读者可以去试一试。
二、如果子类中重写了父类中的一个方法,那么在调用这个方法的时候,将会调用子类中的这个方法;
先看一个简单的例子:
class Parent {
public String ap = getStr();//调用的是Child中的getStr()方法,1
public Parent() {
System.out.println("parent_construct");
System.out.println("ap:"+ap);//2
}
public String getStr() {//这个方法不会被调用
System.out.println("parent_method");
return "Parent";
}
}
class Child extends Parent {
String ac = getStr();//调用的是自己getStr()的方法
public Child() {
System.out.println("Child_construct");
System.out.println("ac:"+ac);
}
public String getStr() {//这个方法被调用两次
System.out.println("child_method");
return "Child";
}
}
public class MainClass {
public static void main(String[] args) {
Parent parent = new Child();
}
}
输出结果:
child_method
parent_construct
ap:Child
child_method
Child_construct
ac:Child
这里要注意的是第一个输出,对应程序中注释为1的地方。同时,由于调用的是子类的getStr()方法,所以ap的值为CHild,因此,第三行输出的是Child,对于程序中注释为2的地方。所以,如果子类中重写了父类中的一个方法,那么在调用这个方法的时候,将会调用子类中的这个方法;
三、如果父类和子类中存在同名变量会是个什么情况?
我们先看一个例子,
class Parent {
public String a = getAParent();
public Parent() {
System.out.println("parent_construct:"+a);
getStr();//调用的是子类的getStr()方法,1
}
public void getStr() {
System.out.println("parent_method");
System.out.println("ap:"+a);
}
public String getAParent() {
System.out.println("getAParent");
return "pA";
}
}
class Child extends Parent {
public String a = getAChild();
public Child() {
System.out.println("Child_construct:"+a);
getStr();
}
public void getStr() {//被调用两次,这里的变量a是子类的变量a,2
System.out.println("child_method");
System.out.println("ac:"+a);
}
public String getAChild() {
System.out.println("getAChild");
return "cA";
}
}
public class MainClass {
int a;
public static void main(String[] args) {
Parent parent = new Child();
}
}
输出结果:
getAParent
parent_construct:pA
child_method
ac:null
getAChild
Child_construct:cA
child_method
ac:cA
输出的第四行竟然是null,好像很奇怪,实则不奇怪。在代码中注释为1的地方,调用的是子类的getStr()方法,而getStr()函数中的变量a是子类的变量a,而不是父类中已经被赋值为字符串“pA”的变量a,由于Java初始化顺序,在子类中的getStr()方法这次被调用的时候,子类中的变量a还没有被赋值为“cA”.
我们再看看子类中没有同名变量a 的情况,我们直接把对应的那一行代码注释掉。
class Parent {
public String a = getAParent();
public Parent() {
System.out.println("parent_construct:"+a);
getStr();//调用的是子类的getStr()方法,1
}
public void getStr() {
System.out.println("parent_method");
System.out.println("ap:"+a);
}
public String getAParent() {
System.out.println("getAParent");
return "pA";
}
}
class Child extends Parent {
//public String a = getAChild();//子类中没有同名变量a
public Child() {
System.out.println("Child_construct:"+a);
getStr();
}
public void getStr() {//被调用两次,这里的变量a是子类的变量a,2
System.out.println("child_method");
System.out.println("ac:"+a);
}
public String getAChild() {
System.out.println("getAChild");
return "cA";
}
}
public class MainClass {
int a;
public static void main(String[] args) {
Parent parent = new Child();
}
}
输出结果:
getAParent
parent_construct:pA
child_method
ac:pA
Child_construct:pA
child_method
ac:pA
输出的第四行变成了“pA”,说明在调用子类的getStr()方法时,里面的变量是父类中的变量a,这不是废话吗:)
我们最后来看一下如果父类和子类中存在同名变量,内存是不是给两个变量都分配了空间。
class Parent {
public String a = getAParent();
public Parent() {
System.out.println("parent_construct:"+a);
getStr();
}
public void getStr() {
System.out.println("parent_method");
System.out.println("ap:"+a);
}
public String getAParent() {
System.out.println("getAParent");
return "pA";
}
public void getParentA() {//
System.out.println("ParentA always is :"+a);
}
}
class Child extends Parent {
public String a = getAChild();
public Child() {
System.out.println("Child_construct:"+a);
getStr();
}
public void getStr() {
System.out.println("child_method");
System.out.println("ac:"+a);
}
public String getAChild() {
System.out.println("getAChild");
return "cA";
}
public void getParentB() {//
System.out.println("ParentA always is :"+a);
}
}
public class MainClass {
int a;
public static void main(String[] args) {
Parent parent = new Child();
parent.getParentA();
Child child = (Child)parent;//1
child.getParentB();
System.out.println("Parent类型 a:"+parent.a);
System.out.println("Child类型 a: "+child.a);
}
}
输出结果:
getAParent
parent_construct:pA
child_method
ac:null
getAChild
Child_construct:cA
child_method
ac:cA
ParentA always is :pA
ParentA always is :cA
Parent类型 a:pA
Child类型 a: cA
说明了内存给两个变量都分配了空间。根据最后两行的输出结果,说明如果直接调用变量a,a所属的类与类型有关,而与具体的引用对象无关。
1、向上转型:父类类型的引用指向子类类型的对象。例如:
class Parent {
}
class Child extends Parent {
}
public class MainClass {
public static void main(String[] args) {
Parent parent = new Child();//向上转型
}
}
2、向上转型中的多态体现,先看例子:
class Parent {
void myType() {
System.out.println("I`m Parent.");
}
}
class Son extends Parent {
void myType() {
System.out.println("I`m Son.");
}
}
class Daughter extends Parent {
void myType() {
System.out.println("I`m Daughter.");
}
}
public class MainClass {
public static void main(String[] args) {
Parent parent_Parent = new Parent();
Parent parent_Son = new Son();
Parent parent_Daughter = new Daughter();
System.out.print("parent_Parent:");
parent_Parent.myType();
System.out.print("parent_Son:");
parent_Son.myType();
System.out.print("parent_Daughter:");
parent_Daughter.myType();
}
}
输出结果:
parent_Parent:I`m Parent.
parent_Son:I`m Son.
parent_Daughter:I`m Daughter.
可以看到,Parent类型引用了不同的对象,调用了相同的方法,输出了不一样的结果。向上转型中的多态体现可以用在函数传递方面,如果函数参数的类型为Parent,我们可以传递给它Parent,Son,Dauther类型的对象。
在学习下面关于Java向上转型的同名变量以及方法覆盖前,希望您能了解Java程序初始化顺序,您先看看这篇博文:点击打开链接 的例子,将非常有助于您对一下例子的理解。
我们先记住这几个知识点:
一、如果使用父类类型的引用指向子类的对象,该引用只能调用父类中定义的方法和变量;
二、如果子类中重写了父类中的一个方法,那么在调用这个方法的时候,将会调用子类中的这个方法;
三、变量不能被重写(覆盖),”重写“的概念只针对方法。
接下来,我们逐点分析:
一、如果使用父类类型的引用指向子类的对象,该引用只能调用父类中定义的方法和变量;
对于第一点,可以在编写程序的时候发现,对于一个父类类型引用了一个子类的对象,在编译器,比如eclipse,不会提示父类没有而子类有的方法,读者可以去试一试。
二、如果子类中重写了父类中的一个方法,那么在调用这个方法的时候,将会调用子类中的这个方法;
先看一个简单的例子:
class Parent {
public String ap = getStr();//调用的是Child中的getStr()方法,1
public Parent() {
System.out.println("parent_construct");
System.out.println("ap:"+ap);//2
}
public String getStr() {//这个方法不会被调用
System.out.println("parent_method");
return "Parent";
}
}
class Child extends Parent {
String ac = getStr();//调用的是自己getStr()的方法
public Child() {
System.out.println("Child_construct");
System.out.println("ac:"+ac);
}
public String getStr() {//这个方法被调用两次
System.out.println("child_method");
return "Child";
}
}
public class MainClass {
public static void main(String[] args) {
Parent parent = new Child();
}
}
输出结果:
child_method
parent_construct
ap:Child
child_method
Child_construct
ac:Child
这里要注意的是第一个输出,对应程序中注释为1的地方。同时,由于调用的是子类的getStr()方法,所以ap的值为CHild,因此,第三行输出的是Child,对于程序中注释为2的地方。所以,如果子类中重写了父类中的一个方法,那么在调用这个方法的时候,将会调用子类中的这个方法;
三、如果父类和子类中存在同名变量会是个什么情况?
我们先看一个例子,
class Parent {
public String a = getAParent();
public Parent() {
System.out.println("parent_construct:"+a);
getStr();//调用的是子类的getStr()方法,1
}
public void getStr() {
System.out.println("parent_method");
System.out.println("ap:"+a);
}
public String getAParent() {
System.out.println("getAParent");
return "pA";
}
}
class Child extends Parent {
public String a = getAChild();
public Child() {
System.out.println("Child_construct:"+a);
getStr();
}
public void getStr() {//被调用两次,这里的变量a是子类的变量a,2
System.out.println("child_method");
System.out.println("ac:"+a);
}
public String getAChild() {
System.out.println("getAChild");
return "cA";
}
}
public class MainClass {
int a;
public static void main(String[] args) {
Parent parent = new Child();
}
}
输出结果:
getAParent
parent_construct:pA
child_method
ac:null
getAChild
Child_construct:cA
child_method
ac:cA
输出的第四行竟然是null,好像很奇怪,实则不奇怪。在代码中注释为1的地方,调用的是子类的getStr()方法,而getStr()函数中的变量a是子类的变量a,而不是父类中已经被赋值为字符串“pA”的变量a,由于Java初始化顺序,在子类中的getStr()方法这次被调用的时候,子类中的变量a还没有被赋值为“cA”.
我们再看看子类中没有同名变量a 的情况,我们直接把对应的那一行代码注释掉。
class Parent {
public String a = getAParent();
public Parent() {
System.out.println("parent_construct:"+a);
getStr();//调用的是子类的getStr()方法,1
}
public void getStr() {
System.out.println("parent_method");
System.out.println("ap:"+a);
}
public String getAParent() {
System.out.println("getAParent");
return "pA";
}
}
class Child extends Parent {
//public String a = getAChild();//子类中没有同名变量a
public Child() {
System.out.println("Child_construct:"+a);
getStr();
}
public void getStr() {//被调用两次,这里的变量a是子类的变量a,2
System.out.println("child_method");
System.out.println("ac:"+a);
}
public String getAChild() {
System.out.println("getAChild");
return "cA";
}
}
public class MainClass {
int a;
public static void main(String[] args) {
Parent parent = new Child();
}
}
输出结果:
getAParent
parent_construct:pA
child_method
ac:pA
Child_construct:pA
child_method
ac:pA
输出的第四行变成了“pA”,说明在调用子类的getStr()方法时,里面的变量是父类中的变量a,这不是废话吗:)
我们最后来看一下如果父类和子类中存在同名变量,内存是不是给两个变量都分配了空间。
class Parent {
public String a = getAParent();
public Parent() {
System.out.println("parent_construct:"+a);
getStr();
}
public void getStr() {
System.out.println("parent_method");
System.out.println("ap:"+a);
}
public String getAParent() {
System.out.println("getAParent");
return "pA";
}
public void getParentA() {//
System.out.println("ParentA always is :"+a);
}
}
class Child extends Parent {
public String a = getAChild();
public Child() {
System.out.println("Child_construct:"+a);
getStr();
}
public void getStr() {
System.out.println("child_method");
System.out.println("ac:"+a);
}
public String getAChild() {
System.out.println("getAChild");
return "cA";
}
public void getParentB() {//
System.out.println("ParentA always is :"+a);
}
}
public class MainClass {
int a;
public static void main(String[] args) {
Parent parent = new Child();
parent.getParentA();
Child child = (Child)parent;//1
child.getParentB();
System.out.println("Parent类型 a:"+parent.a);
System.out.println("Child类型 a: "+child.a);
}
}
输出结果:
getAParent
parent_construct:pA
child_method
ac:null
getAChild
Child_construct:cA
child_method
ac:cA
ParentA always is :pA
ParentA always is :cA
Parent类型 a:pA
Child类型 a: cA
说明了内存给两个变量都分配了空间。根据最后两行的输出结果,说明如果直接调用变量a,a所属的类与类型有关,而与具体的引用对象无关。
上一篇:Java 初始化顺序 下一篇:Java中private方法能重写吗?