2022-07-25 第八小组 学习笔记

目录

多态

什么是多态?

多态的常见形式

多态中成员访问特点

方法调用

变量调用

多态的前提

优势

多态下会产生的一个问题

instanceof关键字详解

匿名对象

案例

链表---单向链表

总结


多态

什么是多态?

同类型的对象,执行同一个行为,会表现出不同的行为特征。

多态的常见形式

向上转型:通过子类对象 (小范围) 实例化父类对象 (大范围) , 这种属于自动转换

父类名称   父类对象名称 =new  子类构造器;

Father            f                 =new   Son();

向下转型: 通过父类对象 (大范围) 实例化子类对象 (小范围) , 这种属于强制转换

Son s = (Son) f;

多态的形式:  父类类型  对象名称  =  new  子类构造器
               Animal    a     =   new    Dog();

多态中成员访问特点

方法调用:编译看左边,运行看右边。

变量调用:编译看左边,运行也看左边(多态侧重行为多态)

方法调用

Animal

package com.jr.afternoon;

public abstract class Animal {
    //不用写吃的方法,因为子类也会重写,所以定义一个抽象的类和方法
    public abstract void eat();
//        System.out.println("吃得好");

}

Dog(重写父类)

package com.jr.afternoon;

public class Dog extends Animal{
    @Override
    public void eat() {
        System.out.println("狗吃的贼快");
    }
}

 Cat(重写父类)

package com.jr.afternoon;

public class Cat extends Animal{
    @Override
    public void eat() {
        System.out.println("猫吃的贼好");
    }
}

左边:编译,指的是看Animal里面的方法,Animal里面有"eat()"方法,真正跑的是走真实对象,毕竟Dog里面有方法。

变量调用

Animal

package com.jr.afternoon;

public abstract class Animal {
    //不用写吃的方法,因为子类也会重写,所以定义一个抽象的类和方法
    public abstract void eat();
//        System.out.println("吃得好");
    public String name="父类动物";//变量调用

}

 Cat

package com.jr.afternoon;

public class Cat extends Animal{
    public String name="子类猫";

    @Override
    public void eat() {
        System.out.println("猫吃的贼好");
    }
}

Dog

package com.jr.afternoon;

public class Dog extends Animal{
    public String name="子类狗";
    @Override
    public void eat() {
        System.out.println("狗吃的贼快");
    }

}

 Test

走的是父类,印证了     变量调用:编译看左边,运行也看左边

多态的前提

有继承/实现关系;有父类引用指向子类对象;有方法重写

优势

在多态形势下,右边对象可以实现解耦合,便于扩展和维护。

Animal a = new Dog();
Animal a = new Cat();
a.run();//后续业务行为随对象而变,后续代码无需修改

定义方法的时候,使用父类型作为参数,该方法就可以接受父类的一切子类对象,体现出多态的扩展性与便利。

多态下会产生的一个问题

多态下不能使用子类的独有功能。

自动类型转换(从子到父):子类对象赋值给父类类型的变量指向。

强制类型转换(从父到子):

此时必须进行强制类型转换:子类对象变量=(子类)父类类型的变量

作用:可以解决多态下的劣势,可以实现调用子类独有的功能。

Dog独有功能:

package com.jr.afternoon;

public class Dog extends Animal{
    public String name="子类狗";
    @Override
    public void eat() {
        System.out.println("狗吃的贼快");
    }
    public void run(){//独有功能

        System.out.println("狗跑的贼溜");
    }
}

Test

 Animal a=new Dog();
        a.eat();
        Dog dog= (Dog) a;//从父类类型到子类类型 强转
        dog.run();

强制类型转换(从父到子):

必须进行强制类型转换:子类   对象变量=(子类)父类类型的变量

作用:可以解决多态下的劣势,可以实现调用子类独有的功能。

注意:如果转型后的类型和对象真实类型不是同一种类型,那么在转换的时候就会出现ClassCastException

Animal a = new Dog();

Cat c = (Cat)c;       //出现异常ClassCastException

Java建议强转转换前使用instanceof判断当前对象的真实类型,再进行强制转换。

变量名 instanceof 真实类型

判断关键字左边的变量指向的对象的真实类型,是否是右边的类型或者是其子类类型,是则返回true,反之。

Animal a=new Dog();//Cat  Dog  tiger
        a.eat();
        Animal a2=new Cat();
        a2.eat();
 if (a instanceof Dog){
            Dog dog1= (Dog) a;
            dog1.run();
        }else if (a instanceof Cat){
            Cat c= (Cat) a2;
            c.climb();
        }

instanceof关键字详解

boolean result = obj instanceof Class

