Java方法

本文详细解释了Java中的方法概念、声明规则、调用机制,包括实例方法与局部变量的区别,方法重载和重写的概念,以及递归调用和对象数组的使用。此外,还讨论了内存分析和参数传递方式,帮助读者掌握Java基础编程技巧。
摘要由CSDN通过智能技术生成

Ⅰ.方法(Method)

1. 方法的概念

方法也叫函数,是一组代码语句的封装,从而实现代码重用,从而减少冗余代码,通常它是一个独立功能的定义,方法是一个类中最基本的功能单元。

2. 方法的特点

(1)必须先声明后使用

类,变量,方法等都要先声明后使用

(2)不调用不执行,调用一次执行一次。

3. 如何声明方法

声明方法的位置必须在类中方法外,即不能在一个方法中直接定义另一个方法。

即:方法不能嵌套方法

类{

           方法1(){       }

                方法2(){       }     

 }

(方法头+方法体)

【修饰符】 返回值类型 方法名(【形参列表 】)【throws 异常列表】{
        方法体的功能代码
}

4 .如何调用实例方法

1、方法调用语法格式

对象.非静态方法(【实参列表】)

2、形参和实参

  • 形参(formal parameter):在定义方法时方法名后面括号中声明的变量称为形式参数(简称形参)即形参出现在方法定义时。

  • 实参(actual parameter):调用方法时方法名后面括号中的使用的值/变量/表达式称为实际参数(简称实参)即实参出现在方法调用时。

  • 调用时,实参的个数、类型、顺序顺序要与形参列表一一对应。如果方法没有形参,就不需要也不能传实参。

  • 无论是否有参数,声明方法和调用方法()都不能丢失

3、返回值问题

方法调用表达式是一个特殊的表达式:

  • 如果被调用方法的返回值类型是void,调用时不需要也不能接收和处理(打印或参与计算)返回值结果,即方法调用表达式只能直接加;成为一个独立语句。

  • 如果被调用方法有返回值,即返回值类型不是void

    • 方法调用表达式的结果可以作为赋值表达式的值,

    • 方法调用表达式的结果可以作为计算表达式的一个操作数,

    • 方法调用表达式的结果可以作为另一次方法调用的实参,

    • 方法调用表达式的结果可以不接收和处理,方法调用表达式直接加;成为一个独立的语句,这种情况,返回值丢失。

代码执行到return就结束

5 .实例方法使用当前对象的成员

