最新Java基础系列课程--Day08-面向对象高级(三)

简介: 最新Java基础系列课程--Day08-面向对象高级

最新Java基础系列课程--Day08-面向对象高级(二)https://developer.aliyun.com/article/1423505


4.3 接口的案例

各位同学,关于接口的特点以及接口的好处我们都已经学习完了。接下来我们做一个案例,先来看一下案例需求.

首先我们写一个学生类,用来描述学生的相关信息

public class Student {
    private String name;
    private char sex;
    private double score;
    public Student() {
    }
    public Student(String name, char sex, double score) {
        this.name = name;
        this.sex = sex;
        this.score = score;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public char getSex() {
        return sex;
    }
    public void setSex(char sex) {
        this.sex = sex;
    }
    public double getScore() {
        return score;
    }
    public void setScore(double score) {
        this.score = score;
    }
}

接着,写一个StudentOperator接口,表示学生信息管理系统的两个功能。

public interface StudentOperator {
    void printAllInfo(ArrayList<Student> students);
    void printAverageScore(ArrayList<Student> students);
}

然后,写一个StudentOperator接口的实现类StudentOperatorImpl1,采用第1套方案对业务进行实现。

public class StudentOperatorImpl1 implements StudentOperator{
    @Override
    public void printAllInfo(ArrayList<Student> students) {
        System.out.println("----------全班全部学生信息如下--------------");
        for (int i = 0; i < students.size(); i++) {
            Student s = students.get(i);
            System.out.println("姓名:" + s.getName() + ", 性别:" + s.getSex() + ", 成绩:" + s.getScore());
        }
        System.out.println("-----------------------------------------");
    }
    @Override
    public void printAverageScore(ArrayList<Student> students) {
        double allScore = 0.0;
        for (int i = 0; i < students.size(); i++) {
            Student s = students.get(i);
            allScore += s.getScore();
        }
        System.out.println("平均分:" + (allScore) / students.size());
    }
}

接着,再写一个StudentOperator接口的实现类StudentOperatorImpl2,采用第2套方案对业务进行实现。

public class StudentOperatorImpl2 implements StudentOperator{
    @Override
    public void printAllInfo(ArrayList<Student> students) {
        System.out.println("----------全班全部学生信息如下--------------");
        int count1 = 0;
        int count2 = 0;
        for (int i = 0; i < students.size(); i++) {
            Student s = students.get(i);
            System.out.println("姓名:" + s.getName() + ", 性别:" + s.getSex() + ", 成绩:" + s.getScore());
            if(s.getSex() == '男'){
                count1++;
            }else {
                count2 ++;
            }
        }
        System.out.println("男生人数是:" + count1  + ", 女士人数是:" + count2);
        System.out.println("班级总人数是:" + students.size());
        System.out.println("-----------------------------------------");
    }
    @Override
    public void printAverageScore(ArrayList<Student> students) {
        double allScore = 0.0;
        double max = students.get(0).getScore();
        double min = students.get(0).getScore();
        for (int i = 0; i < students.size(); i++) {
            Student s = students.get(i);
            if(s.getScore() > max) max = s.getScore();
            if(s.getScore() < min) min = s.getScore();
            allScore += s.getScore();
        }
        System.out.println("学生的最高分是:" + max);
        System.out.println("学生的最低分是:" + min);
        System.out.println("平均分:" + (allScore - max - min) / (students.size() - 2));
    }
}

再写一个班级管理类ClassManager,在班级管理类中使用StudentOperator的实现类StudentOperatorImpl1对学生进行操作

public class ClassManager {
    private ArrayList<Student> students = new ArrayList<>();
    private StudentOperator studentOperator = new StudentOperatorImpl1();
    public ClassManager(){
        students.add(new Student("迪丽热巴", '女', 99));
        students.add(new Student("古力娜扎", '女', 100));
        students.add(new Student("马尔扎哈", '男', 80));
        students.add(new Student("卡尔扎巴", '男', 60));
    }
    // 打印全班全部学生的信息
    public void printInfo(){
        studentOperator.printAllInfo(students);
    }
    // 打印全班全部学生的平均分
    public void printScore(){
        studentOperator.printAverageScore(students);
    }
}

最后,再写一个测试类Test,在测试类中使用ClassMananger完成班级学生信息的管理。

public class Test {
    public static void main(String[] args) {
        // 目标:完成班级学生信息管理的案例。
        ClassManager clazz = new ClassManager();
        clazz.printInfo();
        clazz.printScore();
    }
}

注意:如果想切换班级管理系统的业务功能,随时可以将StudentOperatorImpl1切换为StudentOperatorImpl2。自己试试

4.4 接口JDK8的新特性

各位同学,对于接口最常见的特性我们都学习完了。随着JDK版本的升级,在JDK8版本以后接口中能够定义的成员也做了一些更新,从JDK8开始,接口中新增的三种方法形式。

我们看一下这三种方法分别有什么特点?

public interface A {
    /**
     * 1、默认方法:必须使用default修饰,默认会被public修饰
     * 实例方法:对象的方法,必须使用实现类的对象来访问。
     */
    default void test1(){
        System.out.println("===默认方法==");
        test2();
    }
    /**
     * 2、私有方法:必须使用private修饰。(JDK 9开始才支持的)
     *   实例方法:对象的方法。
     */
    private void test2(){
        System.out.println("===私有方法==");
    }
    /**
     * 3、静态方法:必须使用static修饰,默认会被public修饰
     */
     static void test3(){
        System.out.println("==静态方法==");
     }
     void test4();
     void test5();
     default void test6(){
     }
}

接下来我们写一个B类,实现A接口。B类作为A接口的实现类,只需要重写抽象方法就尅了,对于默认方法不需要子类重写。代码如下:

public class B implements A{
    @Override
    public void test4() {
    }
    @Override
    public void test5() {
    }
}

最后,写一个测试类,观察接口中的三种方法,是如何调用的

public class Test {
    public static void main(String[] args) {
        // 目标:掌握接口新增的三种方法形式
        B b = new B();
        b.test1();  //默认方法使用对象调用
        // b.test2(); //A接口中的私有方法,B类调用不了
        A.test3();  //静态方法,使用接口名调用
    }
}

综上所述:JDK8对接口新增的特性,有利于对程序进行扩展。

4.5 接口的其他细节

最后,给同学们介绍一下使用接口的其他细节,或者说注意事项:

  • 一个接口可以继承多个接口
public class Test {
    public static void main(String[] args) {
        // 目标:理解接口的多继承。
    }
}
interface A{
    void test1();
}
interface B{
    void test2();
}
interface C{}
//比如:D接口继承C、B、A
interface D extends C, B, A{
}
//E类在实现D接口时,必须重写D接口、以及其父类中的所有抽象方法。
class E implements D{
    @Override
    public void test1() {
    }
    @Override
    public void test2() {
    }
}

接口除了上面的多继承特点之外,在多实现、继承和实现并存时,有可能出现方法名冲突的问题,需要了解怎么解决(仅仅只是了解一下,实际上工作中几乎不会出现这种情况)

1.一个接口继承多个接口,如果多个接口中存在相同的方法声明,则此时不支持多继承
2.一个类实现多个接口,如果多个接口中存在相同的方法声明,则此时不支持多实现
3.一个类继承了父类,又同时实现了接口,父类中和接口中有同名的默认方法,实现类会有限使用父类的方法
4.一个类实现类多个接口,多个接口中有同名的默认方法,则这个类必须重写该方法。

综上所述:一个接口可以继承多个接口,接口同时也可以被类实现。

五、枚举

定义枚举类型的语法:

[修饰符] enum 枚举类型名  {
    枚举成员
    方法
  }

枚举类型名:有两层含义,一是作为枚举名使用;二是表示枚举成员的数据类型,正因为如此,枚举成员也称为枚举实例或枚举对象。

5.1 不包含方法的枚举类

每个枚举类型的成员都可以看作是Enum类的实例,这些枚举成员默认被final public static修饰。当访问枚举类型的成员时,直接使用枚举名调用枚举成员即可,即“枚举名.枚举成员”。当然如果不想使用这种形式取得枚举类的对象,也可使用Enum类定义的valueOf()方法通过“枚举名.valueOf()”的形式进行调用来获取枚举的对象。

示例:此时枚举中的成员相当于平时定义的常量

public enum Signal {
    // 定义一个枚举类型
    GREEN,YELLOW,RED
}
public class TrafficLight {
    Signal color = Signal.RED;
    public void change() {
        switch(color) {
            case RED:
                color = Signal.GREEN;
                break;
            case YELLOW:
                color = Signal.RED;
                break;
            case GREEN:
                color = Signal.YELLOW;
                break;
        }
    }
}

Java 中的每一个枚举都继承自 java.lang.Enum 类。当定义一个枚举类型时,每一个枚举类型成员都可以看作是 Enum 类的实例,这些枚举成员默认都被 final、public, static 修饰,当使用枚举类型成员时,直接使用枚举名称调用成员即可。

所有枚举实例都可以调用 Enum 类的方法,常用方法如表 1 所示。

方法名称 描述
values() 以数组形式返回枚举类型的所有成员
valueOf() 将普通字符串转换为枚举实例
compareTo() 比较两个枚举成员在定义时的顺序
ordinal() 获取枚举成员的索引位置

示例:

通过调用枚举类型实例的 values( ) 方法可以将枚举的所有成员以数组形式返回,也可以通过该方法获取枚举类型的成员。

下面的示例创建一个包含 3 个成员的枚举类型 Signal,然后调用 values() 方法输出这些成员。

enum Signal {    // 定义一个枚举类型   
    GREEN,YELLOW,RED;
}
public static void main(String[] args) {    
    for(int i = 0;i < Signal.values().length;i++) { 
        System.out.println("枚举成员:"+Signal.values()[i]);  
    }
}

输出结果如下:

枚举成员:GREEN
枚举成员:YELLOW
枚举成员:RED

示例:

创建一个示例,调用valueOf() 方法获取枚举的一个成员,再调用 compareTo() 方法进行比较,并输出结果。具体实现代码如下:

public class TestEnum {    
    public enum Sex {        // 定义一个枚举        
        male,female;    
    }   
    public static void main(String[] args) {        
        compare(Sex.valueOf("male"));    // 比较    
    }    
    public static void compare(Sex s) {        
        for(int i = 0;i < Sex.values().length;i++) {            
            System.out.println(s + "与" + Sex.values()[i] + "的比较结果是:" + s.compareTo(Sex.values()[i]));        
        }    
    }
}

上述代码中使用 Sex.valueOf(“male”) 取出枚举成员 male 对应的值,再将该值与其他枚举成员进行比较。最终输出结果如下:

male与male的比较结果是:0
male与female的比较结果是:-1

示例:

通过调用枚举类型实例的ordinal() 方法可以获取一个成员在枚举中的索引位置。下面的示例创建一个包含 3 个成员的枚举类型 Signal,然后调用 ordinal() 方法输出成员及对应索引位置。

具体实现代码如下:

public class TestEnum1 {    
   enum Signal {        // 定义一个枚举类型        
       GREEN,YELLOW,RED;    
   }    
   public static void main(String[] args) {        
      for(int i = 0;i < Signal.values().length;i++) {           
         System.out.println("索引" + Signal.values()[i].ordinal()+",值:" + Signal.values()[i]);        
       }    
   }
  }

输出结果如下:

索引0,值:GREEN
索引1,值:YELLOW
索引2,值:RED

5.2 包含方法的枚举类

因为枚举也是一种类,所以它具有与其他类几乎相同的特性,因此可以定义枚举的属性、构造方法以及方法。但是,枚举的构造方法只是在构造枚举实例值时被调用。每一个枚举实例值都是枚举的一个对象,因此创建每个枚举实例时都需要调用该构造方法。

Java 为枚举类型提供了一些内置的方法,同时枚举常量也可以有自己的方法。此时要注意必须在枚举实例的最后一个成员后添加分号,而且必须先定义枚举实例。

示例:

下面的代码创建了一个枚举类型 WeekDay,而且在该类型中添加了自定义的方法

enum WeekDay {
    Mon("Monday"),Tue("Tuesday"),Wed("Wednesday"),Thu("Thursday"),Fri("Friday"),Sat("Saturday"),Sun("Sunday");
    // 以上是枚举的成员,必须先定义,而且使用分号结束
    private final String day;
    private WeekDay(String day) {
        this.day = day;
    }
    public static void printDay(int i) {
        switch(i) {
            case 1:
                System.out.println(WeekDay.Mon);
                break;
            case 2:
                System.out.println(WeekDay.Tue);
                break;
            case 3:
                System.out.println(WeekDay.Wed);
                break;
            case 4:
                System.out.println(WeekDay.Thu);
                break;
            case 5:
                System.out.println(WeekDay.Fri);
                break;
            case 6:
                System.out.println(WeekDay.Sat);
                break;
            case 7:
                System.out.println(WeekDay.Sun);
                break;
            default:
                System.out.println("wrong number!");
        }
    }
    public String getDay() {
        return day;
    }
}

上面代码创建了 WeekDay 枚举类型,下面遍历该枚举中的所有成员,并调用 printDay() 方法。示例代码如下:

public static void main(String[] args) {
    for(WeekDay day : WeekDay.values()) {
        System.out.println(day+"====>" + day.getDay());
    }
    WeekDay.printDay(5);
}

输了结果:

Mon====>Monday
Tue====>Tuesday
Wed====>Wednesday
Thu====>Thursday
Fri====>Friday
Sat====>Saturday
Sun====>Sunday
Fri
相关文章
|
18天前
|
Java 关系型数据库 数据库
面向对象设计原则在Java中的实现与案例分析
【10月更文挑战第25天】本文通过Java语言的具体实现和案例分析,详细介绍了面向对象设计的五大核心原则:单一职责原则、开闭原则、里氏替换原则、接口隔离原则和依赖倒置原则。这些原则帮助开发者构建更加灵活、可维护和可扩展的系统,不仅适用于Java,也适用于其他面向对象编程语言。
12 2
|
2月前
|
Java 编译器
封装,继承,多态【Java面向对象知识回顾①】
本文回顾了Java面向对象编程的三大特性:封装、继承和多态。封装通过将数据和方法结合在类中并隐藏实现细节来保护对象状态,继承允许新类扩展现有类的功能,而多态则允许对象在不同情况下表现出不同的行为,这些特性共同提高了代码的复用性、扩展性和灵活性。
封装,继承,多态【Java面向对象知识回顾①】
|
2月前
|
Java
java中面向过程和面向对象区别?
java中面向过程和面向对象区别?
35 4
|
2月前
|
Java
接口和抽象类【Java面向对象知识回顾②】
本文讨论了Java中抽象类和接口的概念与区别。抽象类是不能被实例化的类,可以包含抽象和非抽象方法,常用作其他类的基类。接口是一种纯抽象类型,只包含抽象方法和常量,不能被实例化,且实现接口的类必须实现接口中定义的所有方法。文章还比较了抽象类和接口在实现方式、方法类型、成员变量、构造方法和访问修饰符等方面的不同,并探讨了它们的使用场景。
接口和抽象类【Java面向对象知识回顾②】
|
1月前
|
存储 Java 程序员
Java基础-面向对象
Java基础-面向对象
16 0
|
2月前
|
安全 Java Go
面向对象程序设计语言:Java
Java语言语法和C语言和C++语言很接近,很容易学习和使用,Java丢弃了C++中很少使用的、很难理解的、令人迷惑的特性,Java语言不使用指针,而是引用,并提供了自动分配和回收内存空间,使得程序员不必为内存管理而担忧
56 2
|
2月前
|
Java 开发者
Java 面向对象
Java 是一种面向对象的编程语言,通过对象与类的概念组织代码和数据。面向对象编程的核心包括类、对象、继承、多态、封装和抽象。类是对象的蓝图,定义了属性和行为;对象则是类的实例。继承允许子类继承父类的属性和方法,增强代码复用性;多态则支持通过相同接口调用不同类型对象的行为,包括方法重载和重写。封装通过公共方法隐藏对象细节,提高安全性;抽象则对对象特征进行提炼,通过抽象类和接口实现。理解这些概念有助于设计高效、可维护的 Java 应用程序。
|
3月前
|
Java 开发者 C++
|
2月前
|
Java 开发者
Java编程之旅:探索面向对象的力量
【9月更文挑战第16天】在编程的世界中,Java以其强大的面向对象编程特性而闻名。本文将带你走进Java的世界,一起探索类与对象的奥秘,学习如何通过封装、继承和多态性构建健壮的软件系统。无论你是初学者还是有经验的开发者,本文都旨在提供实用的代码示例,帮助你提升Java技能。准备好开始这段旅程了吗?让我们启程吧!
|
3月前
|
存储 Java 数据库连接
Java编程之旅:从基础到高级,探索面向对象的力量
【8月更文挑战第31天】本文是一篇深入浅出的Java编程指南,旨在通过生动的例子和实际代码演示,带领读者从Java的基础语法起步,逐步深入到面向对象的核心概念,最后探讨如何在实际项目中应用这些知识。无论你是编程新手还是有一定经验的开发者,这篇文章都将为你提供有价值的见解和实用的技巧。