首页 > 编程语言 >Java SE核心技术——8继承

Java SE核心技术——8继承

时间:2024-08-02 15:42:16浏览次数:16  
标签:重写 Java 核心技术 子类 public 父类 方法 final SE

继承是面向对象的三大特征之一,可以使得子类具有父类的属性和方法,还可以在子类中重新定义,追加属性和方法。

继承是指在原有类的基础上,进行功能扩展,创建新的类型。

  • 继承的本质是对某一批类的抽象,从而实现对现实世界更好的建模。
  • JAVA中类只有单继承,没有多继承!
  • 继承是类和类之间的一种关系。除此之外,类和类之间的关系还有依赖、组合、聚合等。
  • 继承关系的两个类,一个为子类(派生类),一个为父类(基类)。子类继承父类,使用关键字extends来表示。
  • 子类和父类之间,从意义上讲应该具有"is a"的关系。
  • extends的意思是“扩展”,子类是父类的扩展。

继承的格式:

  • 格式: public class 子类名 extends 父类名{}
  • 例如: public class Zi extends Fu {}
  • Fu:是父类,也被称为基类、超类
  • Zi: 是子类,也被称为派生类

继承中子类的特点:

子类可以有父类的内容,子类还可以有自己特有的内容。

// 父类
class Animal {
    String name;

    Animal(String name) {
        this.name = name;
    }

    void eat() {
        System.out.println(name + " is eating.");
    }

    void sleep() {
        System.out.println(name + " is sleeping.");
    }
}

// 子类,继承自Animal类
class Dog extends Animal {
    Dog(String name) {
        super(name); // 调用父类的构造方法
    }

    // 重写eat方法
    void eat() {
        System.out.println(name + " is eating dog food.");
    }

    // 添加新方法
    void bark() {
        System.out.println(name + " says bark!");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal animal = new Animal("Generic Animal");
        Dog dog = new Dog("Buddy");

        animal.eat();
        dog.eat();
        dog.bark();
    }
}

//父类
public class Father {
public void doSome1(){
System.out.println("父类doSome1");
}
public void doSome2(){
System.out.println("父类doSome2");
}
}
//子类
public class Son extends Father{
@Override
public void doSome1() {
System.out.println("子类重写doSome1");
}
public void doOther(){
System.out.println("子类doOther");
}
}
//测试类
public class TestExtend {
public static void main(String[] args) {
Son son = new Son();
son.doSome1();//子类重写
son.doSome2();//继承自父类
son.doOther();//子类扩展
}
}
运行结果
子类重写父类doSome1
父类doSome2
子类doOther

Java中的Object类是所有Java类的根类,位于类继承层次结构的顶端。这意味着Java中的每个类都隐式地继承了Object类,因此Object类中定义的方法可以在任何Java对象上使用。以下是Object类的一些常用方法:

  1. equals(Object obj)

    • 用于比较两个对象的等价性。默认实现比较的是对象的内存地址,但通常需要重写这个方法来提供实际内容的比较逻辑。
  2. hashCode()

    • 返回对象的哈希码值,通常用于哈希表中。如果重写了equals()方法,也应该重写hashCode()方法,以维护equals()hashCode()的一致性。
  3. toString()

    • 返回对象的字符串表示。默认实现返回对象的类名和哈希码的无符号十六进制表示。通常重写这个方法以提供更有意义的信息。
  4. getClass():反射

    • 返回对象的Class对象,表示对象的运行时类。
  5. wait()wait(long timeout):多线程

    • 导致当前线程等待,直到另一个线程调用该对象的notify()notifyAll()方法,或者超过指定的超时时间。
  6. notify():多线程

    • 唤醒在此对象监视器上等待的单个线程。
  7. notifyAll()

    • 唤醒在此对象监视器上等待的所有线程。
  8. clone()

    • 创建并返回对象的一个副本。这个方法在Object类中是受保护的,并且需要在子类中进行重写并声明为public,以实现对象的克隆。
    9.finalize():
    • 释放GC无法回收的资源

下面是一个简单的例子,演示了如何重写Object类的一些方法:

private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null || getClass() != obj.getClass()) return false;
        Person person = (Person) obj;
        return age == person.age && (name != null ? name.equals(person.name) : person.name == null);
    }

    @Override
    public int hashCode() {
        int result = name != null ? name.hashCode() : 0;
        result = 31 * result + age;
        return result;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    // Person类的其他方法...
}