在实例方法中还可以使用当前对象的其他成员。在Java中当前对象用this表示。

  • this:在实例方法中,表示调用该方法的对象

  • 如果没有歧义,完全可以省略this。

  • 但有一种情况不能省略this     (当形式参数(局部变量)的名字与全局变量的名字相同时,this不能省略

  • int count;
    //this不能省略的情况
    public void changecount3(int count){
        //count代表形参与全局变量count有歧义
        //this.count代表属性
       this.count=count;
       System.out.println(count);
    }

6. 方法调用内存分析

方法会放到方法区

        方法不调用不执行,调用一次执行一次,每次调用会在栈中有一个入栈动作,即给当前方法开辟一块独立的内存区域,用于存储当前方法的局部变量的值,当方法执行结束后,会释放该内存,称为出栈,如果方法有返回值,就会把结果返回调用处,如果没有返回值,就直接结束,回到调用处继续执行下一条指令。

栈结构:先进后出,后进先出。

7. 实例变量与局部变量的区别

1、声明位置和方式

(1)实例变量:在类中方法外

(2)局部变量:在方法体{}中或方法的形参列表、代码块中

2、在内存中存储的位置不同

(1)实例变量:堆

(2)局部变量:栈

3、生命周期

(1)实例变量:和对象的生命周期一样,随着对象的创建而存在,随着对象被GC回收而消亡, 而且每一个对象的实例变量是独立的。

(2)局部变量:和方法调用的生命周期一样,每一次方法被调用而在存在,随着方法执行的结束而消亡, 而且每一次方法调用都是独立。

4、作用域

(1)实例变量:通过对象就可以使用,本类中“this.,没有歧义还可以省略this.”,其他类中“对象.” (2)局部变量:出了作用域就不能使用

5、修饰符(后面来讲)

(1)实例变量:public,protected,private,final,volatile,transient等

(2)局部变量:final

6、默认值

(1)实例变量:有默认值

(2)局部变量:没有,必须手动初始化。其中的形参比较特殊,靠实参给它初始化。

8.参数问题

        8.1方法只有可变参数

        【修饰符】 返回值类型 方法名(【非可变参数部分的形参列表,】参数类型... 形参名){  }

        可变参数的特点和要求:

        (1)一个方法最多只能有一个可变参数

        (2)如果一个方法包含可变参数,那么可变参数必须是形参列表的最后一个

        (3)在声明它的方法中,可变参数当成数组使用

        【修饰符】 返回值类型 方法名(【非可变参数部分的形参列表,】参数类型[] 形参名){  }

只是后面这种定义,在调用时必须传递数组,而前者更灵活,既可以传递数组,又可以直接传递数组的元素,这样更灵活了。

        8.2、方法包含非可变参数和可变参数

  •      非可变参数部分必须传入对应类型和个数的实参;

    •   可变参数部分按照可变参数的规则传入0~n个对应类型的实参或传入1个对应类型的数组实参;

8.3特殊参数之二:命令行参数(了解)

通过命令行给main方法的形参传递的实参称为命令行参数

方法的参数传递机制

1、形参是基本数据类型

package com.haogu.test05.param;

public class PrimitiveTypeParam {
    void swap(int a, int b){//交换两个形参的值
        int temp = a;
        a = b;
        b = temp;
    }

    public static void main(String[] args) {
        PrimitiveTypeParam tools = new PrimitiveTypeParam();
        int x = 1;
        int y = 2;
        System.out.println("交换之前:x = " + x +",y = " + y);//1,2
        tools.swap(x,y);//实参x,y是基本数据类型,给形参的是数据的“副本”,调用完之后,x与y的值不变
        System.out.println("交换之后:x = " + x +",y = " + y);//1,2
    }
}

2、形参是引用数据类型

package com.haogu.test05.param;

public class ReferenceTypeParam {
    void swap(MyData my){//形参my是引用数据类型,接收的是对象的地址值,形参my和实参data指向同一个对象
        //里面交换了对象的两个实例变量的值
        int temp = my.x;
        my.x = my.y;
        my.y = temp;
    }

    public static void main(String[] args) {
        ReferenceTypeParam tools = new ReferenceTypeParam();
        MyData data = new MyData();
        data.x = 1;
        data.y = 2;
        System.out.println("交换之前:x = " + data.x +",y = " + data.y);//1,2
        tools.swap(data);//实参是data,给形参my的是对象的地址值,调用完之后,x与y的值交换
        System.out.println("交换之后:x = " + data.x +",y = " + data.y);//2,1
    }

}

public class MyData{
    int x;
    int y;
}

3、形参是数组

package com.haogu.test05.param;

public class ArrayTypeParam {
    void sort(int[] arr){//给数组排序,修改了数组元素的顺序,这里对arr数组进行排序,就相当于对nums数组进行排序
        for (int i = 1; i < arr.length; i++) {
            for (int j = 0; j < arr.length - i; j++) {
                if(arr[j] > arr[j+1]){
                    int temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                }
            }
        }
    }

    void iterate(int[] arr){//输出数组的元素,元素之间使用空格分隔,元素打印完之后换行
                            //这个方法没有修改元素的值
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i]+" ");
        }
        System.out.println();
    }

    public static void main(String[] args) {
        ArrayTypeParam tools = new ArrayTypeParam();

        int[] nums = {4,3,1,6,7};
        System.out.println("排序之前:");
        tools.iterate(nums);//实参nums把数组的首地址给形参arr,这个调用相当于输出nums数组的元素
                            //对数组的元素值没有影响

        tools.sort(nums);//对nums数组进行排序

        System.out.println("排序之后:");
        tools.iterate(nums);//输出nums数组的元素
        //上面的代码,从头到尾,堆中只有一个数组,没有产生新数组,无论是排序还是遍历输出都是同一个数组
    }
}

4、形参指向新对象

package com.haogu.test05.param;

public class AssignNewObjectToFormalParam {
    void swap(MyData my){
        my = new MyData(); //这里让my形参指向了新对象,此时堆中有两个MyData对象,和main中的data对象无关
        int temp = my.x;
        my.x = my.y;
        my.y = temp;
     
    }

