第10章面向对象编程(高级部分)-cnblog

news/2025/4/1 18:58:21/文章来源:https://www.cnblogs.com/tricktong/p/18800703

类变量与类方法

static修饰的成员变量(类变量,静态变量)的特性?

同一个类所有对象共享

类变量是随着类的加载而创建, 所以即使没有创建对象实例也可以访问 ,但是类变量的访问, 必须遵守 相关的访问权限.

static可以修饰类或者函数吗?

可以,使用static修饰的方法称为类方法或静态方法。

static方法可以被重写吗?

静态方法可以被继承,但是,不能被覆盖,即重写。如果父类中定义的静态方法在子类中被重新定义,那么在父类中定义的静态方法将被隐藏。可以使用语法:父类名.静态方法调用隐藏的静态方法。

如果父类中含有一个静态方法,且在子类中也含有一个返回类型、方法名、参数列表均与之相同的静态方法,那么该子类实际上只是 将父类中的该同名方法进行了隐藏,而非重写。 换句话说,父类和子类中含有的其实是两个没有关系的方法,它们的行为也并不具有多态性。

因此,通过一个指向子类对象的父类引用变量来调用父子同名的静态方法时,只会调用父类的静态方法。

所以父类和子类中同名同参数的方法:要么全声明成static的【不考虑重写】;要么全声明成非static的【考虑重写】

静态变量与成员变量的区别?

特性 静态变量(类变量) 成员变量(实例变量)
声明方式 使用static关键字修饰 不使用static关键字
所属范围 属于类,所有实例共享 属于对象实例,每个实例独有一份
内存分配时机 类加载时分配内存 创建对象实例时分配内存
内存位置 方法区(元空间)中的静态区 堆内存
初始化时机 类加载时初始化 对象创建时初始化
生命周期 从类加载到程序结束 从对象创建到被垃圾回收
访问方式 可通过类名直接访问 必须通过对象实例访问
线程安全性 需要考虑线程安全问题 每个线程有自己的实例,相对安全
默认值 与成员变量相同(0, false, null等) 与静态变量相同

静态变量的两种访问方式?

image-20250327210419710

一般什么情况下会将方法使用static设置静态方法?

image-20250327210659059

image-20250327210801582

理解 main 方法语法

如何理解java的main()函数?

image-20250327211234829

代码块

static代码块与普通代码块的区别?

特性 static代码块(静态初始化块) 普通代码块(实例初始化块)
关键字 使用static修饰 无特殊关键字
执行时机 类加载时执行(仅一次) 每次创建对象实例时执行
执行次数 整个程序生命周期只执行一次 每次实例化对象都会执行
访问权限 只能访问静态成员 可以访问静态和非静态成员
内存位置 方法区(元空间) 堆内存
主要用途 初始化静态变量或执行静态初始化逻辑 初始化实例变量或执行对象公共初始化逻辑
执行顺序 类加载时最先执行 在构造方法之前执行

普通代码块在类加载时会执行吗?

普通代码块(非静态代码块)在类加载时不会执行。普通代码块只会在创建类的实例对象时执行,且每次创建对象时都会执行一次。

类加载的时机

创建类的实例:使用new关键字创建对象时

访问类的静态成员:包括静态变量和静态方法

使用反射:通过Class.forName()等方法

初始化子类:当子类被初始化时,其父类也会被加载。创建子类对象实例, 父类也会被加载, 而且, 父类先被加载, 子类后被加载

class Parent {}
class Child extends Parent {} // 初始化Child时Parent也会被加载

作为主类:包含main()方法的类在程序启动时被加载

Java中创建一个对象时类内部各部分的初始化顺序

  1. 静态代码块和静态变量初始化的优先级相同
    • 它们按照在类中定义的先后顺序执行
    • 这部分只在类第一次被加载时执行一次,之后再加载时第一部分不会加载,只会加载后面两部分
  2. 普通代码块和普通属性初始化的优先级相同
    • 同样按照定义顺序执行
  3. 构造方法总是最后执行
    • 在所有初始化工作完成后才执行构造方法
记忆技巧
  1. 先静态后实例:先处理所有静态的,再处理实例相关的
  2. 同级按顺序:同级别的代码块和初始化按定义顺序执行
  3. 构造最后走:构造方法总是最后一步执行

