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…...
uniapp 对接腾讯云IM群组成员管理(增删改查)
UniApp 实战:腾讯云IM群组成员管理(增删改查) 一、前言 在社交类App开发中,群组成员管理是核心功能之一。本文将基于UniApp框架,结合腾讯云IM SDK,详细讲解如何实现群组成员的增删改查全流程。 权限校验…...

C++_核心编程_多态案例二-制作饮品
#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为:煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例,提供抽象制作饮品基类,提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...

【kafka】Golang实现分布式Masscan任务调度系统
要求: 输出两个程序,一个命令行程序(命令行参数用flag)和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽,然后将消息推送到kafka里面。 服务端程序: 从kafka消费者接收…...
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以? 在 Golang 的面试中,map 类型的使用是一个常见的考点,其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...

通过Wrangler CLI在worker中创建数据库和表
官方使用文档:Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后,会在本地和远程创建数据库: npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库: 现在,您的Cloudfla…...

解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八
现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet,点击确认后如下提示 最终上报fail 解决方法 内核升级导致,需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...

第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明
AI 领域的快速发展正在催生一个新时代,智能代理(agents)不再是孤立的个体,而是能够像一个数字团队一样协作。然而,当前 AI 生态系统的碎片化阻碍了这一愿景的实现,导致了“AI 巴别塔问题”——不同代理之间…...
大模型多显卡多服务器并行计算方法与实践指南
一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...

C++ 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...

RNN避坑指南:从数学推导到LSTM/GRU工业级部署实战流程
本文较长,建议点赞收藏,以免遗失。更多AI大模型应用开发学习视频及资料,尽在聚客AI学院。 本文全面剖析RNN核心原理,深入讲解梯度消失/爆炸问题,并通过LSTM/GRU结构实现解决方案,提供时间序列预测和文本生成…...