Java基础学习——Java面向对象(七)多态、引用类型的转换、简单工厂设计模式

一、多态

1.编写程序来学习什么是多态

1)先编写一个女孩和猫玩的程序

创建Cat类,编写猫的方法

public class Cat {
    public void shout(){
        System.out.println("我是小猫,我会喵喵叫");
    }
    public void  scratch(){
        System.out.println("我是小猫,我会挠人");
    }
}

创建Girl类,调用Cat的方法

public class Girl {
    //写个女孩和猫玩的方法
    public void play(Cat cat){
        cat.shout();
    }
}

创建对象,实现女孩和猫玩

public class Test {
    public static void main(String[] args) {
        //让女孩和小猫玩
        //1.创建小猫对象
        Cat c = new Cat();
        //2.创建女孩对象
        Girl g = new Girl();
        //2.让女孩和小猫玩,把c这个实例作为实参传给g的play方法
        g.play(c);
    }
}

运行后可以实现

2)再编写一个女孩和狗玩的程序

创建Dog类

public class Dog {
    public void shout(){
        System.out.println("我是小狗,我会汪汪叫");
    }
    public void  guard(){
        System.out.println("我是小狗,我会看家");
    }
}

在Girl类中加一条实现调用Dog类的方法

public class Girl {
    //写个女孩和猫玩的方法
    public void play(Cat cat){
        cat.shout();
    }
    //女孩和狗玩,方法的重写,方法名相同,参数不同
    public void play(Dog dog){
        dog.shout();
    }
}

创建对象,实现女孩和狗玩

public class Test {
    public static void main(String[] args) {
        //实现女孩和猫玩
        //1.创建猫对象
        Cat c = new Cat();
        //2.创建女孩对象
        Girl g = new Girl();
        //2.让女孩和猫玩,把c这个实例作为实参传给g的play方法
        g.play(c);
        
        //实现女孩和狗玩
        Dog d = new Dog();
        g.play(d);
    }
}

3)由此可见,如果有一百个动物,女孩和一百个动物玩,需要在Girl类中添加一百个分别和这些动物玩的代码,而这些代码中调用的都是shout方法,也就是说这些类都有一个共同的shout方法,所以可以运用之前继承的概念,提取这些类中共同的方法,编写一个父类,动物类Animal

public class Animal {
    public void shout(){
        System.out.println("我是动物,我会叫");
    }
}

让Cat、Dog类都继承Animal类,并且Cat、Dog类中的shout方法就是Animal类中的方法的重写

public class Cat extends Animal{
    public void shout(){
        //对Animal类shout方法的重写
        System.out.println("我是小猫,我会喵喵叫");
    }
    public void  scratch(){
        System.out.println("我是小猫,我会挠人");
    }
}
public class Dog extends Animal{
    public void shout(){
        //对Animal类shout方法的重写
        System.out.println("我是小狗,我会汪汪叫");
    }
    public void  guard(){
        System.out.println("我是小狗,我会看家");
    }
}

4)那么在Girl方法中再调用shout方法就可以直接调用Animal的shout方法

public class Girl {
//    //写个女孩和猫玩的方法
//    public void play(Cat cat){
//        cat.shout();
//    }
//    //女孩和狗玩,方法的重写,方法名相同,参数不同
//    public void play(Dog dog){
//        dog.shout();
//    }
    //和动物玩
    public void play(Animal animal){
        animal.shout();
    }
}

5)但是现在我们要实现的是女孩和具体的动玩,比如猫,那么实现程序如下

public class Test {
    public static void main(String[] args) {
//        //2.创建女孩对象
          Girl g = new Girl();

        //但是现在我们要实现的是让女孩和具体的动物玩,例如和猫玩
        //于是先创建一个猫的实例
        Cat c = new Cat();
        //因为在Girl类里面没有和猫玩的方法,只有和动物玩的方法,于是我们可以让这个动物等于猫
        Animal an = c;
        //再运行程序可以实现和猫玩
        g.play(an);
        
    }
}

这样就可以实现女孩和猫玩,那么如果我想实现女孩和狗玩,我只需要创建一个Dog类的对象,让an等于这个对象,就不用修改Girl类中的代码了

