《JAVA SE》面向对象编程(下篇)

简介: 《JAVA SE》面向对象编程(下篇)

前言

上一篇讲到了接口,接下来将补充一下常用的接口以及Object类的初识,链接如下:
《JAVA SE》面向对象编程(中篇)

《JAVA SE》面向对象编程(上篇)


一、 Object类初识

✦JAVA中的万物之母 : Object类
✦全名称:包名.类名
✦java.lang.Object

  1. Object类是Jvav中所有类的默认父类,无须使用extends来定义。
  2. class声明的类都有一个父类,Object类。
  3. 因为Object类是所有类的父类,使用Object引用来接受所有的类型,参数最高统一化

eg:
在这里插入图片描述
在这里插入图片描述

注:Java中所有类型都可以发生向上转型变成Object类型

  1. Object类中所有的方法都被子类继承下来了~~
  2. 之所以System.out.println(任意的引用类型) = 》是因为里面默认都会调用该类型的toString()方法,因为Object类存在toString();

在这里插入图片描述在这里插入图片描述

在这里插入图片描述
如果想输出当前类的属性值,我们就得覆写toString()方法!!!
在这里插入图片描述

  1. JAVA中引用数据类型之间的相等比较使用equals方法!!不能用“==”,比较的是地址。

在这里插入图片描述

自己覆写equals方法,完成对自己定义的Student类比较属性的方法。

@Override
public boolean equals(Object obj) {
        // 1.若当前对象就是obj
        if (this == obj) {
            return true;
        }
        // 2.此时当前对象和obj指向的对象确实不是一个地址
        // 若此时obj指向的对象和Student压根没关系,obj指向一个Dog对象,没有可比性,直接返回false
        if (obj instanceof Student) {
            // 3.obj这个引用指向的对象确实是Student类的对象且和当前对象不是一个对象
            // Object obj = new Student();
            Student stu = (Student) obj;
            // 所有引用类型比较属性值一定要用equals方法,"=="比的是地址!!!!!!!!
            return this.score == stu.score && this.name.equals(stu.name);
        }
        return false;
    }
  1. Object不仅是所有类的父类,JDK对Object类做了扩展。==Object类可以接受所有引用数据类型的对象(接口、数组、类)==

==因此在Java中,若一个方法参数或者返回值是Object类型,说明该参数或者返回值可以是任意引用数据类型(数组、类、接口)==

此时除了8大基本类型没法用Object类来接收之外,所有类型都能使用Object类来接收

包装类应运而生~

二、接口使用实例

接口优先原则,当一个场景既可以使用抽象类也可以使用抽象类定义时,优先考虑使用接口(更灵活),以下将介绍两个JDK内置的常用接口。

2.1 Comparable 接口

接下来将用一个例子介绍java.lang.Comparable接口:

给对象数组排序

给定一个学生类

class Student {
    private String name;
    private int score;

    public Student(String name, int score) {
        this.name = name;
        this.score = score;
    }

    @Override
    public String toString() {
        return "[" + this.name + ":" + this.score + "]";
    }
}

再给定一个学生对象数组, 对这个对象数组中的元素进行排序(按分数降序).

Student[] students = new Student[] {
            new Student("张三", 95),
            new Student("李四", 96),
            new Student("王五", 97),
            new Student("赵六", 92),
    }

按照我们之前的理解, 数组工具类我们有一个现成的 sort 方法, 能否直接使用这个方法呢?

Arrays.sort(students);
System.out.println(Arrays.toString(students));
 
 // 运行出错, 抛出异常. 
Exception in thread "main" java.lang.ClassCastException: Student cannot be cast to 
java.lang.Comparable    

仔细思考, 不难发现, 和普通的整数不一样, 两个整数是可以直接比较的, 大小关系明确. 而两个学生对象的大小关系怎么确定? 需要我们额外指定

让我们的 Student 类实现 Comparable 接口, 并实现其中的 compareTo 方法:

class Student implements Comparable {
    private String name;
    private int score;
    public Student(String name, int score) {
        this.name = name;
        this.score = score;
    }
    @Override
    public String toString() {
        return "[" + this.name + ":" + this.score + "]";
    }
    @Override
    public int compareTo(Object o) {
       if(this == 0){
       return 0; //返回0表示相等
       }
       if(o instanceof Student){
       //当前传入的o就是Student类型的引用,向下转型还原为Student
       //要比较Student对象的大小关系,就要用到Student的独有属性,向下转型
       Student stu = (Student)o;
       return this.score - stu.score;
       }
       //若传入不是学生类,则抛出异常
       throw new IllegalArgumentException("不是学生类型,无法比较!")
} 

在 sort 方法中会自动调用 compareTo 方法. compareTo 的参数是 Object , 其实传入的就是 Student 类型的对象.

然后比较当前对象和参数对象的大小关系(按分数来算).

✦如果当前对象应排在参数对象之前, 返回小于 0 的数字;

✦如果当前对象应排在参数对象之后, 返回大于 0 的数字;

✦如果当前对象和参数对象不分先后, 返回 0;

再次执行程序, 结果就符合预期了

// 执行结果
[[王五:97], [李四:96], [张三:95], [赵六:92]] 

注意事项:
对于 sort 方法来说, 需要传入的数组的每个对象都是 "可比较" 的, 需要具备 compareTo 这样的能力. 通过重写 compareTo 方法的方式, 就可以定义比较规则。

为了进一步加深对接口的理解, 我们可以尝试自己实现一个 sort 方法来完成刚才的排序过程(使用冒泡排序):(其实Arrays.sort()内部也是和下面代码类似的,只是被封装了)

public static void sort(Comparable[] array) {
        for (int bound = 0; bound < array.length; bound++) {
            for (int cur = array.length - 1; cur > bound; cur--) {
                if (array[cur - 1].compareTo(array[cur]) > 0) {
                    // 说明顺序不符合要求, 交换两个变量的位置
                    Comparable tmp = array[cur - 1];
                    array[cur - 1] = array[cur];
                    array[cur] = tmp;
                }
            }
        }
    }

再次执行代码

sort(students); 
System.out.println(Arrays.toString(students)); 
// 执行结果
[[王五:97], [李四:96], [张三:95], [赵六:92]] 

2.2 Clonable 接口

Java 中内置了一些很有用的接口, java.lang.Clonable 就是其中之一.

在这里插入图片描述

==类似于Clonable接口,把这种接口称之为“标记接口”,这种接口本身内部没有任何的抽象方法,只有打上这个标记的子类才拥有克隆能力!==

在这里插入图片描述

==JVM在运行时会检查所有实现了Cloneable接口的子类,赋予其克隆的能力。==

注意:clone()是Object类提供的方法。

Object 类中存在一个 clone 方法, 调用这个方法可以创建一个对象的 "拷贝". 但是要想合法调用 clone 方法, 必须要先实现 Clonable 接口, 否则就会抛出 CloneNotSupportedException 异常.

class Animal implements Cloneable {
    private String name;
    @Override
    public Animal clone() {
        Animal o = null;
        try {
            o = (Animal)super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return o;
    }
}
public class Test {
    public static void main(String[] args) {
        Animal animal = new Animal();
        Animal animal2 = animal.clone();
        System.out.println(animal == animal2);
    }
}
// 输出结果
// false

2.3 深拷贝VS浅拷贝

Cloneable 拷贝出的对象是一份 "浅拷贝”

观察以下代码:

public class Test {
    static class A implements Cloneable {
        public int num = 0;
        @Override
        public A clone() throws CloneNotSupportedException {
            return (A)super.clone();
        }
    }
    static class B implements Cloneable {
        public A a = new A();
        @Override
        public B clone() throws CloneNotSupportedException {
            return (B)super.clone();
        }
    }
    public static void main(String[] args) throws CloneNotSupportedException {
        B b = new B();
        B b2 = b.clone();
        b.a.num = 10;
        System.out.println(b2.a.num);
    }
} 
// 执行结果
10 
通过 clone 拷贝出的 b 对象只是拷贝了 b 自身, 而没有拷贝内部包含的 a 对象. 此时 b 和 b2 中包含的 a 引用仍然是指向同一个对象. 此时修改一边, 另一边也会发生改变。

==Java中实现深拷贝的方法有两种:==

