java零基础入门学习第八天——相关笔记
多态
多态:多种状态,同一对象在不同情况下表现出不同的状态或行为
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());
}
}
上一篇: java零基础入门学习第八天——相关笔记
下一篇: Java零基础入门——方法