Java面向对象之方法重载、可变个数的形参、方法参数的值传递机制、递归(recursion)方法

1 - 方法的重载(over load)

/*
* 1-方法的重载(over load)
*    ①概念:在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型不同即可。
*    ②特点:与返回值类型无关,只看参数列表,且参数列表必须不同(参数个数或参数类型)。调用时,根据方法参数列表的不同来区别。
*   
*    ③总结:"两同一不同" 即同一个类,相同的方法名。参数列表不同:参数个数不同,参数类型不同。
*
* 2-判断是否是重载:跟方法的权限修饰符,返回值类型,形参变量名,方法体都没有关系。
*
* 3-在通过对象调用方法时,如何确定某一个指定的方法:方法名 --> 参数列表
*
*/

代码示例(如下两个同名方法就够成方法重载)

    // 以下示例就叫做方法重载

    // 反转数组1(int[])
    public void reverseArray(int[] array){
        for(int i = 0;i < array.length / 2;i++){
            int temp = array[i];
            array[i] = array[array.length - i - 1];
            array[array.length - i - 1] = temp;
        }
    }
    // 反转数组2(String[])
    public void reverseArray(String[] array){

    }
    // 注意看它们的方法名和参数

练习题

/*
 * 1-编写程序,定义三个重载方法并调用。方法名为mOL。三个方法分别接收一个int参        
               数、两个int参数、一个字符串。
 * 分别执行平方运算并输出结果,相乘并输出结果,输出字符串信息,在主类的main()方法中分别用参数区别调用三个方法。
 * 
 * 2-定义三个重载方法max(),
 *         第一个方法求两个int值中的最大值,
 *         第二方法求两个double值中的最大值,
 *         第三个方法求三个double值的最大值,
 *         并分别调用三个方法
 */
public class OverLoadTest {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        OverLoadTest load = new OverLoadTest();
        load.mOL(5);
        load.mOL(4, 5);
        load.mOL("hello world");
        
        double res1 = load.max(1.0, 2.0);
        System.out.println(res1);
        double res2 = load.max(20, 30);
        System.out.println(res2);
        double res3 = load.max(1, 2, 3);
        System.out.println(res3);
        
    }
    // 1.如下三个方法构成重载
    public void mOL(int i) {
        System.out.println(i*i);
    }
    public void mOL(int j,int i) {
        System.out.println(j * i);
    }
    public void mOL(String s) {
        System.out.println(s);
    }
    
    // 2.如下三个方法构成重载
    public int max(int i,int j) {
//        if(i > j) {
//            return i;
//        }else {
//            return j;
//        }
        return (i > j)? i : j;
    }
    public double max(double i,double j) {
        return (i > j)? i : j;
    }
    public double max(double d1,double d2,double d3) {
        double max = (d1 > d2)? d1 : d2;
        return (max > d3)? max : d3;
    }
}
方法重载练习

2 - 可变个数的形参

JavaSE 5.0 中提供了Varargs(variable number of arguments)机制,允许直接定 义能和多个实参相匹配的形参。从而,可以用一种更简单的方式,来传递个数可 变的实参。

 

//JDK 5.0以前:采用数组形参来定义方法,传入多个同一类型变量 public static void test(int a ,String[] books);

//JDK5.0:采用可变个数形参来定义方法,传入多个同一类型变量 public static void test(int a ,String…books);

/*
* 可变个数形参的方法
* 1-jdk 5.0新增的内容
* 2-具体使用
*  ①可变个数形参的格式:数据类型 ... 变量名
*  ②当调用可变个数形参的方法时,传入的参数个数可以是:0个,1个,2个,或多个 ...
*  ③可变个数形参的方法与本类中方法名相同,形参不同的方法之间构成重载
*  ④可变个数形参的方法与本类中方法名相同,形参类型也相同的数组之间不构成重载,换句话说,二者不能共存。
*  ⑤可变个数形参在方法的形参中,必须声明在末尾。
*  ⑥可变个数形参在方法的形参中,最多只能声明一个可变形参。
*/

public class MethodArgsTest {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
    }
    public void show(int i) {
        
    }
    public void show(String s) {
        
    }
    public void show(String ... strs) {
        
    }
}

3-具体使用代码示例

