方法的内存

一、方法调用的基本内存原理:

Java内存分配

  1. 栈: 方法运行时使用的内存方法进栈运行,运行完毕就出栈

  2. 堆: newl出来的,都在堆内存中开辟了一个小空间

  3. 方法区: 存储可以运行的class文件

  4. 本地方法栈:JVM在使用操作系统功能的时候使用和我们开发无关

  5. 寄存器:给CPU使用和我们开发无关

方法被调用后就会进栈执行

方法内所有代码执行完毕之后,方法就会出栈,方法出栈之后变量就不会再存在了
package com.itheima.Method;
//方法调用的基本内存原理
public class Demo11Test05 {
    public static void eat() {
        study();
        System.out.println("吃饭");
        sleep();
    }

    public static void sleep() {
        System.out.println("睡觉");
    }

    public static void study() {
        System.out.println("学习");
    }

    public static void main(String[] args) {
        eat();
    }
}

运行结果:

学习

吃饭

睡觉

运行原理:

计算机先进栈,进入main方法;main方法调用了eat方法,此时eat方法进栈;eat方法又调用了study方法,study方法进栈,执行study方法代码,打印学习;学习语句打印完毕后,study方法内的代码全部执行完毕,study方法进行出栈,然后会到study方法调用处继续执行sout“吃饭”,打印吃饭;打印完后又调用了sleep方法,打印睡觉,打印完毕后sleep方法内的代码全部执行完毕,sleep方法出栈,回到调用处继续往下执行;最后eat方法代码执行完毕,main方法内的代码执行完毕,main方法进行出栈。

二、方法传递基本数据类型的内存原理:

  1. 基本数据类型和引用数据类型:

基本数据类型:整数类型、浮点类型、布尔类型、字符类型

引用数据类型:处理上面的其他所有类型

基本数据类型:

在基本数据类型中存储的是真实的数据,数据值是存储在自己的空间中

特点:赋值给其他变量,也是赋的真实的值

引用数据类型:
只要是new出来的就都是引用数据类型

变量中存储的是地址值
引用数据类型:数据值是存储在其他空间中,自己空间中存储的是地址值
特点:赋值给其他变量赋的地址值

三、方法传递引用数据类型的内存原理:

eg1:

package com.itheima.Method;
//方法传递引用数据类型的内存原理
public class Demo11Test06 {
    public static void change(int number) {
        number = 200;
    }

    public static void main(String[] args) {
        int number = 100;
        System.out.println("调用change方法前:"+number);//100
        change(number);
        System.out.println("调用change方法后:"+number);//100
    }
}

运行结果:

100

100

原因:

当主函数调用change(number)的时候,change(number)里面的number已经是两百了,但他等到他回到调用处的时候,change(number)已经出栈了。此时调用change方法后的number只有main方法里面的number=100

当我们要打印出200时可以这样编写代码:

package com.itheima.Method;

public class Demo11Test07 {
    public static int  change(int number) {
        number = 200;
        return number;
    }

    public static void main(String[] args) {
        int number = 100;
        System.out.println("调用change方法前:"+number);//100
        number = change(number);
        System.out.println("调用change方法后:"+number);//200
    }
}

运行结果:

100

200

eg2:

package com.itheima.Method;
//方法传递引用数据类型的内存原理
public class Demo11Test08 {
    public static void change(int[] arr){
        arr[1]= 600;
    }

    public static void main(String[] args) {
        int[] arr = {10,20,30};
        System.out.println("调用change方法前:"+arr[1]);
        change(arr);
        System.out.println("调用change方法后:"+arr[1]);
    }
}

运行结果:

20

600

运行原理:

因为new了一个新数组,所以有两个空间,一个栈内存,一个堆内存。程序刚运行的时候,main方法先进栈,定义了一个变量数组arr,堆里面开辟了一个空间存储arr这个数组里面的索引然后堆里面空间有一个地址值,用来存储arr这个数据的地址。等号把右边的地址值赋值给arr,arr可以通过地然后执行main方法里面的第二行代码,获取到arr索引为1的数据,打印arr[1]。然后调用change方法,Change方法进栈,调用的用的把arr的值传递给了change,现在Change里面的arr记录的是arr的地址值,相当于把地址值交给了change里面的行参。此时main方法里面的arr和change方法里面的arr指向的是同一个地址;然后执行change方法里面的代码arr[1]=600, 把600赋值给地址值的1索引,此时地址值里面的1索引发生改变;然后change方法执行完毕,change方法进行出栈;回到方法调用处继续执行打印arr[1];因为打印的地址是修改后的结果,所以arr[1]=600

