当前位置: 首页 > news >正文

Java基础:面向对象编程3

1 Java可变长参数

1.1 概述

Java 的可变长参数(Varargs)是在 Java 1.5 中引入的功能,允许方法接受任意数量的相同类型的参数。可变参数的语法是在参数类型后面加上三个点(...),例如 int... numbers

1.2 使用规则

  • 可变参数必须放在参数列表的最后一位:如果方法有多个参数,可变参数必须放在最后。例如:
    public void printNumbers(String prefix, int... numbers) {// 方法体
    }
    
  • 只能有一个可变参数:一个方法中只能有一个可变参数。

1.3 原理

当使用可变参数时,Java 会在编译时创建一个数组,数组的大小就是传入的可变参数的数量。然后将这些参数放入数组中,并将数组传递给方法。

例如:

public void printNumbers(int... numbers) {for (int number : numbers) {System.out.println(number);}
}

调用 printNumbers(1, 2, 3) 时,Java 会创建一个 int[] 数组 {1, 2, 3},然后传递给方法。

1.4 使用场景

可变参数通常用于需要处理任意数量相同类型对象的场景。例如:

  • 打印任意数量的整数
  • 计算任意数量的数字的和
  • 处理任意数量的字符串

1.5 注意事项

  • 避免重载带有可变参数的方法:重载带有可变参数的方法可能会导致编译器无法确定调用哪个方法,从而引发编译错误。例如:

    public void print(String... args) {// 方法体
    }public void print(String arg1, String... args) {// 方法体
    }
    

    调用 print("a") 时,编译器无法确定是调用第一个方法还是第二个方法。

  • 明确指示:如果必须重载带有可变参数的方法,确保在调用时明确指示参数,避免编译器混淆。

1.6 示例代码

public class VarargsExample {public static void main(String[] args) {printNumbers(1, 2, 3);printNumbers(4, 5);printNumbers();}public static void printNumbers(int... numbers) {for (int number : numbers) {System.out.println(number);}}
}

2 Java native方法

2.1 概念

本地方法(Native Method)是用 native 关键字修饰的方法,通常不需要用 Java 语言实现。本地方法允许 Java 代码调用其他语言(如 C/C++)编写的代码。

2.2 JNI:Java Native Interface

JNI(Java Native Interface)是 Java 平台的一部分,从 Java 1.1 开始引入,允许 Java 代码与其他语言编写的代码进行交互。JNI 主要用于以下场景:

  • 标准 Java 类库不支持的功能
  • 调用已有的 C/C++ 库
  • 提高性能,特别是在需要接近硬件或运行次数特别多的方法中

2.2.1 JNI 的优点

  • 扩展 Java 功能:可以通过 JNI 调用其他语言编写的库。
  • 性能优化:在某些情况下,使用本地代码可以提高性能。

2.2.2 JNI 的缺点

  • 跨平台性丧失:本地代码通常不跨平台,需要在不同系统环境下重新编译。
  • 安全性降低:本地代码的不当使用可能导致程序崩溃。

2.3 用 C 语言编写本地方法

2.3.1 步骤

  1. 编写带有 native 方法的 Java 类,生成 .java 文件。
  2. 编译 Java 类,生成 .class 文件。
  3. 生成头文件:使用 javah -jnijavac -h 生成 .h 文件。
  4. 实现本地方法:使用 C/C++ 实现 .h 文件中的方法,生成 .c.cpp 文件。
  5. 生成动态链接库:将 C/C++ 编写的文件生成动态链接库(如 .dll.so)。

2.3.2 示例:HelloWorld 程序

  1. 编写 Java 类

    public class HelloJNI {static {System.loadLibrary("hello"); // 加载动态链接库}public native void sayHello(); // 声明本地方法public static void main(String[] args) {new HelloJNI().sayHello(); // 调用本地方法}
    }
    
  2. 编译 Java 类

    javac HelloJNI.java
    
  3. 生成头文件

    javac -h . HelloJNI.java
    

    这将生成 HelloJNI.h 文件。

  4. 实现本地方法

    #include <jni.h>
    #include "HelloJNI.h"
    #include <stdio.h>JNIEXPORT void JNICALL Java_HelloJNI_sayHello(JNIEnv *env, jobject obj) {printf("Hello, JNI!\n");
    }
    
  5. 编写编译脚本

    # compile.sh
    gcc -I"$JAVA_HOME/include" -I"$JAVA_HOME/include/darwin" -dynamiclib -o libhello.dylib HelloJNI.c
    
  6. 执行脚本

    sh compile.sh
    
  7. 运行 Java 程序

    java HelloJNI
    