public class Test {
    public static void main(String[] args) {
          Girl g = new Girl();

        //但是现在我们要实现的是让女孩和具体的动物玩,例如和猫玩
        //于是先创建一个猫的实例
        //Cat c = new Cat();
        Dog d = new Dog();
        //因为在Girl类里面没有和猫玩的方法,只有和动物玩的方法,于是我们可以让这个动物等于猫
        Animal an = d;
        //再运行程序可以实现和猫玩
        g.play(an);
    }
}

像以上这种先有子类,再抽取父类的方式,叫做泛化,而先有父类,再有子类叫做继承

二、多态的概念

1.什么是多态

多态就是指多种状态,同一个行为(方法),不同的的子类表现出不同的形态(动物中的猫喵喵叫,狗汪汪叫)。在Java中就是同一个方法调用,由于对象的不同会产生不同的结果。

2.多态是方法的多态,与属性无关,重写也是

3.多态的优势

提高代码的扩展性(添加一种状态只需要添加相应的类和创建相应的对象),符合开闭原则。想要扩展性更好的话需要使用反射。

4.多态的要素

1)继承:Cat extends Animal、Dog extends Animal···

2)重写:Cat、Dog类对Animal类shout方法的重写(以下几种不能被重写:①static修饰的方法,它属于类,不属于实例②final修饰的方法:常量③3.private方法:私有的)

3)父类引用指向子类对象

Cat c = new Cat();
Animal an = c;

上面两句代码可以合为一句

Animal an = new Cat();

=左侧:编译期类型

=右侧:运行期类型

代码运行时,shout方法的参数被进行了两次赋值Animal animal = an = new Cat()

 public void play(Animal animal){//这里接受到的实参是an,也就是Animal animal = an = new Cat()
        animal.shout();
    }

 也可以直接用父类的对象来调用shout方法, 其实调用的就是子类的shout方法

        Cat c = new Cat();
        Animal an= c;   //这里an和c指向的是同一地址,那么an调shout方法也就是c调用shout方法,所以呈现的结果是cat的结果
        an.shout();

4)经典使用场景:

类作为方法的形参,调用方法时将子类的对象作为实参传入,这样在调用方法时,根据传入的子类不同,实现的效果也不同,这就是多态。

父类作为方法的返回值,简单工厂设计模式。

三、引用类型的类型转换

1.类型转换实例

1)在上面的代码中,可以使用an直接调用子类的方法shout,但是却不可以调用Animal类中没有而子类中有的方法和属性,因为=左边是编译期的类型,在编译时,编译期认为an是Animal类型,而Animal类中只有shout方法而没有scratch方法,所以会报错。并且在内存中Animal也只能访问到Animal中的属性和方法、还有子类中重写的方法。

        Cat c = new Cat();
        Animal an= c;   //这里an和c指向的是同一地址,那么an调shout方法也就是c调用shout方法,所以呈现的结果是cat的结果
        an.shout();
        //an.scratch();//报错
        /*这里=左边的an是编译期的类型,在编译期,编译器认为an是Animal类型的,而在Animal类型中没有scratch()方法
          虽然an和p指向同一地址,但是这是运行后Animal an= c后才会指向同一地址,编译期还没有这一步骤,所以报错
         */
        an.age=10;
        //an.weight=10.5 //属性赋值也报错,原因同上

2)可以使用向下转型使an可以访问到子类的属性和方法

        //将Animal类型的an转换为Cat类型,并且使用一个Cat类型的对象来接收
        Cat cat=(Cat)an;    //父类转为子类,向下转型
        cat.scratch();      //转型后使用cat对象来调用Cat类的方法,则可以调用
        cat.weight=10.5;

在内存中的分析为:

2.在多态中,父类要想使用子类的方法,要进行类型转换

Java中的类型有基本数据类型和引用数据类型

基本数据类型转换:64位>32>16>8   高-->低:强制转换, 低--->高:直接转换

引用数据类型转换:父--->子   强制转换, 子--->父,直接转换

类型转换的作用:方便方法的调用,减少重复的代码

1)先写三个空的Person、Student、Teacher方法

在main方法中输入

import com.rzd.oop.demo11.Person;
import com.rzd.oop.demo11.Student;
import com.rzd.oop.demo11.Teacher;

