第十天多态继承补充和final"/>
第十天多态继承补充和final
继承补充:
方法重写的注意事项:
1、父类中私有的方法不能被重写
2、子类重写父类的方法时候,访问权限不能更低
要么子类重写的方法访问权限比父类的访问权限要高或者一样
建议:以后子类重写父类的方法的时候,权限修饰符写一样就不会发生这样的问题。
3、父类中静态的方法不能被重写,也就是说不能被Override修饰,因为静态的是属于类本身的东西。
class OldPhone {private String name;public void call(String name) {System.out.println("打电话给" + name);}public static void play() {//当这个方法是静态时后面子方法便无法重写System.out.println("玩俄罗斯方块");} }class NewPhone extends OldPhone {@Overridepublic void call(String name) {System.out.println("看抖音");}public static void play(){System.out.println("打王者");}}public class ExtendsDemo1 {public static void main(String[] args) {NewPhone newPhone=new NewPhone();newPhone.call("小王");newPhone.play();} }第二个
class A {static int a = 10;//将父类中的静态成员看作一个全局共享的,被所有的子类共享public static void fun() {System.out.println("hello");} }class B extends A {public void fun2() {a = 200;System.out.println(a);}public static void fun() {System.out.println("world");} }public class ExtendsDemo2 {public static void main(String[] args) {B b=new B();System.out.println(b.a);b.fun();b.fun2();//当调用完这个后改变了a的值为200导致后面的调用a变成了200System.out.println(b.a);System.out.println(A.a);} }
final的特点:
final:最终的的意思。它可以修饰类,成员变量,成员方法
特点:
1、修饰类,类不能被继承
2、修饰成员变量,变量变常量,并且只能赋值一次,在构造方法完毕之前赋值即可。
常量:
字面值常量
自定义常量:被final修饰变量变成自定义常量
3、final修饰成员方法:方法不能被重写
class Fu2 {int num = 10;final int num2 = 20; }class Zi2 extends Fu2 {public void show() {num = 100;System.out.println(num); // num2=300;//报错无法为num2赋值System.out.println(num2);} }public class FinalDemo {public static void main(String[] args) {Zi2 zi2 = new Zi2();zi2.show();} }
final修饰局部变量
1、在方法内部,修饰基本数据类型的变量,变量值只能赋值一次,不能发生改变
2、final修饰引用数据类型的变量呢?
引用的地址值不可以发生改变,但是该对象的堆内存中的值是可以发生改变的。
class Student {int age = 10; }public class FinalDemo2 {public static void main(String[] args) {int x = 100;x = 300;System.out.println(x);final int y = 200;// y = 400; //无法为最终变量y分配值System.out.println(y);Student student=new Student();System.out.println(student.age);final Student s2=new Student();System.out.println(s2.age);s2.age=202;System.out.println(s2.age);System.out.println("===========");// s2 = new Student(); //无法为最终变量s2分配值} }
有些时候,我们不想让子类覆盖重写父类中的方法或者功能,只能让子类去使用。
那怎么办呢?
针对这个情况,java提供了一个关键字:final
final:最终的意思。可以修饰类,成员变量,成员方法。
class Fu{public final void show(){System.out.println("这是父类中的show方法");} }class Zi extends Fu{ // @Override // public void show(){ // System.out.println("这是子类中的show方法"); // }}public class ZiDemo {public static void main(String[] args) {Zi zi = new Zi();zi.show();} }
多态:
多态:某一事物,在不同时刻表现出来的不同状态
举例:
水:
固态、液态、气态
固态的水是水、液态的水也是水、气态的水也是水
水果:
波罗蜜、香蕉、榴莲
波罗蜜是水果、香蕉是水果、榴莲是水果
水果是波罗蜜。// 反过来说是有问题的
动物:
狗、虎、猫、大象
狗是动物,这么说是没问题的
动物是狗,这么说是不可以。
通过观察例子发现,要想有多态,就必须要继承,继承是多态的前提。
多态的前提:
要有继承关系
要有方法的重写
其实没有重写也是可以的,但是不重写就没有意义
动物都有吃这个方法,但是每个具体的动物吃的实现不一样,变现出不同动物的特有属性
要有父类的引用指向子类的对象
父类名 f = new 子类名(...);
多态访问成员的特点:
1、成员变量
编译看左,运行看左
2、构造方法
创建子类对象的时候,先访问父类中的构造方法,对父类的数据先进行初始化
3、成员方法
编译看左,运行看右。
因为成员方法存在重写,所以访问看右边
4、静态成员方法
编译看左,运行也看左。
由于被static修饰的成员都是与类相关的,这里不是重写,所以运行的时候,访问的还是左边的。
class Fu3{int num=100;public void show(){System.out.println("这是父类中的show()f方法");}public static void fun(){System.out.println("这是父类中的静态fun()方法");} } class Zi3 extends Fu3{int num=1000;@Overridepublic void show() {System.out.println("这是子类中的show()方法");}public void show2() {System.out.println("这是子类中的特有方法");}public static void fun() {System.out.println("这是子类中的静态fun()方法");}} public class PolymorphicDemo {public static void main(String[] args) {Fu3 fu3=new Zi3();System.out.println(fu3.num);fu3.show();// 这是子类中的show()方法fu3.fun();//这是父类里的静态方法} }
class Father{public void show(){System.out.println("这是父类的show方法");} } class Son extends Father{@Overridepublic void show() {System.out.println("这是子类里的show方法");}public void show2() {System.out.println("这是子类里特有的show方法");}} public class PolymorphicDemo2 {public static void main(String[] args) {Father father=new Son();father.show();//需求:我现在就想调用父类中的show方法,怎么办?} }
多态的弊端:
多态无法访问父类中的方法名一样的方法
1、我就想使用父类中的方法,能不能用,能。不使用多态
2、如果我想使用子类中的特有方法,还必须使用多态,咋办?
1)就不使用多态,创建子类对象然后调用方法
但是在我上一个例子上,再次创建对象,还会在堆内存中开辟空间,很有可能会造成资源浪费
2、将子类看成一个小的类型,将父类看成一个大的类型,现在想要用小的类型中的方法
我们应该要将大的类型转成小的类型。在我们之前的做法是用强制类型转换。
如果在继承关系,也有类似的这样的做法就好了。
java替我们考虑到这样的问题,提供了一个技术给我们使用:向下转型
将父类的引用强制转换成子类的引用
子类类名 变量名 = (子类类名)父类的引用;
对象之间转型的问题:
1、向上转型:
Fu f = new Son();
2、向下转型
Son s = (Son)f;
int a = 10;
byte b = (byte)a;
向下转型需要注意的一个问题:
要求转型的类与父类引用存在继承关系,并且一开始创建多态的时候,使用的是该类。
关键字abstract,它可以修饰类,方法
1、抽象类中可以没有抽象方法,但是有抽象方法的类一定是抽象类
2、抽象类不能被实例化
3、要想实例化抽象类,必须用一个具体的子类继承它
注意:具体的子类继承抽象类,必须重写该抽象类中的所有的抽象方法
4、最终以抽象多态的形式进行实例化。
class Father2{public void show(){System.out.println("这是父类中的show方法");} } class Son2 extends Father2{@Overridepublic void show() {System.out.println("这是子类中的show方法");}public void show2() {System.out.println("这是子类中的特殊show方法");}} public class PolymorphicDemo3 {public static void main(String[] args) {Father2 father=new Son2();//father.show2();//这里不能直接调用show2()因为父类里没有show2()无法编译Son2 s=(Son2) father;s.show2();s.show();}}
实例:
动物之猫和狗
class Animal2{public void eat(){System.out.println("吃");} } class Dog extends Animal2{@Overridepublic void eat() {System.out.println("狗吃肉");}public void lookDoor(){System.out.println("看门");} } class Cat extends Animal2{@Overridepublic void eat() {System.out.println("猫吃鱼");}public void catchMouse(){System.out.println("猫捉老鼠");} }public class PolymorphicDemo4 {public static void main(String[] args) {Animal2 animal2=new Dog();animal2.eat();Dog d=(Dog) animal2;d.eat();d.lookDoor();Animal2 animal21=new Cat();animal21.eat();Cat c=(Cat) animal21;animal21.eat();((Cat) animal21).catchMouse();} }
不同地方饮食文化不同的案例
Person
eat()
SouthPerson
eat()
NorthPerson
eat()
class Person {public void eat() {System.out.println("吃");} }class SouthPerson extends Person {@Overridepublic void eat() {System.out.println("南方人吃米饭");}public void playMaJiang() {System.out.println("南方人打麻将");} }class NorthPerson extends Person {@Overridepublic void eat() {System.out.println("北方人吃面食");}public void bath() {System.out.println("北方人搓澡");} }public class PolymorphicDemo5 {public static void main(String[] args) {Person person = new SouthPerson();person.eat();SouthPerson s = (SouthPerson) person;s.eat();s.playMaJiang();Person person1 = new NorthPerson();person1.eat();NorthPerson n = (NorthPerson) person1;n.bath();n.eat();} }
多态的好处有哪些?
1、多态可以使代码的扩展性很好(这是由继承所保证的)
2、多态可以使代码的维护性很好(这是由多态保证的)
class Animal {String name;int age;Animal() {}public Animal(String name, int age) {this.name = name;this.age = age;}public void sleep() {System.out.println("睡觉");}public void eat() {System.out.println("吃");} }class Dog1 extends Animal {public Dog1() {}public Dog1(String name, int age) {this.name = name;this.age = age;}@Overridepublic void eat() {System.out.println("狗吃肉");}@Overridepublic void sleep() {System.out.println("狗卷着睡");} }class Cat1 extends Animal {public Cat1() {}public Cat1(String name, int age) {this.name = name;this.age = age;}@Overridepublic void eat() {System.out.println("猫吃鱼");}@Overridepublic void sleep() {System.out.println("猫趴着睡");}}class AnimalTool {//工具类private AnimalTool() {}public static void useDog(Dog1 dog1) {dog1.sleep();dog1.eat();}public static void useCat(Cat1 cat1) {cat1.sleep();cat1.eat();}public static void useAnimal(Animal animal) {animal.eat();animal.sleep();} }public class CatDogDemo {public static void main(String[] args) {System.out.println("=====第二种通过下面创建方法调用=====");//第一种方法调用子类Dog1 dog1 = new Dog1("小白哦", 2);dog1.eat();dog1.sleep();Cat1 cat1 = new Cat1("小号", 3);cat1.eat();cat1.sleep();System.out.println("=====第二种通过下面创建方法调用=====");//第二种通过下面创建方法调用Dog1 d1 = new Dog1("小白", 2);useDog(d1);Cat1 c1 = new Cat1("小红", 2);useCat(c1);System.out.println("====第三种通过工具类调用=====");//第三种通过工具类调用Dog1 d2 = new Dog1("小白", 2);AnimalTool.useDog(d2);Cat1 c2 = new Cat1("小红", 2);AnimalTool.useCat(c2);//这里注意工具类是私有的不可直接调用use方法//工具类里的内容是私有的不好改动System.out.println("=====用多态改进=====");Animal a1 = new Dog1("小白",2);AnimalTool.useAnimal(a1);Animal a2 = new Cat1("小红",2);AnimalTool.useAnimal(a2);}public static void useDog(Dog1 dog1) {//创建方法调用dog1.sleep();dog1.eat();}public static void useCat(Cat1 cat1) {cat1.sleep();cat1.eat();} }
抽象的表述:
之前所说的猫,狗,猪,熊猫,老虎等等都是动物具体的例子,而动物本身是一个抽象的概念 但是回想一下我们之前都是将动物写成了一个具体的,而类又可以创建对象,但是实际上抽象的东西本身应该不能被实例化.
并且动物中吃的方法应该也不是一个具体的实现,以及所有动物共同拥有的方法在动物中应该都是抽象的表现
今天之后,把一个不具体的功能,叫做抽象方法,而如果一个类中有抽象方法,我们就把这个类称之为抽象类。
抽象类的特点:
1、抽象类和抽象方法都要用一个关键字修饰:abstract
修饰一个类 放在class的前面
举例: abstract class Animal3{}
修饰一个方法 一般是放在权限修饰符后面
定义一个抽象的show方法
举例:public abstract void show();
2、有抽象方法的类一定要是抽象类,抽象类不一定要有抽象方法,具体的类中不能有抽象方法,抽象类中既可以存在抽象方法
也可以存在有方法体的方法。
3、抽象类不能被实例化
既然不能被实例化,那写在抽象类中的方法如何被调用呢?
抽象类如何创建呢?
通过多态的形式,使用具体的子类去实例化调用方法,专业术语称之为:抽象多态
4、如果继承抽象类的是一个具体的子类,需要重写该抽象类中所有的抽象方法
如果继承抽象的也是一个抽象类,可以不去重写父类中的抽象方法,也可以选择性的去重写。
abstract class Animal3 {//注意://抽象方法没有方法体{},连大括号都没有,直接以分号结尾//java: 抽象方法不能有主体public abstract void eat();public abstract void drink(); }class Dog3 extends Animal3 {@Overridepublic void eat() {System.out.println("狗吃肉");}@Overridepublic void drink() {System.out.println("狗喝水");} }abstract class Demo2 {public abstract void fun();public abstract void fun2(); }abstract class Demo3 extends Demo2 {@Overridepublic void fun() {System.out.println("抽象类Demo3中重写了fun方法");}@Overridepublic void fun2() {System.out.println("抽象类Demo3中重写了fun2方法");} }public class AbstractDemo1 {public static void main(String[] args) { // Demo2 demo2=new Demo2(); //java: com.shujia.wyh.day11.Demo2是抽象的; 无法实例化//利用具体子类多态形式创建对象//抽象多态的形式Animal3 animal3 = new Dog3();animal3.drink();animal3.eat();//Demo2 demo2= new Demo2() //都是抽象无法调用} }
抽象类的成员的特点:
成员变量:
既可以是变量,也可以是常量
构造方法:
可以存在构造方法,上一个程序中总结出抽象类不能被实例化,这里构造方法意义是什么?
之前在继承中要想初始化子类,必须先初始化父类,所以这里构造方法是提供初始化父类的作用
成员方法:
可以是抽象方法,但是具体的子类必须要重写该方法
也可以不是抽象方法,提高代码的复用性。
abstract class Animal4 {int a = 100;final int b = 20;Animal4() {System.out.println("这是Animal4中无参构造方法");//即使不去定义也会存在}public abstract void eat();public void show() {System.out.println("父类中不是抽象方法的show");} } class Cat4 extends Animal4{@Overridepublic void eat() {System.out.println("猫吃鱼");} } public class AbstractDemo2 {public static void main(String[] args) {Animal4 a = new Cat4();System.out.println(a.a);System.out.println(a.b);a.eat();a.show();} }
不写抽象方法,也是可以的。
1、抽象类中可以没有抽象方法
2、抽象类不能被实例
抽象类中可以存在哪些关键字?
abstract关键字不能和哪些关键字共存?
private
static
final
abstract class YeTi{ // YeTi(){ // super(); // }//不会报错因为所有的类都有一个共同的父类:object //abstract可以和public关键字共存 public abstract void show();//private和abstract关键字冲突 //private abstract void show2(); java: 非法的修饰符组合: abstract和private//static和abstract关键字冲突 // static abstract void show3(); // java: 非法的修饰符组合: abstract和static//final和abstract关键字冲突 // final abstract void show4(); // java: 非法的修饰符组合: abstract和final} public class AbstractDemo3 {public static void main(String[] args) {} }
抽象类改进猫狗案例
abstract class Animal5{public abstract void eat();public abstract void sleep();} class Dog5 extends Animal5 {@Overridepublic void eat() {System.out.println("狗吃肉");}@Overridepublic void sleep() {System.out.println("狗圈着睡");}public void play(){System.out.println("狗和狗玩");} } class Cat5 extends Animal5{@Overridepublic void eat() {System.out.println("猫吃鱼");}@Overridepublic void sleep() {System.out.println("猫趴着睡");}public void play(){System.out.println("猫和猫玩");} } public class AbstractTest1 {public static void main(String[] args) {Animal5 animal5=new Dog5();animal5.eat();animal5.sleep();Dog5 dog5=(Dog5) animal5;dog5.play();Animal5 animal51=new Cat5();animal51.sleep();animal51.eat();Cat5 cat5=(Cat5) animal51;cat5.play();} }
假如我们在开发一个系统时需要对员工类进行设计,员工包含3个属性:姓名、工号以及工资。
经理也是员工,除了含有员工的属性外,另为还有一个奖金属性。
请使用继承的思想设计出员工类和经理类。要求类中提供必要的方法进行属性访问。
分析:
普通员工:
成员变量:姓名,工号,工资
成员方法:工作(敲代码)
经理
成员变量:姓名,工号,工资,奖金
成员方法:工作(做PPT)
abstract class Stuff{private String name;private String id;private int salary;public Stuff(){}public Stuff(String name,String id,int salary){this.id=id;this.name=name;this.salary=salary;}public void setName(String name) {this.name = name;}public void setId(String id) {this.id = id;}public void setSalary(int salary) {this.salary = salary;}public String getName() {return name;}public String getId() {return id;}public int getSalary() {return salary;}public abstract void work(); } class CommonStaff extends Stuff{public CommonStaff(){}public CommonStaff(String name, String id, int salary) {super(name, id, salary);}@Overridepublic void work() {System.out.println("敲代码");} } class Manager extends Stuff{//特有的属性 奖金private int bonus;public Manager(int bonus) {this.bonus = bonus;}public Manager(String name, String id, int salary, int bonus) {super(name, id, salary);this.bonus = bonus;}@Overridepublic void work() {System.out.println("做PPT");} }public class AbstractTest4 {public static void main(String[] args) {//创建第一个对象Stuff s1 = new CommonStaff("小虎","KZ0080",100000);s1.work();//创建第二个对象Stuff s2 = new Manager("小明","SJ00030",200000,1000000);s2.work();} }
更多推荐
第十天多态继承补充和final
发布评论