public class Main {
    public static void main(String[] args) {
        Person person1 = new Person("Alice", 30);
        Person person2 = new Person("Alice", 30);

        System.out.println("person1 == person2: " + person1.equals(person2)); // 输出 true
        System.out.println("person1 toString: " + person1.toString()); // 输出 Person 的字符串表示
    }
}
在这个例子中,Person类重写了equals()、hashCode()和toString()方法,以提供基于Person对象的实际内容的比较和字符串表示。

在子类中,创建了一个与父类中名称、返回值类型、参数列表都完全相同的方法,只是方法体的功能实现不同,。这是多态性的一个重要体现。当父类中的方法无法满足子类的需求,或者子类需要有特殊功能时,就可以进行方法重写。

方法重写规则

● 父类的成员方法只能被它的子类重写,即不能继承一个方法,就不能重写这个方法;

● 被final修饰的方法不能被重写;

● 被static修饰的方法不能被重写,但可以再次声明;

● 构造方法不能被重写;

● 子类和父类在同一个包中时,子类可以重写父类中除了被private和final修饰的其他所有方法;

● 子类和父类不在同一个包中时,子类只能重写父类被public和protected修饰的非final方法;

● 重写的方法建议使用@Override注解来标识。

方法签名要相同:重写的方法和被重写的方法,在方法名、参数上都要相同;

● 返回值类型一致:JDK 1.5之前重写方法的返回值类型必须一样,但之后的Java版本放宽了限制,返回值类型必须小于或等于父类方法的返回值类型;

● 访问修饰符要更宽泛:子类重写父类的方法时,子类方法中的访问修饰符不能比父类中的更严格(public>protected>default>private)。比如父类方法的修饰符是protected,则子类的同名方法其修饰符可以是protected或public,但不能是默认的或private;

● 声明的异常类型要一致:重写的方法一定不能抛出新的检査异常,或者比被重写方法声明更宽泛的检査型异常。例如,父类的方法声明了IOException,重写该方法时就不能抛出Exception,只能拋出IOException或其子类异常。但可以抛出非检査异常

学习网址Java方法重写(Override)与方法重载(Overlode)的区别,方法重写的详细介绍_快速java中怎么重写已有的方法-CSDN博客

方法重写与方法重载的区别

方法重写:在子类中,创建了一个与父类中名称、返回值类型、参数列表都完全相同的方法,只是方法体的功能实现不同

方法重载:允许在同一个类中存在多个同名的方法,只要它们的参数列表不同即可。方法重载有助于提供更清晰和灵活的接口。

方法重写(Method Overriding)和方法重载(Method Overloading)是Java中两种不同的概念,它们在面向对象编程中都非常重要,但用途和规则不同。下面是它们之间的主要区别:

方法重写(Method Overriding)

  1. 目的:改变父类方法的行为。
  2. 继承性:只能在子类中进行。
  3. 方法签名:必须与被重写的方法完全一致(相同的方法名、参数列表和返回类型)。
  4. 访问控制:不能比父类中的方法访问级别更严格。
  5. 返回类型:可以与父类中的方法相同,或为协变返回类型(即返回类型是父类返回类型的子类)。
  6. 异常:可以抛出与父类方法相同的异常或其子集,但不能抛出新的检查型异常或更广泛的异常集合。
  7. 使用场景:实现多态性,允许子类根据需要提供特定于其自己的行为。

方法重载(Method Overloading)

  1. 目的:在一个类中定义多个同名方法,但参数不同。
  2. 继承性:可以在同一个类中或继承体系中进行。
  3. 方法签名:必须不同,可以通过参数的数量、类型或顺序来区分。
  4. 访问控制:可以定义不同访问级别的重载方法。
  5. 返回类型:可以相同也可以不同,但这不影响方法重载的判断。
  6. 异常:可以抛出不同类型的异常。
  7. 使用场景:提供相同功能但接受不同参数的方法,增加代码的灵活性和可读性。
    super 关键字的用法和 this 关键字用法相似QQ图片20240801112537
  • this:代表本类对象的引用(this关键字指向调用该方法的对象一般我们是在当前类中使用this关键字所以我们常说this代表本类对象的引用)
  • super:代表父类存储空间的标识(可以理解为父类对象引用)指向当前对象的直接父类实例。使用 super 可以访问父类中定义的属性、方法和构造函数

