多态:一种事物的多种形态
多态创建对象的前提:
1. 有继承关系
2. 有方法的重写:在子类中出现同名方法。
注意:方法的重写中,子类的方法访问权限不能低于父类的访问权限(访问权限的顺序由高到低:public,protected,友好的,private),如果父类中是private,那么子类就不能继承,也不存在多态。
3. 父类引用指向子类对象(MagicPhone mg = new MagicPhone();等号前面是父类的引用,等号后面表示指向子类对象,是多态创建对象的默认方法,也是向上转型。可以理解为他是父类的对象)
4. 父类中的静态方法,子类必须静态来覆盖。
5. 子类的方法与父类的方法的返回值一致(方法重载中与返回值类型无关)
class Lianxi1
{
publicstatic void main(String[] args)
{
MagicPhonemg = new MagicPhone();
mg.playMusic();
}
}
class Phone
{
final voidplayMusic(){
//privatefinal void playMusic()虽然private的权限比子类中public权限低,但是private修饰的成员不能被继承,就更谈不上重写。private权限最低,public权限最高,介于二者之间的还有两个,其中包括默认的,就是什么都不写
System.out.println("听音乐");
}
}
class MagicPhone extends Phone
{
publicvoid playMusic(){
System.out.println("根据心情推荐歌曲");
//super.playMusic();
inta = 2;
a = 3;
}
}
多态中成员的特点:
1. 成员变量:编译看父类,运行也看父类
2. 成员方法:编译看父类,运行看子类(如果父类中没有该方法,只有子类中有该方法,那么编译的时候会报错。运行看子类,就是运行的时候按照子类的该方法执行)
3. Static方法:与普通方法不同,不能被重写。当父类和子类中有相同的static方法时,是看引用的是谁,如果是父类引用就看父类,子类引用就看子类。
4. 构造方法:因为构造方法 不能被继承,所以也就不存在多态,更没必要讨论她在多态中的特点。
class Lianxi2
{
publicstatic void main(String[] args)
{
Animala = new Cat();
//父类引用,指向子类对象(多态创建对象的默认方式,也是向上转型),可以理解为她是父类的对象。
System.out.println(a.legs);
//多态的成员特点:成员变量:编译看父类,运行也看父类
a.eat(); //运行结果:吃鱼 成员方法:编译看父类,运行看子 类 (运行时执行子类中的方法)。
//a.show();//如果在父类中没有show方法,在子类中有show方法,那么编译会报错
}
}
class Animal
{
int legs =4;
publicvoid eat(){//静态方法:方法如果是static修饰的,那么不存在重写(即静态的方法不能重写,但可以被继承,静态的方法的调用就是看由谁来引用,如果是父类引用指向子类对象,那么就是用父类的static方法,如果是子类引用的,那就是使用子类的static方法)
System.out.println("吃好");
}
}
class Cat extends Animal
{
int legs =2;
publicvoid eat(){
System.out.println("吃鱼");
}
publicvoid show(){
System.out.println("show~~~~");
}
}
多态中的转型:
类似于基本数据类型中的数据类型的转型:
向上转型:默认小的范围可以自动转成大的范围。Byte可以自动转为int
向下转型:强制转型:由大的范围转向小的范围。
格式:目标数据类型变量名 = (目标数据类型)数据;
如:byte b = (byte)300;
引用数据类型转型:(多态中的转型)
默认:多态创建对象 父类引用指向子类对象 (向上转型)
向下转型(强制转型):将父类引用转为子类对象 IronMan i = (IronMan) p;此时i是一个子类对象,这样就可以调用子类特有的对象了。(如果不强转,父类引用就无法调用子类独有的方法,因为父类引用在编译方法的时候看的是父类)
public static void main(String[] args)
{
//多态创建对象
Person p = new IronMan();//子---->父(父类引用指向子类对象,即由子到父的转型)
System.out.println("我:你是谁呀");
System.out.println("他:我"+p.name);//编译看父类,运行看父类
System.out.println("我:你干哈啊");
System.out.print("他:");
p.business();//多态创建对象,运行的是子类的方法
System.out.println("突然:厚街传来一个女人的尖叫声,救命啊!!!!");
//变身----变身为钢铁侠(因为发现多态创建的对象无法调用子类的特有方法-----强转)
IronMan i = (IronMan)p;//从父---->子(强转变为子类对象,否则不能使用子类独有的方法)
i.fly();//iron是子类对象,可以调用子类特有的方法
i.savePerson();
}
}
class Person
{
String name = "tony";
public void business(){
System.out.println("贩卖军火");
}
}
class IronMan extends Person
{
String name = "钢铁侠";
public void fly(){
System.out.println("飞~~~");
}
public void savePerson(){
System.out.println("别怕,我来救你");
}
public void business(){
System.out.println("合影,10块一张");
}
}
多态的好处和弊端:
好处:提高了代码的维护性;提高了代码的扩展性
弊端:不能访问子类特有的方法(解决方法:将父类引用强转为子类对象);
多态小案例:打豆浆
class Work5
{
publicstatic void main(String[] args)
{
DouJiangJid = new DouJiangJi();//创建一个DouJiangJi的对象
Beanb = new Green();//创建多态对象
d.daDouJiang(b);//通过对象d调用daDouJiang方法,传入的参数是一个Bean类的对象
}
}
class DouJiangJi
{
publicvoid daDouJiang(Bean b){ //传入一个参数是对象,类型是类,方法是用该对象调用这个类的toDouJiang()方法。
b.toDouJiang();
}
}
class Bean
{
publicvoid toDouJiang(){
System.out.println("变成豆浆");
}
}
class Yellow extends Bean//各种豆都继承Bean这个类,创建一个多态对象,父类引用指向子类对象,在每一个豆的子类中,都重写Bean中的toDouJiang()方法,使父类引用时执行的是各种豆的子类的toDouJiang()方法,变成不同种类的豆浆。
{
publicvoid toDouJiang(){
System.out.println("黄豆酱");
}
}
class Green extends Bean
{
publicvoid toDouJiang(){
System.out.println("绿豆浆");
}
}
class Red extends Bean
{
publicvoid toDouJiang(){
System.out.println("红豆浆");
}
}