✨✨✨学习的道路很枯燥,希望我们能并肩走下来!
编程真是一件很奇妙的东西。你只是浅尝辄止,那么只会觉得枯燥乏味,像对待任务似的应付它。但你如果深入探索,就会发现其中的奇妙,了解许多所不知道的原理。知识的力量让你沉醉,甘愿深陷其中并发现宝藏。
本篇是对继承的介绍,super的使用与this的区别,final关键字,继承方式的讲解和多态的实现,重写,向上/下转型等。如有错误,请在评论区指正,让我们一起交流,共同进步!
本文开始
继承:用于对共性进行抽取,实现代码的复用。
继承机制:允许程序员在保持原有类特性的基础上进行拓展,增加新的功能。这样产生类称为派生、子类。原有的类称为父类,基类,超类。
使用extends关键字
修饰符 class 子类 extends 父类 {
}
1.子类会将父类中的成员变量或者成员方法继承到子类中了
2. 子类继承父类之后,必须要新添加自己特有的成员,体现出与父(基类的不同,否则就没有必要继承了
1.子类和父类不存在同名方法
class Base {int a = 1;int b;
}
class Derived extends Base {int c;public void func() {System.out.println(a);//访问继承父类的aSystem.out.println(c);//访问子类自己的c}
}
2.子类和父类成员变量同名
class Base {int a;int b;int c = 9;
}
class Derived extends Base {int c = 10;public void func() {System.out.println(a);System.out.println(b);System.out.println(c);//System.out.println(d);//报错,子类父类都没有定义}
}
子类和父类有同名变量,依照就近原则,先使用子类自己的变量,子类没有在找父类的变量!
【注】在子类方法(对象)中,访问成员:
1.访问成员变量子类中有,就先访问子类自己的
2.访问成员变量子类中无,就先访问父类的,父类没有,就报错
3.访问成员变量父类子类同名的成员变量,就先访问子类自己的
1.子类和父类成员方法名相同
class Base {public void methodBase() {System.out.println("Base里的methodBase()");}
}
class Derived extends Base {public void menthodBase() {System.out.println("Derived里的menthodBase()");}
}
2.子类和父类成员方法名不同
优先访问自己的成员方法,自己没有时再到父类中找,如果父类中也没有则报错。
class Base {int a;int b;int c = 9;public void methodBase() {System.out.println("Base里的methodBase()");}
}
class Derived extends Base {int c = 10;public void methodDerived() {System.out.println("Derived()");}
}
【小结:】
1.子类对象访问父类与子类的 同名方法,根据调用方法传递参数列表选择访问(重载),没有则报错
2.子类对象访问父类与子类的 不同名方法时,优先在子类中找,找不到,在父类找,找到访问,找不到报错
super作用 : 子类和父类中存在相同的成员时,使用super,super可以在子类方法中访问父类的成员。
super调用在子类中调用了父类的成员变量和方法
class Base {int a;int b;int c = 9;public void methodBase() {System.out.println("Base里的methodBase()");}
}
class Derived extends Base {int c = 10;public void methodBase() {System.out.println("Derived里的menthodBase()");super.methodBase();}public void func() {System.out.println("Derived中的 c = " + c);System.out.println("Base中的 c = " + super.c);}
}
代码结果:
【注】
1.在子类方法中,如果想要明确访问父类中成员时,借助super关键字
2.只能在非静态方法中使用
this,super不同点:
1.this是当前对象的引用,当前对象即调用实例方法的对象;super相当于是子类对象中从父类继承下来部分成
员的引用
2. 在非静态成员方法中,this用来访问本类的方法和属性,super用来访问父类继承下来的方法和属性
3. 在构造方法中:this(…)用于调用本类构造方法,super(…)用于调用父类构造方法,两种调用不能同时在构造方法中出现
4.构造方法中一定会存在super()的调用,用户没有写编译器也会增加,但是this()用户不写则没有
super,this相同点:
1.只能在类的非静态方法中使用,用来访问非静态成员方法和字段
2.在构造方法中调用时,必须是构造方法中的第一条语句,并且不能同时存在
子类对象构造时,需要先调用父类构造方法,然后执行子类的构造方法。(先构造父类,在构造子类)
1.父类定义无参构造方法或默认构造方法,在子类构造方法中第一行默认含有super()调用;(父类或者子类不写构造方法,默认父类子类无参构造)
class A {public A() {System.out.println("A的无参构造");}
}
class B extends A{public B() {super();//调用父类无参构造System.out.println("B的无参构造");}
}
public class Test {public static void main(String[] args) {new B();}
}
代码结果:
2.如果父类含有带参数的构造方法,此时子类构造需要选择合适的父类构造方法调用;(父类如果写了含参数的构造方法,则就没有无参的构造方法,如果需要用需要自己写无参构造)
3.在子类构造方法中,super()调用父类构造,必须是子类构造函数中的第一条语句;
4.super()只能在子类构造方法中出现一次,并且不能和this同时使用;(this(),super()在构造方法中都必须在第一行,所有不能共存)
1.单继承:
B =》A
class A {
...
}
class B extends A{
}
2.多层继承
C =》B =》A
class A {
....
}
class B extends A{
....
}
class C extends B {....
}
3.不同类继承同一个类
同一包中不同java文件中
public class A {
}
public class B extends A {
}
public class C extends A {
}
4.多继承(不支持)=》err
JAVA中不支持多继承
public class A {
}
public class B {
}
public class C extends A,B {
}
1.final 修饰变量或字段,表示常量(不能修改)
final int a = 10;a = 20;
2.final 修饰类:表示类不能被继承
final public class A {
}
//err
public class B extends A {
}
3.final 修饰方法:不能被重写
组合:仅仅将一个类的示例作为另一个类的字段,为了达到代码的重用
继承:表示对象之间是 is-a 的关系,比如:狗是动物,猫是动物
组合:表示对象之间是 has-a 的关系,比如:学校作为类,学生和老师都是学校里的示例字段
class Stduent {
...
}
class Teacher {
...
}
class School {Stduent[] stduents = new Stduent[3];Teacher[] teachers = new Teacher[3];
}
public class TestDemo {public static void main(String[] args) {School school = new School();}
}
多态 :为了完成某个行为,不同的对象去完成时会产生不同的状态。(同一件事,发生在不同对象上,会产生不同的结果)
例如:动物吃东西
狗吃狗粮,鸟吃鸟粮,鱼吃鱼粮。同样是吃饭的行为,但他们吃的什么却不同。
Java实现多态的条件:
- 必须在继承体系下(子类继承父类)
- 子类必须要对父类中方法进行重写
- 通过父类的引用 , 调用重写的方法
多态示例图示:
多态体现:在代码运行时,当传递不同类对象时,会调用对应类中的方法。
发生重写,子类发生不同的状态,7吃狗粮, qq吃鸟粮
我们下面讲解为什么重写后会调用子类的重写的eat()方法,为什么不调用父类的?
重写(override):也称为覆盖。即外壳不变,核心重写! 也就是说子类能够根据需要实现父类的方法。
重写是子类对 ①父类非静态、②非private修饰,③非final修饰,④非构造方法等的实现过程进行重新编写, 返回值和形参都不能改变。
被final修饰的方法称为密封方法。
重写规则:
发生动态绑定:编译的时候不确定,在从重写的时候,调用子类的重写方法
静态绑定: 重载,编译的时候已经确定调用那个方法
问题1:为什么重写后会调用子类的重写的eat()方法,为什么不调用父类的?
这是因为在重写的时候会发生动态绑定,会在程序运行的时候,帮我们调用了重写的方法。
问题2:为什么不是编译的时候调用子类的重写方法呢?
我们可以通过class字节码文件来看一下
找到字节码文件,通过命令行打开,输入:javap - c 文件名
通过查看字节码文件可知,编译时调用的还是父类的eat()方法。
向上转型:父类对象引用子类的对象
语法格式:父类类型 对象名 = new 子类类型();
向上转型缺点:不能调用子类特有的方法
三种使用:
1.直接赋值
Animal animal = new Dog();
public static void main(String[] args) {Animal animal = new Dog();//animal这个引用只能引用Animal这个类里面的方法//发生向上转型后:父类的引用只能访问父类自己的成员。不能访问到子类特有的成员//相对于子类访问的范围更大一些animal.name = " 7 ";animal.eat();//animal.wang();不能访问子类的方法Animal animal1 = new Bird();//向上转型。前提: Bird继承Animalanimal1.name = "qq";animal1.eat();}
2.方法传参
func(dog)
public static void func(Animal animal) {//方法传参}public static void main(String[] args) {Dog dog = new Dog();func(dog);}
3.返回值
Animal animal = func2();
public static Animal func2() {//返回值return new Dog();}
向下转型:为了调用子类特有的方法,我们可以将父类引用还原为子类对象
public static void main(String[] args) {Animal animal = new Dog();//向下转型:不安全System.out.println("=========");Bird bird = (Bird) animal;bird.fly();}
向下转型不安全,编译没问题,但是运行时会报错
代码修改:
public static void main(String[] args) {Animal animal = new Dog();//向下转型:不安全,需要判断使用关键字instanceof//父类的类型给到子类Dog dog = (Dog) animal;dog.name = "7";dog.wang();System.out.println("=========");if(animal instanceof Bird) {//判断animal是不是引用了Bird的对象Bird bird = (Bird) animal;bird.fly();}}
判断后结果就不会报错了
class B {public B() {
// do nothingfunc();}public void func() {System.out.println("B.func()");}
}
class D extends B {private int num = 1;@Overridepublic void func() {System.out.println("D.func() " + num);}
}
public class TestDemo {public static void main(String[] args) {D d = new D();}
}
代码结果:
结果可知:
num值为0,并没有赋值为1,这是因为在构造器中调用方法所导致的;
代码执行过程:
1.构造D对象的同时调用B构造方法
2.B 的构造方法调用func()方法,此时会触发动态绑定,会调用D中的func()
3.此时D 对象自身还没有构造,此时num处于为初始化状态,值默认0,如果具备多态性,num的值应该是1
【注】尽量不要在构造器中调用方法!!!
当在父类的构造方法当中,去调用父类和子类重写的方法的时候,会发生动态内存绑定,会调用子类重写的同名方法,而产生问题!
✨✨✨各位读友,本篇分享到内容如果对你有帮助给个👍赞鼓励一下吧!!
感谢每一位一起走到这的伙伴,我们可以一起交流进步!!!一起加油吧!!!