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("哈哈");
   } 
}

 

 

 

 

 

posted @ 2019-12-29 08:47  古墩古墩  Views(207)  Comments(0Edit  收藏  举报