java学习笔记(6)方法、内存、重载
方法:
/* 以下程序不使用"方法",分析程序存在哪些缺点? *以下代码都是计算两个int类型数据的和,相同的代码写了两遍(只不过每次参与求和的数据不同)。 代码没有得到重复使用。 *java语言当中应该有这样的一种机制: -某个功能代码只需要写一遍。 -要使用这个功能,只需要给这个功能传递具体的数据。 -这个功能完成之后返回一个最终结果。 这样代码就可以重复利用了,提高代码复用性。【这就是"方法"】 *使用这个方法,我们称为:调用/invoke */ public class Method01{ public static void main(String[] args){ // 需求1:请编写程序计算10和20的和,并将结果输出【功能是 计算两个int类型数据的和】 int a = 10; int b = 20; int c = a + b; System.out.println(a + " + " + b +" = " + c); // 需求2:请编写程序计算666和888的和,并将结果输出【功能是 计算两个int类型数据的和】 int x = 666; int y = 888; int z = a + b; System.out.println(x + " + " + y +" = " + z); // 以上的两个需求其实就是一个需求,需求是:计算两个int类型的和,功能相同 // 只不过每次参与计算的具体数据不同。 } }
/* 以下直接使用方法这种机制【这个例子不讲方法的语法】,分析程序的优点? *代码得到了重复使用 *方法的本质是什么? -方法就是一段代码片段,并且这段代码片段可以完成某个特定的功能,并且可以被重复的使用。 -方法对应的英语单词是:Method -方法在c语言中叫作函数/Function,在java语言中叫方法 *方法定义在类体当中,方法体之外。 *在一个类体重可以定义多个方法,方法编写的位置没有先后顺序,可以随意。 *方法体当中不能再定义方法 *方法体有java语句构成,方法体当中的代码遵守自上而下的顺序执行。 */ public class Method01{ // 类体 public static void main(String[] args){ // 方法体 // 下面是调用方法计算int的和 sumint(30,40);//30 + 40 = 70 Method01.sumint(50,60);//50 + 60 = 110 } // 方法 // 单独定义一个方法 // 该方法完成计算两个int类型的和,并且将结果输出 public static void sumint(int a,int b){ // 方法体 int c = a + b; System.out.println(a + " + " + b + " = " + c); } }
方法定义规则:
/* 关于java语言中的方法: 1、方法怎么定义?语法结构: [修饰符列表] 返回值类型 方法名(形式参数列表){ 方法体; } 2、对以上的语法结构进行解释说明: 2.1、关于修饰符列表 *可选项,不是必须的 *目前可统一写成:public static 【以后再说】 *方法的修饰符列表当中有static关键字的话,怎么调用这个方法? -类名.方法名(实际参数列表); 2.2、返回值类型 *什么是返回值? -一个方法是可以完成某个特定功能的,这个功能结束之后大多数都是需要 返回最终的执行结果,执行结果可能是一个具体存在的数据。只要是数据一定 会有类型,而这个存在的数据就是返回值。 *返回值类型是什么? -返回值是一个具体存在的数据,数据都是由类型的,此处需要指定的是 返回值的具体类型 *返回值类型都可以指定哪些类型呢? -java中任意一种类型都可以,包括基本数据类型和所有的引用数据类型。 *也可能这个方法执行之后不返回任何数据,java中规定,当一个方法执行结束之后 不返回任何数据,返回值类型位置必须编写:void关键字 *返回值类型可以是什么? byte、short、int、long、float、double、boolean、char、String、void...... *返回值类型若不是void,表示这个方法执行结束之后必须返回一个具体的数值。 当方法执行结束的时候没有返回任意数据的话编译器报错。 *怎么返回值呢? return 值; 并且要求"值"的数据类型,必须和"方法的返回值类型一致"。不然编译器报错。 *当返回值类型是void的时候,在方法体当中不能编写"return 值;"这样的语句 但是可以编写"return;"这样的语句 *只要带有return关键字的语句执行,return语句所在的方法结束。【不是jvm结束,是所在的方法结束】 2.3、方法名 *只要是合法的标志符就行 *方法名最好见名知意 *方法名最好是动词 *方法名要求首字母小写,后面的单子首字母大写,驼峰命名方式 2.4、形式参数列表:简称 形参 *形参是局部变量 *形参的个数可以是:0-N个 *多个形参之间用"逗号"隔开 *实参和形参列表必须满足: -数量相同 -类型对应相同 *形参中起决定性作用的是 形参的类型,形参的名字只是一个标识符,形参的名字 就是局部变量的名字。 例如: 方法定义 public static int sum(int a,int b){//(int a,int b)是形参列表 } 方法调用: sum("abc","def");//编译器会报错, sum(10,20);//编译通过 (10,20)是实参列表 2.5、方法体 方法体必须有大括号括起来,方法体当中的代码有顺序,由上而下执行。 并且方法体由java语句构成,java语句有";"结尾。 3、方法怎么调用? 方法只定义时不会执行的,只有调用的时候才执行 语法规则:【这里只说方法的修饰符当中有static关键字的方法】 类名.方法名(是参列表);这是一条java语句,表示调用某个类的某个方法,传递这样的参数 */ public class Method01{//类相当于汽车工厂 // 类体 public static void main(String[] args){ // 方法体 } // 定义一个方法 // 一个车间 public static int sumint(int a,int b){ // 方法体 int c = a + b; System.out.println(a + " + " + b + " = " + c); } }
/* */ // public表示公开的 // class表示定义类的关键字 // Method01是一个类名 public class Method01{//表示定义一个公开的类,起名Method01,由于是公开的类,所以源文件名必须是Method01 // 类体 // 类体中不能直接编写java代码,除声明变量之外 // 方法出现在类体当中 // 方法 // public表示公开的 // static表示静态的 // void表示方法执行结束之后不返回任何数据 // main是方法名:主方法 // (String[] args):形式参数列表,其中String是一种引用数据类型,args是一个局部变量的变量名 // 所以以下只有args这个局部变量的变量名是可以随意写的 // 主方法就需要这样固定编写,这是程序的入口。【sun规定的,必须这样写才行】 public static void main(String[] args){ // 方法体 // 这里的程序是一定会执行的 // main方法是JVM负责调用的,是一个入口的位置 // 从这里来时起点开始执行程序 // 既然是这样,我们就可以在这里编写java语句来调用其它方法 // 调用Method01的sum方法 (只有static修饰符的方法可以这样调用,类名也可以省略 Method01.sum(10,20); // 也可以这样 sum(20,40);//只有static修饰符的方法才可以这样调用 } // 自定义方法 ,不是程序入口 // 方法作用:计算两个int类型数据的和,不要求返回结果,但是要求将结果直接输出到控制台 // 修饰符列表:public static // 返回值类型:void // 方法名:sum // 形式参数列表:(int x,int y) // 方法体:主要任务是,求和之后,输出计算结果 public static void sum(int i,int j){ System.out.println(i + " + " + j + " = " + (i + j)); } }
/* 方法的难点: public static ???(返回值) 方法名(返回什么参数合适){ //如何编写代码 } 方法的调用不一定在main方法当中, 只要程序可以执行到的位置,都可以执行其他方法。 */ public class Method01{ public static void sum(int a,int b){ System.out.println(a +" + " + b + " = " + (a + b)); // 调用dosome方法 Method01.doSome(); } public static void doSome(){ System.out.println("do some"); } // 主方法 public static void main(String[] args){ // 调用 sum方法 Method01.sum(1,2); System.out.println("hello world"); } }
执行javac -encoding UTF-8 Method01.java(编译)
java Method01(执行)
/* 方法调用 1、方法的修饰符列表当中有static关键字,完整的调用方法是:类名.方法(是参列表); 2、但是有的时候"类名."可以省略。什么情况下可以省略呢? m1(){ m2(); } //上述调用省略"类名.",只有在m1和m2方法在同一个类体当中时,可以省略 3、一个java源文件中建议只定义一个class,比较清晰,这里只是举例方便才在java源文件当中写多个class */ public class Method01{ public static void main(String[] args){ // 调用方法 Method01.m(); // 对于方法的修饰符列表当中有static关键字的,"类名."可以省略不写吗? m();//执行成功 "类名."可以省略不写 // 调用其它类,【不是本类中】的方法 A.doOther();//调用成功 // 省略"类名.",试试 (此时,是在当前类中找doOther方法,在当前类中不存在。 // 编译错误: 找不到符号 // doOther(); } public static void m(){ System.out.println("m Method execute!"); // 调用当前类中的方法,可以省略"类名." m2(); // 完整的方式调用m2方法,在其它类中也可以这样调用 Method01.m2(); // 不想调用本类中的m2方法,想调用其它类中的m2方法 // 类名.方法(); // 以后只要调用方法,都不省略"类名.",规范上比较好,如果知道这个语法,可以少写几句代码 A.m2(); } public static void m2(){ System.out.println("m2 execute!"); } } class A{ public static void doOther(){ System.out.println("'A's doOther method invoke"); } public static void m2(){ System.out.println("'A's m2 execute!"); } }
/* 分析程序的输出结果: main begin! m1 begin! m2 begin! m2 over! m1 over! main over! 对于当前的程序来说,main方法最先调用,也是最后一个结束。 最后调用的方法是m2,该方法最先结束 方法中的代码是自上而下执行的即可,上一行代码未执行结束,下一行代码不会执行 */ public class Method01{ public static void main(String[] args){ System.out.println("main begin!"); m1(); System.out.println("main over!"); } public static void m1(){ System.out.println("m1 begin!"); m2(); System.out.println("m1 over!"); } public static void m2(){ System.out.println("m2 begin!"); System.out.println("m2 over!"); } }
/* 方法的返回值类型不是void的时候 1、返回值类型不是void的时候,要求方法必须保证百分百的执行"return 值;"这样的语句来完成值的返回。 没有这个语句,编译器会报错。 2、一个方法有返回值的时候,当我们调用这个方法的时候,方法返回一个值, 对于调用者来说,这个返回值可以选择接受,也可以选择不接受。 但是大部分情况下,我们是选择接收的。 */ public class Method01{ public static void main(String[] args){ // 方法调用 divide(10,3);//这里没有接收这个方法的返回数据 // 这里接收一下方法的返回值 // 采用变量接收 // 变量的数据类型需要和方法的返回值类型相同,或者可以自动类转换 // boolean b = divide(10,3);//编译报错 不兼容的类型: int无法转换为boolean // 赋值运算符的右边线执行,将执行结果赋值给左边的变量 int i = divide(10,3); System.out.println(i);//3 long x = divide(10,3);//小类型想大类型存在自动类型转换 System.out.println(x);//3 } /* 需求: 请定义并实现一个方法,该方法可以计算两个int类型的商; 要就将最终的调用结果返回给调用者。 */ // 编译报错:缺少返回语句 // public static int divide(int a,int b){ // } // 编译错误:缺少返回值 // public static int divide(int a,int b){ // return; // } // 不兼容的类型: boolean无法转换为int // public static int divide(int a,int b){ // return true; // } public static int divide(int a,int b){ return a / b; } }
/* 深入return语句 *带有return关键字的java语句只要执行,所在的方法执行结束。 *在"同一个作用域"当中,return语句下面不能编写任何代码,因为这些代码永远都执行不到。 所以编译报错。 */ public class Method01{ public static void main(String[] args){ int returnValue = m(); System.out.println(returnValue);//1 System.out.println(m());//1 } // public static int m(){ // int a = 10; // if(a>3){//截止到这,m方法无法保证,这个方法百分之百的有返回语句,所以会编译报错 // return 1; // }else{//这样 加上else语句后,就能够百分百保证这个方法有返回语句,殡仪就会通过 // return 0; // } // } // 将m方法改进一下,去掉else语句 // public static int m(){ // int a = 10; // if(a>3){ // return 1; // // return 语句后面加上语句后 无法执行,因为return后的语句执行不到,会编译报错 // // System.out.println("hello"); // } // return 0; // // 在同一作用域下,return后面不能有语句,因为执行不到,会导致编译错误 // // System.out.println("hello"); // } // 将m方法再次改进 public static int m(){ int a = 10; return a > 3 ? 1 : 0; } }
/* 在返回值类型为void的方法中使用return语句。 "return;"可以出现在返回值为void方法当中,主要用来终止方法的执行。 */ public class Method01{ public static void main(String[] args){ m(); s(); } public static void m(){ // return 0;//不兼容的类型: 意外的返回值 return; } public static void s(){ for(int i =0;i<10;i++){ if(i==5){ // return;//return不是终止的for循环,而是终止整个方法 break;//终止for循环 } System.out.println("i--->"+i); } } }
内存:
栈的介绍:
队列是先进先出
/* 方法在执行过程当中,在JVM中的内存是如何分配的?内存是如何变化的? 1、方法只定义,不调用,是不会执行的,并且也不会给该方法分配运行所属的内存空间。 只有在调用这个方法的时候,才会动态的给这个方法分配所属的内存空间。 2、在jvm内存划分上有这样三块主要的内存空间(当然,除了这三块之外还有其它的内存空间) *方法区内存 *堆内存 *栈内存 3、关于栈的数据结构: *栈 stack ,是一种数据结构 *数据结构反应的是数据的存储形态。 *数据结构是独立的学科,不属于任何编程语言的范畴,只不过在大多数编程语言当中要使用数据结构。 *作为程序员需要提前精通:数据结构 + 算法【计算机专业必修的一门课程】 *java程序员在不精通数据结构和算法的前提下,也可能进行java开发,因为java有一套庞大的类库支撑。 说白了就是别人写好了,拿过来直接用,【javase当中集合章节使用了大量的数据结构】 *常见的数据结构: - 数组 - 队列 - 栈 - 链表 - 二叉树 - 哈希表/散列表 ...... 4、方法执行的时候代码片段存在哪里?方法执行的时候执行过程的内存在哪里分配? *方法代码片段属于.class字节码文件的一部分,字节码文件在类加载的时候, 将其放到了方法区当中,所以JVM中的三块只要内存空间中,方法区内存最先有。 存放了代码片段。 *代码片段虽然再内存区当中只有一份,但是可以被重复调用。 没一次调用这个方法的时候,需要给该方法分配独立的活动场所, 在栈内存中分配。 5、方法调用的时候,会给该方法分配独立的内存空间,在栈中分配,此时发生压栈动作, 方法执行结束后,给该方法分配的内存空间全部释放,此时发生图弹栈动作。 *压栈:给方法分配内存空间push *弹栈:释放该方法的内存空间pop 6、局部变量在栈中存储,局部变量运行阶段内存在栈中分配。 */ public class Method01{ public static void main(String[] args){ } }
继续说内存:
上面是下面代码执行时,方法分配内存空间的情况
/* 重点:方法调用的时候,在参数传递的时候,实际上传递的是变量汇总保存的那个"值"传过去了。 */ public class Method01{ public static void main(String[] args){ int a = 10; int b = 20; int retValue = sumInt(a,b); System.out.println(retValue);//10 } public static int sumInt(int i,int j){ int result = i + j; int num = 3; int retValue = divide(result,num); return retValue; } public static int divide(int x,int y){ int z = x / y; return z; } }
下面再次根据代码,画一下方法执行时内存的分配情况:
/* */ public class Method01{ public static void main(String[] args){ int i = 10; method(i); System.out.println("method--->"+i);//10 } public static void method(int i){ i++; System.out.println("method--->"+i);//11 } }
下面开始说方法重载,先不说方法重载,先看看下面的代码有什么缺点:
/* 以下代码不使用方法重载机制,不使用overload,分析程序存在缺点。 */ public class Method01{ public static void main(String[] args){ // 调用方法 int result1 = sumInt(1,2); System.out.println(result1);//3 double result2 = sumDouble(1.0,2.0); System.out.println(result2);//3.0 long result3 = sumLong(1L,2L); System.out.println(result3);//3 } // 定义一个方法,可以计算两个int类型的和 public static int sumInt(int a,int b){ return a + b; } // 定义一个方法,可以计算两个double类型的和 public static double sumDouble(double a,double b){ return a + b; } // 定义一个方法,可以计算两个long类型数据的和 public static long sumLong(long a,long b){ return a + b; } }
缺点:以上方法,都是计算数据的和,但是我们写了3个不同的方法,方法名称也不想同,程序员调用需要记好多方法名称,那么有没有办法,让这些方法名称相同,
当传入long类型数据时就是计算long类型数据的和,当传入int或double数据时,计算的就是对应数据类型的和。java语言中有这种机制,叫方法重载机制。
下面体验一下方法重载的优点:
/* 一下代码体验一下方法重载的优点: 1、调用时只需要记住一个方法名即可,调用比较方便,代码美观。 前提:功能相似的时候,方法名可以相同 但是,功能不同的时候尽可能让这两个方法的名字不同。 */ public class Method01{ public static void main(String[] args){ // 调用方法的时候就想调用一个方法一样 // 参数的类型不同,对应调用的方法不同 // 此时区分方法,不再依靠方法名了,依靠的是参数的数据类型 System.out.println(sum(1,2));//3 System.out.println(sum(1.0,2.0));//3.0 System.out.println(sum(1L,2L));//3 } public static int sum(int a,int b){ System.out.println("sum(int,int)"); return a + b; } public static double sum(double a,double b){ System.out.println("sum(double,double)"); return a + b; } public static long sum(long a,long b){ System.out.println("sum(long,long)"); return a + b; } }
详细介绍方法重载:
/* 1、方法重载,又被称为overload 2、什么时候考虑使用方法重载? *功能相似的时候,尽可能让方法名相同 但是,功能不同/不相似的时候尽量让方法名不同 3、什么条件满足之后构成了方法重载? *在同一个类当中 *方法名相同 *参数列表不同 -数量不同 -顺序不同 -类型不同 4、方法重载和什么有关系和什么没有关系? *方法重载和方法名字和参数列表有关 *方法重载和返回值类型无关 *方法重载和修饰符列表无关 */ public class Method01{ public static void main(String[] args){ m1(); m1(10); m2(1,2.0); m2(2.0,1); m3(1); m3(2.0); } // 以下两个方法构成重载 public static void m1(){} public static void m1(int a){} // 以下两个方法构成重载 public static void m2(int a,double b){} public static void m2(double b,int a){} // 以下两个方法构成重载 public static void m3(int a){} public static void m3(double a){} // 以下不是方法重载,是发生了方法重复了 // public static void m4(int a,int b){}; // public static void m4(int b,int a){}; // 方法重载和返回值类型无关,以下方法重复,编译报错 // public static void x(){} // public static int x(){return 1;} // 方法重载和修饰符列表无关,以下方法重复,编译报错 // void y(){} // public static void y(){} }
方法重载的使用
/* 方法重载的具体应用 */ public class Method01{ public static void main(String[] args){ U.p("哈哈"); U.p(1); } } // 自定义类 class U{ public static void p(byte b){ System.out.println(b); } public static void p(short b){ System.out.println(b); } public static void p(int b){ System.out.println(b); } public static void p(long b){ System.out.println(b); } public static void p(boolean b){ System.out.println(b); } public static void p(float b){ System.out.println(b); } public static void p(double b){ System.out.println(b); } public static void p(char b){ System.out.println(b); } public static void p(String b){ System.out.println(b); } }
我们可以将这个U类前面加上public,单独写个java源文件,编译,之后就可以在其它的java源文件调用了,!!
U.java
public class U{ public static void main(String[] args){ } public static void p(byte b){ System.out.println(b); } public static void p(short b){ System.out.println(b); } public static void p(int b){ System.out.println(b); } public static void p(long b){ System.out.println(b); } public static void p(boolean b){ System.out.println(b); } public static void p(float b){ System.out.println(b); } public static void p(double b){ System.out.println(b); } public static void p(char b){ System.out.println(b); } public static void p(String b){ System.out.println(b); } }
Method01.java
/* 方法重载的具体应用 */ public class Method01{ public static void main(String[] args){ U.p("哈哈"); } }
。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
2018-12-29 看看(详情)