1.特殊参数之一:可变参数
在JDK1.5之后,当定义一个方法时,形参的类型可以确定,但是形参的个数不确定,那么可以考虑使用可变参数。可变参数的格式:
【修饰符】 返回值类型 方法名(【非可变参数部分的形参列表,】参数类型... 形参名){ }
可变参数的特点和要求:
(1)一个方法最多只能有一个可变参数
(2)如果一个方法包含可变参数,那么可变参数必须是形参列表的最后一个
(3)在声明它的方法中,可变参数当成数组使用
(4)其实这个书写...
【修饰符】 返回值类型 方法名(【非可变参数部分的形参列表,】参数类型[] 形参名){ }
只是后面这种定义,在调用时必须传递数组,而前者更灵活,既可以传递数组,又可以直接传递数组的元素,这样更灵活了。
1.1 方法只有可变参数
案例:求 n 个整数的和
public class SumToolss {
// 数组求和
public int sum1(int[] arr) {
int sum = 0;
for (int i = 0; i < arr.length; i++) {
sum += arr[i];
}
return sum;
}
// 一个一个输入 ...
// 可变参数当作数组来使用
public int sum2(int... num) {
int sum = 0;
for (int i = 0; i < num.length; i++) {
sum += num[i];
}
return sum;
}
}
import day0412.model.SumToolss;
public class TestSumToolss {
public static void main(String[] args) {
SumToolss sumtools = new SumToolss();
int[] arr = {1, 2, 3, 4, 5};
int rel1 = sumtools.sum1(arr);
int rel3 = sumtools.sum2(2, 12, 3, 4, 5, 6);
int rel2 = sumtools.sum3(2, arr);
int rel4 = sumtools.sum3(2, 12, 3, 4, 5, 6);
System.out.println(rel1);
System.out.println(rel2);
System.out.println(rel3);
System.out.println(rel4);
}
}
1.2 方法包含非可变参数和可变参数
-
非可变参数部分必须传入对应类型和个数的实参;
-
可变参数部分按照可变参数的规则传入0~n个对应类型的实参或传入1个对应类型的数组实参;
案例:
n个字符串进行拼接,每一个字符串之间使用某字符进行分割,如果没有传入字符串,那么返回空字符串""
public class StringTools {
// n 个字符串进行拼接,每一个字符串之间用某个字符进行分割
// 如果没有传入字符串,那么返回空字符串""
public String concat(String st, String... arr) {
String str = "";
for (int i = 0; i < arr.length; i++) {
if (i == 0) {
str += arr[i];
} else {
str += st + arr[i];
}
}
return str;
}
}
public class TestStringToolss {
// public class StringTools {
// n 个字符串进行拼接,每一个字符串之间用某个字符进行分割
// 如果没有传入字符串,那么返回空字符串""
public static String concat(String st, int... arr) {
String str = " ";
for (int i = 0; i < arr.length; i++) {
if (i == 0) {
str += arr[i];
} else {
str += st + arr[i];
}
}
return str;
}
// }
public static void main(String[] args) {
// StringTools st = new StringTools();
//String[] arr = {"123", "456", "789"};
System.out.println(concat("-", 1));// 1
}
}
2.特殊参数之二:命令行参数(了解)
通过命令行给main方法的形参传递的实参称为命令行参数
public class SpeParam {
// 直接接受 args ,命令行参数
// 直接通过命令行给 main 方法的形参传递的实参为命令行参数
// String...args
// JDK 1.0 main方法就有了 15
// 1.只有一个可变参数 2.有多个参数时,可变参数放置最后一个 3.main 主执行程序的参数(命令行参数) String...args
public static void main(String[] args) {
for (int i = 0; i < args.length; i++) {
System.out.println(args[i]);
}
}
}
命令行:
java TestCommandParamjava TestCommandParam 1 2 3java TestCommandParam hello haog
3.方法的参数传递机制
方法的参数传递机制:实参给形参赋值,那么反过来形参会影响实参吗?
-
方法的形参是基本数据类型时,形参值的改变不会影响实参;
-
方法的形参是引用数据类型时,形参地址值的改变不会影响实参,但是形参地址值里面的数据的改变会影响实参,例如,修改数组元素的值,或修改对象的属性值。
-
注意:String、Integer等特殊类型容易错
3.1 形参是基本数据类型
public void swapData2(int a, int b) {
// 两两交换,使用中间值
// 局部的区域
int temp;
temp = a;
a = b;
b = temp;
System.out.println("交换之后的x:" + a);
System.out.println("交换之后的y:" + b);
}
public class TestCahngeData {
public static void main(String[] args) {
ChangeData ch = new ChangeData();
int x = 2;
int y = 3;
// 这个在内存中属于不同的区域
// 全局的量区域 不同的
ch.swapData2(x, y);
System.out.println("交换之前的x:" + x);
System.out.println("交换之前的y:" + y);
}
}
3.2 形参是数组
public int[] swapData(int[] arr) {
// 两两交换,使用中间值
// 局部的区域
System.out.println(arr[0]);
System.out.println(arr[1]);
int temp;
temp = arr[0];
arr[0] = arr[1];
arr[1] = temp;
return arr;
}
public class TestCahngeData2 {
public static void main(String[] args) {
ChangeData ch = new ChangeData();
String[] arr = {"5", "6"};
System.out.println("下面是交换之前的数据:");
ch.itra(arr);
System.out.println("下面是交换之后的数据:");
ch.swapData(arr);
ch.itra(arr);
}
}
3.3 形参是引用数据类型
public int[] swapData(String[] arr) {
// 两两交换,使用中间值
// 局部的区域
System.out.println(arr[0]);
System.out.println(arr[1]);
String temp;
temp = arr[0];
arr[0] = arr[1];
arr[1] = temp;
return arr;
}
public class TestCahngeData2 {
public static void main(String[] args) {
ChangeData ch = new ChangeData();
String[] arr = {"5", "6"};
System.out.println("下面是交换之前的数据:");
ch.itra(arr);
System.out.println("下面是交换之后的数据:");
ch.swapData(arr);
ch.itra(arr);
}
}
3.4 形参指向新对象
// 对象的值传递过来 引用数据类型传递也是地址 修改的数据与传递数据也是一致的
public void swapData3(MyData my) {
// 两两交换,使用中间值
// 局部的区域
// 新开辟一个空间就不行了 my= new myData();
int temp;
temp = my.x;
my.x = my.y;
my.y = temp;
System.out.println("交换之后的x:" + my.x);
System.out.println("交换之后的y:" + my.y);
}
public class MyData {
public int x;
public int y;
}
public class TestChangeData3 {
public static void main(String[] args) {
ChangeData ch = new ChangeData();
MyData myData = new MyData();
myData.x = 7;
myData.y = 8;
System.out.println("操作之前x:" + myData.x);
System.out.println("操作之前y:" + myData.y);
ch.swapData3(myData);
}
}
4.方法的重载
-
方法重载:指在同一个类中,允许存在一个以上的同名方法,只要它们的参数列表不同即可,与修饰符和返回值类型无关。
-
参数列表:数据类型个数不同,数据类型不同(按理来说数据类型顺序不同也可以,但是很少见,也不推荐,逻辑上容易有歧义)。
-
重载方法调用:JVM通过方法的参数列表,调用匹配的方法。
-
先找个数、类型最匹配的
-
再找个数和类型可以兼容的,如果同时多个方法可以兼容将会报错
-
案例,用重载实现:
(1)定义方法求两个整数的最大值
(2)定义方法求三个整数的最大值
(3)定义方法求两个小数的最大值
(4)定义方法求n个整数最大值
public class MathTools {
//求两个整数的最大值
public int max(int a,int b){
return a>b?a:b;
}
//求两个小数的最大值
public double max(double a, double b){
return a>b?a:b;
}
//求三个整数的最大值
public int max(int a, int b, int c){
return max(max(a,b),c);
}
//求n整数的最大值
public int max(int... nums){
int max = nums[0];//如果没有传入整数,或者传入null,这句代码会报异常
for (int i = 1; i < nums.length; i++) {
if(nums[i] > max){
max = nums[i];
}
}
return max;
}
}
4.1 找最匹配的
public class SuperMarket {
// 支付方法 pay
// 1个 String 参数
public String pay(String type) {
return "所有超市都支持" + type;
}
// 2个 String 参数
public String pay(String type1, String type2) {
return "所有超市都支持" + type1 + ",还支持" + type2;
}
// 1个 float 参数
public String pay(float money) {
return "今天我去超市花费了" + money + "元";
}
public String pay(String... type) {
/*// String str = "";
if (type == null || type.length == 0) {
return "";
} else {
String str = type[0];
for (int i = 0; i < type.length; i++) {
str += type[i];
}
return "所有超市都支持:" + str;
}*/
String str = "";
for (int i = 0; i < type.length; i++) {
str += type[i];
}
return "所有超市都支持:" + str;
}
}
public class TestSuperMarket {
public static void main(String[] args) {
SuperMarket market = new SuperMarket();
String rel1 = market.pay("现金");
System.out.println(rel1);// 所有超市都支持现金
String rel2 = market.pay("现金", "刷卡");
System.out.println(rel2);// 所有超市都支持现金,还支持刷卡
String rel3 = market.pay(131.4f);
System.out.println(rel3);// 今天我去超市花费了131.4元
String rel4 = market.pay("现金", "、支付宝", "、微信");
System.out.println(rel4);// 所有超市都支持:现金、支付宝、微信
String rel5 = market.pay();
System.out.println(rel5);// 所有超市都支持:
}
}
4.2 找唯一可以兼容的
package com.haogu.test06.overload;
public class MethodOverloadMostCompatible {
public static void main(String[] args) {
MathTools tools = new MathTools();
System.out.println(tools.max(5.7,9));
System.out.println(tools.max(5,6,8,3));
// System.out.println(tools.max(5.7,9.2,6.9)); //没有兼容的
}
}
5.方法的递归调用
递归调用:方法自己调用自己的现象就称为递归。
递归的分类:
-
递归分为两种,直接递归和间接递归。
-
直接递归称为方法自身调用自己。
-
间接递归可以A方法调用B方法,B方法调用C方法,C方法调用A方法。
注意事项:
-
递归一定要有条件限定,保证递归能够停止下来,否则会发生栈内存溢出。
-
在递归中虽然有限定条件,但是递归深度不能太深,否则效率低下,或者也会发生栈内存溢出。
-
能够使用循环代替的,尽量使用循环代替递归
-
案例:计算斐波那契数列(Fibonacci)的第n个值,斐波那契数列满足如下规律,
1,1,2,3,5,8,13,21,34 ....
即从第三个数开始,一个数等于前两个数之和。假设f(n)代表斐波那契数列的第n个值,那么f(n)满足:
f(n) = f(n-2) + f(n-1);
public class Feibo {
long fei(int n) {
// 小于 1
if (n < 1) {
return 0;
}
// 等于 1或者 等于 2
if (n == 1 || n == 2) {
return 1;
}
return fei(n - 2) + fei(n - 1);
/*
fei(5)
第一次:fei(3)+fei(4)
第二次:fei(1)+fei(2)+fei(2)+fei(3)
第三次:fei(1)+fei(2)+fei(2)+fei(1)+fei(2)
*/
}
public static void main(String[] args) {
// 计算斐波那契额数列的第 n 个值,满足一下规律:1,1,2,3,5,8,13,21 f(n)=f(n-2)+f(n-1)
Feibo feibo = new Feibo();
System.out.println(feibo.fei(5));
System.out.println(feibo.fei(6));
System.out.println(feibo.fei(48));
}
}
6.对象数组
数组是用来存储一组数据的容器,一组基本数据类型的数据可以用数组装,那么一组对象也可以使用数组来装。
即数组的元素可以是基本数据类型,也可以是引用数据类型。当元素是引用数据类型是,我们称为对象数组。
注意:对象数组,首先要创建数组对象本身,即确定数组的长度,然后再创建每一个元素对象,如果不创建,数组的元素的默认值就是null,所以很容易出现空指针异常NullPointerException。
6.1 对象数组的声明和使用
案例:
(1)定义矩形类,包含长、宽属性,area()求面积方法,perimeter()求周长方法,String getInfo()返回圆对象的详细信息的方法
(2)在测试类中创建长度为5的Rectangle[]数组,用来装3个矩形对象,并给3个矩形对象的长分别赋值为10,20,30,宽分别赋值为5,15,25,遍历输出
public class Dog {
// 狗的名字
public String name;
// 狗的年龄
public int age;
}
public class TestDog2 {
public static void main(String[] args) {
Dog[] dog = new Dog[5];
// 数组对象中得先设置值,然后再使用对象中的属性和方法
// 对象排序时,是比较对象的属性值
Dog dog1 = new Dog();
// 第一个
dog1.name = "花花";
dog1.age = 2;
dog[0] = dog1;
// 第二个
Dog dog2 = new Dog();
dog2.name = "老黄";
dog2.age = 10;
dog[1] = dog2;
// 第三个
Dog dog3 = new Dog();
dog3.name = "小白";
dog3.age = 7;
dog[2] = dog3;
// 第四个
Dog dog4 = new Dog();
dog4.name = "小红";
dog4.age = 4;
dog[3] = dog4;
// 第五个
Dog dog5 = new Dog();
dog5.name = "小黑";
dog5.age = 5;
dog[4] = dog5;
// 根据狗的年龄进行狗的对象数据的排序
for (int i = 0; i < dog.length - 1; i++) {
for (int j = 0; j < dog.length - i - 1; j++) {
if (dog[j].age > dog[j + 1].age) {
Dog temp = new Dog();
temp = dog[j];
dog[j] = dog[j + 1];
dog[j + 1] = temp;
}
}
}
String dogMsg = "";
for (int i = 0; i < dog.length; i++) {
dogMsg += dog[i].name + dog[i].age + "岁\t";
}
System.out.println(dogMsg);
}
}
后续内容,正在更新...