public class MethodArgsTest {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        MethodArgsTest test = new MethodArgsTest();
        test.show(1);
        test.show("hello world");
        test.show("hello","world");
        test.show();
    }
    public void show(int i){

    }
    public void show(String s){
        System.out.println(s);
    }
    public void show(String ... strings){
        // System.out.println("执行可变个数形参方法 ...");
        for(int i = 0;i < strings.length;i++){
            System.out.print(strings[i]+"\t");
        }
        System.out.println();
    }
//    public void show(String[] args){
//        System.out.println("");
//    }
// 调用时:test.show(new String[]{"aa","bb"});

    public void show(int i,String ... strings){
        // 可变个数形参,必须声明在末尾,且最多只能声明一个。
    }
}
可变个数形参

3 - 方法参数的值传递机制

1 方法,必须由其所在类或对象调用才有意义。若方法含有参数:

  ✔ 形参:方法声明时的参数

  ✔ 实参:方法调用时实际传给形参的参数值


2 Java的实参值如何传入方法呢?

Java里方法的参数传递方式只有一种:值传递。 即将实际参数值的副本 (复制品)传入方法内,而参数本身不受影响。

  ✔ 形参是基本数据类型:将实参基本数据类型变量的“数据值”传递给形参

  ✔ 形参是引用数据类型:将实参引用数据类型变量的“地址值”传递给形参

1-关于变量的赋值

/*
 * 关于变量的赋值
 * 1-如果变量是基本数据类型,此时赋值的是变量所保存的数据值。
 * 2-如果变量是引用数据类型,此时赋值的是变量所保存的数据的地址值
 */
public class ValueTransferTest {

    public static void main(String[] args) {
        // 基本数据类型之局部变量赋值
        int m = 20;
        int n = m;
        System.out.println("m="+m+", n="+n);
        n = 10;
        System.out.println("m="+m+", n="+n);
        
        // 引用数据类型
        Order order1 = new Order();
        order1.orderId = 50;
        
        Order order2 = order1; // order1 和 order2 的地址值相同,都指向了堆空间中的同一个实体
        System.out.println("order1.Id="+order1.orderId+"\norder2.Id="+order2.orderId);
        order2.orderId = 100;
        System.out.println("order1.Id="+order1.orderId+"\norder2.Id="+order2.orderId);
    }
}

class Order{
    int orderId;
    
}
基本数据类型和引用数据类型的赋值

2-方法参数的值传递机制

/*
 * 方法的形参的传递机制:值传递
 * 1-形参:方法定义时,声明的小括号内的参数
 * 2-实参:方法调用时,实际传递给形参的数据
 *
 * 3-值传递机制
 * 如果形参是基本数据类型,此时实参赋给形参的是实参真实存储的数据值。
 * 如果参数是引用数据类型,此时赋值的是变量所保存的数据的地址值。
 */
public class ValueFransferTest {
    public static void main(String[] args) {
        // 交换两个变量的值操作
        int m = 10;
        int n = 20;
        System.out.println("交换前:m="+m+"\tn="+n); // 交换前:m=10    n=20
//        int temp = m;
//        m = n;
//        n = temp;
        ValueFransferTest test = new ValueFransferTest();
        test.swap(m,n);
        System.out.println("交换后:m="+m+"\tn="+n); // 交换后:m=10    n=20

    }

    public void swap(int m,int n) {
        int temp = m;
        m = n;
        n = temp;
    }
}
值传递机制

图解

 

 

3-在声明的方法中实现 m 和 n 的值交换

public class ValueTransferTest {
    public static void main(String[] args) {
        Data data = new Data();
        data.m = 10;
        data.n = 20;
        System.out.println("交换前:m="+data.m+"\tn="+data.n);

        // 交换 m 和 n 的值
//        int temp = data.m;
//        data.m = data.n;
//        data.n = temp;
        ValueTransferTest test = new ValueTransferTest();
        test.swap(data);
        System.out.println("交换后:m="+data.m+"\tn="+data.n);
    }
    public void swap(Data data){
        int temp = data.m;
        data.m = data.n;
        data.n = temp;
    }
}

class Data{
    int m;
    int n;
}
在声明的方法中实现交换

图解

 

4-值传递机制总结(重点)

/*
* 如果形参是基本数据类型,此时实参赋给形参的是实参真实存储的数据值。
* 如果参数是引用数据类型,此时赋值的是变量所保存的数据的地址值。
*/

4 - 面试题