用途:

  1. 访问父类构造函数:在子类的构造函数中,可以使用 super() 调用父类的构造函数,以确保父类的初始化逻辑被执行。

    javaclass Parent {
        public Parent() {
            // 初始化代码
        }
    }
    
    class Child extends Parent {
        public Child() {
            super(); // 调用父类的构造函数
            // 子类自己的初始化代码
        }
    }
    
  2. 访问父类方法:当子类重写了父类的方法,但仍然需要调用父类中的方法实现时,可以使用 super.methodName()

    javaclass Parent {
        void show() {
            System.out.println("Parent show()");
        }
    }
    
    class Child extends Parent {
        @Override
        void show() {
            super.show(); // 调用父类的方法
            System.out.println("Child show()");
        }
    }
    
  3. 访问父类属性:如果子类需要访问父类中定义的属性,可以使用 super

    javaclass Parent {
        int value = 10;
    }
    
    class Child extends Parent {
        void printValue() {
            System.out.println(super.value); // 访问父类的属性
        }
    }
    
  4. 调用父类方法的另一个版本:当父类中有多态方法时,使用 super 可以调用父类中定义的版本,而不是子类重写后的版本。

  5. 在静态上下文中不能使用:由于 super 引用的是当前对象的实例,它不能在静态方法中使用,因为静态方法不与任何特定实例关联。

  6. 在接口的实现中使用:如果一个类实现了多个接口,且这些接口中定义了同名方法,可以使用 super 来调用另一个接口中的方法。

    javainterface A {
        void doSomething();
    }
    
    interface B {
        void doSomething();
    }
    
    class Implementor implements A, B {
        public void doSomething() {
            A.super.doSomething(); // 调用接口 A 中的方法
            B.super.doSomething(); // 调用接口 B 中的方法
        }
    }
    
  7. superclass 和 subclass 关系super 关键字总是指向直接父类,即使存在更高层次的父类。

使用 super 关键字可以保持代码的清晰和正确性,尤其是在涉及继承和多态性的场景中。

final是 最终 的意思。
在java这门编程语言中,final是一个关键字,它可以被用来修饰类,变量以及成员方法。final 关键字可以用于多个上下文,具有不同的含义,但核心概念是表示不可改变性。
被final修饰的变量,又叫被称为 自定义常量。

在java中,final关键字有三个用法,修饰类(不能继承),修饰方法(不能被子类重写),以及修饰成员方法(常量不能修改)。

final修饰变量(成员变量和局部变量)
变量分为成员变量和局部变量(成员变量和局部变量介绍传送门),他们被final修饰时有不同的注意事项。

(1) final修饰成员变量:该成员变量必须在其所在类对象创建之前被初始化(且只能被初始化一次)。

这句话的意思是: 被final修饰的成员变量,一定要被赋值且只能被赋值一次,且必须是在这个成员变量所在的类对象创建之前被赋值。

final修饰局部变量,在定义时该变量可以不被直接初始化,但是在使用该变量之前,该变量必须完成初始化,否则报错!

用法

  1. 最终变量:当一个变量被声明为final,这意味着它的值在初始化之后不能被再次修改。

    java
    final int CONSTANT = 10; // 常量
    
  2. 最终方法:当一个方法被声明为final,这意味着子类不能重写(Override)这个方法。

    javaclass Parent {
        final void show() {
            System.out.println("I can't be overridden");
        }
    }
    // Child class cannot override show() method
    
  3. 最终类:当一个类被声明为final,这意味着这个类不能被继承。没有其他类可以成为这个类的子类。

    javafinal class UtilityClass {
        // class implementation
    }
    // Cannot create a subclass of UtilityClass
    
  4. 匿名内部类使用final成员:在匿名内部类中,如果需要使用外部类的局部变量,该变量必须被声明为final,即使实际上没有打算修改它。

    javafinal int value = 5;
    new Thread(new Runnable() {
        public void run() {
            System.out.println(value);
        }
    }).start();
    
  5. 不可变对象:使用final关键字可以帮助创建不可变对象。不可变对象一旦创建,其状态就不能被改变,这有助于保证线程安全性和简化对象的同步。

  6. 重写final方法的限制:如果父类中的方法被声明为final,则不能被子类重写。

  7. 性能优化final方法可以被编译器优化,因为它们不能被子类覆盖。这有时可以提高执行效率。

  8. 接口中的默认方法:在Java 8及以后的版本中,接口可以包含默认方法。如果一个方法在接口中是default的,那么在实现该接口的类中可以将其声明为final,以防止被子类覆盖。

    javainterface MyInterface {
        default void myMethod() {
            // default implementation
        }
    }
    
    class MyClass implements MyInterface {
        @Override
        final void myMethod() {
            // specific implementation
        }
    }
    

使用final关键字可以增强代码的清晰度和健壮性,同时在某些情况下还可以提供性能优势。

总结:
final修饰成员变量,该变量必须在 其所在类对象 创建之前完成初始化且只能被初始化一次(我的理解:对象被创建,说明要使用这个对象,所以身为这个对象属性之一的成员变量就必须要被赋值)
final修饰局部变量,该变量在定义时可以不被初始化,但是使用之前,必须完成初始化且只能初始化一次!

