文章目录
继承
什么是继承
什么是继承呢?在面向对象的特性中我们知道面向对象有三大特性。
- 继承
*封装
*多态
那么今天我们要讲的就是继承和多态,什么是继承呢?举一个现实中的例子,我们在未来会身为儿女继承家庭未来的资产,那么在计算机层面上也是一样的身为子类会继承父类的属性和方法等。
继承(inheritance)机制:是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特 性
的基础上进行扩展,增加新功能,这样产生新的类,称派生类。继承呈现了面向对象程序设计的层次结构, 体现了
由简单到复杂的认知过程。继承主要解决的问题是:共性的抽取,实现代码复用。
举个例子就是比如说我们创建了一个动物类这个类里面呢我们创建了两个变量分别是name和age然后呢创建了一个dog类这个类里面我们写了一个方法叫做call,其余的我们就不写了,然后这个dog类继承了动物类,那么即使这个dog没有写name和age这两个变量也依然拥有这两个变量。
为什么要继承
为什么要继承呢?同过上面的例子我们很清楚的发现继承使得我们的代码可以复用也就是说这个类的代码我们可以直接让自己的子类使用,在现实中的例子就是你的父亲给你留下了一套房子那你自己是不是就可以不用买房子了。压力就小了。这就是继承的作用。
继承的语法
那么我们的继承是怎么实现的呢?下面就以动物类和dog类为例来写一下代码
class Animal{
public int age;
public String name;
}
class Dog extends Animal{
public void call(){
System.out.println(name+"已经"+age+"岁了正在"+"汪汪叫");
}
}
public class test {
public static void main(String[] args) {
Dog d=new Dog();
d.age=18;
d.name="zzz";
d.call();
}
}
运行上面的代码最终的结果是什么呢?
那么从这个代码我们可以看出来继承的语法如下
class SonClass_name extends FatherClass_name{
//...代码内容.
}
那么继承的语法就是上面那般了我们也发现确实子类继承父类即便子类中我们没有定义name和age我们依旧可以使用这两个变量。
继承中子类和父类的关系
那么讲完了上面这些有些同学就有疑惑那么继承中子类和父类究竟是什么关系呢?就是子类获得了父类的内容在内存上是子类包含了父类还是说把父类的代码和内容重新复制了一份放在了子类中呢?那么下面这张图片能回答你的疑惑
因此其实在内存上你可以看做子类包含了父类,就像你继承了你父亲的一套房子那么这个房子严格来说是你父亲本来就有的而不是他又给你弄了一个一模一样的。其实也就是说当你继承你家长的财产之后你的实际财产等于你自己本身的加上从父母那里继承来的,那么有些同学可能会有疑惑那假如说我的变量是private修饰的呢?这个我们下面来说
子类对父类属性方法的访问和拥有
有些同学会有疑惑那就是假如说我父类的方法是private修饰的呢?就像下面这个代码块
class Animal{
private int age;
public String name;
}
class Dog extends Animal{
public void call(){
System.out.println(name+"已经"+age+"岁了正在"+"汪汪叫");
}
}
public class test {
public static void main(String[] args) {
Dog d=new Dog();
d.age=18;//这里是会报错的!!!
d.name="zzz";
d.call();
}
}
也就是把上面的代码中的age改成private之后你的子类还能使用吗?很明显是不能的。然后有些同学可能就会认为,子类只继承了父类中被public修饰的元素其实并不是这样的,他其实也是继承了被private修饰的元素了但只是无法使用而已,继承中子类是继承父类的全部的,但是由于被private修饰的元素只允许父类自己使用,哪怕是子类也不能使用,因此private修饰的方法和变量是被子类继承但是无法使用而已。
子类的构造
那么讲完继承的基本结构之后我们开始来讲一下继承之后的子类是如何完成自身的构造的,我们刚刚上面画了一张图如果子类继承了父类那么子类特有+父类=子类那么在构造的时候会怎么构造呢?在构造的时候我们的构造顺序是先完成父类的构造再完成子类的构造当然了也有特殊情况这里我直接给大家把构造的顺序说清楚以免后期的学习困难。
class Person {
public String name;
public int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
System.out.println("Person:构造方法执行");
}
{
System.out.println("Person:实例代码块执行");
}
static {
System.out.println("Person:静态代码块执行");
}
}
class Student extends Person{
public Student(String name,int age) {
super(name,age);
System.out.println("Student:构造方法执行");
}
{
System.out.println("Student:实例代码块执行");
}
static {
System.out.println("Student:静态代码块执行");
}
}
public class TestDemo4 {
public static void main(String[] args) {
Student student1 = new Student("张三",19);
System.out.println("===========================");
Student student2 = new Student("gaobo",20);
}
public static void main1(String[] args) {
Person person1 = new Person("bit",10);
System.out.println("============================");
Person person2 = new Person("gaobo",20);
}
}
那么关于上面的代码中呢我们先说一些语法基础首先就是
super关键字
上面的super是什么,我们刚刚讲过继承之后子类可以访问父类中的非private元素那么关于访问的话我们就有几个问题首先第一个
第一个:父类中和子类元素同名的怎么访问
*答案是优先访问子类的。
第二个:如果我偏要访问父类中的元素怎么办?
*答案是利用super关键字
那么现在关于上面的代码大家应该就懂了super其实就是用来访问父类的元素的。
super和this
super和this都可以在成员方法中用来访问:成员变量和调用其他的成员函数,都可以作为构造方法的第一条语
句,那他们之间有什么区别呢?
【相同点】
- 都是Java中的关键字
- 只能在类的非静态方法中使用,用来访问非静态成员方法和字段
- 在构造方法中调用时,必须是构造方法中的第一条语句,并且不能同时存在
【不同点】
- this是当前对象的引用,当前对象即调用实例方法的对象,super相当于是子类对象中从父类继承下来部分成
员的引用
- 在非静态成员方法中,this用来访问本类的方法和属性,super用来访问父类继承下来的方法和属性
- 在构造方法中:this(…)用于调用本类构造方法,super(…)用于调用父类构造方法,两种调用不能同时在构造
方法中出现 - 构造方法中一定会存在super(…)的调用,用户没有写编译器也会增加,但是this(…)用户不写则没有
子类构造的代码运行结果
Person:静态代码块执行
Student:静态代码块执行
Person:实例代码块执行
Person:构造方法执行
Student:实例代码块执行
Student:构造方法执行
===========================
Person:实例代码块执行
Person:构造方法执行
Student:实例代码块执行
Student:构造方法执行
那么根据上面的代码运行结果我们可以看出来运行的顺序就是
父类的静态>子类的静态>父类的实例代码>父类的构造方法>子类的实例代码>子类的构造方法
抽象类
那么上面的说完了之后我们来讲一下什么是抽象类,为什么放到继承这里说什么是抽象类呢?那且听我娓娓道来,首先最直观的特征是什么呢?抽象类会有一个关键字叫做abstract来做修饰如下
abstract class Animal {
// 抽象方法
abstract void makeSound();
// 具体方法
void sleep() {
System.out.println("Animal is sleeping");
}
}
此时我们就命名了一个抽象类,那么有抽象类就肯定也有抽象方法抽象方法也就像上面写的代码一样,被abstract修饰的方法那么这些抽象类抽象方法都有什么别的特点和不同之处呢?
抽象类和普通类
- 首先就是最大不同那就是抽象类是不能被实例化的也就是说抽象类没法去实例化出一个对象,哪有人可能会有疑问抽象类的作用是什么?其实抽象类的作用主要就是为了被作为父类被继承的。
- 其次抽象类是可以包含抽象方法或者具体的方法的。抽象方法就是上面那个代码块那样被abstract修饰并且没有具体实现的方法
- 抽象类被普通类继承的时候子类必须实现其所有的抽象方法
- 可以拥有构造方法和成员变量,因为我们上面讲了子类的实例化需要先调用父类的构造函数,因此虽然抽象类不能被实例化但是子类被实例化的时候依然需要抽象类的构造。另外普通类是不能包含抽象方法的。
final关键字
接下来讲述一下final关键字
final修饰类
修饰类:在类声明前加上 final 关键字可以使该类变为最终类,也就是说不能被继承。被 final 修饰的类不能有子类。例如
final class FinalClass {
// 类的内容
}
final修饰方法
修饰方法:在方法声明前加上 final 关键字可以使该方法变为最终方法,也就是说不能被子类重写。被 final 修饰的方法不能被子类覆盖或重写。例如:
class MyClass {
final void finalMethod() {
// 方法的内容
}
}
final修饰变量
修饰变量(字段):在成员变量声明前加上 final 关键字可以使该变量成为常量,一旦赋值后就不能再修改。常量一般使用大写字母命名。例如:
class MyClass {
final int MY_CONSTANT = 10;
}
继承与组合
多态
什么是多态
多态指的其实就是多种形态可以简单理解为,不同任务做同一件事情时会表现出不同的行为状态就像买火车票,学生,军人,普通成年人。他们去做购票这个相同的事情的时候会产生不同结果(购买票的价格不同)再举个例子同样是叫但是猫的话是喵喵,狗确实汪汪,因此狗和猫在做同样的一个事情的时候会产生不同的结果这个其实也是多态。
多态的条件
多态的条件有以下几个:
- 必须在继承体系下
- 子类必须要对父类中方法进行重写
- 通过父类的引用调用重写的方法
给大家写一个代码块举一个例子
class Animal{
public int age=18;
public String name="zzz";
public void call(){
}
}
class Dog extends Animal{
public void call(){
System.out.println(name+"已经"+age+"岁了正在"+"汪汪叫");
}
}
class Cat extends Animal{
public void call(){
System.out.println(name+"已经"+age+"岁了正在"+"喵喵叫");
}
}
public class test {
public static void main(String[] args) {
Animal d=new Dog();
Animal c=new Cat();
d.call();
c.call();
}
}
如上述代码块狗和猫做的是同一个行为但是调用的时候产生的结果不一样
重写
那么关于上面之后还有一个问题就是什么是重写呢?
在面向对象编程中,重写(Override)是指子类定义一个与父类中同名、参数列表相同,但实现不同的方法的过程。当子类重写了父类的方法时,子类中的方法会覆盖父类中的同名方法,从而在子类实例调用该方法时,实际上调用的是子类中的方法,而不是父类中的方法。
重写方法通常用于子类需要提供自己特定的实现,覆盖父类中的默认实现。这样可以在不改变原有类层次结构的情况下,为子类添加特定行为。
重写方法需要满足以下几个条件:
- 方法名与父类中被重写的方法名相同。
- 方法参数列表与父类中被重写的方法的参数列表相同。
- 访问权限不能比父类中被重写的方法的访问权限更低。可以更高,比如父类中的方法是public,子类中的方法可以是public或protected。
- 返回类型和异常类型可以不同,但是子类返回的类型必须是父类返回类型的子类型。
向上转型和向下转型
向上转型(Upcasting):向上转型是指将子类的对象引用转换为父类的对象引用。在向上转型中,子类对象可以被赋值给父类引用变量,这样做是安全的,因为子类是父类的一个特殊类型。向上转型是自动的,无需显式的类型转换。
Parent parent = new Child(); // 将 Child 对象向上转型为 Parent 对象
向下转型(Downcasting):向下转型是指将父类的对象引用转换为子类的对象引用。在向下转型中,父类引用变量指向的对象必须是子类对象,否则会在运行时抛出 ClassCastException 异常。向下转型需要显式的类型转换。
Child child = (Child) parent; // 将 Parent 对象向下转型为 Child 对象
我们一定不会分开