Java多态之向上转型、同名变量以及方法覆盖

首先,我们先要简单理解两个概念:

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所属的类与类型有关,而与具体的引用对象无关。


  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值