    public static void main(String[] args) {
        //创建这个对象的目的是为了调用swap方法
        AssignNewObjectToFormalParam tools = new AssignNewObjectToFormalParam();
        
        MyData data = new MyData();
        data.x = 1;
        data.y = 2;
        System.out.println("交换之前:x = " + data.x +",y = " + data.y);//1,2
        tools.swap(data);//调用完之后,x与y的值交换?
        System.out.println("交换之后:x = " + data.x +",y = " + data.y);//1,2
    }
}

方法的重载 (Overload)与重写(Override)

  • 方法重载:指在同一个类中,允许存在一个以上的同名方法,只要它们的参数列表不同即可,与修饰符和返回值类型无关。

  • 参数列表:数据类型个数不同,数据类型不同(按理来说数据类型顺序不同也可以,但是很少见,也不推荐,逻辑上容易有歧义)。

  • 重载方法调用:JVM通过方法的参数列表,调用匹配的方法。

    • 先找个数、类型最匹配的

    • 再找个数和类型可以兼容的,如果同时多个方法可以兼容将会报错

    • 重载规则:

    • 被重载的方法必须改变参数列表(参数个数或类型不一样);
    • 被重载的方法可以改变返回类型;
    • 被重载的方法可以改变访问修饰符;
    • 被重载的方法可以声明新的或更广的检查异常;
    • 方法能够在同一个类中或者在一个子类中被重载。
    • 无法以返回值类型作为重载函数的区分标准。

重写(Override)(快捷键ctrl+O)

重写是子类对父类的允许访问的方法的实现过程进行重新编写, 返回值和形参都不能改变。即外壳不变,核心重写!

重写的好处在于子类可以根据需要,定义特定于自己的行为。 也就是说子类能够根据需要实现父类的方法。

重写方法不能抛出新的检查异常或者比被重写方法申明更加宽泛的异常。例如: 父类的一个方法申明了一个检查异常 IOException,但是在重写这个方法的时候不能抛出 Exception 异常,因为 Exception 是 IOException 的父类,抛出 IOException 异常或者 IOException 的子类异常。

方法的重写规则

  • 参数列表与被重写方法的参数列表必须完全相同。

  • 返回类型与被重写方法的返回类型可以不相同,但是必须是父类返回值的派生类(java5 及更早版本返回类型要一样,java7 及更高版本可以不同)。

  • 访问权限不能比父类中被重写的方法的访问权限更低。例如:如果父类的一个方法被声明为 public,那么在子类中重写该方法就不能声明为 protected。

  • 父类的成员方法只能被它的子类重写。

  • 声明为 final 的方法不能被重写。

  • 声明为 static 的方法不能被重写,但是能够被再次声明。

  • 子类和父类在同一个包中,那么子类可以重写父类所有方法,除了声明为 private 和 final 的方法。

  • 子类和父类不在同一个包中,那么子类只能够重写父类的声明为 public 和 protected 的非 final 方法。

  • 重写的方法能够抛出任何非强制异常,无论被重写的方法是否抛出异常。但是,重写的方法不能抛出新的强制性异常,或者比被重写方法声明的更广泛的强制性异常,反之则可以。

  • 构造方法不能被重写。

  • 如果不能继承一个类,则不能重写该类的方法。

  • Super 关键字的使用

    当需要在子类中调用父类的被重写方法时,要使用 super 关键字。

方法的递归调用

递归调用:方法自己调用自己的现象就称为递归。

递归的分类:

  • 递归分为两种,直接递归和间接递归。

  • 直接递归称为方法自身调用自己。

  • 间接递归可以A方法调用B方法,B方法调用C方法,C方法调用A方法。

注意事项

  • 递归一定要有条件限定,保证递归能够停止下来,否则会发生栈内存溢出。

  • 在递归中虽然有限定条件,但是递归深度不能太深,否则效率低下,或者也会发生栈内存溢出。

    • 能够使用循环代替的,尽量使用循环代替递归

对象数组

数组是用来存储一组数据的容器,一组基本数据类型的数据可以用数组装,那么一组对象也可以使用数组来装。

即数组的元素可以是基本数据类型,也可以是引用数据类型。当元素是引用数据类型是,我们称为对象数组。

注意:对象数组,首先要创建数组对象本身,即确定数组的长度,然后再创建每一个元素对象,如果不创建,数组的元素的默认值就是null,所以很容易出现空指针异常NullPointerException。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值