image-20250327214709173


单例设计模式

什么是设计模式?

image-20250329152205577

什么是单例设计模式?

image-20250329152233364

单例设计模式的两种实现方法?

饿汉式
image-20250329152558895
懒汉式

image-20250329152650515

饿汉式 VS 懒汉式

image-20250329152809549

Java中final关键字的用法总结

1. final修饰属性(常量)

  • final修饰的属性称为常量,命名规范:全部大写字母,单词间用下划线连接(如MAX_VALUE
  • 必须赋初值,且后续不能修改,赋值位置三选一:
    1. 定义时直接赋值public final double TAX_RATE = 0.08;
    2. 在构造器中赋值
    3. 在代码块中赋值

2. final修饰静态属性

  • 如果是static final修饰的静态常量,初始化位置只能是:

    1. 定义时直接赋值

    2. 在静态代码块中赋值
      注意:不能在构造器中赋值

      构造器是在创建对象的时候才会被调用,而使用final修饰静态属性需要在类加载时就要赋值,所以不能在构造器中初始化。

3. final修饰类

  • final不能被继承(不能有子类)

  • 可以实例化对象
    示例:

    java

    复制

    final class A2 {}  // 不能被继承
    A2 obj = new A2(); // 可以创建对象
    

4. final修饰方法

  • 如果类不是final类但包含final方法:
    • 该方法不能被子类重写
    • 可以被继承使用

5. final类与final方法的关系

  • 如果一个类已经是final类(不能被继承),那么:
    • 不需要再将其方法修饰为final方法
    • 因为final类本身禁止继承,所有方法自然也无法被重写

6. final与构造方法

  • final不能修饰构造方法(构造器)
    • 构造方法本身就不能被继承或重写
    • 语法上不允许使用final修饰构造器

7. final与static的搭配使用

  • final和static经常组合使用(static final)

  • 优势:

    1. 效率更高:编译器会进行优化处理
    2. 避免类加载:使用static final常量不会导致类的初始化

    参考《类加载的时机》访问类的静态成员:包括静态变量和静态方法类会被加载。

8. Java核心类中的final应用

  • 包装类都是final类
    • Integer, Double, Float, Boolean等
  • String类也是final类
    • 这些类设计为final是为了保证核心功能的安全性和不可变性

抽象类

image-20250329153052815

image-20250329153212154

image-20250329153332269

image-20250329153358447

为什么父类方法访问修饰符为 private/final/static 则子类就不能重写该方法

private 修饰符:

private 修饰的方法是私有方法,只能在当前类中访问,子类无法访问到这个方法,更不用说重写了。

final 修饰符:

final 修饰的方法表示该方法是最终版本,不允许被子类重写。如果子类尝试重写一个被 final 修饰的方法,编译器会报错。

static 修饰符:

在Java中,static方法属于类级别,这意味着它们与特定的实例对象无关,而是与整个类相关联。当你调用一个static方法时,你是通过类名来调用它,而不是通过实例对象。因此,static方法在编译时就确定了调用哪个方法,而不是在运行时根据实例对象的类型来确定。

而子类重写父类方法的过程是通过动态绑定(也称为运行时多态)来实现的。这意味着在运行时,通过实例对象的类型来确定调用的方法。

由于static方法的调用在编译时就确定了,而不是在运行时确定,所以子类无法重写父类的static方法。子类可以定义与父类static方法同名的方法,但这只是在子类中隐藏了父类的方法,并不能称之为重写

接口

image-20250329154758507

接口的特性与实现

1. 接口不能被实例化(抽象类也不能被实例化)
  • 知识点:接口不能被实例化。
  • 解释:接口是一种抽象类型,不能直接创建对象。它需要通过类来实现其定义的方法。
2. 接口中的方法
  • 知识点
    • 接口中所有的方法默认是 public 的。 (不写public也行,这样默认为public)
    • 接口中的抽象方法可以省略 abstract 关键字。
  • 示例
    void aaa();  // 实际上是 public abstract void aaa();
    
    • 注意:接口中不能有方法体(所有的方法都不能有方法体,即不能有实现)。
    • 错误示例:
      void aaa(){}  // 错误!接口中不能包含具体实现。
      
3. 普通类实现接口
  • 知识点:一个普通类实现接口时,必须实现接口中定义的所有方法。 (IDEA中使用alt+enter快速实现接口)
  • 解释:普通类需要为接口中的每个抽象方法提供具体的实现,否则会编译错误。
4. 抽象类实现接口
  • 知识点:抽象类实现接口时,可以选择不实现接口中的方法。
  • 解释:抽象类本身可以包含抽象方法,因此可以将接口的抽象方法延迟到子类中实现。

接口中属性和方法的区别

特性 方法 属性
默认修饰符 public abstract(可省略) public static final(可省略)
是否需实现 普通类必须实现 无需实现(常量不可修改)
访问方式 通过实现类实例调用 通过接口名直接访问(如 接口名.属性名
初始化要求 无方法体(抽象方法) 必须显式初始化

阿里巴巴开发规范中提到:

img

  1. 多实现:一个类可同时实现多个接口(解决单继承局限)。

    class Dog implements Runnable, Barkable {}  
    
  2. 一个类可同时继承父类且实现多个接口。

    class LittleMonkey extends Monkey implements Fishable,Birdable{}
    
  3. 接口继承:接口可继承多个父接口(但不能继承类)。

    interface A extends B, C {}  
    
  4. 修饰符限制:接口的修饰符仅限 public 或默认(包访问权限)。

如何理解接口的多态特性?

接口的多态是面向对象编程的核心特性之一,它允许同一接口引用指向不同实现类的对象,从而在运行时动态调用具体实现。以下是接口多态的三种典型体现:


1. 多态参数(灵活接收不同实现对象)
  • 核心思想:接口类型作为方法参数,可以接收任何实现了该接口的类的对象。
  • 示例InterfacePolyParameter.java):
    interface UsbInterface {void start();void stop();
    }class Phone implements UsbInterface {public void start() { System.out.println("手机连接USB"); }public void stop() { System.out.println("手机断开USB"); }
    }class Camera implements UsbInterface {public void start() { System.out.println("相机连接USB"); }public void stop() { System.out.println("相机断开USB"); }
    }public class Test {// 多态参数:方法接收UsbInterface类型,实际传入Phone或Camera对象public static void work(UsbInterface usb) {usb.start();usb.stop();}public static void main(String[] args) {work(new Phone());  // 输出手机逻辑work(new Camera()); // 输出相机逻辑}
    }
    
  • 关键点
    • 方法work()无需关心具体是Phone还是Camera,只需调用接口定义的方法。
    • 新增设备类(如Keyboard)时,只需实现UsbInterface,无需修改work()方法。

2. 多态数组(统一管理不同实现对象)
  • 核心思想:通过接口类型数组,存储多种实现类的对象,并统一处理。
  • 示例InterfacePolyArray.java):
    UsbInterface[] usbs = new UsbInterface[2];
    usbs[0] = new Phone();  // 存放手机对象
    usbs[1] = new Camera(); // 存放相机对象for (UsbInterface usb : usbs) {usb.start();usb.stop();// 调用Phone特有方法:需类型判断和向下转型if (usb instanceof Phone) {((Phone)usb).call(); // 调用Phone的call()}
    }
    
  • 关键点
    • 数组usbs统一管理所有UsbInterface实现类。
    • 通过instanceof判断具体类型,访问实现类特有方法(如call())。

