欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

java零基础入门学习第八天——相关笔记

程序员文章站 2022-07-10 08:21:16
...

多态

多态:多种状态,同一对象在不同情况下表现出不同的状态或行为

Java中实现多态的步骤:

1.要有继承(或实现)关系

2.要有方法重写

3.父类引用指向子类对象(is a关系)

package study3.demo;
//Animal类的子类
public class Dog extends Animal {
//因为狗吃骨头,所以优化父类的eat()方法
        @Override       //方法重写的关键字;有方法重写时建议写上
    public void eat() {
//            getName()通过这个调用父类的name,父类用private修饰了
            System.out.println(getName()+"吃骨头");
        }
}
package study3.demo;
//定义父类
public class Animal {
//    姓名
    private String name;
//空参
    public Animal() {
    }

    public Animal(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void eat() {
        System.out.println("吃东西");
    }
}
package study3.demo;
/*
    动物类案例:
        已知父类Animal,成员变量为:姓名,成员方法为:eat()方法
        其有一子类Dog类,请用该案例摸你多态
 */
public class Test4 {
    public static void main(String[] args) {
//需求“演示多态
       /*
            Java中实现多态的是哪个步骤:
                1.要有继承(或实现)关系
                2.要有方法重写
                3.要有父类引用指向子类对象
        */
//        多态:狗是一个动物
        Animal a = new Dog();       //父类引用指向子类对象
        
//        测试成员方法的调用
//        结论:多态中调用成员方法是
//        编译看左(左边的类型(父类:Animal)有没有这个成员)
//        运行看右(运行时具体用的是右边类(子类:Dog)中的该成员)
        a.setName("哈士奇");
//        
        a.eat();
    }
}

结论:多态中调用成员方法是
编译看左(左边的类型(父类)有没有这个成员)
运行看右(运行时具体用的是右边类(子类)中的该成员)

多态效果演示

需求:父类型变量作为参数时,可以接受任意子类对象

package study3.demo;

public class Dog2 extends Animal2 {
    @Override
    public void eat() {
        System.out.println(getName()+"吃骨头");
    }
}
package study3.demo;

public class Mouse extends Animal2 {
    @Override
    public void eat() {
        System.out.println(getName()+"吃奶酪");
    }
}
package study3.demo;
//Animal类父类
public class Animal2 {
    private String name;

    public Animal2() {
    }

