从零开始学Java-面向对象进阶(一)

182 阅读13分钟

前几篇文章中我们学习了面向对象的一些基础知识,下面我们来学一下进阶的面向对象!

目录

  • static关键字
  • 继承
  • this、super总结

static

  • 什么是static:

    • static关键字:表示静态的,是Java中的一个修饰符,可以修饰成员方法,也可以是成员变量
    • 被static修饰的成员变量, 叫做静态变量
    • 被static修饰的成员方法,叫做静态方法
  • 静态变量的特点:

    • 特点:

      被该类所有对象共享。(所有的对象都共用同一个值)

      不属于对象,属于类。

      随着类的加载而加载,优先于对象存在

    • 调用:

      类名调用: static.teacherName = "值";对象名调用 (不常用)

  • 静态方法的特点:

    • 特点:

      多用在测试类和工具类中

      JavaBean类中很少会用

    • 调用:

      类名调用: ArrayUtil.printArrr(arr);对象名调用 (不常用)

  • JavaBean类:用来描述一类事物的类。

  • 测试类:用来检查其他类是否书写正确的类,带有main方法的类,是程序的人口。

  • 工具类:可以帮助我们做一些事情的,但是不描述任何事物的类。

前面我们接触了不少的测试类和JavaBean类,下面我们来学一下工具类吧:

  • 注意:

    • 需要创建私有化构造方法。目的为了不让外界创建他的对象。
    • 方法定义为静态。

    例如:

    image.png

    下面我们来实操一下吧:

    • 定义学生工具类

    需求:定义一个集合,用于存储3个学生对象。 学生类的属性为:name,age,gender。 定义一个工具类,用于获取集合中最大学生的年龄。

    首先定义学生的JavaBean类:

    private String name;
    private int age;
    private String gender;
    

    然后创建一个测试类并创建一个集合:

    // 1.创建集合用来存储学生对象
    ArrayList<Student> list = new ArrayList<>();
    

    创建3个学生对象并添加到集合中:

    // 2.创建3个学生对象
    Student stu1 = new Student("张三",19,"男");
    Student stu2 = new Student("李四",18,"女");
    Student stu3 = new Student("王五",120,"男");
    // 3.把学生对象添加到集合当中
    list.add(stu1);
    list.add(stu2);
    list.add(stu3);
    

    接着创建一个工具类:

    // 私有化构造方法
    // 目的:为了不让外界创建它的对象
    private StudentUtil(){}
    

    定义一个求最大值的静态方法

    // 静态方法
    public static int getMaxAgeStudent(ArrayList<Student> list){
        // 1.定义一个参照物,默认0索引的学生年龄最大
        int max = list.get(0).getAge();
        // 2.循环遍历集合
        for (int i = 1; i < list.size(); i++) {
            // i索引 list.get(i)元素/学生对象  我们还需要getAge获取到年龄之后在进行比较
            int tempAge = list.get(i).getAge();
            if(tempAge > max){
                max = tempAge;
            }
        }
        return max;
    }
    

    调用工具类中的方法:

    // 4.调用工具类中的方法
    int maxAgeStudent = StudentUtil.getMaxAgeStudent(list);
    System.out.println(maxAgeStudent);
    

    好啦,我们到这里就写完了,我们来运行看一下吧

    image.png

    怎么样,是不是通过工具类中的方法获取出来了呢!下面我们来说一下static的注意事项吧!

  • static注意事项:

    • 静态方法只能访问静态变量和静态方法

    • 非静态方法可以访问静态变量或者静态方法,也可以访问非静态的成员变量和非静态的成员方法。

    • 静态方法中是没有this关键字的。(this表示当前方法调用者的地址值)

    • 总结一下:

      • 静态方法中只能访问静态。
      • 非静态方法可以访问所有
      • 静态方法中没有this关键字。
    • 静态:是随着类的加载而加载。

    • 非静态:跟对象有关的。

继承

什么是继承

面向对象的三大特征:封装、继承、多态 image.png 封装:对象代表什么,就得封装对应的数据,并提供数据对应的行为。

前面我们学过了封装,下面我们来学一下继承吧!我们先来看一张图片: image.png

这张图片是什么意思呢?其实呀就是定义了三个JavaBean类,而Person类中的属性是Student和Teachar类都需要用到的属性,那么就可以继承给他们两个用,这就是继承。

  • 继承:Java中提供了一个关键字extends,用这个关键字我们可以让一个类和另外一个类建立起继承关系。
  • 例如public class Student extends Person{}
  • Student称为子类,Person称为父类
  • 使用继承的好处:
    • 可以把多个子类中重复的代码抽取到父类中,提高代码的复用性。
    • 子类可以在父类的基础上增加其他的功能,使子类更强大。
  • 使用继承的好处:
    • 可以让子类跟类之间产生子夫关系。
    • 当类与类之间,存在相同的内容,并满足子类是父类中的一种,就可以考虑使用继承来优化代码。
  • 继承的格式:
    • public class 子类 extends 父类{}。
  • 继承后子类的特点:
    • 子类可以得到父类的属性和行为,子类可以使用

下面我们来了解一下继承的特点吧:

继承的特点

  • 继承的特点

    • Java只支持单继承,不支持多继承,但支持多层继承。
    • 单继承:
      • 一个子类只能继承一个父类。
    • 不支持多继承:
      • 子类不能同时继承多个父类。
    • 多层继承:
      • 子类A继承父类B,父类B可以继承父类C。
    • 最大的祖类:
      • 每一个类都直接或者间接的继承于Object

    为什么不能多继承呢?我们来看一个例子:

    父类A:

    image.png

    父类B:

    image.png

    子类:

    image.png 因为子类不知道该用谁,使用就不支持多继承。下面我们来看一张多继承的图片你就明白啦!

    image.png

    那是不是可以一直继承父类呢?其实不是的,间接父类的最大类是Object。我们来看一下Java的继承体系吧!

    image.png

  • 下面我们来总结一下吧:

    1:Java中只能单继承:一个类只能继承一个直接父类。

    2:Java不支持多继承,但是支持多层继承。

    3:Java中所有的类都直接或间接继承于Object类。

    4.子类只能访问父类中非私有的成员

下面我们来实操一下吧:

定义间接父类行为:

// 父类A
public class AnimalParent {
    // 不能加private修饰符
    // 子类只能访问父类中非私有的成员方法
    public void eat(){
        System.out.println("吃东西");
    }

    public void drink(){
        System.out.println("喝水");
    }
}

定义父类行为:

// 父类Dog这个类继承父类A的属性         父类Dog
public class Dog extends AnimalParent {
    public void lookHome(){
        System.out.println("狗在看家");
    }
}

定义子类行为:

// 子类TeddyDog这个类继承父类Dog的属性    泰迪子类
public class TeddyDog extends Dog {
    public void touch(){
        System.out.println("泰迪又在蹭我的腿了!");
    }
}

下面在测试类中调用:

// 2.创建泰迪对象
TeddyDog dog2 = new TeddyDog();
dog2.eat();         // 间接父类A的eat行为
dog2.drink();       // 间接父类A的drink行为
dog2.lookHome();    // 继承父类的lookHome行为
dog2.touch();       // 继承子类的touch行为

我们来运行看一下:

image.png

怎么样,是不是奇葩的知识又增进了一点呢?

子类到底能继承父类中哪些内容

子类到底能继承父类中哪些内容呢?我们来看一张总结图:

image.png

  • 我们来总结一句话吧:
    • 构造方法:父类不管什么修饰符,子类都不能继承
    • 成员变量:父类不管什么修饰符,子类都可以被继承下来但是私有的变量需要用到set和get方法
    • 成员方法:父类的虚方法子类不能继承(有private、static、final都不能),简称私有方法都不能非私有的成员方法子类能继承下来

继承中的特点

继承中:成员变量的访问特点

成员变量的访问特点:采取就近原则:谁离我近我就用谁

先在局部变量去找,局部变量没有会到本类变量位置去找,父类位置去找,逐级往上。

我们来看段代码吧:

public class Test {
    public static void main(String[] args) {
        Zi z = new Zi();
        z.zishow();
    }
}
//创建父类
class Fu{
    String name = "Fu";
}
//创建子类
class Zi extends Fu{
    String name = "Zi";
    public void zishow(){
        String name = "zishow";
        System.out.println(name);           // zishow
        // this表示本类,会从本类变量中去找
        System.out.println(this.name);      // Zi
        // super表示父类,会从父类变量中去找
        System.out.println(super.name);     // Fu
    }
}

继承中:成员方法的访问特点

成员方法的访问特点:直接调用满足采取就近原则:谁离我近我就用谁

public class Test2 {
    public static void main(String[] args) {
        Zi2 z = new Zi2();
        z.zishow();
    }
}
//创建父类
class Fu2 {
    public void eat(){
        System.out.println("吃米饭");
    }
    public void drink(){
        System.out.println("喝开水");
    }
}
//创建子类
class Zi2 extends Fu2 {
    public void zishow(){
        eat();          // 吃米饭
        drink();        // 喝开水
    }
}

成员方法会先在本类中查看eat和drink方法,就会调用子类,如果没有,就会调用父类中继承下来的eat和drink方法。

  • 继承中成员方法的访问特点:
    • this调用:就近原则。
    • super调用:直接找父类。

那这个时候就有个问题了,我的朋友不想吃米饭和喝开水,我的朋友想吃米线和喝饮料怎么办呢?难道要在父类重新定义两个方法来写吗?那不是每次改都要重新定义方法吗?其实不是的,我们可以利用方法重写,那什么是重写呢?我们接着看:

方法重写

  • 什么时候使用方法重写?
    • 当父类的方法不能满足子类的现在需求时,需要进行方法重写
  • 书写格式:
    • 在继承体系中,子类出现了和父类中一模一样的方法声明,我们就称子类这个方法时重写方法。
  • @Override重写注解
    • @Override是放在重写后的方法上,校验子类重写时语法是否正确。
    • 加上注解后如果有红色波浪线,表示语法错误。
    • 建议重写方法都加@Override注解,代码安全,优雅。