3. 多态传递(接口继承时的多态)
  • 核心思想:接口类型的引用可以指向实现了该接口的子接口或实现类的对象。
  • 示例InterfacePolyPass.java):
    interface A { void f1(); }
    interface B extends A {} // 子接口继承父接口
    class C implements B {public void f1() { System.out.println("实现f1"); }
    }public class Test {public static void main(String[] args) {A a = new C(); // 父接口引用指向实现类对象a.f1();       // 输出"实现f1"}
    }
    
  • 关键点
    • 子接口B继承A后,实现类C必须实现所有父接口方法。
    • 父接口类型(如A)可以接收子接口或实现类的对象。

Java内部类与外部类

类的五大成员

属性,方法,构造器,代码块,内部类

内部类,外部类,外部其他类举例

class Outer {  // 外部类:Outerclass Inner {  // 内部类:Inner}
}
class Other {  // 外部其他类:Other
}

内部类的分类

1.局部内部类(有类名)
  • 定义在方法或代码块中,有显式的类名。
  • 不能添加访问修饰符(如public/private),因其地位等同于局部变量。允许final修饰(与局部变量规则一致)。
  • 作用域仅限于所在方法或代码块。
  • 可直接访问外部类的所有成员(包括私有成员)。访问方式:直接调用(无需特殊语法)。
  • 外部类访问局部内部类成员,必须在局部内部类的作用域内(定义它的方法或代码块)创建对象后访问。
  • 外部其他类不能访问局部内部类,因为局部内部类的地位是一个局部变量。
  • 如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员,可以使用(外部类名.this.成员)去访问。外部类名.this:代表外部类的当前实例对象。

代码演示

class Outer {private int num = 10; // 外部类成员变量public void method() {class LocalInner {int num = 20; // 局部内部类成员变量(与外部类重名)public void show() {System.out.println(num); // 默认访问局部内部类的num(输出20)System.out.println(Outer.this.num); // 显式访问外部类的num(输出10)Outer.this 本质就是外部类的对象, 即哪个对象调用了 method, Outer.this 就是哪个对象。本例中Outer.this是outer_example}}LocalInner inner = new LocalInner();inner.show();}
}public class Test {public static void main(String[] args) {Outer outer_example = new Outer();outer_example.method();}
}
2.匿名内部类(无类名,重点!)

匿名:没有名字的意思。内部类:写在其他类内部的类。匿名内部类的作用是简化代码。

原本我们需要创建子类或者实现类,去继承父类(包含抽象类)和实现接口,才能重写其中的方法。但是有时候我们这样做了,然而子类和实现类却只使用了一次(定义了一个对象)。这个时候我们就可以使用匿名内部类,不用去写子类和实现类,起到简化代码的作用。

匿名内部类的格式:父类/接口 对象 = new 父类/接口(){ 重写父类/接口中的方法 };

这样做就把子类继承父类,重写父类中的方法,创建子类对象,合成了一步完成,减少了其中创建子类的过程。或者将实现类实现接口,重写接口中的方法,创建实现类对象,合成了一步完成,减少了其中创建实现类的过程。下面将会用代码演示如何使用匿名内部类。

匿名内部类实现接口或抽象类是否需要重写所有抽象方法?
需要。匿名内部类在实现接口时,必须重写接口中定义的所有抽象方法。

3.成员内部类(无static修饰)
  • 属于外部类的实例成员,可访问外部类的所有实例变量和方法。
  • 必须先创建外部类对象才能实例化。
4.静态内部类(有static修饰)
  • 属于外部类的静态成员,仅能访问外部类的静态成员。
  • 可直接通过外部类名访问,无需外部类实例。
5.内布类比较
特性 局部内部类 匿名内部类 成员内部类 静态内部类
定义位置 外部类的方法或代码块内 外部类的方法或代码块内 外部类的成员位置(非静态) 外部类的成员位置(静态)
访问修饰符 不能添加(仅允许final修饰) 不能添加 可添加(如public/private 可添加(如public/private
作用域 仅限于定义它的方法或代码块 仅限于定义它的方法或代码块 整个外部类 整个外部类
访问外部类成员 直接访问所有成员(包括私有成员) 直接访问所有成员(包括私有成员) 直接访问所有成员(包括私有成员) 仅能访问静态成员(包括私有成员)
外部类访问内部类 需在作用域内创建对象访问 无法直接访问(匿名无类名) 需通过外部类实例创建内部类对象 可直接访问(无需外部类实例)
外部类与内部类成员重名时的访问规则 就近原则,外部类名.this.成员名 就近原则,外部类名.this.成员名 就近原则,外部类名.this.成员名 就近原则,外部类名.静态成员名

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/908150.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网站被劫持且快照被黑,如何快速修复与解决?

一、问题现象与原因分析现象描述从百度点击进入网站时,跳转到非法页面。 直接输入网址访问则正常,未发生跳转。 百度快照显示非法内容,site查看网站收录出现大量非法关键词。 百度网址安全中心提示“该页面可能存在钓鱼欺诈信息”。原因分析首页代码被篡改:黑客在首页文件中…

halcon 深度学习教程(三) 目标检测之水果分类

原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/18777081深度学习教程目录如下,还在继续更新完善中 深度学习系列教程目录有兴趣可以多看其他的halcon教程halcon 学习教程目录本篇主要讲一下halcon的目标检测案例,都是halcon22版本以后才可以用的哈,没有的话…

相或为K

贪心思想:通过排除非法数,确保或运算不会引入多余的1位。 代码展示: #include <bits/stdc++.h> using namespace std; //对于k来说 如果k的第i位为0,则ai的第i为也为0(贪心思想 最优解) //利用二进制进行拆位,用>>和&的方式进行 int t,n,k;bool check(int…

WebKit Inside: 渲染树

iOS WebKit 渲染树的构建过程经过CSS的匹配,就要进入渲染树的构建。 渲染树也叫RenderObject树,因为渲染树上每一个节点,都是RenderObject的子类。 首先来看一下RenderObject的继承类图。 1 RenderObject 继承类图RenderText表示要渲染的文本。 RenderButton表示要渲染的按钮…

使用Chat2DB操作WINCC的Microsoft SQL Server数据库

配置WINCC软件自动安装的Microsoft SQL Server 数据库,使之可以被外部程序访问2025年3月30日 11:59 周日 记录 WINCC软件安装时,会同时安装对应版本的Microsoft SQL Server 数据库。 该记录主要是配置WINCC软件自动安装的Microsoft SQL Server 数据库,使之可以被外部程序访问…

GO单元测试-工具

本文介绍如何在GO语言中编写单元测试,主要内容包括:标准库中的testing包,第三方框架testify和mockery工具,monkey patching框架gomonkey,以及如何查看覆盖率。GO单元测试 摘要 本文介绍如何在GO语言中编写单元测试,主要内容包括:标准库中的testing包,第三方框架testify…

36.7K star!拖拽构建AI流程,这个开源LLM应用框架绝了!

`Flowise` 是一款革命性的低代码LLM应用构建工具,开发者通过可视化拖拽界面,就能快速搭建基于大语言模型的智能工作流。该项目在GitHub上线不到1年就斩获**36.7K星标**,被开发者誉为"AI时代的乐高积木"。36.7K star!拖拽构建AI流程,这个开源LLM应用框架绝了! 只…

Tandis 解法集()

1-x 的关卡都比较简单。 2-1: 现在我们有一个常驻的旋转操作。 和某个 1-x 的关卡一样处理即可。 2-2: 开始起飞了。 操作类似于一个极坐标变换:把方块平放即可得到圆。 2-3如果要通过这种变换得到一个中心对称图形,那左侧放的一定也是长度恰好为 8 的倒下的柱体。 而柱体的切…

Java24发布,精心总结

Java 24作为2025年3月发布的最新版本,延续了Java平台每半年发布一次的节奏,带来了24项重要改进。本文将按照核心改进领域分类,详细解析每个特性的技术原理和实际价值,帮助开发者全面了解这一版本的能力边界和应用场景。 不过Java24是自Java 21 以来的第三个非长期支持版本,…

一台电脑上快速切换git账号

如果你的一台笔记本,既要开发公司的项目,同时你又要参与github,或者是gitee上的开源项目。你就需要使用不同的账号来提交代码。如何快速、高效的切换和管理不同的git账号? 本人使用的就是这种方式,只要配置好,会自动切换的。本文来自博客园,作者:Eular,转载请注明原文…

从 0 到 1 打造代码扫描工具:实战指南与技术解析

在团队协作开发的场景中,代码规范的重要性不言而喻。当团队规模逐渐扩大,如何确保每个人提交的代码都符合规范,比如不能 import *、代码嵌套不能超3层,代码包层级依赖结构约定、 不能修改核心文件等,成为了一个亟待解决的问题。今天,咱们就来聊聊如何开发一个代码扫描工具…

深入解析Java Web开发中的异常处理机制:策略、实践与案例分析

一、引言 1. Java Web开发概述 Java Web开发是基于Java语言构建网络应用程序的过程,它通过Java Servlet、JSP(JavaServer Pages)、Spring MVC等技术,实现动态网页的生成和交互。Java Web应用广泛应用于企业级系统、电子商务平台、在线教育等领域。在这些应用中,用户通过浏…