public class Application {
    public static void main(String[] args) {
        //先写个多态
        Object object = new Student();  //Object是Student的父类,可以写多态

        //Object>Person>Student
        //Object>Person>Teacher
        //Object>String

        //由于object是Student类型的,那么object是Student及其父类的类型
        System.out.println(object instanceof Object);   //true
        System.out.println(object instanceof Student);  //true
        System.out.println(object instanceof Person);   //true
        System.out.println(object instanceof Teacher);  //false Student和Teacher是平行的
        System.out.println(object instanceof String);   //false Student和String无关

        System.out.println("==================================");
        Person person = new Student();  //这里new出来的person到底是什么类型?

        //person是Person类型的
        System.out.println(person instanceof Object);   //true
        System.out.println(person instanceof Student);  //true
        System.out.println(person instanceof Person);   //true
        System.out.println(person instanceof Teacher);  //false Person是Teacher的父
        //System.out.println(person instanceof String);   //false instanceof两边的类型没有继承关系就会编译报错

        Student student = new Student();
        System.out.println(student instanceof Object);   //true
        System.out.println(student instanceof Student);  //true
        System.out.println(student instanceof Person);   //true
        //System.out.println(student instanceof Teacher);  //false instanceof两边的类型没有继承关系就会编译报错
        //System.out.println(student instanceof String);   //false instanceof两边的类型没有继承关系就会编译报错

    }
}

先在子类中写一个方法study()

public class Student extends Person{
     public void study(){
         System.out.println("Student在学习");
     }
 }

在main方法中创建一个父类的obj对象,调用子类的方法

//类型转换
         Person obj = new Student();    //将student类的oj转换为Person类,子--->父,低--->高,是直接转换
         obj.study();//这行无法运行,报错。
         // 这里表示,obj本来是Student,是子类,被转换成了父类之后,不能调用本身的study方法了,说明子类转换为父类会丢失自己本来的方法

当子类转换成父类时,会丢失方法。

所以父类使用子类本身的方法, 需要强制转换,将父类转换为子类

public class Application {
    public static void main(String[] args) {
        //类型转换
        Person obj = new Student();    //将student类的oj转换为Person类,子--->父,低--->高,是直接转换
        obj.study();//这行无法运行,报错。
        // 这里表示,obj本来是Student,是子类,被转换成了父类之后,不能调用本身的study方法了,说明子类转换为父类会丢失自己本来的方法

        //父类要想使用子类的方法,还需要类型转换.obj现在是是Person类型,要转换为Student类型,高转低,要强制转换
        //先输入(Student)obj;,Alt+回车,选择第二个。
        //这里就是用一个Student类型的对象student1来接收被强制转换为Student类型的对象obj
        Student student1 = (Student) obj;
        //然后student1就可以使用Student的方法
        student1.study();
        //上面两行可以简化成
        ((Student) obj).study();
    }
}

四、简单工厂设计模式

不仅可以用父类做方法的形参,还可以用父类做方法的返回值,真实返回的对象可以是父类的任意一个子类对象。

简单工厂设计模式中工厂(petStore类)只负责创建对象,将创建和使用分开,解决了在代码中大量创建对象的问题。

1.简单工厂设计模式的要素

1)工厂类中定义static方法,通过类名直接调用

2)返回值类型定义为父类类型,返回值可以是任意子类类型

3)调用方法传入参数,工厂根据参数创建对应子类对象

2.上面的动物类,可以提取出他们都由宠物店提供,那么可以创建一个宠物店类,来提供动物。

package com.rzd.no02oop.demo10;

public class Petstore {
    //提供动物,,这里定义为静态方法,可以再Test1中直接雷鸣.方法名调用
    public static Animal getAnimal(String petName){
        //这里需要返回的是动物,所以返回值定义为Animal类型
        //定义一个动物,局部变量要赋初始值
        Animal an = null;
        if ("猫".equals(petName)){
            an=new Cat();
        }else if ("狗".equals(petName)){
            an=new Dog();
        }
        return an;
    }
}

 这里如果传入的参数是猫,那么就是an=new Cat()。

package com.rzd.no02oop.demo10;

public class Test1 {
    public static void main(String[] args) {
        Girl g = new Girl();
        Animal an=Petstore.getAnimal("猫");
        g.play(an);

    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值