Java——多态

基本介绍

方法或者是对象具有多种形态。是面向对象的低三大特征,多太是建立在封装和继承的基础之上的。

多态的具体体现

(1)方法的多态

方法的重写和重载就体现了多态。

public class A {

    //方法的重载
    //都是sum方法,但是传入的参数不一样
	public int sum(int n1, int n2) {
		return n1+n2;
	}
	public int sum(int n1, int n2, int n3) {
		return n1+n2+n3;
	}
	
	public void say(String a) {
		System.out.println("调用A类方法say..."+a);
	}

}

public class B extends A{
	
	public void say(String a) {
		System.out.println("调用B类方法say..."+a);
	}

}

public class Test {

	public static void main(String[] args) {		
		//通过传入不同的参数,从而调用不同的方法
		A a = new A();
		System.out.println(a.sum(20, 30));
		System.out.println(a.sum(20, 30, 40));
			
		B ob = new B();
		//根据对象的不同,我们去调用不同的方法
        //方法的重写
		a.say("hello");
		ob.say("ok");
	}
}
50
90
调用A类方法say...hello
调用B类方法say...ok

(2)对象的多态

1.一个对象的编译类型和运行类型可以不一致。

2.编译类型在定义对象时,就确定了,不能改变。

3.运行类型是可以改变的。

4.编译类型看定义时 = 号的左边,运行类型看 = 号的右边。

//animal指向Animal这个对象
//编译对象是Animal,运行对象也是Animal
Animal animal = new Animal();

//如果Animal是Dog的父类,Dog是子类
//animal的编译类型是Animal,但是animal的运行类型是Dog
Animal animal = new Dog();

作用

public class Animal {
	
	public void say() {
		System.out.println("Animal say()方法...");	
	}
}

public class Cat extends Animal{
	
	public void say() {
		System.out.println("Cat say()方法...");	
	}
}

public class Dog extends Animal{
	
	public void say() {
		System.out.println("Dog say()方法...");	
	}
}

public class Test {

	public static void main(String[] args) {
		//animal的运行类型:Dog,编译类型是Animal
		Animal animal = new Dog();
		//输出Dog类当中的say方法
		animal.say();
		
		//animal的运行类型:Cat,编译类型是Animal
		animal = new Cat();
		//输出Cat类当中的say方法
		animal.say();
		
		//animal的运行类型:Animal,编译类型是Animal
		animal = new Animal();
		//输出Animal类中的say方法
		animal.say();
	}
}
Dog say()方法...
Cat say()方法...
Animal say()方法...

在上述代码我们可以看出,当我们创建的指向哪一个对象的时候,我们就会调用哪一个类当中的方法,也就是,我们真的调用方法的时候,是我们的运行对象当中的方法。

多态的向上转型

多态前提条件:两个对象(类)存在继承关系。

本质:父类的引用指向子类的对象

语法:父类类型  引用名 = new 子类类型();

特点:编译类型:看等号的左边,运行类型:看等号的右边

可以调用父类当中的所有成员(需要遵循访问权限的规则),不能调用子类当中特有的成员。

最中的运行效果还是需要看子类的具体实现。

public class Animal {
	
	String name;
	int age;
	
	public void sleep() {
		System.out.println("Animal sleep()方法...");	
	}
	
	public void run() {
		System.out.println("Animal run()方法...");	
	}
	
	public void eat() {
		System.out.println("Animal eat()方法...");	
	}
	
	public void show() {
		System.out.println("Animal show()方法...");	
	}
}

public class Cat extends Animal{
	
	//方法的重写,子类重写父类
	public void eat() {
		System.out.println("Cat eat()方法...");	
	}
	
	public void catchMouse() {
		System.out.println("Animal catchMouse()方法...");	
	}
}

public class Test {

	public static void main(String[] args) {
		
		//向上转型
		Animal animal = new Cat();
		//这个是可行的,Animal的父类是Object,可以不是直接父类
		//Object object = new Cat();

		//调用规则:当我们进行方法的调用时,我们会首先来看我们的子类(运行类型),如果子类(运行类型)当中有这个方法,那么就进行调用
		//如果子类(运行类型)没有这个方法,便会进入到父类当中(如果走到这里,运行类型会变成父类),如果父类有,那么便会调用,如果没有,就会接着向父类的父类查找
		//知道object类,如果都没有便会报错
		animal.eat();
		animal.run();
		animal.sleep();
		animal.show();
		//报错,因为catchMouse是子类Cat的特有方法
		//在编译阶段,能调用的成员是由编译类型来决定的,Cat类时运行类型,所以不能调用
		//animal.catchMouse();
		
	}
}
Cat eat()方法...
Animal run()方法...
Animal sleep()方法...
Animal show()方法...

向下转型

语法:子类类型 引用名 = (子类类型)父类引用;