obj 是一个对象,Class 表示一个类或接口。obj 是 class 类的实例或者子类实例时,结果 result 返回 true,否则返回 false。

instanceof是 Java 的保留关键字。作用是测试它左边的对象是否是它右边的类的实例,返回boolean的数据类型。

匿名对象

匿名对象就是没有明确的给出名字的对象,是对象的一种简写形式。每次 new 都相当于开辟了一个新的对象,并开辟了一个新的物理内存空间。

类名称 对象名 = new 类名称();

public class Person {
    public String name; // 姓名
    public int age; // 年龄

    // 定义构造方法,为属性初始化
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // 获取信息的方法
    public void tell() {
        System.out.println("姓名:" + name + ",年龄:" + age);
    }

    public static void main(String[] args) {
        new Person("张三", 30).tell(); // 匿名对象
    }
}

案例

输出下图的内容 

编写步骤:

1. 定义父类Universe,提供方法doAnything。

2. 定义普通类Star,继承 父类Universe 提供成员发光shine方法

3. 定义普通类Sun,继承Star类,

4. 测试类中,创建Star对象,调用shine方法

5. 测试类中,多态的方式创建Sun对象,调用doAnything方法,向下转型,调用shine方法。

Universe

package com.jr.night;

public class Universe {
    public void doAnything(){
        System.out.println("我是父类");
    }

}

Star

package com.jr.night;

public class Star extends Universe{
    @Override
    public void doAnything() {//重写父类
        System.out.println("星星发光");
    }
    public void shine(){//特有方法
        System.out.println("星星一闪一闪亮晶晶");
    }
}

Sun

package com.jr.night;

public class Sun extends Star{
    @Override
    public void doAnything() {
        System.out.println("太阳吸引着9大行星旋转");
    }
    public void shine(){
        System.out.println("光照八分钟,到达地球");
    }

}

Test

package com.jr.night;

public class Test {
    public static void main(String[] args) {
        Universe u=new Star();
        Star star=(Star) u;//强制
        star.shine();
        System.out.println("===================");

        //向上
        Universe u1=new Sun();
        u1.doAnything();
        //向下
        Sun sun=(Sun) u1;
        sun.shine();


    }
}

输出 

链表---单向链表

单向链表每个节点包含当前节点的数据域和一个指向下一个节点的指针域。


在创建好链表节点之后下来看链表的构造方法和成员变量,成员方法包括一个完整链表的头结点、尾节点以及链表的长度,创建get和set方法、无参构造函数、带参构造函数。

package com.jr.afternoon;

/**
 *  单向
 */
public class Node {

    private Integer data;
    private Node next;

    public Integer getData() {
        return data;
    }

    public void setData(Integer data) {
        this.data = data;
    }

    public Node getNext() {
        return next;
    }

    public void setNext(Node next) {
        this.next = next;
    }

    public Node() {
    }

    public Node(Integer data, Node next) {
        this.data = data;
        this.next = next;
    }

    @Override
    public String toString() {
        return "Node{" +
                "data=" + data +
                ", next=" + next +
                '}';
    }
}

 定义链表的长度、链表的第一个结点,最后一个结点。

package com.jr.afternoon;

public class SuperLinked {

    private int size;

    private Node first;

    private Node last;

}

 尾部插入、指定位置

// 无参构造器
    public SuperLinked() {
    }

    // 把数组添加到链表的尾部
    public boolean add(Integer data){
        // 把传入的数据构建成一个结点
        Node node = new Node(data,null);
        // 如果现在链表是空的,那我就是第一个结点
        if(first == null) {
            first = node;
        }else {
            // 如果链表不是空,那我就是最后一个结点
            // 我应该是在原来的last结点后面
            // 我是原来last结点的下一个结点
            last.setNext(node);
        }
        last = node;
        size++;
        return true;
    }

    public Node getNode(int index){
        if(index < 0){
            index = 0;
        }
        if(index >= size - 1){
            index = size - 1;
        }
        // 找到第index个
        Node cursor = first;
        for (int i = 0; i < index; i++) {
            cursor = cursor.getNext();
        }
        return cursor;
    }

运行结果

总结

今日学习了面向对象的第三个特征-----多态、instanceof关键字、匿名对象、单向链表。多态有两种形式:向上转型、向下转型。其中向下转型要进行强制转换,属于父转子,多态的前提是:有继承/实现关系;有父类引用指向子类对象;有方法重写。通过一天学习,我掌握了向上转型和向下转型的使用,并能独立写出一个简单的小案例。开心!开心!开心!但是单向链表没太听明白555555......多看视频回放吧...

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值