    public Animal2(String name) {
        this.name = name;
    }
//因为成员变量时私有的,所以要有setXxx()和getXxx()方法
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

//    成员方法
    public void eat() {
        System.out.println("吃饭");
    }
}
package study3.demo;
/*
    已知父类Animal,成员变量为:姓名,成员方法为:eat()方法
    它有两个子类Dog类,Mouse类,两个子类都重写了Animal类中的eat()方法
    在测试类中,定义showAnimal()方法,用来测试Dog类和Mouse类
 */
public class Test5 {
    public static void main(String[] args) {
//用来测试Dog类和Mouse类
//        测试Dog类
        Dog2 d = new Dog2();
        d.setName("小A");
        showAnimal(d);

//        测试Mouse类
        Mouse m = new Mouse();
        m.setName("小B");
//        m.eat();
        showAnimal(m);
    }
    //        需求:在该类中定义showAnimal()方法
//    传统做法
//    因为是在测试类中的,所以要加static
//    public static void showAnimal(Dog2 d) {
//        d.eat();
//    }
//    public static void showAnimal(Mouse m) {
//        m.eat();
//    }
//    多态的做法
//    多态的使用场景:
//    父类型可以作为形参的数据类型,这样可以接受其任意的子类对象
    public static void showAnimal(Animal2 a) {
        a.eat();
    }
}

多态的使用场景:父类型可以作为形参的数据类型,这样可以接受其任意的子类对象

多态关系中成员变量的使用

需求:子父类中定义了同名的成员变量,如何调用

package study3.demo;

public class Animal3 {
    String name = "小A";

}
package study3.demo;

public class Dog3 extends Animal3 {
    String name = "小B";

}
package study3.demo;
/*
    结论:多态关系中,成员变量是不涉及到重写的
    简答记忆:多态关系中,使用成员变量,遵循“编译看左,运行看左”
            编译看左:在编译期间会看左边的类型有没有这个成员,没有就报错,有就不报错
            运行看左:在运行期间使用的是左边的类型中的这个成员
 */

public class Test6 {
    public static void main(String[] args) {
//        通过多态的方式创建对象,然后测试成员变量的使用
//        多态:父类引用指向子类对象
        Animal3 a = new Dog3();
        System.out.println(a.name);
//        通过普通方式创建对象,然后测试
        Dog3 d = new Dog3();
        System.out.println(d.name);
    }
}

结论:多态关系中,成员变量是不涉及到重写的(成员变量不能重写)
简答记忆:多态关系中,使用成员变量,遵循“编译看左,运行看左
编译看左:在编译期间会看左边的类型有没有这个成员,没有就报错,有就不报错
运行看左:在运行期间使用的是左边的类型中的这个成员

多态的好处:

**1.可维护性:**基于计划才能关系,只需要维护父类代码,提高了代码的复用性,大大降低了维护程序的工作量

**2.可扩展性:**把不同的子类对象都当做父类看待,屏蔽了不同子类对象间的差异,做出通用的代码,以适应不同的需求,实现了向后兼容

多态的缺点:

不能使用子类特有成员

类型转换:当需要使用子类特有功能时,需要进行类型转换

向上转型(自动类型转换):子类型转换成父类型

如:将Dog()类型的转成Animal类型的

Animal a = new Dog();

向下转型(强制类型转换):父类型转换成子类型

如:将Animal类型的animal转成Dog类型,小括号里面写要转成的类型

Dog d = (Dog) animal;

注意事项:

1.只能在继承层次内进行转换(ClassCastException)

2.将父类对象咋混换成子类对象之前,使用instanceof进行检查

package study3.demo;

public class Animal4 {
    public void eat() {
        System.out.println("吃饭");
    }
}
package study3.demo;

public class Dog4 extends Animal4 {
    public void eat() {
        System.out.println("狗吃骨头");
    }
//    狗类独有的方法,父类中是没有这个成员方法的
    public void whtch() {
        System.out.println("狗会看家");
    }
}
package study3.demo;
//子类,
public class Cat extends Animal4 {

}
package study3.demo;
/*
    需求:
    多态的好处:1.可维护性;2.可扩展性
    多态的弊端:父类引用不能使用子类的特有成员
    解决方案:通过“类型转换”实现
    注意:只能在继承层次内进行转换,否则会报ClassCastException异常
    将父类对象转换成子类之前,使用instanceof进行检查
    instanceof关键字的用法:
    对象名 instanceof 数据类型
    意思是判断前边的对象是否是后边的数据类型
 */
public class Test7 {
    public static void main(String[] args) {
//        需求:通过多态创建对象,调用子类中的成员
//        Animal4 a = new Animal4();
        Animal4 a = new Dog4();

//        调用eat()方法
        a.eat();

//        调用watch()方法,属于子类独有的方法
//        a.watch();      //报错
//        正确的写法
//        Dog4 d = (Dog4) a;
//        d.whtch();

//        不正常的转换            ClassCastException
//        Cat c =(Cat)a;
//            优化后的方法:判断当前对象是否Dog类的对象,如果是,再调用watch()方法
        if (a instanceof Dog4) {        //判断是否是Dog类的对象
//            能走到这里,说明条件满足
            Dog4 d = (Dog4)a;
            d.whtch();
        }
    }
}

抽象类

抽象类的概念:包含抽象方法的类,用abstract修饰

抽象方法的概念:只有方法声明,没有方法体的方法。用abstract修饰

抽象方法的由来:当需要定义一个方法,却不明确方法的具体实现时,可以将方法定义为abstract,具体实现延迟到子类

package study4.demo;
//子类老鼠类
public class Mouse extends Animal {

    @Override
    public void eat() {
        System.out.println("老鼠吃奶酪");
    }
}
package study4.demo;

public class Dog extends Animal {
//快捷键:alt+enter自动帮你重写方法
    @Override
    public void eat() {
        System.out.println("狗吃骨头");
    }
}
package study4.demo;
//父类,动物类,抽象类
public abstract class Animal {
//    public void eat() {
//        System.out.println("吃饭");
//    }
//    抽象方法(特点:要求子类必须重写)
    public abstract void eat();
}
package study4.demo;
/*
    抽象类的概念:包含抽象方法的类,用abstract修饰

    抽象方法的概念:只有方法声明,没有方法体的方法。用abstract修饰

    抽象方法的由来:当需要定义一个方法,却不明确方法的具体实现时,可以将方法定义为abstract,具体实现延迟到子类
 */
public class Test {
    public static void main(String[] args) {
//        测试狗类
        Dog d = new Dog();
            d.eat();
//测试老鼠类
        Mouse m = new Mouse();
        m.eat();
        System.out.println("——————————");
//        多态做法
//        调用成员方法:编译看左,运行看右
        Animal a = new Dog();
        a.eat();
        Animal am = new Mouse();
        am.eat();
    }

}
抽象类的特点

**1.**修饰符:必须用abstract关键字修饰

​ 修饰符 abstract class 类名{}

​ 修饰符 abstract 返回值类型 方法名()

**2.**抽象类不能被实例化,只能创建子类对象

**3.**抽象类子类的两个选择:重写父类所有抽象方法;定义抽象类

抽象类成员的特点

1.成员变量:可以有普通的成员变量;也可以有成员常量(final)

2.成员方法:可以有普通方法,也可以有抽象方法;抽象类不一定有抽象方法,有抽象方法的类一定是抽象类(或接口)

3.构造方法:像普通类一样有构造方法,且可以重载

package study4.demo;

//public class Pig extends Animal2 {
//
//}         不想重写父类抽象方法,添加abstract也成为抽象类
public abstract class Pig extends Animal2 {

}
package study4.demo;

public class Cat extends Animal2 {