注意:只能强转父类的引用,不能强转父类的对象。

要求:父类的引用必须指向的是当前目标类型的对象。

作用:可以调用子类类型中所有的成员。

//向下转型
		
		//cat的编译类型:Cat 运行类型:Cat
		Cat cat = (Cat)animal;
		//编译类型为cat,便可以查找到catchMouse方法
		cat.catchMouse();
		
		//如果说我们创建一个Dog类,其父类为Animal
		//这里是运行不通过的,因为Dog与Animal没有向上转型,没有办法通过运行
		//错误:
		//Dog dog = (Dog)animal;
Cat catchMouse()方法...

多态注意事项

(1)属性

属性是没有重写之说的,属性的值要看编译类型。

class Base {
	public int count = 10;
}

class Sub extends Base{
	public int count = 20;
}

public class Test {

	public static void main(String[] args) {

        //属性的值要看编译类型
		//base的编译类型为Base,运行类为Sub;
		Base base = new Sub();
		System.out.println("base.count="+base.count);
		
		//sub编译类型为Sub,运行类型为Sub
		Sub sub = new Sub();
		System.out.println("sub.count="+sub.count);
		
		//b1的编译类型为Base,运行类型为Base
		Base b1 = new Base();
		System.out.println("b1.count="+b1.count);
	}
}
base.count=10
sub.count=20
b1.count=10

(2)instanceof

比较操作符:instanceof,用于判断对象的(运行类型)类型是否为某某类型或者是某某类型的子类型。

        //instanceof
		//BB的父类是AA
		//bb的编译类型:BB,运行类型:BB
		BB bb = new BB();
		System.out.println(bb instanceof BB);
		System.out.println(bb instanceof AA);
		
		//aa的编译类型:AA,运行类型:BB
		AA aa = new BB();
		System.out.println(aa instanceof AA);
		System.out.println(aa instanceof BB);
		
		Object object = new Object();
		System.out.println(object instanceof AA);

		String str = "";
		System.out.println(str instanceof Object);
true
true
true
true
false
false
true

Java的动态绑定机制

1.当调用对象方法的时候,该方法会和该对象的内存地址/运行类型绑定。

2.当调用属性的时候,属性没有动态绑定,哪里声明,哪里使用。

public class A {
	
	public int n1 = 10;
	
	public int sum() {
		return getSum() + 10;
	}
	public int sum1() {
		return n1 + 10;
	}
	public int getSum() {
		return n1;
	}
}

public class B extends A{
	
	public int n1 = 20;
	
	public int sum() {
		return n1 + 20;
	}
	public int sum1() {
		return n1 + 10;
	}
	public int getSum() {
		return n1;
	}

}

public class Test {
	public static void main(String[] args) {
		
		//a的编译类型:A,运行类型B
		A a = new B();
        //a.sum首先会调用运行类型的方法,在B子类当中查找sum方法,返回值为n1+20,20+20=40
		System.out.println(a.sum());
		//a.sum1首先调用运行类型的方法,即B子类,返回值为n1+10,20+10=30
		System.out.println(a.sum1());
	}

}

如果我们把B类当中的sum和sum1方法去掉

public class A {
	
	public int n1 = 10;
	
	public int sum() {
		return getSum() + 10;
	}

	public int sum1() {
		return n1 + 10;
	}
	
	public int getSum() {
		return n1;
	}
}

public class B extends A{
	
	public int n1 = 20;
	
	public int getSum() {
		return n1;
	}

}

public class Test {
	public static void main(String[] args) {
		
		//a的编译类型:A,运行类型B
		A a = new B();
        //首先a.sum在运行类型的B类查找,没有找到,然后到父类A查找,找到,返回值为getSum.()+10
        //注意,这里的getSum方法要用B类当中的,这里getSum方法的查找也是一样,要从子类开始查找
        //子类有那么就直接调用,如果子类没有在到父类查找。20+10=30 
		System.out.println(a.sum());
		//这里的规则和上述是一样的,但是这里的返回值为n1+10,我们知道属性是没有动态绑定的,
        //哪里声明,哪里使用,10+10 = 20;
		System.out.println(a.sum1());
	}

}
30
20

如果把B类的getSum方法去掉

public class A {
	
	public int n1 = 10;
	
	public int sum() {
		return getSum() + 10;
	}

	public int sum1() {
		return n1 + 10;
	}
	
	public int getSum() {
		return n1;
	}
}

public class B extends A{
	
	public int n1 = 20;
}

public class Test {
	public static void main(String[] args) {
		
		//a的编译类型:A,运行类型B
		A a = new B();
        //注意,这里的getSum方法要用A类当中的,这里getSum方法的查找要从子类开始查找
        //子类没有要到父类查找。
		System.out.println(a.sum());
		
		System.out.println(a.sum1());
	}

}
20
20

如有错误,还望指正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值