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

相关文章
|
4天前
|
Java
Java 面向对象编程的三大法宝:封装、继承与多态
本文介绍了Java面向对象编程中的三大核心概念:封装、继承和多态。
47 15
|
4天前
|
Java 数据安全/隐私保护 开发者
【潜意识Java】深入理解 Java 面向对象编程(OOP)
本文介绍了Java中的面向对象编程(OOP)核心概念,包括封装、继承、多态和抽象。封装通过访问控制保护数据,提高安全性;继承支持代码复用,减少冗余;多态实现灵活的行为调用;抽象则隐藏细节,简化接口设计。掌握这些概念有助于编写高效、灵活且易于维护的代码。文章通过实例详细讲解了每个概念在Java中的应用,并总结了它们的优势。
21 3
|
2月前
|
Java 开发者
Java 面向对象编程
总之,Java 的面向对象编程为开发者提供了一种有效的编程范式,帮助他们构建出高质量、可维护的软件系统。理解和掌握面向对象的概念和原则是成为优秀 Java 开发者的重要基础。
205 63
|
5月前
|
Java 开发者
在Java面向对象编程的广阔海洋中,多态犹如一股深邃的潜流,它推动着代码从单一走向多元,从僵化迈向灵活。
在Java面向对象编程的广阔海洋中,多态犹如一股深邃的潜流,它推动着代码从单一走向多元,从僵化迈向灵活。
49 7
|
5月前
|
Java 开发者
那些年,我们一同踏入Java编程的大门,多态,这个充满魔法的名字,曾无数次点亮我们探索面向对象编程的热情。
那些年,我们一同踏入Java编程的大门,多态,这个充满魔法的名字,曾无数次点亮我们探索面向对象编程的热情。
57 5
|
5月前
|
Java 程序员
Java中的继承和多态:理解面向对象编程的核心概念
【8月更文挑战第22天】在Java的世界中,继承和多态不仅仅是编程技巧,它们是构建可维护、可扩展软件架构的基石。通过本文,我们将深入探讨这两个概念,并揭示它们如何共同作用于面向对象编程(OOP)的实践之中。你将了解继承如何简化代码重用,以及多态如何为程序提供灵活性和扩展性。让我们启程,探索Java语言中这些强大特性的秘密。
|
4月前
|
Oracle Java 关系型数据库
Java(TM) Platform SE binary 已停止工作”的解决方法
Java(TM) Platform SE binary 已停止工作”的解决方法
328 2
|
5月前
|
存储 前端开发 JavaScript
【前端学java】面向对象编程基础-类的使用(4)
【8月更文挑战第9天】面向对象编程基础-类的使用
31 0
|
5月前
|
Java 程序员 开发者
Java的面向对象编程:从基础到深入
【8月更文挑战第21天】在本文中,我们将探讨Java的面向对象编程(OOP)的核心概念,包括类、对象、继承、多态和封装。我们将通过实例和比喻,以通俗易懂的方式,深入理解这些概念的内涵和意义,以及它们如何影响我们的编程思维和实践。无论你是初学者还是有经验的开发者,这篇文章都将帮助你更深入地理解Java的OOP,并启发你思考如何在你的项目中应用这些概念。
|
6月前
|
Java API 项目管理
Java中的函数式编程与传统面向对象编程对比
Java中的函数式编程与传统面向对象编程对比

热门文章

最新文章