12.23_学习Java的day07【面向对象基础–上】可变参数、重载、递归、对象数组

  • Post author:
  • Post category:java




day07【面向对象基础–上】



今日内容

  • 可变参数
  • 方法的重载
  • 递归
  • 对象数组



教学目标


  • 掌握方法的可变参数的使用

  • 掌握方法重载的概念

  • 能够判断出方法的重载

  • 了解命令行参数

  • 理解递归方法

  • 理解对象数组



第五章 面向对象基础–上(续)



5.6 可变参数



JDK1.5

之后,如果我们定义一个方法时,此时某个形参的类型可以确定,但是形参的个数不确定,那么我们可以使用可变参数。

格式:

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

要求:

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

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

(3)其实这个书写“≈”

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

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



示例一: 求n个整数的和

public class ChangeArgs {
	public static void main(String[] args) {
		int[] arr = { 1, 4, 62, 431, 2 };
		int sum1 = getSum1(arr);
		System.out.println(sum1);

		int sum2 = getSum2(arr);
		System.out.println(sum2);
		int sum3 = getSum2(1, 4, 62, 431, 2);
		System.out.println(sum3);
	}

	// 完成数组 所有元素的求和
	// 原始写法
	public static int getSum1(int[] arr) {
		int sum = 0;
		for (int i = 0; i < arr.length; i++) {
			sum += arr[i];
		}

		return sum;
	}

	// 可变参数写法
	public static int getSum2(int... arr) {
		int sum = 0;
		for (int i = 0; i < arr.length; i++) {
			sum += arr[i];
		}
		return sum;
	}
}



示例二:求1-n个整数中的最大值

public class ChangeArgs_Exer1 {
	public static void main(String[] args) {
		System.out.println(max(1));
		System.out.println(max(5,3,2,6));
	}

	public static int max(int num, int... others){
		int max = num;
		for (int i = 0; i < others.length; i++) {
			if(max < others[i]){
				max = num;
			}
		}
		return max;
	}
}



示例三:字符串拼接

需求一:返回n个字符串拼接结果,如果没有传入字符串,那么返回空字符串””

public class ChangeArgs_Exer2 {
	public static void main(String[] args) {
		System.out.println(concat());
		System.out.println(concat("hello","world"));
	}
	public static String concat(String... args){
		String str = "";
		for (int i = 0; i < args.length; i++) {
			str += args[i];
		}
		return str;
	}
}

需求二:n个字符串进行拼接,每一个字符串之间使用某字符进行分割,如果没有传入字符串,那么返回空字符串””

public class ChangeArgs_Exer4 {
	public static void main(String[] args) {
		System.out.println(concat('+'));
		System.out.println(concat('+',"hello","world"));
	}
	public static String concat(char seperator, String... args){
		String str = "";
		for (int i = 0; i < args.length; i++) {
			if(i==0){
				str += args[i];
			}else{
				str += seperator + args[i];
			}
		}
		return str;
	}
}



课后练习

1、声明一个方法,可以找出任意个整数的最大公约数

2、声明一个方法,可以找出任意个字符串中的公共字符,例如:hello与world的公共字符是o和l,如果没有就返回””

提示:获取字符串长度的方法:int length()

​ 例如:字符串.length(), “hello”.length()返回5

​ 获取字符串[index]位置的字符:char charAt(int index)

​ 例如:字符串.charAt(index) hello.charAt(1)返回’e’

参考答案:

class Test12MethodExer1{
	public static void main(String[] args){
		System.out.println(maxYue(6,9));
		System.out.println(maxYue(16,18,4,8));
	}
	