/*
 * 面试题:
 * 定义一个int型的数组,int[] arr = new int[]{12,3,3,34,56,77,43}; 让数组的每个位置上的值去除 以首位置的元素
 * 得到的结果,作为该位置上的新值,遍历新的数组
 */
public class ValueFransferTest {
    public static void main(String[] args) {
        int[] arr = new int[] {12,3,3,34,56,77,43};
        // 写法1
//        for(int i = arr.length - 1;i >= 0;i--) {
//            arr[i] = arr[i] / arr[0];
//        }
        // 写法2
        int temp = arr[0];
        for(int i = 0;i < arr.length;i++) {
            arr[i] = arr[i] / temp;
            System.out.println(arr[i]);
        }
    }
}

5 - 值传递机制练习

1-题目

/*
* 1-定义一个Circle类,包含一个double型的radius属性代表圆的半径
*   一个findArea()方法返回圆的面积
*
* 2-定义一个类PassObject,在 类中定义一个方法printAreas(),
* 该方法的定义如下:public void printAreas(Circle c,int time)
* 在printAreas方法中打印输出1到time之间的每个整数半径值,以及对应的面积
* 例如,times为5,则输出半径1,2,3,4,5,以及对应的圆面积。
* 在main方法中调用printAreas()方法,调用完毕后输出当前半径值。
*/

2-在 Circle.java 文件中

/*
 * 定义一个Circle类,包含一个double型的radius属性代表圆的半径
 * 一个findArea()方法返回圆的面积
 */
public class Circle {
    double radius; // 半径

    // 求圆的面积
    public double findArea(){
        return Math.PI * radius * radius;
    }
}
Circle.java

3- 在 PassObject.java 文件中

/*
 *
 * 2-定义一个类PassObject,在 类中定义一个方法printAreas(),
 * 该方法的定义如下:public void printAreas(Circle c,int time)
 * 在printAreas方法中打印输出1到time之间的每个整数半径值,以及对应的面积
 * 例如,times为5,则输出半径1,2,3,4,5,以及对应的圆面积。
 * 在main方法中调用printAreas()方法,调用完毕后输出当前半径值。
 */
public class PassObject {
    public static void main(String[] args) {
        PassObject test = new PassObject();
        test.printAreas(new Circle(),5);
    }
    public void printAreas(Circle c,int time){
        System.out.println("Radius\t\tAreas");
        for(int i = 1;i <= time;i++){
            c.radius = i;
            System.out.println(c.radius+"\t\t"+c.findArea());
        }
    }
}
PassObject.java

6 - 递归(recursion)方法

/*
 * 1-递归方法:一个方法体内调用它本身
 * 2-方法递归包含了一种隐式的循环,它会重复执行某段代码,单这种重复执行无须循环控制
 * 3-递归一定要向已知方向递归,否则这种递归就变成了无穷递归,类似于死循环。
 */
public class RecursionTest {

    public static void main(String[] args) {
        // 例题:计算1-100之间所有自然数之和
        // 方式1
        int sum = 0;
        for(int i =0;i <= 100;i++) {
            sum += i;
        }
        System.out.println(sum);
        
        // 方式2
        RecursionTest test = new RecursionTest();
        int res = test.getSum(100);
        System.out.println(res);
    }
    // 方式2
    public int getSum(int n) {
        if(n == 1) {
            return 1;
        }else {
            return n + getSum(n - 1);
        }
    }

}

经典例题:斐波那契数列

/*
 * 输入一个数据n,计算斐波那契数列(Fibonacci)的第n个值 1 1 2 3 5 8 13 21 34 55
 * 规律:一个数等于前两个数之和
 * 要求:计算斐波那契(Fibonacci)的第n个值,并将整个数列打印出来
 */
public class FibonacciTest {

    public static void main(String[] args) {
        // 递归方法
        FibonacciTest test = new FibonacciTest();
        int res = test.Fibonacci(10);
        System.out.println(res);
    }
    public int Fibonacci(int n) {
        // 出口
        if((n <= 2)) {
            return 1;
        }
        return Fibonacci(n - 1) + Fibonacci(n - 2);
    }
}
递归与斐波那契数列

总结递归的使用

1. 必须有一个明确的结束条件

2. 每次进入更深一层递归时,问题规模相比上次递归都应有所减少

3. 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出

 

posted @ 2020-05-30 13:50  赖正华  阅读(356)  评论(0编辑  收藏  举报