2.4 JNI 调用 C 的流程图

Java 代码 -> JNI 接口 -> 本地代码 (C/C++)

在这里插入图片描述

2.5 native 关键字

  • native 用于修饰方法,表示该方法的实现在外部定义,通常用 C/C++ 实现。

  • 语法

    • 修饰方法的位置必须在返回类型之前。
    • 不能用 abstract 修饰,没有方法体。
    • 返回值可以是任意类型。
  • native 方法示例

public native void sayHello();

2.6 小结

  • JNI 允许 Java 代码与其他语言编写的代码进行交互,扩展了 Java 的功能。
  • 本地方法native 关键字修饰,通常用于调用 C/C++ 库或提高性能。
  • 注意事项:使用 JNI 会丧失跨平台性,且本地代码的不当使用可能导致程序崩溃。

3 Java构造方法

3.1 概念

构造方法(Constructor)是 Java 中的一种特殊方法,用于在创建对象时初始化对象的状态。每次使用 new 关键字创建对象时,构造方法至少会被调用一次。如果没有显式定义构造方法,编译器会提供一个默认的无参构造方法。

3.2 创建构造方法的规则

  • 名称与类名相同:构造方法的名称必须与类名完全一致。
  • 无返回类型:构造方法没有返回类型,包括 void
  • 不能是抽象的、静态的、最终的、同步的
    • 抽象:构造方法不能被子类继承,因此用 abstract 修饰没有意义。
    • 静态:构造方法用于初始化对象,因此用 static 修饰没有意义。
    • 最终:构造方法不能被子类继承,因此用 final 修饰没有意义。
    • 同步:多个线程不会同时创建内存地址相同的同一个对象,因此用 synchronized 修饰没有必要。

3.3 语法格式

class class_name {public class_name(){}    // 默认无参构造方法public ciass_name([paramList]){}    // 定义有参数列表的构造方法// 类主体
}

3.4 默认构造方法

  • 无参构造方法:如果构造方法没有任何参数,它就是一个无参构造方法。
  • 默认构造方法:如果类中没有显式定义构造方法,编译器会自动提供一个无参构造方法。
  • 目的:主要为对象的字段提供默认值。
  • 代码示例
public class DefaultConstructorExample {private int value;// 编译器提供的默认构造方法public DefaultConstructorExample() {this.value = 0; // 默认值}public static void main(String[] args) {DefaultConstructorExample obj = new DefaultConstructorExample();System.out.println(obj.value); // 输出: 0}
}

3.5 有参构造方法

  • 有参数的构造方法:可以有一个或多个参数,用于为不同的对象提供不同的初始值。
  • 替代方案:如果没有有参构造方法,可以通过 setter 方法为字段赋值。
  • 代码示例
public class ParameterizedConstructorExample {private String name;public ParameterizedConstructorExample(String name) {this.name = name;}public static void main(String[] args) {ParameterizedConstructorExample obj = new ParameterizedConstructorExample("Java");System.out.println(obj.name); // 输出: Java}
}

3.6 重载构造方法

  • 构造方法重载:通过提供不同的参数列表来重载构造方法。编译器会根据参数的数量和类型来决定调用哪一个构造方法。
  • 代码示例
public class OverloadedConstructorExample {private int id;private String name;public OverloadedConstructorExample(int id) {this.id = id;}public OverloadedConstructorExample(int id, String name) {this.id = id;this.name = name;}public static void main(String[] args) {OverloadedConstructorExample obj1 = new OverloadedConstructorExample(1);OverloadedConstructorExample obj2 = new OverloadedConstructorExample(2, "Java");System.out.println(obj1.id); // 输出: 1System.out.println(obj2.id + " " + obj2.name); // 输出: 2 Java}
}

3.7 构造方法和方法的区别

特性方法构造方法
目的反映对象的行为初始化对象的字段
返回类型可以有返回类型没有返回类型
调用方式明确的,开发者通过代码决定调用隐式的,通过编译器完成
编译器提供不会由编译器提供如果没有明确提供无参构造方法,编译器会提供
名称可以和类名相同,也可以不同必须和类名相同

3.8 复制对象

复制一个对象可以通过以下三种方式完成:

  1. 通过构造方法:使用另一个对象作为参数来创建新对象。
  2. 通过对象的值:手动复制对象的每个字段。
  3. 通过 Object 类的 clone() 方法:实现 Cloneable 接口并重写 clone() 方法。
  • 通过构造方法
public class CopyConstrutorPerson {private String name;private int age;public CopyConstrutorPerson(String name, int age) {this.name = name;this.age = age;}public CopyConstrutorPerson(CopyConstrutorPerson person) {this.name = person.name;this.age = person.age;}public void out() {System.out.println("姓名 " + name + " 年龄 " + age);}public static void main(String[] args) {CopyConstrutorPerson p1 = new CopyConstrutorPerson("沉默王二",18);p1.out();CopyConstrutorPerson p2 = new CopyConstrutorPerson(p1);p2.out();}
}

在上面的例子中,有一个参数为 CopyConstrutorPerson 的构造方法,可以把该参数的字段直接复制到新的对象中,这样的话,就可以在 new 关键字创建新对象的时候把之前的 p1 对象传递过去。

  • 通过对象的值
public class CopyValuePerson {private String name;private int age;public CopyValuePerson(String name, int age) {this.name = name;this.age = age;}public CopyValuePerson() {}public void out() {System.out.println("姓名 " + name + " 年龄 " + age);}public static void main(String[] args) {CopyValuePerson p1 = new CopyValuePerson("沉默王二",18);p1.out();CopyValuePerson p2 = new CopyValuePerson();p2.name = p1.name;p2.age = p1.age;p2.out();}
}

直接拿 p1 的字段值复制给 p2 对象(p2.name = p1.name)

  • 通过 Object 类的 clone() 方法
public class ClonePerson implements Cloneable {private String name;private int age;public ClonePerson(String name, int age) {this.name = name;this.age = age;}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}public void out() {System.out.println("姓名 " + name + " 年龄 " + age);}public static void main(String[] args) throws CloneNotSupportedException {ClonePerson p1 = new ClonePerson("沉默王二",18);p1.out();ClonePerson p2 = (ClonePerson) p1.clone();p2.out();}
}

通过 clone() 方法复制对象的时候,ClonePerson 必须先实现 Cloneable 接口的 clone() 方法,然后再调用clone()方法(ClonePerson p2 = (ClonePerson) p1.clone())

3.9 小结

  • 构造方法虽然没有返回值,但返回的是类的对象
  • 初始化字段只是构造方法的一种工作,它还可以做更多,比如启动线程、调用其他方法等。

4 思维导图

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

在这里插入图片描述

参考链接

  1. Java可变参数详解,5分钟教会我妹

  2. 手把手教你用 C语言实现 Java native 本地方法