	public static int maxYue(int... args){
		//找很多个数的公约数
		//(1)找出它们中最小的
		//类似于在数组中找最小值
		int min = args[0];
		for(int i=1; i<args.length; i++){
			if(args[i] < min){
				min = args[i];
			}
		}
		
		//(2)从小的数往1的方向找,找到的第一个公约数就是它们的最大公约数
		for(int i=min; i>=1; i--){
			//这个i得把args中所有的数都整除了,那么i就是他们的公约数
			boolean flag = true;//假设i可以把args中所有数都整除了
			for(int j=0; j<args.length; j++){
				if(args[j] % i !=0){//args中有一个数不能被i整除,说明这个i不是它们的公约数
					flag = false;
					break;
				}
			}
			if(flag){
				return i;//return会结束当前方法
			}
		}
		
		return 1;//1是所有数的公约数
		/*
		假设args中6和9  args[0]是6,args[1]是9,min=6
		外循环第一次i=min=6,  
				内循环第一次:j=0,  if(args[0] % 6!=0)不成立 j++
				内循环第二次:j=1,  if(args[1] % 6!=0)成立   flag = false  ;break;
				说明i不是它们公约数
		外循环第二次i=5
				内循环第一次:j=0,  if(args[0] % 5 !=0)成立 j++  flag = false;break;
				说明i不是它们公约数
		外循环第三次i=4
				内循环第一次:j=0,  if(args[0] % 4 !=0)成立 j++  flag = false;break;
				说明i不是它们公约数
		外循环第四次i=3
				内循环第一次:j=0,  if(args[0] % 3 !=0)不成立 j++ 
				内循环第二次:j=1,  if(args[1] % 3 !=0)不成立 j++  
				if(flag)成立,return i;
		*/
	}
}
class Test12MethodExer2{
	public static void main(String[] args){
		System.out.println(sameChars("hello","world"));//ol
		System.out.println(sameChars("chai","wolrd"));
		System.out.println(sameChars("atguigu","java"));
		System.out.println(sameChars("samething","string","thin"));
	}
	
	public static String sameChars(String... words){
		String same = "";
		//找出所有words中相同的字符,拼接起来
		//先用一个数组,表示26个字母是否在所有单词中出现过
		boolean[] appear = new boolean[26];//默认值false
		/*
		appear[0]表示a字符是否在所有的单词中出现,如果是true,表示出现了,就是共同的
												如果是false,表示没有出现,不是共同的
		*/
		//从'a' -> 'z'
		for(char letter = 'a'; letter <= 'z'; letter++){
			boolean flag = true;//假设所有words中都有这个letter
			for(int i=0; i<words.length; i++){
				//判断letter是否在words中出现过,
				boolean now = false;//假设在words[i]中没有出现过
				for(int j=0; j<words[i].length(); j++){
					if(words[i].charAt(j) == letter){//说明letter在当前words中出现了
						now = true;
						break;
					}
				}			
				if(now == false){//说明letter在当前words[i]中没有出现
					flag = false;
					break;
				}
			}
			if(flag==true){
				appear[letter-97]=true;
			}
		}
		
		for(int i=0; i<appear.length; i++){
			if(appear[i] == true){
				same += (char)(97+i);
			}
		}
		
		return same;
	}
}



5.7 方法重载


  • 方法重载

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



示例一:比较两个数据是否相等

比较两个数据是否相等。参数类型分别为两个

byte

类型,两个

short

类型,两个

int

类型,两个

long

类型,并在

main

方法中进行测试。

public class Method_Demo6 {
    public static void main(String[] args) {
        //定义不同数据类型的变量
        byte a = 10;
        byte b = 20;
        short c = 10;
        short d = 20;
        int e = 10;
        int f = 10;
        long g = 10;
        long h = 20;
        // 调用
        System.out.println(compare(a, b));
        System.out.println(compare(c, d));
        System.out.println(compare(e, f));
        System.out.println(compare(g, h));
    }
    // 两个byte类型的
    public static boolean compare(byte a, byte b) {
        System.out.println("byte");
        return a == b;
    }

    // 两个short类型的
    public static boolean compare(short a, short b) {
        System.out.println("short");
        return a == b;
    }

    // 两个int类型的
    public static boolean compare(int a, int b) {
        System.out.println("int");
        return a == b;
    }

    // 两个long类型的
    public static boolean compare(long a, long b) {
        System.out.println("long");
        return a == b;
    }
}



示例二:求各种最大值

用重载实现:

定义方法求两个整数的最大值

定义方法求三个整数的最大值

定义方法求两个小数的最大值

//求两个整数的最大值
public int max(int a,int b){
    return a>b?a:b;
}
	
//求三个整数的最大值
public int max(int a, int b, int c){
    return max(max(a,b),c);
}
	
//求两个小数的最大值
public double max(double a, double b){
    return a>b?a:b;
}



示例三:判断两个方法是否是合理的重载方法

//判断如下两个方法是否构成重载:是
class StringUtil{
	public static String concat(char seperator, String... args){
		String str = "";
		for (int i = 0; i < args.length; i++) {
			if(i==0){
				str += args[i];
			}else{
				str += seperator + args[i];
			}
		}
		return str;
	}
	public static String concat(String[] args){
		String str = "";
		for (int i = 0; i < args.length; i++) {
			str += args[i];
		}
		return str;
	}
}
//判断如下两个方法是否构成重载:不是
class Count{
	public static int getSum(int... nums){
		int sum = 0;
		for (int i = 0; i < nums.length; i++) {
			sum += nums[i];
		}
		return sum;
	}
	public static int getSum(int[] nums){
		int sum = 0;
		for (int i = 0; i < nums.length; i++) {
			sum += nums[i];
		}
		return sum;
	}
}
class Test06_Overload_Problem2{
	public static void main(String[] args){
		System.out.println(sum(1,2));//(int a, int b)
		System.out.println(sum(1,2,3));//(int... args)和(int a, int... args)都兼容,就有问题
	}

	//不调用编译没问题,但是调用时就有问题
	public static int sum(int a, int b){
		return a+b;
	}
	public static int sum(int... args){
		int sum = 0;
		for(int i=0; i<args.length; i++){
			sum += args[i];
		}
		return sum;
	}
	public static int sum(int a, int... args){
		int sum = a;
		for(int i=0; i<args.length; i++){
			sum += args[i];
		}
		return sum;
	}	
}



课后练习

1、声明一个数组工具类ArraysTools,包含几个重载方法

(1)重载方法系列1:可以为byte[],short[],int[],long[],double[],char[]数组实现从小到大排序

(2)重载方法系列2:可以遍历byte[],short[],int[],long[],double[],char[]数组,遍历结果形式:

​ [元素1,元素2,。。。]

2、声明一个图形工具类GraphicTools,包含两个重载方法

(1)包含方法1:根据底边和高,求三角形面积,

(2)包含方法2:根据三条边,求三角形面积

提示:根据三角形三边求面积的海伦公式:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5h6a31Zm-1577105280120)(imgs/1577091140580.png)]



5.8 命令行参数(了解)

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

在这里插入图片描述

public class TestCommandParam{
	//形参:String[] args
	public static void main(String[] args){
		System.out.println(args);
		System.out.println(args.length);
		
		for(int i=0; i<args.length; i++){
			System.out.println("第" + (i+1) + "个参数的值是:" + args[i]);
		}
	}
}

运行命令:

java TestCommandParam
java TestCommandParam 1 2 3
java TestCommandParam hello atguigu



5.9 递归


  • 递归

    :指在当前方法内调用自己的这种现象。

  • 递归的分类:

    • 递归分为两种,直接递归和间接递归。
    • 直接递归称为方法自身调用自己。
    • 间接递归可以A方法调用B方法,B方法调用C方法,C方法调用A方法。

  • 注意事项

    • 递归一定要有条件限定,保证递归能够停止下来,否则会发生栈内存溢出。
    • 在递归中虽然有限定条件,但是递归次数不能太多。否则也会发生栈内存溢出。



示例一:计算1-100之间所有自然数的和

public class RecursionMethod1{
	public static void main(String[] args) {
		int sum = sum(100);
		System.out.println("1-100的和:" + sum);
	}

	public static int sum(int n){
		if(n == 1){
			return 1;
		}else{
			return n + sum(n-1);
		}
	}
}

在这里插入图片描述



示例二:求n!

在这里插入图片描述

