项目5 5.4 方法参数与重载_第1页
项目5 5.4 方法参数与重载_第2页
项目5 5.4 方法参数与重载_第3页
项目5 5.4 方法参数与重载_第4页
项目5 5.4 方法参数与重载_第5页
已阅读5页,还剩28页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

Java程序设计语言概述5.3方法参数与重载5.3参数的传值

参数是方法中最重要的一个部分。在方法定义中定义了参数的个数及参数的数据类型,称为形式参数。当对象调用方法时,调用者必须提供与形参类型及数量严格匹配的‌值,即方法调用时参数变量必须有具体的值,称为实际参数。如果以圆的面积计算来做简单类比,参数的形式参数相当于圆面积计算中公式s=πr2中的半径r,而实际参数相当于实际的圆的半径10.0。在圆的面积计算时,将具体的圆的半径10.0传递给公式πr2中的半径r,最终在公式中计算得到圆的面积。

在Java中,方法的参数传递可以分为两种类型:值类型(ValueType)和引用类型(ReferenceType)。这两种类型的参数在方法调用时的行为有所不同,主要体现在参数的传递方式上。01值类型参数传值01值类型参数传值

值类型参数传值包括基本数据类型(如int、double、char等)和String(String虽然是引用类型,但Java中的String是不可变的)。对于这些类型的参数,方法调用实际上是传递了参数值的副本。这意味着在方法内部对参数的修改不会影响到原始数据。示例如下:publicclassValuePassDemo{publicstaticvoidmain(String[]args){intoriginalNum=10;System.out.println("方法调用前实际参数值:"+originalNum);//输出:10//尝试在方法中修改参数modifyValue(originalNum);

System.out.println("方法调用后实际参数值:"+originalNum);//输出:10(未改变)}//num形参(接收实参值的副本)publicstaticvoidmodifyValue(intnum){System.out.println("\t方法内修改前形参值:"+num);//输出:10num=num*2;//修改形参副本的值System.out.println("\t方法内修改后形参值:"+num);//输出:20}}02引用类型参数传值02引用类型参数传值若在方法内部对形参进行重新赋值(例如将其指向一个新对象),则形参的地址副本会更新为指向新对象的地址,而实参的原始引用仍保留原对象的地址。此时,若通过形参修改新对象的状态(例如修改其成员变量),这些改动仅作用于新对象,对实参指向的原始对象不产生影响。在Java中,引用类型参数的传值机制本质上遵循‌值传递‌规则,但因其操作对象的内存地址特性,其行为与基本数据类型存在显著差异。当方法接收引用类型参数时,实际传递的是对象在堆内存中地址的‌副本值‌,而非对象本身。这意味着,调用方传入的实参(如一个对象的引用)会将其存储的地址值复制一份赋予方法内的形参,此时形参与实参指向同一个堆内存中的对象实体。这种机制使得方法内部可以通过形参副本地址直接访问并修改对象的状态(例如修改对象的成员变量),这种修改会直接影响原始对象,因为二者通过不同引用操作同一内存区域的数据。02引用类型参数传值classCampusCard{//校园卡类doublebalance;//直接操作字段(简化示例)CampusCard(doubleinitialBalance){balance=initialBalance;//初始化卡余额}voidspend(doubleamount){//消费方法balance-=amount;}StringshowBalance(){//显示校园卡余额return"校园卡余额:"+balance+"元";}}classStudent{Stringname;CampusCardcard;//学生持有的校园卡publicStudent(StringstudentName,CampusCardstudentCard){name=studentName;card=StudentCard;}voidrecharge(CampusCardcard,intamount){//充值操作(修改对象状态)card.balance+=amount;//直接修改字段System.out.println("\n充值处操作后:"+card.showBalance());}CampusCardreplaceCard(CampusCardstudentcard){//换卡(重新赋值形参)doubleamount=card.balance;card=newCampusCard(50);//换卡时充入50元模拟校园卡消费与换卡的场景card.balance+=amount;//原卡金额充入新卡System.out.println("\n发卡处换新卡:"+card.showBalance());returncard;}}classCampusCardDemo{publicstaticvoidmain(String[]args){CampusCardoriginal=newCampusCard(20);//初次发卡,卡上金额20元StudentliMing=newStudent("李明",original);CampusCardcard=liMing.card;//设定当前校园卡为李明的卡System.out.println("-----初始状态-----");System.out.println(liM+card.showBalance());//显示初始金额liMing.recharge(card,100);//充值100元,显示充值后金额System.out.println("主程序检查原卡:"+liM+card.showBalance());liMing.card=liMing.replaceCard(original);//换卡,显示换卡后新卡金额card=liMing.card;//设定李明的卡为新卡System.out.println("查询原卡金额:"+liM+original.showBalance());card.spend(15);//使用校园卡消费System.out.println("\n买奶茶后:"+liM+card.showBalance());card=original;//原校园卡找到了。card.spend(15);//使用原校园卡消费(这是不诚信的行为)System.out.println("\n买奶茶后:"+liM+card.showBalance());}}02引用类型参数传值

该场景有三个类:校园卡类、学生类及主类。通过“校园卡余额充值”和“换新卡”两个操作展示引用类型参数的特性。其中充值操作以学生校园卡对象为参数,直接修改校园卡对象的余额,这一操作直接影响了作为实际参数的校园卡的余额;换新卡操作在方法内创建了新的校园卡,充入初始余额,并将老卡金额存入新卡。但是由于程序中未对原校园卡做任何操作,原校园卡任然存在,且换卡操作未影响原校园卡的余额,且仍然可以消费。

该程序执行结果如下图:

图5-1校园卡模拟03可变参数03可变参数Java方法的可变参数是简化方法参数处理的重要特性。该特性允许开发者在定义方法时声明一个可以接收任意数量指定类型参数的形参,编译器会自动将这些参数封装为数组进行处理。可变参数的语法通过在参数类型后添加三个连续的点号(...)实现,例如:voidprintValues(int...numbers)

这种设计既保持了代码的简洁性,又提供了处理不确定参数数量的灵活性,常见于需要聚合计算或批量操作的场景。可变参数在底层实现上等价于数组参数,但使用方式更为直观。当调用带有可变参数的方法时,开发者可以直接传递零个或多个相同类型的参数,也可以直接传递数组对象。两种调用形式完全等效。例如:printValues(1,2,3)与printValues(newint[]{1,2,3})

使用可变参数时需遵循特定的语法规则。可变参数必须作为方法的最后一个参数声明,否则会导致编译错误。这种限制源于方法调用时参数解析的顺序要求,编译器需要明确区分常规参数与可变参数的边界。当方法存在多个参数时,常规参数应全部排列在可变参数之前,例如:voidsaveData(StringtableName,String...columns)

可变参数对空值的处理需要特别注意。当不传递任何参数时,可变参数对应的数组将为空数组而非null,这避免了潜在的风险。但在显式传递null值时仍可能引发异常,因此建议在方法内部进行空值检查。对于需要区分空参数和未传参数的场景,可以通过方法重载实现不同的处理逻辑,例如单独定义无参版本的方法来处理特殊情况。03可变参数

可变参数对空值的处理需要特别注意。当不传递任何参数时,可变参数对应的数组将为空数组而非null,这避免了潜在的风险。但在显式传递null值时仍可能引发异常,因此建议在方法内部进行空值检查。对于需要区分空参数和未传参数的场景,可以通过方法重载实现不同的处理逻辑,例如单独定义无参版本的方法来处理特殊情况。

尽管可变参数具有诸多优势,但也存在性能优化的考量。频繁调用可变参数方法可能产生数组创建的开销,在性能敏感的循环中需要注意。利用可变参数实现平均值计算的代码示例如下:03可变参数publicclassAverageCalculator{//使用可变参数接收多个double类型数值staticdoublecalculateAverage(double...numbers){if(numbers.length==0){System.out.print("[注意]未输入任何数值,");return0.0;}doublesum=0.0;for(doublenum:numbers){sum+=num;}returnsum/numbers.length;}publicstaticvoidmain(String[]args){//测试用例1:常规输入System.out.println("85+90+78的平均值:"+String.format("%.2f",calculateAverage(85,90,78)));//测试用例2:单个数值System.out.println("仅有99的平均值:"+String.format("%.2f",calculateAverage(99)));//测试用例3:空参数System.out.println("空输入的平均值:"+String.format("%.2f",calculateAverage()));}}04实例成员与类成员04实例成员与类成员

在Java中类体的内容包含两个主要部分:成员变量和方法,它们是类的基本成员,成员变量和方法根据其归属关系可分为实例成员与类成员。类成员是使用static关键字修饰的成员,也称为静态成员,而没有用static关键字修饰的成员称作实例成员。这两者在使用方式上存在本质差异。05实例变量与类变量05实例变量与类变量

在声明成员变量时使用static关键字修饰的成员变量称为类变量,也称为静态变量,而没有用static关键字修饰的成员变量称为实例变量。例如以下是老虎类的声明,其中变量“speciesName”是物种名,老虎的物种名为“Pantheratigris”,“MAX_SPEED”是老虎的最大速度,“age”和“weight”是老虎的年龄和体重。“speciesName”和“MAX_SPEED”使用了static修饰符,是类变量,而“age”和“weight”没有使用static修饰符是成员变量。显然,物种名和最大速度是所有老虎共有的属性,而年龄和体重虽然也是老虎的属性,但每只老虎都有自己特定的年龄和体重。classTiger{//------------类变量声明区域------------staticStringspeciesName="Pantheratigris";//staticdoubleMAX_SPEED=65.0;//最大奔跑速度(单位:km/h,常量类变量)//------------实例变量声明区域------------intage;//个体年龄(单位:年)

doubleweight;//当前体重(单位:千克)}05实例变量与类变量1.不同对象的实例变量互不相同以老虎类的具体实现为例,实例变量age和weight分别记录每只老虎的年龄与体重。当创建不同的对象时,它们在内存中各自拥有独立的存储空间。实例变量在对象各自的存储空间内存储,对一个对象实例变量的操作不影响其它对象的相同实例变量。2.所有对象实例共享类变量类变量属于类本身的共享资源,所有对象实例共享同一存储单元。无论创建多少老虎对象,这些类变量始终只有一份内存拷贝。这种设计使得speciesName这类物种名称信息无需重复存储,既节省内存又确保数据一致性,当修改类变量时会立即影响所有对象实例。3.实例变量与类变量的访问方式不同实例变量必须通过对象引用操作。这就是说,要访问实例变量首先必须创建一个对象,然后通过对象来访问相应的实例变量。类变量则通过类名直接访问,无需绑定到具体对象,这体现了类变量作为全局共享数据的特性。需要注意的是,类变量也是对象的变量,只是该变量与其它对象共享,通过对象引用也能访问类变量,但这种写法会混淆类成员与实例成员的概念,因此应严格使用类名访问。正如以上代码所展现的,实例变量与类变量存在明显的区别。类变量适用于描述物种级特征或全局状态,实例变量则记录对象级动态属性,这种分工体现了面向对象设计中“类描述共性,对象承载个性”的核心原则。06实例方法与类方法06实例方法与类方法正如以上代码所展现的,实例变量与类变量存在明显的区别。类变量适用于描述物种级特征或全局状态,实例变量则记录对象级动态属性,这种分工体现了面向对象设计中“类描述共性,对象承载个性”的核心原则。在声明方法时使用static关键字修饰的方法称为类方法,也称为静态方法,而没有用static关键字修饰的方法称为实例方法。与实例变量与类变量一样,实例方法与类方法同样存在明显的区别。‌类方法通过类名直接调用,无需创建对象实例。其内存在类加载时完成分配,执行过程不依赖对象实例的存在。类方法允许访问类变量(静态变量)和调用其他类方法,但禁止直接访问实例变量或调用实例方法。当方法逻辑无需操作实例变量且与实例方法无关时,可以优先设计为类方法。实例方法‌必须通过具体对象实例调用,当创建多个对象时,每个对象的成员变量独立存储,而实例方法在创建第一个对象时被分配入口地址,所有对象共享同一份方法代码。实例方法可直接访问‌当前对象的实例变量‌和调用实例方法,也可以访问类的类变量和类方法。06实例方法与类方法publicclassTiger{//------------类变量声明区域------------staticStringspeciesName="Pantheratigris";//物种学名(所有老虎共享)staticintpopulation=0;//现存老虎总数(类级别统计)

publicstaticfinaldoubleMAX_SPEED=65.0;//最大奔跑速度(单位:km/h,常量类变量)//------------实例变量声明区域------------intage;//个体年龄(单位:年)

doubleweight;//当前体重(单位:千克)

booleanisHealthy;//健康状态标记

double[]habitatCoordinates;//栖息地坐标(对象级地理信息)//------------构造函数------------publicTiger(intage,doubleweight,booleanisHealthy,doublex,doubley){this.age=age;this.weight=weight;this.isHealthy=isHealthy;this.habitatCoordinates=newdouble[]{x,y};population++;//创建新个体时更新类变量}

一个实例成员和类成员的示例如下,该示例模拟了野外老虎种群调查的情况。//------------实例方法------------publicvoidgrow(){//模拟年度生长过程age++;weight+=age<5?8.5:3.2;//幼虎生长更快}publicstaticStringgetSpeciesInfo(){//获取物种信息returnspeciesName+"现存数量:"+population;}publicstaticvoidmain(String[]args){//示例调用TigersiberianTiger=newTiger(3,180.5,true,45.75,126.63);//发现西伯利亚虎TigerbengalTiger=newTiger(5,220.0,false,27.47,88.21);//发现孟加拉虎

System.out.println(Tiger.getSpeciesInfo());//输出:Pantheratigris现存数量:2System.out.println("最大奔跑速度:"+Tiger.MAX_SPEED+"km/h");siberianTiger.grow();System.out.println("西伯利亚虎新体重:"+siberianTiger.weight+"kg");//输出:189.0kg}}07方法重载07方法重载

在Java中,方法重载(MethodOverloading)是一种允许在同一个类中定义多个方法名相同但参数列表不同的方法的能力。这是多态性的一种形式,允许根据不同的参数类型或参数数量来调用不同的方法。通俗来说,它类似于生活中的“一词多义”。例如,一个“打印”操作,根据传入的内容不同自动适配不同的处理方式:打印一张‌纸‌时,启动激光打印机;打印一张‌照片‌时,启动彩色喷墨打印机;打印一个‌3D模型‌时,启动3D打印机。虽然都叫“打印”,但具体执行哪种打印方式,完全由传入的“参数”(纸张、照片、3D模型)决定。在Java中,这种多态性由编译器在代码编译阶段静态绑定

方法重载的关键在于方法签名的唯一性。方法签名由方法名称和参数类型列表共同决定,与返回值类型、访问修饰符无关。方法重载的实现依赖于‌参数列表的唯一性,具体通过以下三种方式实现:07方法重载

例如,处理整数和浮点数的加法方法可以分别定义为add(inta,intb)和add(doublea,doubleb)。‌参数类型不同1例如,计算两数之和和三数之和的方法可以共用sum作为方法名,但参数个数不同。‌参数数量不同2

例如,方法format(Stringname,intage)和format(intcode,Stringdescription)通过参数顺序的调换形成重载。‌参数顺序不同‌:307方法重载publicclassCoffeeMachine{privatestaticfinalintMAX_CAFFEINE=300;//每日咖啡因安全上限(毫克)

publicvoidmakeCoffee(){//基础制作:默认参数(参数数量不同)makeCoffee("美式",150);//委托给三参数方法}publicvoidmakeCoffee(Stringtype,intml){//常规制作:名称+容量(参数数量不同)intcaffeine=calculateCaffeine(type,ml);System.out.printf("☕

制作[%s]%dml(咖啡因:%dmg)\n",type,ml,caffeine);checkCaffeineSafe(caffeine);}

publicvoidmakeCoffee(Stringtype,StringsugarLevel){//定制糖量:名称+糖包数(参数类型不同)intsugar=switch(sugarLevel){case"无糖"->0;case"微糖"->1;case"半糖"->2;default->3;//全糖};System.out.printf("🍬%s添加%d包糖\n",type,sugar);}publicvoidmakeCoffee(intml,Stringtype){//逆向参数顺序:容量+名称(参数顺序不同)

以下是一个典型的方法重载示例。makeCoffee(type,ml);//重用原有逻辑System.out.println("⚠️

注意:参数顺序已调整为标准顺序");}//咖啡因计算(私有方法)privateintcalculateCaffeine(Stringtype,intml){returnswitch(type){case"浓缩"->ml*2;case"美式"->ml;case"拿铁"->ml/2;default->0;};}privatevoidcheckCaffeineSafe(intcurrent){//咖啡因安全检测if(current>MAX_CAFFEINE){System.out.println("‼️

警告:单杯咖啡因超过安全值!");}}publicstaticvoidmain(String[]args){CoffeeMachinemachine=newCoffeeMachine();machine.makeCoffee();//无参方法

参数数量不同machine.makeCoffee("拿铁",300);//名称+容量

参数数量不同machine.makeCoffee("浓缩","半糖");//名称+糖量

参数类型不同machine.makeCoffee(50,"浓缩");//容量+名称

参数顺序不同}}07方法重载‌1.返回值不参与重载‌:仅修改返回值类型无法构成重载。例如,以下代码会编译失败:publicintcalculate(inta,intb){returna+b;}publicdoublecalculate(inta,intb){return(double)(a+b);}//编译错误2.可变参数的优先级‌:可变参数(String...)本质是数组,当与固定参数方法冲突时,固定参数版本优先。例如:publicvoidprint(Strings1,Strings2){/*...*/}publicvoidprint(String...strs){/*...*/}07方法重载‌2.避免歧义调用‌:当参数类型存在隐式转换时,可能导致编译器无法确定最佳匹配,从而导致编译错误。例如下面这个“食谱助手”的小例子,addSth()方法的两种方法重载中的两个参数int和double存在隐式转换,当数据类型明确时方法编译执行正常,但如果提供需要隐式转换的数据(10,5)调用方法,则产生歧义,系统报错。注意使用注释帮助查看这一现象。publicclassRecipeHelper{//食谱助手

publicvoidaddSth(intsugar,doubleliquid){//加糖(g)和液体(ml)System.out.printf("添加%dg糖+%.1fml液体\n",sugar,liquid);}publicvoidaddSth(doubleliquid,intsugar){//加液体(ml)和糖(g)System.out.printf("混合%.1fml液体+%dg糖\n",liquid,sugar);}publicstaticvoidmain(String[]args){RecipeHelperchef=newRecipeHelper();chef.addSth(10.0,15);//编译正常chef.addSth(10,15.0);//编译正常

chef.addSth(10,15);//歧义调用!编译错误}}08项目演练08项目演练项目名称:垃圾分类小卫士‌场景设定:城市环保局推出一款垃圾分类训练系统,用户通过创建不同垃圾对象进行投放练习。每个垃圾对象具有固定属性,系统自动判断分类正确性并给出环保知识提示。设计要求:1.垃圾对象创建后不可修改属性(体现环保的确定性)2.通过方法调用实现分类验证3.展示对象间的协作与责任意识08项目演练importjava.util.Scanner;classGarbageItem{//垃圾实体类(封装核心属性)Stringname;//垃圾名称StringrealType;//真实分类StringuserGuess;//用户猜测分类booleanisChecked;//是否已验证

publicGarbageItem(Stringname,StringrealType){//构造方法=name;this.realType=realType;this.isChecked=false;}publicvoidclassify(GarbageItemitem){//用户进行分类尝试(行为封装)Scannerscanner=newScanner(System.in,"UTF-8");System.out.println("\n请对【"+name+"】进行分类(可回收/有害/厨余/其他):");StringuserType=scanner.nextLine();this.userGuess=userType;this.isChecked=true;System.out.println(+"投放至["+this.userGuess+"]收集箱");if(item.userGuess.equals(item.realType)){System.out.println("✅

正确!"+getEnvironmentalTip());}importjava.util.Scanner;classGarbageItem{//垃圾实体类(封装核心属性)Stringname;//垃圾名称StringrealType;//真实分类StringuserGuess;//用户猜测分类booleanisChecked;//是否已验证

publicGarbageItem(Stringname,StringrealType){//构造方法=name;this.realType=realType;this.isChecked=false;}publicvoidclassify(GarbageItemitem){//用户进行分类尝试(行为封装)Scannerscanner=newScanner(System.in,"UTF-8");System.out.println("\n请对【"+name+"】进行分类(可回收/有害/厨余/其他):");StringuserType=scanner.nextLine();this.userGuess=userTyp

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论