多态
class BaseClass { //父类
public int book = 6;
public void base(){
System.out.println("父类的普通方法");
}
public void test(){
System.out.printn("父类被覆盖的方法");
}
}
public class SubClass extends BaseClass { //子类
public String book = "我爱JAVA";
public void test(){
System.out.println("子类的覆盖父类的方法");
}
public void sub(){
System.out.println("子类的普通方法");
}
public static void main(String[] args){
BaseClass p = new SubClass;
System.out.println(p.book); //输出6,表明访问的是父类对象的实例变量
p.base(); //将调用父类继承到的base()方法
p.test(); //调用将执行子类的test()方法
//因为p的编译时类型是BaseClass
//BaseClass类没有提供sub()方法,所以下面的代码编译时会出现错误
//p.sub();
}
}
p引用变量的编译时的类型BaseClass,而运行时的类型是SubClass,当运行时调用该引用变量的方法时,其方法总是表现出子类方法的行为特性,而不是父类方法的行为特性。
与方法不同的是,对象的实例变量则不具备多态性。比如上面p.book,输出的是BaseClass类而不是SubClass类的实例变量。
所以:多态的前提
1.要有继承关系
2.要有方法重写
3.要有父类引用指向子类对象。
PS.引用变量只能调用申明该变量时所用类里所包含的方法。比如P 只能调用BaseClass类里的方法,而不能调用SubClass类的的方法。
多态的成员特点
Fu f = new zi();
在多态中成员函数的特点:
在编译时期:参阅引用型变量所属的类中是否有调用的方法。如果有,编译通过,如果没有编译失败。
在运行时期:参阅对象所属的类中是否有调用的方法。先在子类中找,没有再去父类。
简单总结:成员函数在多态调用时,编译看左边,运行看右边。引用变量只能调用声明变量时所用类里包含的方法。比如Fu f = new zi(); 代码定义一个变量f ,则这额f只能调用Fu类的方法。
在多态中,成员变量的特点;
无论编译和运行,都参考左边(引用型变量所属的类)
abstract class Animal{
abstract void eat();
}
class Cat extends Animal{
public void eat() {
System.out.println("吃鱼");
}
public void catchMouse() {
System.out.println("抓老鼠");
}
}
class Dog extends Animal{
public void eat() {
System.out.println("吃骨头");
}
public void KanJia() {
System.out.println("看家");
}
}
class Pig extends Animal{
public void eat() {
System.out.println("饲料");
}
public void GongDi() {
System.out.println("拱地");
}
}
class DuoTaiDemo {
public static void main(String[] args) {
//Cat c = new Cat();
//c.eat();
//Dog d = new Dog();
//d.eat();
Cat c1 = new Cat();
function(c1);
function(new Dog());
function(new Pig());
Animal c = new Cat(); //既是猫的类型 又是动物的类型, 这就是多态在程序中的表现
c.eat();
}
public static void function(Cat c){ //封装方法 ,提高代码复用性
c.eat();
}
public static void function(Dog d){
d.eat();
}
public static void function(Pig p){
p.eat();
}
}
输出;
吃鱼
吃骨头
饲料
吃鱼
1,多态的体现
父类的引用指向了自己的子类对象。
父类的引用也可以接受自己的子类对象。
优化
abstract class Animal{
abstract void eat();
}
class Cat extends Animal{
public void eat(){
System.out.println("吃鱼");
}
public void catchMouse(){
System.out.println("抓老鼠");
}
}
class Dog extends Animal{
public void eat(){
System.out.println("吃骨头");
}
public void KanJia(){
System.out.println("看家");
}
}
class Pig extends Animal{
public void eat(){
System.out.println("饲料");
}
public void GongDi(){
System.out.println("拱地");
}
}
class DuoTaiDemo {
public static void main(String[] args) {
function(new Cat());
function(new Dog());
function(new Pig());
}
public static void function(Animal a){ //提高了程序的扩展性,后期出现新的动物也能直接用
a.eat();
}
输出;
吃鱼
吃骨头
饲料
2,多态的优点
多态的出现大大的提高了程序的扩展性。
3,多态的前提
必须是类与类之间有关系,要么继承,要么实现。
通常,还有一个前提:存在覆盖
4多态的弊端
提高了扩展性,但是只能使用父类的引用访问父类中的成员。
多态-转型
class DuoTaiDemo {
public static void main(String[] args) {
Animal a = new Cat(); //类型提升。向上转型。 a为父类的引用
a.eat();
//如果想要调用猫的特有方法,如何操作?
//强制将父类的引用。转成子类类型。
Cat c = (Cat)a;
c.catchMouse();
//千万不能出现这种操作,就是将父类对象转成子类类型,不可以将动物转成猫
//我们能转换的是父类应用指向了自己的子类对象时,还引用可以被提升,也可以被强制转换。
//多态自始至终都是子类对象在做着变化。
//Animal a = new Animal();
//Cat C = (Cat)a;
}
public static void function(Animal a){
a.eat();
}
向上转型为动物
如果把一个父类实例转换成子类类型,则这个对象必须实际上是子类实例才行。(即编译时类型为父类类型,而运行时类型为子类类型)