总而言之一句话:
final修饰的成员变量在定义时必须初始化(三种方法),final修饰的局部变量定义时可以不被初始化,但是使用之前必须完成初始化!

标签:重写,Java,核心技术,子类,public,父类,方法,final,SE
From: https://www.cnblogs.com/zxt102220/p/18338870

相关文章

  • 图书《数据资产管理核心技术与应用》核心章节节选-3.1.2. 从Spark 执行计划中获取数据
    本文节选自清华大学出版社出版的图书《数据资产管理核心技术与应用》,作者为张永清等著。从Spark执行计划中获取数据血缘因为数据处理任务会涉及到数据的转换和处理,所以从数据任务中解析血缘也是获取数据血缘的渠道之一,Spark是大数据中数据处理最常用的一个技术组件,既可以做实......
  • Java SE核心技术——6类与对象
    面向对象编程(Object-OrientedProgramming,简称OOP)和面向过程编程(Procedure-OrientedProgramming)是两种不同的编程范式,它们在设计和实现软件时采用了不同的方法和哲学。一、面向对象编程核心概念:面向对象编程的核心是"对象",对象可以包含数据(属性)和代码(方法)。万物皆对象。封......
  • Java SE核心技术——7封装
    封装的概述对外部隐藏内部细节1、封装的目的是隐藏对象的内部状态和实现细节,只暴露出一个可以被外界访问和操作的接口。通过将类的属性设置为私有(private),防止外部直接访问和修改这些属性。2、好处:高内聚低耦合(面向对象设计的最高原则)(1)隐藏事物的实现细节降低使用难度(2)提高了......
  • java的数据类型之基本类型
    强类型语言要求变量的使用要严格符合规定,所有变量都必须先定义后使用。如果没有按照指定要求使用变量,则该变量将报错。java就是强类型语言。java的两大数据类型1.基本类型2.引用类型其中基本类型分为八小种按照图示内容了解各个类型的字节范围(若超过该范围,则IDEA会报错)1......
  • 使用pg_basebackup备份和恢复一个pg数据库
    创建用于备份用的用户:创建数据库备份用户:psql-Upostgres-c"CREATEUSERdbbackupWITHREPLICATIONPASSWORD'123456'"-U指定备份用户-c指定创建用户命令备份用户只需要授权:replication即可创建用于备份的目录:创建备份目录:mkdir-p/pgdata/backup/如果不是本......
  • 反序列化靶机serial
    1.安装靶场进行配置2.打开kali扫描IPnmap-PS-T4192.168.245.0/243.物理机访问靶场4.F12查看网络,刷新一下得到一串base64编码5.进行base64解码,乱码为空格改为\x00,再次进行base64加密,得到payload如下Tzo0OiJVc2VyIjoyOntzOjEwOiIAVXNlcgBuYW1lIjtzOjM6InNrNCI7czo5O......
  • WEEK5|WEB Unserialize Again
    进入后是一个文件上传但是这里并没有漏洞点看cookie得到源码<?phphighlight_file(__FILE__);error_reporting(0);classstory{private$user='admin';public$pass;public$eating;public$God='false';publicfunction__wakeup(){......
  • 基于SpringBoot的智能购房推荐系统-09040(免费领源码)可做计算机毕业设计JAVA、PHP、爬
    Springboot智能购房推荐系统摘 要近年来随着我国经济的高速发展,房地产业也随之蓬勃发展,尤其是最近国家新出台的房改政策。鼓励居民购房,这对房产公司无疑是一个极好的发展势头。尤为重要的是,近几年随着信息技术和电子商务的快速发展,许多企业都开发了自己房产信息软件。智......
  • java之WIFI信号模块
    开发步骤分为以下几点:1.在AndroidManifest中声明相关权限(网络和文件读写权限)声明权限:<uses-permissionandroid:name="android.permission.ACCESS_WIFI_STATE"/><uses-permissionandroid:name="android.permission.CHANGE_WIFI_STATE"/><uses-permissiona......
  • 在cmd/powershell中使用java/javac -cp/--class-path命令链接多个jar包
    ​ 之前使用ide,习惯了傻瓜式一键运行java文件,对于java虚拟机以及java指令了解的很少,最近重温java,在使用windows中的cmd来运行java项目时,遇到了一点问题,相同的指令在cmd中能够运行,在powershell中不能正确运行,在国内网站上搜索无果后,果断去国外,在stackoverflow上找到解决办法。​ ......