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

导读:本篇文章讲解 《JAVA SE》面向对象编程(下篇),希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

前言

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

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由半码博客整理,本文链接:https://www.bmabk.com/index.php/post/115497.html

(0)
Java光头强的头像Java光头强

相关推荐

发表回复

登录后才能评论
半码博客——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!