结论:传递引用数据类型时递的是地址值,行参的改变,影响实际参数的值。

方法的练习

练习1:

package com.itheima.Method;

import java.sql.SQLOutput;
import java.util.Scanner;

/*卖飞机票
需求:机票价格按照淡季,旺季头等舱和经济舱收费,输入机票原价。月份和头等舱或经济舱
按照如下规则计算机票价格:旺季(5~10月)头等舱9折,经济舱8.5折。淡季(11月~来年四月)头等舱7折,经济舱6.5折
 */
public class DemoPractice01 {
    public static void main(String[] args) {
        Scanner price = new Scanner(System.in);
        System.out.println("请输入机票原价:");
        double primaryPrice = price.nextInt();
        Scanner m = new Scanner(System.in);
        System.out.println("请输入月份");
        int month = m.nextInt();
        Scanner g = new Scanner(System.in);
        System.out.println("请输入您的舱数等级(1:头等舱,2:经济舱):");
        int seat = g.nextInt();
        double countPrice = 0;
        double lastPrice = 0;
        if (month >= 5 && month <= 10) {
            if (seat == 1) {
                lastPrice = primaryPrice * 0.9;
            } else if (seat == 2) {
                lastPrice = primaryPrice * 0.65;
            } else {
                System.out.println("没有这个座位");
            }
        } else if ((month >= 1 && month <= 4) || (month >= 11 || month <= 12)) {
            if (seat == 1) {
                lastPrice = primaryPrice * 0.85;
            } else if (seat == 2) {
                lastPrice = primaryPrice * 0.7;
            } else {
                System.out.println("没有这个座位");
            }
        } else {
            System.out.println("您输入的月份不合法");
        }
        System.out.println(lastPrice);
    }
}

运行结果:

请输入机票原价:
1000
请输入月份
6
请输入您的舱数等级(1:头等舱,2:经济舱):
1
900.0

练习1改进:(用方法改进)

package com.itheima.Method;

import java.util.Scanner;
//改进!!!
/*卖飞机票
需求:机票价格按照淡季,旺季头等舱和经济舱收费,输入机票原价。月份和头等舱或经济舱
按照如下规则计算机票价格:旺季(5~10月)头等舱9折,经济舱8.5折。淡季(11月~来年四月)头等舱7折,经济舱6.5折
 */
public class DemoPractice02 {
    public static double getPrice(double ticket,int seat,double v1,double v2) {

        if (seat == 1) {
           ticket = ticket * v1;
        } else if (seat == 2) {
            ticket = ticket * v2;
        } else {
            System.out.println("没有这个舱位");
        }
        return ticket;
    }
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入机票原价:");
        double ticket = sc.nextInt();
        System.out.println("请输入月份");
        int month = sc.nextInt();
        System.out.println("请输入您的舱数等级(1:头等舱,2:经济舱):");
        int seat = sc.nextInt();
        double lastPrice = 0;
        if (month >= 5 && month <= 10) {
            //旺季
            ticket = getPrice(ticket,seat,0.9,0.85);
        } else if ((month >= 1 && month <= 4) || (month >= 11 || month <= 12)) {
            //淡季
            ticket = getPrice(ticket,seat,0.7,0.65);
        } else {
            System.out.println("您输入的月份不合法");
        }
        System.out.println(ticket);
    }
}

运行结果:

请输入机票原价:
1000
请输入月份
6
请输入您的舱数等级(1:头等舱,2:经济舱):
1
900.0

练习1改进:(用快捷键自动生成方法:)

package com.itheima.Method;

import java.util.Scanner;

//用系统快捷键Ctrl+alt+m自动抽取方法,提取想要写成方法的代码,然后系统会自动生成一个方法
/*卖飞机票
需求:机票价格按照淡季,旺季头等舱和经济舱收费,输入机票原价。月份和头等舱或经济舱
按照如下规则计算机票价格:旺季(5~10月)头等舱9折,经济舱8.5折。淡季(11月~来年四月)头等舱7折,经济舱6.5折
 */