  3. Java构造方法:打开Java对象创建之门的钥匙

相关文章:

Java基础:面向对象编程3

1 Java可变长参数 1.1 概述 Java 的可变长参数&#xff08;Varargs&#xff09;是在 Java 1.5 中引入的功能&#xff0c;允许方法接受任意数量的相同类型的参数。可变参数的语法是在参数类型后面加上三个点&#xff08;...&#xff09;&#xff0c;例如 int... numbers。 1.…...

实验kubernetes的CPU绑定策略

CPU 管理配置 CPU 管理策略通过 kubelet 参数 --cpu-manager-policy 或 KubeletConfiguration 中的 cpuManagerPolicy 字段来指定。 支持两种策略&#xff1a; none&#xff1a;默认策略。static&#xff1a;允许为节点上具有某些资源特征的 Pod 赋予增强的 CPU 亲和性和独占…...

Zsh 安装与配置

目录 1 环境配置 1.1 基本工具安装 1.2 安装 oh-my-zsh 1.3 从.bashrc中迁移配置&#xff08;可选&#xff09; 2 主题配置 2.1 内置主题 2.2 自定义主题 2.2.1 推荐主题 3 插件安装 3.1 推荐插件 3.1.1 zsh -autosuggestions 3.1.2 zsh-syntax-highlighting 3.2 启…...

Redis可视化工具Redis Desktop Manager(附安装包)

前言 redis工具&#xff0c;我相信每个开发都需要&#xff0c;如果每次查都去client执行指令&#xff0c;我怕查完之后&#xff0c;老大就要发版咯。我之前一直用的Redis可视化工具RedisDesktopManager&#xff0c;总觉得差点意思&#xff0c;直到同事推荐了个新的&#xff0c…...

sql server删除过期备份文件脚本

一、通过脚本查看过期文件&#xff0c;时间可以自己设定 for /f "delims" %i in (dir /b /a-d "E:\mybak_file\*.bak" ^| findstr /i "backup" ^| findstr /v /i "no_backup") do if "%~ti" LSS "2024/09/29 16:50&qu…...

【Docker系列】Docker查看镜像架构

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...

Python案例 | 测试网络的下载速度上传速度和 ping 延迟

使用了 speedtest 库来测试网络的下载速度上传速度和 ping 延迟 注意&#xff0c;这里需要先卸载speedtest&#xff0c;再安装speedtest-cli pip uninstall speedtest pip install speedtest-cli其次运行代码&#xff1a; # 使用了 speedtest 库来测试网络的下载速度上传速度…...

一键找回,2024四大固态硬盘数据恢复工具推荐!

虽然固态硬盘&#xff08;SSD&#xff09;因其读写速度快、功耗低等特点受到广泛欢迎&#xff0c;但它并非无懈可击&#xff0c;数据丢失的问题依然存在。如果你也遇到了固态硬盘数据丢失的问题&#xff0c;那么一下的这几款软件可以一试&#xff01; 福昕数据恢复 直达链接&…...

数据结构~AVL树

文章目录 一、AVL树的概念二、AVL树的定义三、AVL树的插入四、AVL树的平衡五、AVL树的验证六、AVL树的删除七、完整代码八、总结 一、AVL树的概念 AVL树是最先发明的自平衡二叉查找树&#xff0c;AVL是⼀颗空树&#xff0c;或者具备下列性质的二叉搜索树&#xff1a;它的左右子…...

ffmpeg面向对象——rtsp拉流探索(1)

目录 0.avformat_open_input的rtsp流程程纯净版1.rtsp拉流流程图2.rtsp拉流对象图 标准rtsp协议的基石是tcp&#xff0c;本节探索下ffmpeg的rtsp拉流协议tcp的创建及rtsp协商过程。 0.avformat_open_input的rtsp流程程纯净版 ffmpeg拉流&#xff0c;从avformat_open_input接口…...

【启明智显分享】ZX7981PM WIFI6 5G-CPE:2.5G WAN口,2.4G/5G双频段自动调速

昨天&#xff0c;我们向大家展现了ZX7981PG WIFI6 5G-CPE&#xff0c;它强大的性能也引起了一波关注&#xff0c;与此同时&#xff0c;我们了解到部分用户对更高容量与更高速网口的需求。没关系&#xff01;启明智显早就预料到了&#xff01;ZX7981PM满足你的需求&#xff01; …...

openresty“热部署“lua

一、前言 频繁reload 或者restart影响测试使用nginx&#xff0c;修改lua脚本后要实际查看效果值&#xff0c;使用关闭lua代码缓存&#xff0c;可以实现实时查看代码效果。 每次请求都会从磁盘中加载lua脚本&#xff0c;生产上面不要开启&#xff0c;影响响应速度 二、修改ngin…...

基于SpringBoot+Vue+MySQL的企业招聘管理系统

系统展示 用户前台界面 管理员后台界面 企业后台界面 系统背景 在当今数字化转型的大潮中&#xff0c;企业对于高效、智能化的人力资源管理系统的需求日益增长。招聘作为人力资源管理的首要环节&#xff0c;其效率与效果直接影响到企业的人才储备与竞争力。传统的招聘方式不仅耗…...

vue3之defineComponent

defineComponent 是 Vue 3 中提供的一个辅助函数&#xff0c;用于定义组件。它可以帮助你更好地利用 TypeScript 的类型推断和 IDE 的自动补全功能。defineComponent 主要用于组合式 API&#xff08;Composition API&#xff09;和单文件组件&#xff08;SFC&#xff09;。 使…...

springboot+vue家政服务管理平台

作者&#xff1a;计算机学长阿伟 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、ElementUI等&#xff0c;“文末源码”。 系统展示 【2024最新】基于JavaSpringBootVueMySQL的&#xff0c;前后端分离。 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;…...

python pip安装requirements.txt依赖与国内镜像

python pip安装requirements.txt依赖与国内镜像 如果网络通畅&#xff0c;直接pip安装依赖&#xff1a; pip install -r requirements.txt 如果需要国内的镜像&#xff0c;可以考虑使用阿里的&#xff0c;在后面加上&#xff1a; -i http://mirrors.aliyun.com/pypi/simple --…...

解决Qt的QWidget设计师编辑UI后和软件运行显示不一致

解决方法&#xff0c;只需要在main.cpp中加入下面一段代码 if (QT_VERSION > QT_VERSION_CHECK(5, 6, 0))QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling,true); 完整的代码如下 int main(int argc, char *argv[]) { if (QT_VERSION > QT_VERSION_C…...

交易所开发:构建安全、高效、可靠的数字资产交易平台

数字资产交易平台是加密市场中连接用户与数字货币的重要枢纽。开发一个安全、高效、可靠的交易所&#xff0c;不仅需要综合考虑技术架构、安全策略、用户体验等方面&#xff0c;还需严格遵循法规要求以确保合规性。本文总结了交易所开发的关键要素&#xff0c;包括其类型、核心…...

【Next.js 入门教程系列】09-优化技巧

原文链接 CSDN 的排版/样式可能有问题&#xff0c;去我的博客查看原文系列吧&#xff0c;觉得有用的话&#xff0c; 给我的库点个star&#xff0c;关注一下吧 上一篇【Next.js 入门教程系列】08-发送邮件 优化技巧 本篇包括以下内容: Optimizing imagesUsing third-party JS…...

Windows 11 开发详解:工具与高级用法

1. 引言 Windows 11 是微软最新的操作系统&#xff0c;它不仅带来了全新的用户界面和设计理念&#xff0c;还为开发者提供了强大的开发工具和平台支持。在过去的几年中&#xff0c;开发工具和技术栈发生了巨大的变化&#xff0c;Windows 11 通过其集成的开发环境、虚拟化技术、…...

Python|GIF 解析与构建(5):手搓截屏和帧率控制

目录 Python&#xff5c;GIF 解析与构建&#xff08;5&#xff09;&#xff1a;手搓截屏和帧率控制 一、引言 二、技术实现&#xff1a;手搓截屏模块 2.1 核心原理 2.2 代码解析&#xff1a;ScreenshotData类 2.2.1 截图函数&#xff1a;capture_screen 三、技术实现&…...

国防科技大学计算机基础课程笔记02信息编码

1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制&#xff0c;因此这个了16进制的数据既可以翻译成为这个机器码&#xff0c;也可以翻译成为这个国标码&#xff0c;所以这个时候很容易会出现这个歧义的情况&#xff1b; 因此&#xff0c;我们的这个国…...

web vue 项目 Docker化部署

Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段&#xff1a; 构建阶段&#xff08;Build Stage&#xff09;&#xff1a…...

React Native 导航系统实战(React Navigation)

导航系统实战&#xff08;React Navigation&#xff09; React Navigation 是 React Native 应用中最常用的导航库之一&#xff0c;它提供了多种导航模式&#xff0c;如堆栈导航&#xff08;Stack Navigator&#xff09;、标签导航&#xff08;Tab Navigator&#xff09;和抽屉…...

MFC内存泄露

1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...

解锁数据库简洁之道:FastAPI与SQLModel实战指南

在构建现代Web应用程序时&#xff0c;与数据库的交互无疑是核心环节。虽然传统的数据库操作方式&#xff08;如直接编写SQL语句与psycopg2交互&#xff09;赋予了我们精细的控制权&#xff0c;但在面对日益复杂的业务逻辑和快速迭代的需求时&#xff0c;这种方式的开发效率和可…...

第25节 Node.js 断言测试

Node.js的assert模块主要用于编写程序的单元测试时使用&#xff0c;通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试&#xff0c;通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...

linux 下常用变更-8

1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行&#xff0c;YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID&#xff1a; YW3…...

Module Federation 和 Native Federation 的比较

前言 Module Federation 是 Webpack 5 引入的微前端架构方案&#xff0c;允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...

【C语言练习】080. 使用C语言实现简单的数据库操作

080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...