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 步骤
- 编写带有 native 方法的 Java 类,生成
.java
文件。 - 编译 Java 类,生成
.class
文件。 - 生成头文件:使用
javah -jni
或javac -h
生成.h
文件。 - 实现本地方法:使用 C/C++ 实现
.h
文件中的方法,生成.c
或.cpp
文件。 - 生成动态链接库:将 C/C++ 编写的文件生成动态链接库(如
.dll
或.so
)。
2.3.2 示例:HelloWorld 程序
-
编写 Java 类:
public class HelloJNI {static {System.loadLibrary("hello"); // 加载动态链接库}public native void sayHello(); // 声明本地方法public static void main(String[] args) {new HelloJNI().sayHello(); // 调用本地方法} }
-
编译 Java 类:
javac HelloJNI.java
-
生成头文件:
javac -h . HelloJNI.java
这将生成
HelloJNI.h
文件。 -
实现本地方法:
#include <jni.h> #include "HelloJNI.h" #include <stdio.h>JNIEXPORT void JNICALL Java_HelloJNI_sayHello(JNIEnv *env, jobject obj) {printf("Hello, JNI!\n"); }
-
编写编译脚本:
# compile.sh gcc -I"$JAVA_HOME/include" -I"$JAVA_HOME/include/darwin" -dynamiclib -o libhello.dylib HelloJNI.c
-
执行脚本:
sh compile.sh
-
运行 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 复制对象
复制一个对象可以通过以下三种方式完成:
- 通过构造方法:使用另一个对象作为参数来创建新对象。
- 通过对象的值:手动复制对象的每个字段。
- 通过
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 思维导图
参考链接
-
Java可变参数详解,5分钟教会我妹
-
手把手教你用 C语言实现 Java native 本地方法
-
Java构造方法:打开Java对象创建之门的钥匙
相关文章:

Java基础:面向对象编程3
1 Java可变长参数 1.1 概述 Java 的可变长参数(Varargs)是在 Java 1.5 中引入的功能,允许方法接受任意数量的相同类型的参数。可变参数的语法是在参数类型后面加上三个点(...),例如 int... numbers。 1.…...
实验kubernetes的CPU绑定策略
CPU 管理配置 CPU 管理策略通过 kubelet 参数 --cpu-manager-policy 或 KubeletConfiguration 中的 cpuManagerPolicy 字段来指定。 支持两种策略: none:默认策略。static:允许为节点上具有某些资源特征的 Pod 赋予增强的 CPU 亲和性和独占…...

Zsh 安装与配置
目录 1 环境配置 1.1 基本工具安装 1.2 安装 oh-my-zsh 1.3 从.bashrc中迁移配置(可选) 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工具,我相信每个开发都需要,如果每次查都去client执行指令,我怕查完之后,老大就要发版咯。我之前一直用的Redis可视化工具RedisDesktopManager,总觉得差点意思,直到同事推荐了个新的,…...
sql server删除过期备份文件脚本
一、通过脚本查看过期文件,时间可以自己设定 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查看镜像架构
💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...
Python案例 | 测试网络的下载速度上传速度和 ping 延迟
使用了 speedtest 库来测试网络的下载速度上传速度和 ping 延迟 注意,这里需要先卸载speedtest,再安装speedtest-cli pip uninstall speedtest pip install speedtest-cli其次运行代码: # 使用了 speedtest 库来测试网络的下载速度上传速度…...

一键找回,2024四大固态硬盘数据恢复工具推荐!
虽然固态硬盘(SSD)因其读写速度快、功耗低等特点受到广泛欢迎,但它并非无懈可击,数据丢失的问题依然存在。如果你也遇到了固态硬盘数据丢失的问题,那么一下的这几款软件可以一试! 福昕数据恢复 直达链接&…...

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

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

【启明智显分享】ZX7981PM WIFI6 5G-CPE:2.5G WAN口,2.4G/5G双频段自动调速
昨天,我们向大家展现了ZX7981PG WIFI6 5G-CPE,它强大的性能也引起了一波关注,与此同时,我们了解到部分用户对更高容量与更高速网口的需求。没关系!启明智显早就预料到了!ZX7981PM满足你的需求! …...
openresty“热部署“lua
一、前言 频繁reload 或者restart影响测试使用nginx,修改lua脚本后要实际查看效果值,使用关闭lua代码缓存,可以实现实时查看代码效果。 每次请求都会从磁盘中加载lua脚本,生产上面不要开启,影响响应速度 二、修改ngin…...

基于SpringBoot+Vue+MySQL的企业招聘管理系统
系统展示 用户前台界面 管理员后台界面 企业后台界面 系统背景 在当今数字化转型的大潮中,企业对于高效、智能化的人力资源管理系统的需求日益增长。招聘作为人力资源管理的首要环节,其效率与效果直接影响到企业的人才储备与竞争力。传统的招聘方式不仅耗…...
vue3之defineComponent
defineComponent 是 Vue 3 中提供的一个辅助函数,用于定义组件。它可以帮助你更好地利用 TypeScript 的类型推断和 IDE 的自动补全功能。defineComponent 主要用于组合式 API(Composition API)和单文件组件(SFC)。 使…...

springboot+vue家政服务管理平台
作者:计算机学长阿伟 开发技术:SpringBoot、SSM、Vue、MySQL、ElementUI等,“文末源码”。 系统展示 【2024最新】基于JavaSpringBootVueMySQL的,前后端分离。 开发语言:Java数据库:MySQL技术:…...
python pip安装requirements.txt依赖与国内镜像
python pip安装requirements.txt依赖与国内镜像 如果网络通畅,直接pip安装依赖: pip install -r requirements.txt 如果需要国内的镜像,可以考虑使用阿里的,在后面加上: -i http://mirrors.aliyun.com/pypi/simple --…...
解决Qt的QWidget设计师编辑UI后和软件运行显示不一致
解决方法,只需要在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…...

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

【Next.js 入门教程系列】09-优化技巧
原文链接 CSDN 的排版/样式可能有问题,去我的博客查看原文系列吧,觉得有用的话, 给我的库点个star,关注一下吧 上一篇【Next.js 入门教程系列】08-发送邮件 优化技巧 本篇包括以下内容: Optimizing imagesUsing third-party JS…...
Windows 11 开发详解:工具与高级用法
1. 引言 Windows 11 是微软最新的操作系统,它不仅带来了全新的用户界面和设计理念,还为开发者提供了强大的开发工具和平台支持。在过去的几年中,开发工具和技术栈发生了巨大的变化,Windows 11 通过其集成的开发环境、虚拟化技术、…...
Python|GIF 解析与构建(5):手搓截屏和帧率控制
目录 Python|GIF 解析与构建(5):手搓截屏和帧率控制 一、引言 二、技术实现:手搓截屏模块 2.1 核心原理 2.2 代码解析:ScreenshotData类 2.2.1 截图函数:capture_screen 三、技术实现&…...

国防科技大学计算机基础课程笔记02信息编码
1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制,因此这个了16进制的数据既可以翻译成为这个机器码,也可以翻译成为这个国标码,所以这个时候很容易会出现这个歧义的情况; 因此,我们的这个国…...
web vue 项目 Docker化部署
Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段: 构建阶段(Build Stage):…...
React Native 导航系统实战(React Navigation)
导航系统实战(React Navigation) React Navigation 是 React Native 应用中最常用的导航库之一,它提供了多种导航模式,如堆栈导航(Stack Navigator)、标签导航(Tab Navigator)和抽屉…...

MFC内存泄露
1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...
解锁数据库简洁之道:FastAPI与SQLModel实战指南
在构建现代Web应用程序时,与数据库的交互无疑是核心环节。虽然传统的数据库操作方式(如直接编写SQL语句与psycopg2交互)赋予了我们精细的控制权,但在面对日益复杂的业务逻辑和快速迭代的需求时,这种方式的开发效率和可…...
第25节 Node.js 断言测试
Node.js的assert模块主要用于编写程序的单元测试时使用,通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试,通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...
linux 下常用变更-8
1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行,YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID: YW3…...

Module Federation 和 Native Federation 的比较
前言 Module Federation 是 Webpack 5 引入的微前端架构方案,允许不同独立构建的应用在运行时动态共享模块。 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语言实现简单的数据库操作 在…...