那注释其实和注解是一样的,注释是给程序员看的,而注解是给程序员和虚拟机看的,当虚拟机看到@Override的时候就会知道你是重写方法的,他就会检查你重写的方法是否正确,如果错误的话会出现红色波浪线,我们来看一下错误的情况吧:

image.png

当我们的方法名和父类不一样的时候就会看到出现了红色的波浪线,就表示报错了,所以需要注意一定要和父类的方法名一样!

  • 方法书写的注意事项和要求:
    • 重写方法的名称、形参列表必须与父类的一致。
    • 子类重写父类的方法时,访问权限子类必须大于等于父类(暂时了解:空着不写<protected<public)
    • 子类重写父类方法时,返回值类型子类必须小于等于父类。
    • 建议:重写的方法尽量和父类保持一致(建议复制父类的方法)
    • 只有能被添加到虚方法表中的方法才能被重写
  • 方法重写的本质:
    • 覆盖虚方法表中的方法。

继承中:构造方法的特点

  • 构造方法的访问特点:
    • 父类中的构造方法不会被子类继承。因为如果被继承下来子类构造方法的方法名和类名就不一样了。
    • 子类中所有的构造方法默认会先访问父类中的无参构造,在执行自己。
      • 为什么呢?
        • 因为子类在初始化的时候,有可能会使用到父类中的数据,如果父类没有完成初始化,子类将无法使用父类的数据
    • 子类初始化之前,一定要调用父类构造方法先完成父类数据空间的初始化。
  • 怎么调用父类的构造方法:
    • 子类构造方法的第一行语句默认是:super(),不写虚拟机会自动加载且必须在第一行
    • 如果想调用父类的有参构造,必须手动写super进行调用。

下面我们来实操一下吧:

如果不写在第一行就会报错:

image.png

下面我们通过空参构造创建对象:

image.png 下面我们来运行看一下吧:

image.png

是不是父类在子类前面呀!那下面我们想要创建的时候赋值怎么办呢?我们接着看:

image.png

  • 下面我们来说一下构造方法的访问特点吧:
    • 子类不能继承父类的构造方法,但是可以通过super调用。
    • 子类构造方法的第一行,有一个默认的super();
    • 默认先访问父类中无参的构造方法,在执行自己。
    • 如果想要父类的有参构造,必须手动书写。

this、super总结

  • this:理解为一个变量,表示当前方法调用者的地址值。
  • super:代表父类存储空间
关键字访问成员变量访问成员方法访问构造方法
thisthis.成员变量(访问本类成员变量)this.成员方法(参数)(访问本类成员方法)this(参数)(访问本类构造方法)
supersuper.成员变量(访问父类成员变量)super.成员方法(参数)(访问父类成员方法)super(参数)(访问父类构造方法)

下面我们来看个案例吧:

  • 带有继承结构的标准Javabean类

    1.经理

    成员变量:工号,姓名,工资,管理奖金。

    成员方法:工作(管理其他人),吃饭(吃米饭)。

    2.厨师

    成员变量:工号,姓名,工资

    成员方法:工作(炒菜),吃饭(吃米饭)

由于经理和厨师都有共同的属性:工号和姓名,工资属性,使用可以创建一个父类用来存放:

```
private String id;
private String name;
private double salary;
// 空参构造方法
public Employee() {
}
// 带全部参数构造方法
public Employee(String id, String name, double salary) {
    this.id = id;
    this.name = name;
    this.salary = salary;
}

public void work(){
    System.out.println("员工在工作!");
}

public void eat(){
    System.out.println("吃米饭!");
}
```

经理类:由于厨师的工作是管理工人,所以需要重写他的工作方法。

 // 经理类
 private double bouns;

 // 空参构造方法
 public Manager() {}
 // 带全部参数构造方法    (父类+子类)
 public Manager(String id, String name, double salary, double bouns) {
    super(id, name, salary);        // 自动继承父类的参数
    this.bouns = bouns;
}

// 重写父类的工作方法
@Override
public void work(){
 System.out.println("正在管理其他人!");
}

厨师类:由于厨师的工作是炒菜,所以需要重写他的工作方法。

// 厨师类
public Cook() {
}

public Cook(String id, String name, double salary) {
    super(id, name, salary);
}

// 重写父类的工作方法
@Override
public void work(){
    System.out.println("正在炒菜");
}

然后在测试类中创建对象并赋值调用他们各自的方法:

// 创建经理对象并赋值调用
Manager m = new Manager("zhangsan001","张三",12000,8000);
System.out.println(m.getId() + "," + m.getName() + "," + m.getSalary() + "," + m.getBouns());
// 调用工作和吃饭方法
m.work();
m.eat();
System.out.println("==========================================");
// 创建厨师对象并赋值调用
Cook c = new Cook("lisi001","李四",8000);
System.out.println(c.getId() + "," + c.getName() + "," + c.getSalary());
// 调用工作和吃饭方法
c.work();
c.eat();

我们来运行看一下吧:

image.png

好啦,到这里static、继承、重写就学习完毕啦,有不懂的可以在评论区评论互相讨论哟,我们下期不见不散!

==最后非常感谢您的阅读,也希望能得到您的反馈  ==