一、方法
以下的程序不使用"方法" 分析有哪些缺点? 代码冗余
以下相同的代码写了三遍(只不过每次参与求和的数据不同)代码没有得到重复使用。
应该在java语言中有这样一个机制:
-某个功能代码只需要写一遍
-要使用这个功能,只需要给这个功能传递具体的数据
-这个功能完成之后返回一个最终的结果。*** 方法定义在类体当中,在一个类当中可以定义多个方法,方法编写的位置没有先后顺序,可以随意。 !!! 但是方法体当中不能再定义方法!!!!!!!
public class A
{
public static void main(String[] args){
//需求1:计算10+20的和 并输出结果 【功能:计算两个int类型数据的和】
int a=10;
int b=20;
int c=a+b;
System.out.println(c);
// 需求2: 计算30+40的和 并输出结果 【功能:计算两个int类型数据的和】
int d=30;
int e=40;
int f=d+e;
System.out.println(f);
// 需求3: 计算50+60的和 并输出结果 【功能:计算两个int类型数据的和】
int g=50;
int h=60;
int i=g+h;
System.out.println(i);
}
}
关于java语言当中的方法:
1、方法怎么定义,语法结构:【修饰符列表】 返回值类型 方法名{形式参数列表}{
方法体;
}2、对以上的语法结构进行解释说明:
2.1、关于修饰符列表
* 可选项,不是必须的
* 目前统一写成:public static
* 方法的修饰符列表当中“有static关键字”的话,怎么调用这个方法?
- 类名.方法名(实际参数列表);
2.2、返回值类型
* 什么是返回值?
一个方法是可以完成某个特定功能的,这个功能结束之后大多数都是需要
返回最终的结果的,执行结果可能是一个具体存在的数据,而这个具体存
在的数据就是返回值。
* 返回值类型?
返回值是一个具体存在的数据,数据都是有类型的,此处需要指定的是返
回值的具体类型。
* 返回值类型都可以指定哪些类型呢?
java任意一种类型都可以,包括基本数据类型和所有的引用数据类型。* 返回值?
return 值; 并且要求"值"的数据类型必须和“方法的返回值类型”一致。
返回值类型是void的时候,在方法体当中不能(用)编写"return 值;"这样的
语句。但是要注意可以编写"return;"这样的语句。
只要带有return关键字的语句执行,return语句所在的方法结束。【不是JVM结束,是return所在的方法结束】
*形式参数列表: 简称形参
形参是局部变量:int a; double b; float c;
代码框架如下
public class A // 汽车工厂
{
public static void main(String[] args){
//调用这个方法
}
// 定义一个方法
// 一个车间
public static int sumInt(int a, int b){
}
}
简单的代码演示
public class A
{
//主方法就需要这样固定的编写,这是程序的入口。
public static void main(String[] args){
// 在程序的入口进行调用(可调用多次)
A.sumInt(10,20); // 形式参数列表类型为int类型
}
// 修饰符列表:public static
// 返回值类型: void
// 方法名: sumInt
// 形式参数列表: (int a, int b)
public static void sumInt(int a, int b){
int c =a+b;
System.out.println(a+"+"+b+"="+c);
}
}
方法的调用不一定都在main方法当中,可以在其他方法当中。只要是程序可以执行到的位置,都可以去调用其他方法。
代码演示:
public class A
{
public static void dosome(int a,int b){
int c =a-b;
System.out.println(a+"-"+b+"="+c);
A.sumInt(10,20); // 再调用sumInt方法
}
// 主方法程序入口
public static void main(String[] args){
A.dosome(60,50); // 先调用dosome方法
System.out.println("hello world!"); // 最后输出hello world!
}
public static void sumInt(int a, int b){
int c =a+b;
System.out.println(a+"+"+b+"="+c);
}
}
输出结果:
方法调用的时候实参和形参要求个数对应相同,数据类型对应相同。 类型不同的时候要求能够进行相应的自动类型转换
代码演示如下:
public class A
{
public static void main(String[] args){
A.sumLong(10L,20L);
// 存在自动类型转换 int--->long (小容量到大容量)
A.sumLong(10,20);
// 编译错误 3.0为double类型(大容量)
//A.sumLong(3.0,20);
A.sumLong((int)(3.0),20); // 添加转换符(精度会损失)
}
public static void sumLong(long a,long b){
System.out.println(a+"+"+b+"="+(a+b));
}
}
方法的返回值类型不是void的时候。
返回值类型不是void的时候:
要求方法必须保证百分百的执行"return 值;"这样的语句来完成值得返回。
没有这个语句编译器会报错。
需求:
请定义并实现一个方法,该方法可以计算两个int类型数据的商,
要求将最终的计算结果返回给调用者
代码演示1:(没有接收返回值的情况如下)
public class A
{
public static void main(String[] args){
A.divide(30,10); // 此时调用后程序能够运行 但没有接收返回值
}
public static int divide(int a,int b){
//int c =a/b;
//return c; //返回的值c必须和返回值类型int类型一致
// 不一致则会报错
// 例如报错类型有(return; return true; return其他数据类型的值;)
return a/b;
}
}
一般调用别人的方法都会接收方法中的数据,接收数据代码如下:
public class A
{
public static void main(String[] args){
//采用变量接收: 变量要和返回值的数据类型一致
// 第一种接收:
int i=A.divide(30,10);
System.out.println(i);
// 第二种接收:
long x=A.divide(30,10); // 整数型中:小容量转换成大容量
System.out.println(x);
// 第三种接收:
System.out.println(A.divide(30,10));
}
public static int divide(int a,int b){
return a/b;
}
}
深入return语句
深入return语句
* 带有return关键字的java语句只要执行,所在的方法执行结束。
* 在"同一个作用域"当中,return语句下面不能编写任何代码,因
为这些代码永远都执行不到,所以编译错误。
public class A
{
public static void main(String[] args){
/*
// 接收成功
int i=A.m();
System.out.println(i);
*/
//报错: 把m当成了变量
//System.out.println(A.m);
// 成功
System.out.println(A.m());
}
public static int m(){
/*
int a=10;
if (a>3) //报错:缺少返回语句 因为编译器只能知道要判断a>3 不知道是false 还是 true
// 如果是false的话 则在int返回值类型中没有返回语句 所以报错。
// 也就是说无法保证return 1;百分百被执行。
{
return 1;
}
*/
// 编译成功 因为编译器假如判断a>3为false时候 还能else输出返回语句 return 0;
int a=10;
if (a>3)
{
return 1;
// 这里不能编写代码,编译错误,因为return下面无法访问到该语句
//System.out.println("hello world!");
}
else{
// 编译成功: 当a<=3的时候能访问到该语句
System.out.println("hello world!");
return 0;
// 同理 访问不到该语句
//System.out.println("hello world!");
}
//也可以用三元运算符进行改写代码
//return 10>3? 1:0;
}
}
在返回类型是void的方法当中使用“return;”语句。 "return;"语句出现在返回值为void的方法当中主要是为了结束当前方法。
代码演示:
public class A
{
public static void main(String[] args){
A.m();
for (int i=10;i>1 ;i-- )
{
if (i==2)
{
return;
}
System.out.println("data--->:"+i);
}
// 不会被执行i==2时return;已经终止main()方法
System.out.println("junker");
}
public static void m(){
/*
编译错误:不兼容的类型: 意外的返回值(对于结果类型为空的方法,无法返回值)
return 10;
*/
for (int a=0;a<=10 ;a++ )
{
if (a==5)
{
return; // return 作用: 不是终止for循环, 是终止m()方法。
}
System.out.println("a--->"+a);
}
// 不会被执行 a==5时return;已经终止m()方法
System.out.println("hello world!");
}
}
return; 和 break; 的区别
public class A
{
public static void main(String[] args){
A.m();
}
public static void m(){
/*
编译错误:不兼容的类型: 意外的返回值(对于结果类型为空的方法,无法返回值)
return 10;
*/
for (int a=0;a<=10 ;a++ )
{
if (a==5)
{
return; // return 作用: 不是终止for循环, 是终止m()方法。
//break; // 终止的是for循环
}
System.out.println("a--->"+a);
}
System.out.println("hello world!");
}
}
重点!!!
方法在执行过程当中,在JVM中的内存是如何分配的呢? 内存是如何变化的?
/*
方法在执行过程当中,在JVM中的内存是如何分配的呢? 内存是如何变化的?
1、方法只定义不调用,是不会被执行的,并且在JVM中也不会给该方法分配"运行所属"的内存空间。
2、在JVM内存划分上有这样三块主要的内存空间:
*方法区内存【方法区】
*堆内存【堆区】
*栈内存【栈区】
3、关于"栈"数据结构:
*栈:stack,是一种数据结构
*数据结构反映的是数据的存储形态
*作为程序员需要提前精通:数据结构+算法
4、方法代码片段存在哪里?方法执行的时候执行过程的内存在哪里分配?
*方法代码片段属于.class字节码文件的一部分,字节码文件在类加载的时候,
将其放到了方法区当中。所以JVM中的三块主要的内存空间中方法区内存最先有
数据。存放了代码片段。*代码片段虽然在方法区内存当中只有一份,但是可以被重复调用。
每一次调用这个方法的时候,需要给该方法分配独立的活动场所,在栈内存中分配。5、方法在调用的瞬间,会给该方法分配内存空间,会在栈中发生压栈动作,
方法执行结束之后,给该方法分配的内存空间全部释放,此时发生弹栈动作。
*压栈:给方法分配内存
*弹栈:释放该方法的内存空间
6、局部变量在"方法体"中声明,局部变量运行阶段内存在栈中分配。
*/
对栈进行图像分析描述
方法执行内存分析
public class A {
public static void main(String[] args){
int a =10;
int b =20;
int retValue =sumInt(a,b);
System.out.println("retValue>>>:"+retValue);
}
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;
}
}
二、方法重载
以下代码不使用"方法重载机制",不使用overload,分析程序存在的缺点?
1、sumInt,sumLong,sumDouble方法虽然功能不同,但是功能是相似的。都是求和。
在以下程序当中功能相似的方法,分别起了三个不同的名字,这对于程序员来说,调用
方法的时候不方便,程序员需要记忆更多的方法,才能完成调用【不方便】
2、代码不美观。有没有这样的一种机制:
功能虽然不同,但是“功能相似”的时候可以让程序员更加的方便。
方法重载机制:Overload
public class A
{
public static void main(String[] args){
int result1 =sumInt(1,2);
System.out.println(result1);
long result2 =sumLong(1L,2L);
System.out.println(result2);
double result3 =sumDouble(1.0,2.0);
System.out.println(result3);
}
public static int sumInt(int a,int b){
return a+b;
}
public static long sumLong(long a,long b){
//long c =a+b;
//return c;
return a+b; // a+b 为long型
}
public static double sumDouble(double a,double b){
return a+b;
}
}
体验以下方法重载的优点:(两者结果相同 优点: 不再记方法名了 ,此时区分方法不再依靠方法名了,依靠的是参数的数据类型。)
public class A
{
public static void main(String[] args){
//调用方法的时候就像在使用一个方法一样
//参数的类型不同,对应调用的方法也不同
//此时区分方法不再依靠方法名了,依靠的是参数的数据类型。
System.out.println(sum(1,2));
System.out.println(sum(1L,2L));
System.out.println(sum(1.0,2.0));
}
// 以下三个方法构成了方法重载机制
// sum方法名
public static int sum(int a,int b){
return a+b;
}
// sum方法名
public static long sum(long a,long b){
return a+b;
}
// sum方法名
public static double sum(double a,double b){
return a+b;
}
}
加强了解方法重载机制
方法重载:
1、方法重载又被称为:overload
2、什么时候考虑使用方法重载?
* 功能相似的时候 尽可能让方法名相同。
【但是功能不同/不相似的时候 极可能让方法名不同】
3、什么条件满足之后构成了方法重载?
*在同一个类当中
*方法名相同
*参数列表不同:
数量不同 or 顺序不同 or 类型不同
4、方法重载和什么有关系,和什么没关系?
* 方法重载和方法名+参数列表有关系
* 方法重载和返回值类型无关
* 方法重载和修饰符列表无关
public class A
{
public static void main(String[] args){
m1();
m1(1);
m2(2,2.0);
m2(2.0,2);
m3(3);
m3(3.0);
}
//以下两个方法构成重载如下:
// 参数列表数量不同时:
public static void m1(){}
public static void m1(int a){}
// 参数顺序不同时:
public static void m2(int a,double b){}
public static void m2(double a,int b){}
// 参数类型不同时:
public static void m3(int x){}
public static void m3(double y){}
/*
编译错误:以下两个方法都不是构成方法重载,是发生了方法重复
public static void m4(int a,int b){}
public static void m4(int b,int a){}
编译错误:
public static void m5(){}
public static int m5(){
return 1;
}
编译错误:
void y(){}
public static void y(){}
*/
}
报错结果如下:
方法重载的应用:
可以自定义一个封装包
然后直接进行调用
结果如下:
三、递归******
关于方法的递归调用
1、 什么是递归?
方法自身调用自身。
2、递归很耗费内存的,递归算法可以不用的时候尽量不使用。
3、以下程序运行的时候发生了这样的一个错误【不是异常,是错误Error】:
java.lang.StackOverflowError
栈内存溢出错误。
错误发生无法挽回,只有一个结果,就是JVM停止工作。
4、递归必须有结束条件,没有结束条件一定会发生栈内存溢出错误。
5、递归即使有了结束条件,即使结束条件是正确的,也肯能发生栈内存溢出错误,因为递归的太深了。
public class A
{
public static void main(String[] args){
System.out.println("main begin");
doSome();
System.out.println("main over");
}
// 以下代码片段虽然只有一份
// 但是可以被重复调用,并且只要调用doSome方法就会在栈内存中新分配一块所属的内存空间。
public static void doSome(){
System.out.println("doSome begin");
doSome(); //这行代码不结束 下面的代码是不能够被执行的。
System.out.println("doSome over");
}
}
运行结果:
不使用递归 求1~N的和
public class A
{
/*
public static void main(String[] args){
/*
int sum=0;
for (int a=1;a<=4 ;a++ )
{
sum+=a;
}
System.out.println("sum:"+sum);
*/
// 以上计算的1~4的和 是没有学习方法的时候运用的
// 学习完方法后要学会运用方法来进行完成代码
public static void main(String[] args){
System.out.println(sumInt(4));
}
//单独的定义一个方法,这是一个独立的功能,可以完成1~N的求和
public static int sumInt(int n){
int sum =0;
for (int a=1;a<=n ;a++ )
{
sum+=a;
}
return sum;
}
}