public class RecursionMethod2{
	public static void main(String[] args) {
		int jieCheng = jieCheng(10);
		System.out.println("10的阶乘是:" + jieCheng);
	}
	public static int jieCheng(int n){
		if(n <= 1){
			return 1;
		}else{
			return n * jieCheng(n-1);
		}
	}
}

在这里插入图片描述



示例三:计算斐波那契数列(Fibonacci)的第n个值

规律:一个数等于前两个数之和,

​ f(0) =1,

​ f(1) = 1,

​ f(2) = f(0) + f(1) =2,

​ f(3) = f(1) + f(2) = 3,

​ f(4) = f(2) + f(3) = 5

​ …

​ f(n) = f(n-2) + f(n-1);

public class RecursionMethod3{
	public static void main(String[] args) {
		Count c = new Count();
		
		System.out.println("f(10):" + c.f(10));
		System.out.println("f方法被调用的总次数:" + c.total);
	}
}
class Count{
	int total = 0;
	public int f(int n){
		total++;
		if(n <= 1){
			return 1;
		}else{
			return f(n-2) + f(n-1);
		}
	}
}

在这里插入图片描述



练习

1、描述:猴子吃桃子问题,猴子第一天摘下若干个桃子,当即吃了所有桃子的一半,还不过瘾,又多吃了一个。第二天又将仅剩下的桃子吃掉了一半,又多吃了一个。以后每天都吃了前一天剩下的一半多一个。到第十天,只剩下一个桃子。试求第一天共摘了多少桃子?

在这里插入图片描述

2、有n级台阶,一次只能上1步或2步,共有多少种走法?

在这里插入图片描述

3、

在这里插入图片描述



5.10 对象数组

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

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

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



示例一:声明一个MyDate,包含年,月,日,用对象数组存储几个日期,并遍历显示

class MyDate{
	int year;
	int month;
	int day;
}
class Test{
    public static void main(String[] args){
        MyDate[] arr = new MyDate[3];//创建数组对象本身,指定数组的长度
        
        for(int i=0; i<arr.length; i++){
            arr[i] = new MyDate();//每一个元素要创建对象
            arr[i].year = 1990 + i;
            arr[i].month = 1 + i;
            arr[i].day = 1 + i;
        }
    }
}



对象数组的内存图分析

在这里插入图片描述



练习1

(1)定义学生类Student

​ 声明姓名和成绩实例变量,

​ getInfo()方法:用于返回学生对象的信息

(2)测试类ObjectArrayTest的main中创建一个可以装3个学生对象的数组,并且按照学生成绩排序,显示学生信息

public class ObjectArrayTest {
	public static void main(String[] args) {
		Student[] arr = new Student[3];
		arr[0] = new Student();
		arr[0].name = "张三";
		arr[0].score = 89;
		
		arr[1] = new Student();
		arr[1].name = "李四";
		arr[1].score = 84;
		
		arr[2] = new Student();
		arr[2].name = "王五";
		arr[2].score = 85;
		
		for (int i = 1; i < arr.length; i++) {
			for (int j = 0; j < arr.length-1; j++) {
				if(arr[j].score > arr[j+1].score){
					Student temp = arr[j];
					arr[j] = arr[j+1];
					arr[j+1] = temp;
				}
			}
		}
		
		for (int i = 0; i < arr.length; i++) {
			System.out.println(arr[i].getInfo());
		}
	}
}
class Student{
	String name;
	int score;
	public String getInfo(){
		return "姓名:" + name + ",成绩:" + score;
	}
}
class Test18_ObjectArrayExer2_2{
	public static void main(String[] args){
		//创建一个可以装3个学生对象的数组
		Student[] arr = new Student[3];//只是申明这个数组,可以用来装3个学生,此时里面没有学生对象
		
		//从键盘输入
		java.util.Scanner input = new java.util.Scanner(System.in);
		for(int i=0;i<arr.length; i++){
			System.out.println("请输入第" + (i+1) + "个学生信息:");
			arr[i] = new Student();
			
			System.out.print("姓名:");
			arr[i].name = input.next();
			
			System.out.print("成绩:");
			arr[i].score = input.nextInt();
		}
		
		//先显示一下目前的顺序
		for(int i=0; i<arr.length; i++){
			System.out.println(arr[i].getInfo());
		}
		
		System.out.println("------------------------------------------");
		//冒泡排序
		for(int i=1; i<arr.length; i++){
			for(int j=0; j<arr.length-i; j++){
				//arr[j] > arr[j+1]//错误的
				if(arr[j].score > arr[j+1].score){
					//交换两个元素,这里是两个学生对象,所以temp也得是Student类型
					Student temp = arr[j];
					arr[j] = arr[j+1];
					arr[j+1] = temp;
				}
			}
		}
		//再显示一下目前的顺序
		for(int i=0; i<arr.length; i++){
			System.out.println(arr[i].getInfo());
		}
	}
}
class Student{
	String name;
	int score;//使用int或double都可以
	
