打印三角形金字塔 debug20241225
package com.pangHuHuStudyJava.struct; public class Print_Tran {public static void main(String[] args) {for (int j = 0; j < 5; j++) {for (int r = 5; r > j; r--) {System.out.print(' ');}for (int s = 0; s < ((2*j)+1); s++) {System.out.print('*');}System.out.println();}} }
输出结果
**************** *********
调试 debug
java的方法 20241225
什么是方法?
方法是语句的集合,他们在一起可以执行一个功能。
也有一些系统自带的方法,只需要引用进去就行。
如
System,out.println()
,这样的形式就是一个方法,他们之间有层级关系,System是一个类,out是System里的一个输出对象,Println(),是out内的输出对象,可以理解为,调用系统类System中的标准输出对象out中的方法println()package method; public class Demo01 { //main方法 public static void main(String[] args) {//main方法int sum = add(5, 2);//调用加法,输入add(),在内部给ab赋值即可System.out.println(sum);//输出方法, //输出:7 } //加法 /*public和static都为修饰符,static用来将这个方法变成类变量,从而可以在main方法中引用。* int和main方法中的void一样,是返回值类型,void代表空,即不返回。但加法需要返回值,所以* 使用int,add为方法名,方法名遵循首字母小写,后面的字母首字母大写。最后,给ab声明是int类型*/public static int add(int a,int b){return a+b;//返回一个a+b的步骤,这样在使用时,只有给a b赋值,他们默认是相加关系。} }
package com.pangHuHuStudyJava.method; // 定义包名 import java.util.Scanner; // 导入 Scanner 类,用于获取用户输入 public class Demo01 { // 定义类 Demo01public static void main(String[] args) { // 主方法,程序入口Scanner scanner = new Scanner(System.in); // 创建 Scanner 对象用于获取输入System.out.print("请输入你想打印三角形金字塔的行数:"); // 提示用户输入金字塔的行数int num = scanner.nextInt(); // 获取用户输入的整数(即金字塔的行数)print_tran(num); // 调用 print_tran 方法打印金字塔,传递用户输入的行数scanner.close(); // 关闭 Scanner 对象,释放资源}// 定义 print_tran 方法,接收一个整数参数 num,表示金字塔的行数public static void print_tran(int num){// 外层循环控制金字塔的行数,行数为 numfor (int j = 0; j < num; j++) {// 内层第一个循环:输出空格// 每一行的空格数随着层数的增加而减少for (int r = num; r > j; r--) {System.out.print(' '); // 输出空格} // 内层第二个循环:输出 '*',表示金字塔的星号部分// 每一行的星号数量为 2*j + 1for (int s = 0; s < ((2*j)+1); s++) {System.out.print('*'); // 输出星号}// 打印完一行后换行System.out.println();}} }
请输入你想打印三角形金字塔的行数:4****************
以这个的形式,可以在main方法之外制造一个加法。
方法 是语句的结合,他们在一起可以执行一个功能
方法是解决一类问题的步骤的有序组合
方法包含在类或对象中
方法在程序中被创建,在其他地方被引用
方法的命名规则:首字母小写驼峰原则
方法的定义
java的方法和其他语言的函数类似,是一段用来完成特定功能的代码片段
方法包含一个方法头和一个方法体:
基本内容:
- 修饰符、(可选的,告诉编译器如何调用该方法,定义了该方法的访问类型 Static)
- 返回值类型(如一些不需要返回的语句,就用void,其他则用关联的关键词int,double,char等,返回值需要通过return的关键词返回出去)
- 方法名、(方法的名称,遵循首字母小写,后面单词首字母大写的命名规范,方法名只是为了方便调用)
- 参数类型(形参,*用来定义参数、实参,实际调用方法内传递给他的参数)
- 方法体(定义方法的功能)
修饰符 返回值类型 方法名(参数类型 参数名){...方法体...return 返回值; }
创建并使用比大小方法:
return 除了返回结果,还可以终止方法
package weiwei.method; public class Dem3 {public static void main(String[] args) {int max = max(3, 3);//在main方法里输出参数类型(实体参数)} // 修饰符 返回值类型 方法名 参数类型(形式参数)public static int max (int num1,int num2){//比大小的方法//方法体int result = 0;//定义一个变量if (num1==num2){//如果相等,用return来终止方法System.out.println("num1==num2");return 0;//除了返回结果,还可以终止方法}if (num1>num2){//如果num1大于num2result = num1;//变量result就等于num1}else{result = num2;}return result;//方法的最后需要一个return来返回结果} }
方法调用
调用方法:对象名.方法名(实参列表)
Java 支持两种调用方法的方式,根据方法是否返回值来选择。
当方法返回一个值的时候,方法调用通常被当做一个值。例如:
int larger = max(30,40);
如果方法返回值是void,方法调用一定是一条语句。
System.out.println("Hello,kuangshen!");
课后拓展了解:值传递(java都是值传递!)和引用传递
值传递: 是指在调用方法时,将实际参数拷贝一份传递给方法,这样在方法中修改形式参数时,不会影响到实际参数。
引用传递: 也叫地址传递,是指在调用方法时,将实际参数的地址传递给方法,这样在方法中对形式参数的修改,将影响到实际参数。 也就是说值传递,传递的是副本。 引用传递,传递的是实际内存地址。
值传递:再方法中改变不了原始值,要想改可以带返回值再赋值
public class Demo03 {public static void main(String[] args) {int origin_value = 10; // 原始值为 10modifyValue(origin_value); // 调用方法并传递原始值System.out.println("原始值没有改变仍为:" + origin_value); // 输出原始值}public static void modifyValue(int num) {num = 24; // 修改 num 的值为 24System.out.println("方法将值改为:" + num); // 输出方法内修改后的 num} }
形参名字和方法内定义局部变量名能重名吗?
肯定不可以
public class ValuePassExample {public static void main(String[] args) {int a = 10;System.out.println("Before method call: " + a); // 输出 10modifyValue(a);System.out.println("After method call: " + a); // 输出 10,a 不会改变}public static void modifyValue(int num) { // 方法参数 numint num = 20; // 定义与方法参数同名的局部变量 num,这会导致编译错误System.out.println("Inside method: " + num); // 输出 20} }
引用传递:
在 C 语言中,引用传递可以通过传递指针来实现。你可以传递一个变量的地址,然后在函数内部通过指针修改原始变量的值。
#include <stdio.h> void modifyValue(int *p) {*p = 24; // 通过指针修改原始值 }int main() {int a = 10;printf("Before: %d\n", a); // 输出 10modifyValue(&a); // 传递 a 的地址printf("After: %d\n", a); // 输出 24return 0; }
Before: 10 After: 24
3. Java 中是否能模拟引用传递?
虽然 Java 只有值传递,但我们可以通过传递对象的引用来模拟类似于引用传递的效果。引用传递的感觉是,在 Java 中,虽然依旧是值传递,但对于对象类型来说,传递的是对象的引用副本,因此你可以修改对象的内部状态(属性、字段等),而不是重新赋值给整个对象。
Java 示例:
class Person {String name;public Person(String name) {this.name = name;} } public class Demo03 {public static void main(String[] args) {Person p = new Person("Alice");System.out.println("Before: " + p.name); // 输出 AlicemodifyValue(p); // 传递对象引用System.out.println("After: " + p.name); // 输出 Bob}public static void modifyValue(Person p) {p.name = "Bob"; // 修改对象的字段值} }
- 传递的仍然是对象引用的副本(值传递),但你可以通过这个引用来修改对象的内容(属性值)。
- 注意:你不能通过值传递改变引用对象本身的指向(即不能让
p
变成指向另一个对象),但可以修改对象的内部状态。4. 总结:
- 值传递:Java 所有方法调用参数都使用值传递,无论是基本类型还是引用类型。对于基本类型,传递的是值的副本;对于对象类型,传递的是引用的副本(即对象的地址的副本),修改对象的属性会反映到外部,但不会改变对象引用本身。
- 引用传递(C语言):C 语言可以通过传递指针来实现引用传递,直接操作原始数据(通过地址)。Java 没有直接的指针概念,但通过对象引用模拟了类似的效果。
- 如果你想在 Java 中修改传入参数的值,可以通过返回值来实现:
- 对于基本数据类型,你可以将修改后的值返回并赋给原始变量。
- 对于对象类型,修改对象的属性即可(引用类型可以直接修改对象的状态)。
方法的重载
重载就是在一个类中,有相同的函数名称,但形参不同的函数。
就是一个类里有两个不同的方法,方法名相同
package weiwei.method; public class Dem4 {public static void main (String[]args){double orange = orange(1.2, 2.3);int orange1 = orange(5, 3);//调用时将double改为int类型,并输入对应的有效数据}public static int orange(int a, int b) {//整数比大小方法int c = 0;if (a == b) {System.out.println("相等");} else if (a > b) {a += c;} else if (b > a) {b += c;} else {System.out.println("不是有效数据");}return c;}public static double orange(double a,double b){//浮点数类型查看是否相等double c = 0;if (a!=b){System.out.println("不等");}else if (a==b){System.out.println("相等")}else{System.out.println("不是有效数据");}return c;} }
方法的重载规则:
方法名称必须相同
参数列表必须不同(个数不同、或类型不同、参数排列顺序不同等……)
方法返回类型可以相同可以不同
仅返回类型不同不足以称为方法的重载
实现理论:
◆方法名称相同时,编译器会根据调用方法的参数个数、参数类型等去逐个匹配,以选择对应的方法,如果匹配失败,则编译器报错。
package com.pangHuHuStudyJava.method; public class Demo05 {public static void main (String[] args){// 调用重载方法时传入了浮点数类型的参数double orangeResult = orange(1.2, 2.3); // 调用 double 版本的 orange 方法 double orange = orange(1.2, 2.3);//orange = orange(1.2, 2.3);System.out.println(orangeResult); // 输出浮点数方法的返回值// 调用重载方法时传入了整数类型的参数System.out.println(orange(5, 3)); // 调用 int 版本的 orange 方法,并输出整数方法的返回值}// 这个方法接受两个整数类型的参数,比较它们并返回更大的值public static int orange(int a, int b) { int c = 0; // 用于存储比较结果// 判断两个整数是否相等,并输出相应的提示信息if (a == b) {System.out.println("相等");} else if (a > b) { // 如果第一个参数大于第二个,则返回第一个参数的值c += a;} else if (b > a) { // 如果第二个参数大于第一个,则返回第二个参数的值c += b;} else {System.out.println("不是有效数据");}return c; // 返回较大的值}// 这个方法接受两个浮点数类型的参数,比较它们是否相等,并输出相应的提示信息public static double orange(double a, double b) { double c = 0; // 用于存储比较结果// 判断两个浮点数是否相等,并输出相应的提示信息if (a != b) {System.out.println("不等");} else if (a == b) {System.out.println("相等");} else {System.out.println("不是有效数据");}return c; // 返回浮点数比较的结果} }
输出结果:
不等 5
命令行传参20241225
有时候你希望运行一个程序时候再传递给它消息。这要靠传递命令行参数给main()函数实现。
package com.pangHuHuStudyJava.method; public class Demo04 {public static void main(String[] args) {for (int i = 0; i < args.length; i++) {System.out.println("arg["+i+"]:"+args[i]);}} }
Microsoft Windows [版本 10.0.22631.4602] (c) Microsoft Corporation。保留所有权利。D:\download\code\JavaSE\basic_demo\src\com\pangHuHuStudyJava\method>javac Demo04.javaD:\download\code\JavaSE\basic_demo\src\com\pangHuHuStudyJava\method>cd ../D:\download\code\JavaSE\basic_demo\src\com\pangHuHuStudyJava>cd ../D:\download\code\JavaSE\basic_demo\src\com>cd ../D:\download\code\JavaSE\basic_demo\src>java com/pangHuHuStudyJava/method/Demo04 hello World!我是胖乎乎 arg[0]:hello arg[1]:World!我是胖乎乎
编译可以在源文件(
Demo04.java
)的文件夹中,但是编译要在method 文件夹中编译:
D:\download\code\JavaSE\basic_demo\src\com\pangHuHuStudyJava\method>javac Demo04.java
编译用 javaci命令 带上文件后缀 .java 在源文件所在目录下就可以
运行:
D:\download\code\JavaSE\basic_demo\src>java com/pangHuHuStudyJava/method/Demo04 hello World!我是胖乎乎
运行时如果你在其他目录,先切换到项目的
src
目录:使用 java命令 写清楚文件位置(不需要class 后缀了,加了反而报错!),加上main函数中命令行要输入的字符串
1. 为什么编译可以在源文件文件夹下就可以,运行就必须要到
src
文件夹下呢?这是因为 Java 编译 和 Java 运行 机制的不同。
- 编译(
javac
):
当你执行javac Demo04.java
时,编译器会把源代码文件(.java
文件)转换成字节码文件(.class
文件)。编译器会在当前工作目录下生成.class
文件,所以如果你在com/pangHuHuStudyJava/method
目录下编译源文件,生成的.class
文件会放在同一目录下。- 运行(
java
):
当你运行 Java 程序时,Java 虚拟机(JVM)需要知道你希望运行的类(.class
文件)在哪里。在命令行中,你需要提供类的全路径(包路径),而且必须从src
目录开始。这是因为在 Java 中,类的路径结构是由包名(package
)来决定的,src
目录通常是你项目的根目录,而com/pangHuHuStudyJava/method/Demo04
是该类的路径。
- 例如,如果你的
.class
文件在src/com/pangHuHuStudyJava/method/Demo04.class
目录下,JVM 需要从src
目录开始加载类。- 因此,你必须从
src
目录运行你的程序(或确保类路径正确),这样 JVM 才能根据包名找到类文件。2. 为什么运行时必须明确指定
.class
后缀而不加.class
后缀?
java
命令不需要加.class
后缀:
在 Java 中,运行类时使用的是类名(包括包路径),而不是文件名。命令java com.pangHuHuStudyJava.method.Demo04
就是告诉 JVM 从com/pangHuHuStudyJava/method/Demo04.class
中加载类,不需要加.class
后缀。
如果加了.class
后缀(如java com.pangHuHuStudyJava.method.Demo04.class
),JVM 会无法识别类名,导致报错。- 为什么不能加
.class
后缀:
JVM 会自动从类路径(classpath
)中查找带有指定包名的.class
文件。例如,java com.pangHuHuStudyJava.method.Demo04
会自动查找com/pangHuHuStudyJava/method/Demo04.class
文件,而加了.class
后缀后就变成了错误的路径,导致加载失败。3. 为什么在 IDEA 终端中不行?//暂时不管!!!
这是因为 IDEA 中的 终端 可能没有自动配置正确的类路径,或者你没有指定
src
目录为类路径。
IDEA 和命令行的区别:
在 IDEA 中,IDE 会自动设置好项目的类路径,编译和运行时不需要手动设置类路径,而命令行中你必须自己处理路径和类路径。IDEA 终端中可能的问题:
- IDEA 的终端默认没有正确配置
classpath
。例如,你没有设置正确的工作目录或类路径。- IDEA 的终端和 Java 项目结构不匹配。IDEA 的终端有时和项目结构不完全一致,因此你可能需要手动指定类路径。
你可以通过以下方式来配置 IDEA 终端:
- 设置
classpath
环境变量,确保运行时能够找到你的.class
文件。- 或者在 IDEA 的 运行配置 中,确保设置了正确的类路径。
4. 如何解决?//暂时不管!!!
解决在 IDEA 终端中运行的问题:
- 确保类路径正确:你可以在 IDEA 中配置好类路径,确保在终端中运行时使用正确的类路径。
- 使用 IDEA 的运行配置:IDEA 提供了运行配置的功能,可以在不使用命令行的情况下直接运行 Java 程序。确保你在 IDEA 的运行配置中正确设置了项目的类路径。
在命令行中正确运行:
确保在
src
目录下运行:命令行运行时,进入src
目录,并使用java com.pangHuHuStudyJava.method.Demo04
运行程序。编译并运行时的步骤
进入
method
目录进行编译:
javac Demo04.java
回到
src
目录并运行:
bash java com.pangHuHuStudyJava.method.Demo04 hello World!我是胖乎乎
如何在命令行中配置类路径: 如果你不想切换到
src
目录,也可以通过-cp
或-classpath
参数来显式设置类路径。例如:复制代码 java -cp D:\download\code\JavaSE\basic_demo\src com.pangHuHuStudyJava.method.Demo04 hello World!我是胖乎乎
总结:
- 编译:你可以在
method
文件夹下编译源文件。- 运行:在运行时,JVM 需要通过类路径加载类,因此你必须从
src
文件夹运行,或者使用-cp
参数指定类路径。- IDEA:IDEA 会自动处理类路径和运行配置,而命令行需要你手动处理这些细节。
希望这些解释能帮助你理解为什么编译和运行有不同的要求以及如何在命令行和 IDEA 中运行 Java 程序。
可变参数20241225
Java1.5增加了新特性:可变参数:适用于参数个数不确定,类型确定的情况,java把可变参数当做数组处理。
注意:可变参数必须位于最后一项。当可变参数个数多余一个时,必将有一个不是最后一项,所以只支持有一个可变参数。因为参数个数不定,所以当其后边还有相同类型参数时,java无法区分传入的参数属于前一个可变参数还是后边的参数,所以只能让可变参数位于最后一项。
可变参数的特点:
(1)只能出现在参数列表的最后;
(2)定义方式:类型... 参数名
(3)调用可变参数的方法时,编译器为该可变参数隐含创建一个数组,在方法体中以数组的形式访问可变参数。
public class Varable {public static void main(String[] args) {// 调用 add 方法,传递 2 和 3,返回 2+3=5System.out.println(add(2, 3)); // 输出 5// 调用 add 方法,传递 2、3 和 5,返回 2+3+5=10System.out.println(add(2, 3, 5)); // 输出 10}// 定义一个方法 add,接受一个必选参数 x 和一个可变参数 argspublic static int add(int x, int... args) {int sum = x; // 初始化 sum 为 x 的值// 遍历可变参数 args,累加每个值到 sumfor (int i = 0; i < args.length; i++) {sum += args[i]; // 累加 args 数组中的每个元素}// 返回最终的 sumreturn sum;} }
注释分析:
- 可变参数的定义:
add
方法接受两个参数:
- 第一个参数
int x
是必选的参数。- 第二个参数
int... args
是可变参数,表示可以接受多个int
类型的参数,这些参数会自动封装成一个数组args
。- 方法调用:
- 在
main
方法中,首先调用add(2, 3)
,传递了两个整数2
和3
,方法内部的args
数组包含一个元素3
。最终返回2 + 3 = 5
。- 接着调用
add(2, 3, 5)
,传递了三个整数2
、3
和5
,方法内部的args
数组包含两个元素3
和5
,最终返回2 + 3 + 5 = 10
。- 数组处理:
args
被当作一个数组处理。在add
方法中,我们通过遍历args
数组,累加数组中的每个元素到sum
中。- 由于可变参数会被自动转换成数组,因此你可以像访问普通数组一样访问
args
数组中的元素。- 方法的灵活性:
- 该方法的一个优点是,可以接收不同数量的参数,调用时不必显式声明每一个参数。你可以传入任意数量的整数,方法会根据传入的参数数量自动处理。
- 即使你没有传递任何额外的参数,
args
数组也会自动变为空数组,不会导致错误。- 可变参数的限制:
- 可变参数必须是方法的最后一个参数。如果你在方法中同时使用了其他类型的参数(如本例中的
int x
),则可变参数args
必须放在参数列表的最后。- 如果方法中有多个参数类型,且最后一个是可变参数,那么在调用时必须正确传递数据,否则编译器会报错。
package com.pangHuHuStudyJava.method; // 可变参数! public class Demo06 {public static void main(String[] args) {// 调用 search_Max 方法,传递多个整数作为可变参数System.out.println("这组数的最大值:" + search_Max(1, 2, 3, 4, 5, 6, 7, 8, 9));System.out.println("这组数的最大值:" + search_Max(10, 15, 16, 23, 453, 434, 23, 313));}// 定义一个方法 search_Max,接受一个可变参数 nums(类型为 int)public static int search_Max(int... nums) {int max = nums[0]; // 初始化 max 为第一个数// 遍历可变参数 numsfor (int i = 0; i < nums.length; i++) {// 判断当前数是否大于 max,如果是,则更新 maxif (max < nums[i]) {max = nums[i];}}// 返回最大值return max;} }
注释分析:
- 可变参数的定义:
search_Max
方法接收一个可变参数int... nums
,可以接受多个整数作为输入。这些整数会被自动封装为一个数组nums
。- 调用时:在
main
方法中,调用search_Max
并传递不同的整数列表。每次调用时,传入的整数会作为一个数组传递给search_Max
方法。- 处理可变参数:在方法内部,通过遍历
nums
数组,找出最大的数并返回。初始化max
为第一个数,然后遍历数组,更新最大值。- 可变参数的限制:方法
search_Max
中的nums
必须是方法的最后一个参数,且只能有一个可变参数。可以使用nums.length
获取传入参数的个数。package com.pangHuHuStudyJava.method; // 可变参数 public class Demo07 {public static void main(String[] args) {// 调用 print_number 方法,传递多个不同类型的数字(double 类型)print_number(2.3, 3453, 54, 54543, 3.34);}// 定义一个方法 print_number,接受一个可变参数 numbers(类型为 double)public static void print_number(double... numbers) {// 使用增强型 for 循环遍历可变参数数组 numbersfor (double number : numbers) {// 打印每个数字System.out.println(number);}} };
注释分析:
- 可变参数的定义:方法
print_number
的参数double... numbers
是可变参数,表示可以接受任意数量的double
类型参数。可变参数使用三个点(...
)来表示,表示它是一个数组。- 调用时:在
main
方法中调用print_number
时,传递了五个数字(2.3, 3453, 54, 54543, 3.34
)。这些数字会作为numbers
数组传递给print_number
方法。- 在方法内部处理:在方法内部,
numbers
被当作一个数组处理,可以通过for
循环访问每个传入的数字。通过for-each
循环,number
遍历数组中的每一个元素,并打印输出。- 可变参数的限制:可变参数必须是方法的最后一个参数,且只能有一个。如果方法中有多个参数,且其中之一是可变参数,那么可变参数必须放在最后。