public class DemoPractice03 {
    public static void main(String[] args) {
        Scanner price = new Scanner(System.in);
        System.out.println("请输入机票原价:");
        double primaryPrice = price.nextInt();
        Scanner m = new Scanner(System.in);
        System.out.println("请输入月份");
        int month = m.nextInt();
        Scanner g = new Scanner(System.in);
        System.out.println("请输入您的舱数等级(1:头等舱,2:经济舱):");
        int seat = g.nextInt();
        double countPrice = 0;
        double lastPrice = 0;
        if (month >= 5 && month <= 10) {
            lastPrice = getPrice(seat, lastPrice, primaryPrice, 0.9, 0.65);
        } else if ((month >= 1 && month <= 4) || (month >= 11 || month <= 12)) {
            lastPrice = getPrice(seat, lastPrice, primaryPrice, 0.85, 0.7);
        } else {
            System.out.println("您输入的月份不合法");
        }
        System.out.println(lastPrice);
    }

    private static double getPrice(int seat, double lastPrice, double primaryPrice, double x, double x1) {
        if (seat == 1) {
            lastPrice = primaryPrice * x;
        } else if (seat == 2) {
            lastPrice = primaryPrice * x1;
        } else {
            System.out.println("没有这个座位");
        }
        return lastPrice;
    }
}

运行结果:

请输入机票原价:
1000
请输入月份
6
请输入您的舱数等级(1:头等舱,2:经济舱):
2
650.0

练习总结:

练习1:找质数

package com.itheima.Method;
//找质数:判断101~200之间有多少个质数,并输出所有质数
public class DemoPractice04 {
    public static void main(String[] args) {
        int count = 0;
        for (int i = 101; i < 200; i++) {
            boolean flag = true;
            for (int j = 2;j< i;j++){
                if(i%j==0){
                    flag = false;
                    break;
                }
            }
            if (flag){
                System.out.println(i+"是一个质数");
                count++;
            }
        }
        System.out.println("一共有"+count+"个质数");
    }
}

运行结果:
101是一个质数
103是一个质数
107是一个质数
109是一个质数
113是一个质数
127是一个质数
131是一个质数
137是一个质数
139是一个质数
149是一个质数
151是一个质数
157是一个质数
163是一个质数
167是一个质数
173是一个质数
179是一个质数
181是一个质数
191是一个质数
193是一个质数
197是一个质数
199是一个质数
一共有21个质数

练习2:数组元素的复制

package com.itheima.Method;
/*数组元素的复制
需求:把一个数组中的元素复制到另一个新数组中
 */
public class 数组元素的复制练习02 {
    public static void main(String[] args) {
        int[] arr = {45,21,37,69,54,66,73};
        int[] newArr = new int[arr.length];
        for(int i=0;i<arr.length;i++){
            newArr[i] = arr[i];
        }
        for (int i = 0; i < newArr.length; i++) {
            System.out.print(newArr[i]+" ");
        }
    }
}

运行结果:

45 21 37 69 54 66 73

练习3:评委打分

package com.itheima.Method;

import java.util.Scanner;

/*评委打分:
需求:在唱歌比赛中有六名评委给选手打分,分数范围是0~100之间的整数,选手的最后得分为
去掉最高分,去掉最低分后的四个评委的平均分
 */
public class 评委打分练习03 {
    public static int[] getScore() {
        int[] scores = new int[6];
        Scanner sc = new Scanner(System.in);
        for (int i = 0; i < scores.length; ) {
            System.out.println("请分别输入六个分数");
            int score = sc.nextInt();
            if (score>=0&&score<=100){
                scores[i] = score;
                i++;//只有输入一个合法的数据,系统才会存入,否则不会存入
            }else {
                System.out.println("成绩超出范围,继续录入,当前i为:"+i);
            }
        }
        return scores;
    }

    public static void main(String[] args) {
        int[] scoreArr = getScore();
        double max = scoreArr[0];
        double min = scoreArr[0];
        double lastScore = 0;
        int sum = 0;
        for (int i = 0; i < scoreArr.length; i++) {
            System.out.println(scoreArr[i]);
            if (max>scoreArr[i]){
                max = scoreArr[i];
            }
            if (min<scoreArr[i]){
                min = scoreArr[i];
            }
            sum +=scoreArr[i];
        }
        lastScore = (sum-max-min)/(scoreArr.length-2);
        System.out.println("去掉一个最高分一个最低分,最后分数为"+lastScore);
    }
}

运行结果:

请分别输入六个分数
10
请分别输入六个分数
20
请分别输入六个分数
30
请分别输入六个分数
40
请分别输入六个分数
50
请分别输入六个分数
60
10
20
30
40
50
60
去掉一个最高分一个最低分,最后分数为35.0

练习4:数字加密

package com.itheima.Method;

import java.util.Scanner;

/*
数字加密:
某系统的数字密码(大于0),比如1983,采用加密方式进行传输。
规则如下:每位数加上5,再对十求余,最后将所有数字反转,得到一串新数
 */
public class 数字加密练习04 {
    public static void main(String[] args) {
        int[] arr ={1,9,8,3};
        for (int i = 0; i < arr.length; i++) {
            arr[i] += 5;
        }
        for (int i = 0; i < arr.length; i++) {
            arr[i] %=10;
        }
        for (int i = 0,j =arr.length-1; i < j; i++,j--) {
            int tem = arr[i];
            arr[i] = arr[j];
            arr[j] = tem;
        }
        int number = 0;
        for (int i = 0; i < arr.length; i++) {
            number =number*10+arr[i];
        }
        System.out.println("加密后的密码是:"+number);
    }
}

运行结果:

加密后的密码是:8346

练习5:数字解密

package com.itheima.Method;
/*
数字解密:
每位数加上5,再对10求余,得到一串新数,按照以上规则进行解密
 */
public class 数字解密练习05 {
    public static void main(String[] args) {
        int[] arr = {8,3,4,6};
        //反转
        for (int i = 0,j=arr.length-1; i < j; i++,j--) {
            int temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
        //由于加密是通过对10取余的方式进行获取。
        //所以在解密的时候就需要判断0~9之间加10,5~9之间数字不变。
        for (int i = 0; i < arr.length; i++) {
            if (arr[i]>=0&&arr[i]<=4){
                arr[i] = arr[i]+10;
            }
        }
        //每一位减5
        for (int i = 0; i < arr.length; i++) {
            arr[i] = arr[i]-5;
        }
        int number = 0;
        for (int i = 0; i < arr.length; i++) {
            number = number*10+arr[i];
        }
        System.out.println(number);
    }
}

运行结果:

1983

练习6:抢红包游戏

package com.itheima.Method;

import java.util.Random;

/*
抢红包游戏 :
需求 :一个大V直播抽奖奖品是现金红包分别有 2,588 ,888, 1000,10000个奖金
请使用代码模拟抽奖打印出每个奖项奖项的出现顺序要随机且不重复。
 */
public class 抢红包练习06 {
    public static boolean contains(int[] arr, int prize) {
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] == prize) {
                return true;
            }
        }
        return false;
    }

    public static void main(String[] args) {
        int[] arr = {2,588,888,1000,10000};//1、定义数组表示奖池
        int[] newArr = new int[arr.length];//2、定义新数组用于存储抽奖结果
        //3、抽奖
        Random r = new Random();//定义一个随机变量
        //因为有五个奖项,所以要循环五次
        for (int i = 0; i < 5; i++) {
            int randomIndex = r.nextInt(arr.length);//获取随机索引
            int prize = arr[randomIndex];
            //判断当前奖项是否存在,如果存在则重新抽取,如果不存在就表示有效奖项
            boolean flag = contains(newArr, prize);
            if (!flag) {
                newArr[i] = prize;//把当前抽取道德奖项添加到newArray中
                //添加完毕之后,移动索引
                i++;
            }
        }
        //4、遍历newArr
        for (int i = 0; i < newArr.length; i++) {
            System.out.println(newArr[i]);
        }
    }
}

练习6改进:抢红包游戏

package com.itheima.Method;

import java.util.Random;

/*
抢红包游戏 改进:
需求 :一个大V直播抽奖奖品是现金红包分别有 2,588 ,888, 1000,10000个奖金
请使用代码模拟抽奖打印出每个奖项奖项的出现顺序要随机且不重复。
 */
public class 抢红包练习07 {
    public static void main(String[] args) {
        //1、把奖池里面的所有奖项打乱顺序
        int[] arr = {2,588 ,888, 1000,10000};
        Random r = new Random();
        for (int i = 0; i < arr.length; i++) {
            int randomIndex = r.nextInt(arr.length);//获取随机索引
            int temp = arr[i];
            arr[i] = arr[randomIndex];
            arr[randomIndex] = temp;
        }
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }
    }
}

运行结果:

1000
2
588
888
10000