    @Override
    public void eat() {
        System.out.println("猫吃鱼");

    }

    @Override
    public void sleep() {
        System.out.println("猫睡觉");
    }
}
package study4.demo;

public abstract class Animal2 {
//    构造方法
    public Animal2() {
    }

    public Animal2(String name) {
        this.name = name;
    }

    //    成员变量:其值可以变化
    String name = "A";
//    成员常量:其值不能发生改变
    final int age = 10;

    public abstract void eat();
    public abstract void sleep();
    public void call() {
        System.out.println("动物会叫");
    }
}
package study4.demo;
//总结:抽象类中的成员比普通类多一样:抽象方法
//        其他和普通类一样
public class Test2 {
    public static void main(String[] args) {
//        抽象类不能new(抽象类不能实例化)
//        Animal2 an = new Animal2();   报错
//        初始化抽象类
        Animal2 c = new Cat();
        System.out.println("————————");

//        抽象类的成员特点
        c.name = "B";
        System.out.println(c.name);

//        c.age = 30;     //报错,常量的值不能改变
        System.out.println(c.age);
    }
}

总结:

抽象类中的成员比普通类多一样:抽象方法;其他和普通类一样

案例:

需求:开发团队中有程序员和经理两种角色,他们都有姓名、工资、工号等属性,都有工作的行为,经理还有奖金属性。请使用继承思想设计出上诉需求中的类,并分别创建对象使用。

package study4.demo;
//抽象类,父类
public abstract class Worker {
//    成员变量
//    姓名
    private String name;
//    工资
    private double salary;
//    工号,一般是要加部门的,所以用String
    private String id;

//    构造方法
//    空参
    public Worker() {
    }
//全参
    public Worker(String name, double salary, String id) {
        this.name = name;
        this.salary = salary;
        this.id = id;
    }
//setXxx和getXxx方法
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }
//成员方法
//    工作(抽象方法 )
    public abstract void work();
}
package study4.demo;
//程序员类
public class Coder extends Worker {
    @Override
    public void work() {
        System.out.println("程序员要敲代码");
    }
//    小细节:在实际开发中,子类一般都有两个构造方法
//    子类的空参构造访问父类的空参构造;子类的全参构造访问父类的全参构造

    public Coder() {
        super();        //默认存在,访问父类的空参
    }

    public Coder(String name, double salary, String id) {
        super(name, salary, id);        //访问父类的带参
    }
}
package study4.demo;
//经理类
public class Manager extends Worker {
//    使用快捷键时会自动添加本类私有属性
    public Manager() {
    }

    public Manager(String name, double salary, String id, int bonus) {
        super(name, salary, id);
        this.bonus = bonus;
    }

    //    奖金属性
    private int bonus;

//setXxx和getXxx方法

    public int getBonus() {
        return bonus;
    }

    public void setBonus(int bonus) {
        this.bonus = bonus;
    }

    @Override
    public void work() {
        System.out.println("经理划水");
    }
}
package study4.demo;

public class WorkerTest {
    public static void main(String[] args) {
//        测试员工类
//        Worker w = new Worker();   报错,抽象类是不能实例化的
        Worker c = new Coder();
        c.work();

//        测试经理类
        Worker m = new Manager();
        m.work();
        System.out.println("————————");

//        扩展内容,快速实例化对象
//        需求:创建一个姓名叫张三,工资为8000,工号为研发部01的程序员
//        Coder co = new Coder();
//        co.setName("张三");
//        co.setSalary(8000);
//        co.setId("研发部01");
//        子类加上两个构造方法后
        Coder co = new Coder("张三",8000,"研发部01");
        System.out.println("姓名为:"+co.getName()+",工资为:"+co.getSalary()+"元,工号为:"+co.getId());

//        创建一个名字叫李四,工资为12000,工号为:研发部00,奖金
        Manager ma = new Manager("李四",12000,"研发部00",50000);
        System.out.println("姓名为:"+ma.getName()+",工资为:"+ma.getSalary()+"元,工号为:"+ma.getId()+"奖金:"+ma.getBonus());

    }
}