  1. 递归使用clone()方法
  2. 序列化(json字符串)

总结

抽象类和接口都是 Java 中多态的常见使用方式. 都需要重点掌握. 同时又要认清两者的区别。
核心区别:
抽象类中可以包含普通方法和普通字段, 这样的普通方法和字段可以被子类直接使用(不必重写), 而接口中不能包含普通方法, 子类必须重写所有的抽象方法.

相关文章
|
3月前
|
Java 开发者
在Java面向对象编程的广阔海洋中,多态犹如一股深邃的潜流,它推动着代码从单一走向多元,从僵化迈向灵活。
在Java面向对象编程的广阔海洋中,多态犹如一股深邃的潜流,它推动着代码从单一走向多元,从僵化迈向灵活。
41 7
|
3月前
|
Java 开发者
那些年,我们一同踏入Java编程的大门,多态,这个充满魔法的名字,曾无数次点亮我们探索面向对象编程的热情。
那些年,我们一同踏入Java编程的大门,多态,这个充满魔法的名字,曾无数次点亮我们探索面向对象编程的热情。
48 5
|
3月前
|
Java 程序员
Java中的继承和多态:理解面向对象编程的核心概念
【8月更文挑战第22天】在Java的世界中,继承和多态不仅仅是编程技巧,它们是构建可维护、可扩展软件架构的基石。通过本文,我们将深入探讨这两个概念,并揭示它们如何共同作用于面向对象编程(OOP)的实践之中。你将了解继承如何简化代码重用,以及多态如何为程序提供灵活性和扩展性。让我们启程,探索Java语言中这些强大特性的秘密。
|
5月前
|
Java
Java面向对象编程新篇章:多态,你准备好了吗?
【6月更文挑战第17天】Java的多态性是面向对象编程的核心,它允许通过统一的接口处理不同类型的对象。例如,在一个虚拟宠物游戏中,抽象类`Pet`定义了`speak()`方法,猫、狗和鹦鹉等子类各自重写此方法以实现独特叫声。在`main`方法中,使用`Pet`类型的引用创建子类对象并调用`speak()`,多态机制确保调用实际对象的方法,实现代码的灵活性和可扩展性。通过多态,我们能以更低的耦合度和更高的复用性编写更优雅的代码。
36 3
|
2月前
|
Oracle Java 关系型数据库
Java(TM) Platform SE binary 已停止工作”的解决方法
Java(TM) Platform SE binary 已停止工作”的解决方法
212 2
|
3月前
|
存储 前端开发 JavaScript
【前端学java】面向对象编程基础-类的使用(4)
【8月更文挑战第9天】面向对象编程基础-类的使用
19 0
【前端学java】面向对象编程基础-类的使用(4)
|
3月前
|
Java 程序员 开发者
Java的面向对象编程:从基础到深入
【8月更文挑战第21天】在本文中,我们将探讨Java的面向对象编程(OOP)的核心概念,包括类、对象、继承、多态和封装。我们将通过实例和比喻,以通俗易懂的方式,深入理解这些概念的内涵和意义,以及它们如何影响我们的编程思维和实践。无论你是初学者还是有经验的开发者,这篇文章都将帮助你更深入地理解Java的OOP,并启发你思考如何在你的项目中应用这些概念。
|
4月前
|
Java API 项目管理
Java中的函数式编程与传统面向对象编程对比
Java中的函数式编程与传统面向对象编程对比
|
5月前
|
Java 数据安全/隐私保护 开发者
Java是一种完全支持面向对象编程的语言,其面向对象特性包括封装、继承、多态和抽象等
【6月更文挑战第18天】**面向对象编程(OOP)通过对象封装状态和行为,实现问题域的抽象。Java全面支持OOP,核心特性包括**: - **封装**:保护数据安全,隐藏内部细节。 - **继承**:子类继承父类属性和行为,促进代码重用。 - **多态**:一个接口多种实现,增强灵活性和扩展性。 - **抽象**:通过接口和抽象类抽离共性,简化复杂性。 **Java的OOP便于理解和解决复杂系统问题。**
56 3
|
5月前
|
Java 开发者
Java面向对象编程(OOP)的四个主要概念
【6月更文挑战第19天】Java OOP的基石是封装、抽象、继承和多态。封装是通过类隐藏数据细节;抽象简化复杂性,用接口和抽象类实现;继承让子类从父类继承属性和行为,促进代码重用;多态一个接口可有多种形态,分编译时和运行时。这些概念支持灵活且可扩展的软件设计。
45 1