	public String getInfo(){
		return "姓名:" + name +",成绩:" + score;
	}
}



练习2

(1)定义圆Circle类,包含radius半径属性,getArea()求面积方法,getPerimeter()求周长方法,String getInfo()返回圆对象的详细信息的方法

(2)在测试类中创建长度为5的Circle[]数组,用来装5个圆对象,并给5个圆对象的半径赋值为[1,10)的随机值

class Test16_ObjectArray{
	public static void main(String[] args){
		//要在数组中存储5个圆对象
		//声明一个可以用来存储圆对象的数组
		Circle[] arr = new Circle[5];
		//for(int i=0; i<arr.length; i++){
		//	System.out.println(arr[i]);
		//}
		//System.out.println(arr[0].radius);//NullPointerException
		
		//给元素赋值
		//元素的类型是:Circle,应该给它一个Circle的对象
		//arr[0] = 1.2;//错误的
		//arr[0]相当于它是一个Circle类型的变量,也是对象名
		/*
		arr[0] =  new Circle();
		arr[0].radius = 1.2;
		System.out.println(arr[0].radius);
		*/
		
		//创建5个对象,半径随机赋值为[1,10)的随机值
		//Math.random()==>[0,1)
		//Math.random()*9==>[0,9)
		//Math.random()*9+1==>[1,10)
		for(int i=0; i<arr.length; i++){
			arr[i] = new Circle();//有对象才有半径
			arr[i].radius = Math.random()*9+1;
		}
		
		
		//遍历显示圆对象的信息
		for(int i=0; i<arr.length; i++){
			//arr[i]是一个Circle的对象,就可以调用Circle类中的属性和方法
			System.out.println(arr[i].getInfo());
		}
	}
}
class Circle{
	double radius;
	public double getArea(){
		return 3.14 * radius * radius;
	}
	public double getPerimeter(){
		return 3.14 * 2 * radius;
	}
	public String getInfo(){
		return "半径:" + radius +",面积:" + getArea() + ",周长:" + getPerimeter();
	}
}

量,也是对象名

/*

arr[0] = new Circle();

arr[0].radius = 1.2;

System.out.println(arr[0].radius);

*/

	//创建5个对象,半径随机赋值为[1,10)的随机值
	//Math.random()==>[0,1)
	//Math.random()*9==>[0,9)
	//Math.random()*9+1==>[1,10)
	for(int i=0; i<arr.length; i++){
		arr[i] = new Circle();//有对象才有半径
		arr[i].radius = Math.random()*9+1;
	}
	
	
	//遍历显示圆对象的信息
	for(int i=0; i<arr.length; i++){
		//arr[i]是一个Circle的对象,就可以调用Circle类中的属性和方法
		System.out.println(arr[i].getInfo());
	}
}

}

class Circle{


double radius;

public double getArea(){


return 3.14 * radius * radius;

}

public double getPerimeter(){


return 3.14 * 2 * radius;

}

public String getInfo(){


return “半径:” + radius +”,面积:” + getArea() + “,周长:” + getPerimeter();

}

}






版权声明:本文为weixin_45506970原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。