JAVA 学习·类与方法
不同于 C ,Java 是一门面向对象的编程语言。C++ 也有面向对象的内容,但是 C++ 和 Java 在方法的具体实现上存在区别。
方法的定义
方法(method)是为执行一个复杂操作组合在一起的语句集合。一个类中可以声明多个方法。其语法是采用 BNF 范式(Backus-Naur Form,巴科斯范式)描述的,用来描述计算机语言语法的符号集。
例如,下面是一个求两个整数中最大值的方法max
:
public static int max(int num1,int num2){int result = 0;if(num1 > num2)result = num1;elseresult = num2;return result;
}
其中,public
和static
是修饰符,int
是返回值,max
是方法名称。
方法签名(Method Signature)是指方法名称+形参列表,如上面方法的签名就是max(int num1,int num2)
。一个类中不能包含方法签名相同的多个方法,因为这样在调用方法时编译器不知道要调用哪个。
方法的调用
Java 类中的成员方法可以分为构造方法、类方法和对象方法。
构造方法的调用
构造方法只能在新建一个对象时,由 Java 虚拟机进行调用。创建对象通常是通过类名 对象名 = new 类名(构造函数的参数)
建立。比如下面的例子:
class TestConstructor{private int value;public TestConstructor(){this.value = 1;}public TestConstructor(int value){this.value = value;}public int getValue(){return this.value;}
}public class CallConstructor{public static void main(String[ ] args) {TestConstructor tc = new TestConstructor();System.out.println("Value: " + tc.getValue());tc = new TestConstructor(5);System.out.println("Value: " + tc.getValue());}
}
运行的结果是:
Value: 1
Value: 5
this 调用
可以通过this
调用该类的其它构造函数,但是必须是构造函数的第一条语句。例如:
class TestConstructor{private int value;public TestConstructor(){this(114);}public TestConstructor(int value){this.value = value;}public int getValue(){return this.value;}
}public class ThisConstructor{public static void main(String[ ] args) {TestConstructor tc = new TestConstructor();System.out.println("Value: " + tc.getValue());}
}
运行的结果为Value: 114
。这是因为在调用无参数构造函数时,无参构造函数通过this(114)
调用了构造函数TestConstructor(int value)
,并给其形参传递值value = 114
,从而使得value
成员初始化为114
。
super 调用
一个类还能够通过super
调用其父类的构造函数。例如
class TestConstructor{private int value;public TestConstructor(){this(114);}public TestConstructor(int value){this.value = value;}public int getValue(){return this.value;}
}public class SuperConstructor extends TestConstructor{public SuperConstructor(){super(514);}public static void main(String[ ] args) {SuperConstructor sc = new SuperConstructor();System.out.println("Value: " + sc.getValue());}
}
运行的结果为Value: 514
。这是因为在调用SuperConstructor
类的午餐构造函数时,通过super(514)
语句调用了父类TestConstructor
中的含参构造函数TestConstructor(int value)
,并给其形参传递值value = 514
,从而使成员value
初始化为514
。
类方法的调用
类方法就是由static
修饰的方法,也称静态方法。静态方法可以通过类名调用,也可以通过对象实例调用。比如下面的代码:
import java.lang.Math;
public class CallStaticMethod{public static void main(String[] args){int a = 114,b = 514;System.out.println(Math.max(a,b));}
}
在这里,调用了 Java 中自带的类Math
中的方法max
,输出的结果为514
。可以看到静态方法max
是通过类名.方法名
的方式调用的max
方法不需要通过创造Math
对象math
,并通过math.max(a,b)
来调用,因为计算一个最大值没有必要依赖对象。
事实上,Java 的开发者也考虑到了这一点,所以将Math
类的构造函数设置为私有的,这就导致我们其实也无法创造一个Math
类的实例对象。
对象方法的调用
对象方法只能通过实例对象来调用。比如下面的代码:
class Wallet{private int money;Wallet(){money = 0;}public void addMoney(int amount){this.money += amount;}public int getMoney(){return this.money;}
}public class CallObjectMethod{public static void main(String[] args){Wallet wallet = new Wallet();System.out.println("Now we have money: " + wallet.getMoney());wallet.addMoney(520);System.out.println("Then we have money: " + wallet.getMoney());}
}
运行结果为:
Now we have money: 0
Then we have money: 520
可以看到实例方法addMoney
和getMoney
都是通过对象名.方法名
调用的。显然不能通过Wallet.addmoney
或者Wallet.getMoney
调用这两个方法,因为我可以有多个Wallet
对象wallet1,wallet2,...
,使用类名.方法名
无法知道调用的是哪个Wallet
对象。
方法的重载
方法重载(Overloading)是指方法名称相同,但形参列表不同的方法。仅返回类型不同的方法不是合法的重载。一个类中可以包含多个重载的方法(同名的方法可以重载多个版本)。
方法重载实例
方法重载,例如
public class InputCheckTest{public static void CheckInput(String s){System.out.println("You entered a string.");}public static void CheckInput(int i){System.out.println("You entered an integer.");}public static void CheckInput(double d){System.out.println("You entered a double.");}public static void main(String[] args){CheckInput(114514);CheckInput("114514");CheckInput(114514.0);}
}
运行结果:
You entered an integer.
You entered a string.
You entered a double.
有歧义的重载
系统根据我们的输入自动判断调用哪个方法。但是有时候,可能会有多个合适的方法。例如
public class AmbiguousOverloading {public static void main(String[ ] args) {// System.out.println(max(1, 2));}public static double max(int num1, double num2) {return (num1 > num2)?num1:num2;}public static double max(double num1, int num2) {return (num1 > num2)?num1:num2;}
}
将注释符号去掉,上面的代码编译时将产生错误,因为编译器不知道max(1,2)
调用的是哪个函数。
包和类的导入
Java 源程序在开头通过import 包名;
语句导入其它包(类),可以使用其它包中的类及其方法。有点类似于 C/C++ 中的#include "头文件名"
语句。Java 程序在编译时会自动导入java.lang.System
类,所以我们在编写源程序时可以直接使用System.out
和System.in
以及它们的方法。
总的来说,import
有两种类型:单类型导入和按需类型导入。
单类型导入
把导入的标识符引入到当前.java文件,因此当前文件里不能定义同名的标识符,类似C++中的 using nm::id
; 把名字空间nm
的名字id
引入到当前代码处。
比如,在包p1
中定义了类A
:
package p1;
public class A{// some statements...
}
那么在包p2
中:
package p2;
import p1.A;//单类型导入,把p1.A引入到当前域
//这个时候当前文件里不能定义A,下面语句编译报错
public class A {//some statements...
}
按需类型导入
不是把包里的标识符都引入到当前.java文件,只是使包里名字都可见,使得我们要使用引入包里的名字时可以不用使用完全限定名,因此在当前.java文件里可以定义与引入包里同名的标识符。但二义性只有当名字被使用时才被检测到。类似于C++里的using nm
。
比如,包p1
还是和上面一样,此时p2
中:
package p2;
import p1.*; //按需导入,没有马上把p1.A引入到当前域
//因此当前文件里可以定义A
public class A {public static void main(String[] args){A a1 = new A(); //这时A是p2.ASystem.out.println(a1 instanceof p2.A); //true//当前域已经定义了A,因此要想使用package p1里的A,只能用完全限定名p1.A a2 = new p1.A();}
}
如果出现了名字冲突,要用完全限定名消除冲突。
类及其方法的可见性修饰符
Java 中的可见性修饰符有private
、public
和protected
,不加可见性修饰符的方法默认访问权限为包级。Java 继承时无继承控制(即都是公有继承,和 C++ 不同),故父类成员继承到派生类时访问权限保持不变(除了私有)。
成员访问控制符的作用:
private
: 只能被当前类定义的函数访问。- 包级:无修饰符的成员,只能被同一包中的类访问。
protected
:子类、同一包中的类的函数可以访问。public
: 所有类的函数都可以访问。
访问权限 | 本类 | 本包 | 子类 | 它包 |
---|---|---|---|---|
public | Yes | Yes | Yes | Yes |
protected | Yes | Yes | Yes | No(非子类时) |
包级(默认) | Yes | Yes | No(非本包时) | No |
private | Yes | No | No | No |
其它的都很好理解,只是需要注意一点:子类类体中可以访问从父类继承来的protected
成员。但如果子类和父类不在同一个包里,子类里不能访问另外父类实例的protected
成员。可以举一个例子说明这一点。我们在p1
包里定义C1
类:
package p1;
public class C1{protected int u = 3;
}
然后在包p2
中,会出现以下情况:
package p2;
import p1.C1
public class C2 extends C1{int u = 5;public static void main(String[] args){System.out.println(u) // OK. u 相当于 this.u,打印结果是 5。System.out.println(super.u) // OK. super.u 指的是父类 C1 中的 u,在子类中能够访问。打印结果是 3。C1 o = new C1();System.out.println(o.u) // ERROR. 虽然这里是 C1 的子类,但是与 C1 不在同一个包中,且 o 是一个另外的父类实例,不能访问 o 的保护成员。}
}
类的继承
Java 中可以用 extends
关键字表示继承,在上面举的例子中也能看到。子类对象是一个父类对象,即子类对象实例 instanceof 父类名
的结果为true
。
方法覆盖与方法隐藏
如果子类重新定义了从父类中继承的实例方法,称为方法覆盖(Method Override)。如果子类重新定义了从父类中继承的类方法,称为方法隐藏(Method Hidden)。它们具有如下性质:
- 仅当父类方法在子类里是可访问的,该实例方法才能被子类覆盖/隐藏;否则只是定义了一个普通方法而已,不叫作覆盖/隐藏。
- 父类的
final
方法不能被子类覆盖/隐藏,否则编译时会报错。 - 在子类函数中可以使用
super
调用被覆盖的父类方法。
实例方法的多态性
之所以会产生实例方法的多态性这个概念,是因为父类引用变量可以指向子类对象。例如,如果A
是B
的父类,那么A o = new B()
是可行的。其中,A
是变量o
的声明类型,编译时对有关变量o
的语句进行检查时,都是将o
视作声明类型;B
是o
的运行时类型,在运行的时候,因为o
实际指向的对象并不是A
类型的,这就会产生多态性。
实例方法的多态性可以通过下面的代码说明:
class A{public void m() {System.out.println("A's m");}public static void s() {System.out.println("A's s");}
}
class B extends A{//覆盖父类实例方法public void m() {System.out.println("B's m");}//隐藏父类静态方法public static void s() {System.out.println("B's s");}
}
public class OverrideDemo {public static void main(String[] args) {A o1 = new B();o1.m(); // B's mo1.s(); // A's s((A)o1).m // B's m,被覆盖的父类实例方法不能再发现B o2 = new B();o2.s // B's s((A)o2).s // A's s,被隐藏的父类静态方法可以再发现}
}
对于上面运行结果的解释是:静态函数没有多态性,函数入口地址在编译时确定,编译时所有的变量都是按照其声明类型;实例方法具有多态性,在运行时时根据实际的运行时类型确定函数入口地址。
相关文章:
JAVA 学习·类与方法
不同于 C ,Java 是一门面向对象的编程语言。C 也有面向对象的内容,但是 C 和 Java 在方法的具体实现上存在区别。 方法的定义 方法(method)是为执行一个复杂操作组合在一起的语句集合。一个类中可以声明多个方法。其语法是采用 BNF 范式(Bac…...
4. python练习题4-水仙花数
4. python练习题4-水仙花数 【目录】 文章目录 4. python练习题4-水仙花数1. 目标任务2. 水仙花数的特点3. 如何判断一个数是否是水仙花数?4. 打印3位水仙花数5. 判断一个数是不是水仙花数6. 列表推导式6. 列表推导式判断一个数是不是水仙花数 【正文】 1. 目标任务…...

【Qt 学习笔记】Qt 开发环境的搭建 | Qt 安装教程
博客主页:Duck Bro 博客主页系列专栏:Qt 专栏关注博主,后期持续更新系列文章如果有错误感谢请大家批评指出,及时修改感谢大家点赞👍收藏⭐评论✍ Qt 开发环境的搭建 | Qt 安装教程 文章编号:Qt 学习笔记 /…...

ids工业相机与电控位移台同步控制及数据采集
通过VS2017和OpenCV,实现ids工业相机与电控位移台同步控制及数据采集 目录项目环境配置代码流程及思路项目架构项目开发运行效果开发关键ids相机配置位移台环境配置相机头文件相机参数设置保存图像函数设置电控位移台头文件电控位移台设置参数最后就是通过main函数进行调用和控…...

景联文科技提供高质量医疗健康AI大模型数据
医疗行业是典型的知识和技术密集型行业,其发展水平直接关系到国民健康和生命质量。 医疗健康AI大模型,作为人工智能的一个分支,能够通过学习大量的数据来生成新的数据实例,在医药研发、医学影像、医疗文本分析等都有广泛的应用前景…...
【Python第三方库】lxml 解析器和xpath路径语言
1.lxml是做什么的 是xml/html的解析器,主要是用来解析和提取html/xml数据 2.lxml语法 使用etree.HTML(html字符串),将字符串转换为Element对象通过使用Element对象.xpath(语法)提取信息,返回的是一个列表的内存地址,需要通过使用索引获取信…...

Java(Lambda、集合)、题解
一、Lambda表达式 标准格式 ()对应方法的形参 ;->固定格式 注意点: Lambda表达式可以用来简化匿名内部类的书写 Lambda表达式只能简化函数式接口的匿名内部类的写法 函数式接口: 有且仅有一个抽象方法的接口叫做函数式接口&…...

Transformer学习: Transformer小模块学习--位置编码,多头自注意力,掩码矩阵
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 Transformer学习 1 位置编码模块1.1 PE代码1.2 测试PE1.3 原文代码 2 多头自注意力模块2.1 多头自注意力代码2.2 测试多头注意力 3 未来序列掩码矩阵3.1 代码3.2 测试掩码 1 …...
easyexcel 动态列导出
1. 引入easyexcel <dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.2.1</version></dependency> 2.导出write public void export(HttpServletResponse response) {try {String f…...

flink源码编译-job提交
1、启动standalone集群的taskmanager standalone集群中的taskmanager启动类为 TaskManagerRunner 2 打开master启动类 通过 ctrln快捷键,找到、并打开类: org.apache.flink.runtime.taskexecutor.TaskManagerRunner 3 修改运⾏配置 基本完全按照mas…...

Mysql密码修改问题
docker安装mysql,直接拉取镜像,挂载关键目录即可启动,默认3306端口。此时无法直接连接,需要配置密码。docker进入mysql容器中 docker exec -it mysql bash #mysq是容器名称,也可以用容器id通过修改mysql的配置进行免密…...
建独立站,对FP商家有什么好处?
2024年都过去四分之一了,还有许多人对是否投身于跨境独立站领域仍犹豫不决。然而,观望不如实践,如果渴望在跨境电商领域开创一片新天地,那么现在就是行动的最佳时机。 特别是对于FP商家来说,由于电商平台对于黑五类产品…...

使用Postman进行websocket接口测试
因为最近要搞关于基于AI的文本接口测试.需要用到websocket协议,于是看了一下发现postman也可以测而且很方便 位置 File->New->WebSocket 可以看到不止WebSocket还支持其他的各种协议 使用 首先先点击connect进行连接 连接成功之后可以选择多种文本格式添加请求参数 每…...
Android音视频开发 - MediaMetadataRetriever 相关
Android音视频开发 - MediaMetadataRetriever 相关 MediaMetadataRetriever 是android中用于从媒体文件中提取元数据新的类. 可以获取音频,视频和图像文件的各种信息,如时长,标题,封面等. 1:初始化对象 private MediaMetadataRetriever mediaMetadataRetriever new MediaMe…...

注解(Annotation)
10.1 注解概述 10.1.1 什么是注解 注解(Annotation)是从JDK5.0开始引入,以“注解名”在代码中存在。例如: Override Deprecated SuppressWarnings(value”unchecked”) Annotation 可以像修饰符一样被使用,可用于修饰…...

蓝桥杯:七步诗 ← bfs
【题目来源】https://www.lanqiao.cn/problems/3447/learning/【题目描述】 煮豆燃豆苴,豆在釜中泣。本是同根生,相煎何太急?---曹植 所以,这道题目关乎豆子! 话说赤壁之战结束后,曹操的船舰被刘备烧了,引领军队从华容…...

Vue 如何快速上手
目录 1. Vue 是什么 (概念) 1.1. Vue 的两种使用方式 1.2. 优点 1.3. 缺点 2. 创建 Vue 实例,初始化渲染 2.1. 步骤(核心步骤 4步) 2.2. 练习——创建一个Vue实例 3. 插值表达式 {{ }} 3.1. 介绍 3.2. 作用…...
Vue3:组件间通信-provide和inject实现祖先组件与后代组件间直接通信
一、情景说明 我们学习了很多的组件间通信 这里在学习一种,祖先组件与后代组件间通信的技术 这里的后代,可以是多层继承关系,子组件,子子组件,子子子组件等等。 在祖先组件中通过provide配置向后代组件提供数据在后代…...
微信小程序——小程序和页面生命周期详解
小程序的生命周期 小程序的生命周期主要分为以下几个阶段: 创建(onLoad): 当小程序启动时,或者从其他页面跳转到当前页面时,会触发 onLoad 生命周期函数。 这个阶段通常用于初始化页面数据,从服…...
android studio中添加module依赖
android常用的三种依赖 库依赖(Library dependency):以访问网址的形式将依赖库相应版本下载到本地; 文件依赖(File dependency): 将下载下来的依赖库以.jar文件的形式添加依赖. module依赖(Modu…...

【JavaEE】-- HTTP
1. HTTP是什么? HTTP(全称为"超文本传输协议")是一种应用非常广泛的应用层协议,HTTP是基于TCP协议的一种应用层协议。 应用层协议:是计算机网络协议栈中最高层的协议,它定义了运行在不同主机上…...

智能在线客服平台:数字化时代企业连接用户的 AI 中枢
随着互联网技术的飞速发展,消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁,不仅优化了客户体验,还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用,并…...

跨链模式:多链互操作架构与性能扩展方案
跨链模式:多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈:模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展(H2Cross架构): 适配层…...
如何为服务器生成TLS证书
TLS(Transport Layer Security)证书是确保网络通信安全的重要手段,它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书,可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...
数据库分批入库
今天在工作中,遇到一个问题,就是分批查询的时候,由于批次过大导致出现了一些问题,一下是问题描述和解决方案: 示例: // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...

什么是Ansible Jinja2
理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具,可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板,允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板,并通…...

使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...
解决:Android studio 编译后报错\app\src\main\cpp\CMakeLists.txt‘ to exist
现象: android studio报错: [CXX1409] D:\GitLab\xxxxx\app.cxx\Debug\3f3w4y1i\arm64-v8a\android_gradle_build.json : expected buildFiles file ‘D:\GitLab\xxxxx\app\src\main\cpp\CMakeLists.txt’ to exist 解决: 不要动CMakeLists.…...
深度学习之模型压缩三驾马车:模型剪枝、模型量化、知识蒸馏
一、引言 在深度学习中,我们训练出的神经网络往往非常庞大(比如像 ResNet、YOLOv8、Vision Transformer),虽然精度很高,但“太重”了,运行起来很慢,占用内存大,不适合部署到手机、摄…...

五子棋测试用例
一.项目背景 1.1 项目简介 传统棋类文化的推广 五子棋是一种古老的棋类游戏,有着深厚的文化底蕴。通过将五子棋制作成网页游戏,可以让更多的人了解和接触到这一传统棋类文化。无论是国内还是国外的玩家,都可以通过网页五子棋感受到东方棋类…...