day07.可变参数 命令行参数 递归 对象数组

  1. 课前回顾:
  2. 1.面向对象:Java语言的核心变成思想,自己的事情自己不做,找别人帮我去做事
  3. 2.为什么要使用面向对象思想编程:
  4. 为了让编写过程更简单(很多的功能别人都已经封装好了,不用我们自己一步一步的写,直接调用,就能完成想要的功能)
  5. 3.什么情况下使用面向对象思想:
  6. 在一个类中使用别的类的成员时,就需要new对象 点方法(new对象,点方法的过程就是在使用面向对象的过程)
  7. 4.怎么用?
  8. new 对象 点方法
  9. 5.类和对象
  10. 类:
  11. 属性(成员变量)
  12. 行为(成员方法(不带static的))
  13. 对象:一类事物的具体体现
  14. 导包:import 包名.类名
  15. 两个类不在同一个包下,需要导包
  16. 在同一个包下,不用导包了
  17. lang包下类使用时无需导包
  18. 创建对象:想使用哪个类中的成员,就new哪个类的对象
  19. 类名 对象名 = new 类名()
  20. 调用成员(成员方法,成员变量):想调用哪个成员,就用哪个对象去点哪个成员
  21. 对象名.成员变量 =
  22. 对象名.成员方法(参数)
  23. 6.成员变量和局部变量的区别:
  24. a.定义位置
  25. 成员变量:定义在类中方法外
  26. 局部变量:定义在方法内部或者参数位置
  27. b.作用范围
  28. 成员变量:作用于整个类
  29. 局部变量:只作用于自己的方法中
  30. c.默认值
  31. 成员:有默认值的
  32. 局部:没有默认值,不手动赋值,不能直接使用
  33. d.在内存中的位置
  34. 成员:在堆中
  35. 局部:在栈中
  36. e.生命周期不同
  37. 成员:随着对象的创建而存在,随着对象的消失而消失
  38. 局部:随着方法被调用而产生,随着方法调用完毕而消失
  39. 7.static:静态
  40. a.被static修饰的成员,属于类,随着类的加载而加载
  41. b.非static的属于对象,所以static的成员优先于非静态成员存在的
  42. c.只要是根据static所在的类创建出来的对象,都可以共享这个static成员
  43. d.访问:类名直接调用
  44. 今日重点:
  45. 1.会使用可变参数定义方法
  46. 2.会简单使用递归
  47. 3.会往数组中存储对象,遍历数组,获取每一个对象中的属性值
  48. 4.会二分查找法

第一章.可变参数

1介绍和基本使用

  1. 1.需求:定义一个方法,实现若干个整数相加(参数类型确定,个数不确定)
  2. 2.可变参数什么时候使用:
  3. 当定义方法时,参数类型确定,但是个数不确定
  4. 3.格式:
  5. 数据类型...变量名
  6. 4.可变参数的本质:
  7. 数组
  8. 5.注意事项:
  9. a.参数位置只能出现一个可变参数
  10. b.如果可变参数和其他的普通参数一起出现,可变参数放在最后面
  1. public class Test01 {
  2. public static void main(String[] args) {
  3. sum(1,2,3,4,5,6,6,5,6,4,5,7);
  4. }
  5. public static void sum(int...arr){
  6. //定义一个变量sum接收两个数的和
  7. int sum = 0;
  8. for (int i = 0; i < arr.length; i++) {
  9. sum+=arr[i];
  10. }
  11. System.out.println(sum);
  12. }
  13. }
  1. Collections类中的方法:
  2. static <T> boolean addAll(Collection<? super T> c, T... elements)->将elements代表的元素批量放到c代表的集合中
  1. public class Test02 {
  2. public static void main(String[] args) {
  3. ArrayList<String> list = new ArrayList<>();
  4. list.add("张三");
  5. list.add("李四");
  6. list.add("王五");
  7. Collections.addAll(list,"涛哥","柳岩","金莲","武松");
  8. System.out.println(list);
  9. }
  10. }

2可变参数

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

格式:

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

要求:

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

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

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

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

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

示例二:求n个整数的和

  1. public class Test01 {
  2. public static void main(String[] args) {
  3. sum(1,2,3,4,5,6,6,5,6,4,5,7);
  4. }
  5. public static void sum(int...arr){
  6. //定义一个变量sum接收两个数的和
  7. int sum = 0;
  8. for (int i = 0; i < arr.length; i++) {
  9. sum+=arr[i];
  10. }
  11. System.out.println(sum);
  12. }
  13. }

示例二:字符串拼接

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

  1. public class Test03 {
  2. public static void main(String[] args) {
  3. String concat = concat("hello", "world", "柳岩", "最美");
  4. System.out.println(concat);
  5. }
  6. public static String concat(String...arr){
  7. //定义一个str,用于接收两个字符串拼接的结果
  8. String str = "";
  9. for (int i = 0; i < arr.length; i++) {
  10. str+=arr[i];
  11. }
  12. return str;
  13. }
  14. }

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

  1. 调用方法:
  2. concat(",","hello","world")-> hello,world
  1. public class Test04 {
  2. public static void main(String[] args) {
  3. String concat = concat(",", "hello", "world");
  4. System.out.println(concat);
  5. }
  6. public static String concat(String s,String...arr){
  7. String str = "";
  8. for (int i = 0; i < arr.length; i++) {
  9. if (i==arr.length-1){
  10. // str = str+arr[i];
  11. str+=arr[i];
  12. }else{
  13. //str = str+arr[i]+s;
  14. str+=arr[i]+s;
  15. }
  16. }
  17. return str;
  18. }
  19. }

第二章.递归

  1. 1.从前有座山,山上有座庙,庙里有个老和尚,老和尚跟小和尚讲故事,讲的啥呢?
  2. 从前有座山,山上有座庙,庙里有个老和尚,老和尚跟小和尚讲故事,讲的啥呢?
  3. 从前有座山,山上有座庙,庙里有个老和尚,老和尚跟小和尚讲故事,讲的啥呢?
  4. 2.递归概述:
  5. 方法内部自己调用自己->直接递归
  6. public static void method(){
  7. method();
  8. }
  9. 方法之间互相调用->间接递归
  10. public static void method1(){
  11. method2();
  12. }
  13. public static void method2(){
  14. method3();
  15. }
  16. public static void method3(){
  17. method1();
  18. }
  19. 3.注意:
  20. 递归一定要有条件限定,保证递归能够停止下来,否则会发生栈内存溢出(因为会不断的压栈)。
  21. 在递归中虽然有限定条件,但是递归次数不能太多。否则也会发生栈内存溢出。

3.1 递归

  • 递归:指在当前方法内调用自己的这种现象。
  • 递归的分类:
    • 递归分为两种,直接递归和间接递归。
    • 直接递归称为方法自身调用自己。
    • 间接递归可以A方法调用B方法,B方法调用C方法,C方法调用A方法。
  • 注意事项

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


    示例一:需求:利用递归输出3到1

  1. public class Test01 {
  2. public static void main(String[] args) {
  3. method(3);
  4. }
  5. public static void method(int n) {
  6. System.out.println(n);
  7. n--;
  8. if (n==1){
  9. System.out.println(1);
  10. //结束方法
  11. return;
  12. }
  13. method(n);
  14. }
  15. }

day07[可变参数_命令行参数_递归_数组] - 图1

示例二:求n!

day07[可变参数_命令行参数_递归_数组] - 图2

  1. 1.定义一个方法f() 表示 阶乘方法
  2. 2.分析过程
  3. f(1): 1
  4. f(2): 1*2-> f(1)*2
  5. f(3): 1*2*3->f(2)*3
  6. f(4): 1*2*3*4->f(3)*4
  7. f(5): 1*2*3*4*5->f(4)*5
  8. ....
  9. 总结规律: f(n) = f(n-1)*n
  1. public class Test02 {
  2. public static void main(String[] args) {
  3. int result = f(5);
  4. System.out.println(result);
  5. }
  6. /*
  7. f(1): 1
  8. f(2): 1*2-> f(1)*2
  9. f(3): 1*2*3->f(2)*3
  10. f(4): 1*2*3*4->f(3)*4
  11. f(5): 1*2*3*4*5->f(4)*5
  12. ....
  13. 总结规律: f(n) = f(n-1)*n
  14. */
  15. public static int f(int n){
  16. if (n==1){
  17. return 1;
  18. }
  19. return f(n-1)*n;
  20. }
  21. }

day07[可变参数_命令行参数_递归_数组] - 图3

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

  1. 不死神兔
  2. 故事得从西元1202年说起,话说有一位意大利青年,名叫斐波那契。
  3. 在他的一部著作中提出了一个有趣的问题:假设一对刚出生的小兔一个月后就能长成大兔,再过一个月就能生下一对小兔,并且此后每个月都生一对小兔,一年内没有发生死亡
  4. 问:一对刚出生的兔子,一年内繁殖成多少对兔子?144

规律:一个数等于前两个数之和,比如: 1 1 2 3 5 8 13 21 34 55….

day07[可变参数_命令行参数_递归_数组] - 图4

  1. 定义一个方法f 代表递归方法,传递的参数代表月份
  2. f(1) : 1
  3. f(2) : 1
  4. f(3) : 2 f(1)+f(2)
  5. f(4) : 3 f(2)+f(3)
  6. f(5) : 5 f(3)+f(4)
  7. 总结:
  8. 问第n个月,有多少对兔子
  9. f(n-2)+f(n-1)

day07[可变参数_命令行参数_递归_数组] - 图5

  1. public class Test03 {
  2. public static void main(String[] args) {
  3. int result = f(12);
  4. System.out.println(result);
  5. }
  6. public static int f(int n){
  7. if (n==1 || n==2){
  8. return 1;
  9. }
  10. return f(n-2)+f(n-1);
  11. }
  12. }

第三章 对象数组

  1. 需求:定义一个长度为3的数组,存储3Person对象 遍历数组,将Person对象的属性值获取出来
  1. public class Person {
  2. String name;
  3. int age;
  4. }
  1. public class Test01 {
  2. public static void main(String[] args) {
  3. /*
  4. 1.定义数组,长度为3
  5. Person p = new Person()->Person类型
  6. Person[] arr = new Person[3]
  7. "abc"->String类型
  8. String[] arr = new String[3]
  9. 1->int类型
  10. int[] arr = new int[3]
  11. 2.5->double类型
  12. double[] arr = new double[3]
  13. */
  14. /*
  15. 创建一个专门存储Person对象的数组,
  16. 由于数组中的Person对象数据类型为Person类型
  17. 所以,我们定义数组时就写Person[]
  18. */
  19. Person[] arr = new Person[3];
  20. //创建3个Person对象
  21. Person p1 = new Person();
  22. p1.name = "柳岩";
  23. p1.age = 36;
  24. Person p2 = new Person();
  25. p2.name = "金莲";
  26. p2.age = 26;
  27. Person p3 = new Person();
  28. p3.name = "杨幂";
  29. p3.age = 32;
  30. //将三个对象存储到数组中
  31. arr[0] = p1;
  32. arr[1] = p2;
  33. arr[2] = p3;
  34. //遍历
  35. /*
  36. 第一次循环: i = 0 arr[i]->arr[0]->p1
  37. p1.name = "柳岩"
  38. p1.age = 36
  39. 第二次循环: i = 1 arr[i]->arr[1]->p2
  40. 第三次循环: i = 2 arr[i]->arr[2]->p3
  41. */
  42. for (int i = 0; i < arr.length; i++) {
  43. Person p = arr[i];
  44. System.out.println(p.name+"..."+p.age);
  45. }
  46. }
  47. }

day07[可变参数_命令行参数_递归_数组] - 图6

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

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

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

练习1

(1)定义学生类Student

  1. 声明姓名和成绩实例变量

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

  1. public class Student {
  2. String name;
  3. int score;
  4. }
  1. public class Test02_Student {
  2. public static void main(String[] args) {
  3. //1.创建长度为3的数组
  4. Student[] students = new Student[3];
  5. //2.创建3个Student对象
  6. Student s1 = new Student();
  7. s1.name = "柳岩";
  8. s1.score = 36;
  9. Student s2 = new Student();
  10. s2.name = "金莲";
  11. s2.score = 26;
  12. Student s3 = new Student();
  13. s3.name = "涛哥";
  14. s3.score = 100;
  15. //3.将三个对象,存储到数组中
  16. students[0] = s1;
  17. students[1] = s2;
  18. students[2] = s3;
  19. //4.根据成绩排序
  20. for (int j = 0;j<students.length-1;j++){
  21. for (int i = 0; i < students.length-1-j; i++) {
  22. if (students[i].score>students[i+1].score){
  23. Student temp = students[i];
  24. students[i] = students[i+1];
  25. students[i+1] = temp;
  26. }
  27. }
  28. }
  29. //5.遍历
  30. for (int i = 0; i < students.length; i++) {
  31. System.out.println(students[i].name+"..."+students[i].score);
  32. }
  33. }
  34. }

第四章.二分查找

  1. 1.前提:数组元素是有序
  2. 2.怎么查:一次干掉一半这种方式去查询

day07[可变参数_命令行参数_递归_数组] - 图7

  1. public class Test01 {
  2. public static void main(String[] args) {
  3. //定义数组
  4. int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9};
  5. //定义min 和max 分别代表数组的最小索引和最大索引
  6. int min = 0;
  7. int max = arr.length - 1;
  8. //定义mid,代表中间索引
  9. int mid = 0;
  10. //明确要查找的数据
  11. int key = 0;
  12. while(min<=max){
  13. //计算出中间索引
  14. mid = (min+max)/2;
  15. if (key>arr[mid]){
  16. min = mid+1;
  17. }else if (key<arr[mid]){
  18. max = mid-1;
  19. }else{
  20. System.out.println(mid);
  21. return;//结束方法
  22. }
  23. }
  24. System.out.println(-1);
  25. }
  26. }

第五章.数组翻转

  1. 1.对称索引位置上的元素互换位置

day07[可变参数_命令行参数_递归_数组] - 图8

  1. public class Test01 {
  2. public static void main(String[] args) {
  3. int[] arr = {1,2,3,4,5,6,7,8};
  4. for (int min = 0,max = arr.length-1;min<max;min++,max--){
  5. int temp = arr[min];
  6. arr[min] = arr[max];
  7. arr[max] = temp;
  8. }
  9. for (int i = 0; i < arr.length; i++) {
  10. System.out.print(arr[i]+" ");
  11. }
  12. }
  13. }

第六章.命令行参数(了解)

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

day07[可变参数_命令行参数_递归_数组] - 图9

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

运行命令:

  1. java TestCommandParam
  1. java TestCommandParam 1 2 3
  1. java TestCommandParam hello atguigu

第七章.API文档的使用

  1. 1.API概述:定义好的类以及接口以及类和接口中的方法
  2. 2.API文档:是我们程序员的"字典"

1.查找想要使用的API

day07[可变参数_命令行参数_递归_数组] - 图10

2.看对应API的成员

day07[可变参数_命令行参数_递归_数组] - 图11

day07[可变参数_命令行参数_递归_数组] - 图12

第八章.封装

1.封装的介绍和基本使用

  1. 1.面向对象的三个特征: 封装 继承 多态
  2. 2.概述:
  3. a.为什么需要封装?封装的作用和含义?
  4. 我要用洗衣机,只需要按一下开关和洗涤模式就可以了。有必要了解洗衣机内部的结构吗?有必要碰电动机吗?
  5. b.隐藏对象内部的复杂性,只对外公开简单的接口。便于外界调用,从而提高系统的可扩展性、可维护性。通俗的说,把该隐藏的隐藏起来,该暴露的暴露出来。这就是封装性的设计思想。
  6. 将细节隐藏起来,对外提供一个暴露的接口,供我们使用者使用,我们只需要调用这个接口,接口中的细节(代码)就执行起来了
  7. 3.考虑的问题:不是说private(私有的权限修饰符)就代表了所有的封装
  8. 将代码放到一个代码块中也可以称之为封装
  9. 4.关键字(在封装思想中比较有代表性的)
  10. a.private-> 私有权限
  11. b.修饰一个成员变量: private 数据类型 变量名
  12. 修饰一个成员方法: private 返回值类型 方法名(参数){}
  13. c.私有的成员,只能当前类使用,别的类中不能直接使用
  14. 5.问题:
  15. a.当一个成员被private修饰,外界彻底使用不了了,我们使用private将细节隐藏起来,我们还需要将接口暴露出来供别人使用
  16. b.被private修饰的成员变量,需要提供对应的getxxx/setxxx方法来为private修饰的成员变量赋值.取值
  17. c.getxxx()获取属性值
  18. setxxx()为属性赋值
  1. public class Person {
  2. private String name;
  3. //隐藏细节->封装思想
  4. private int age;
  5. //对外提供可使用的接口
  6. public void setAge(int nianLing){
  7. if (nianLing<0){
  8. System.out.println("你疯了,你没了");
  9. }else{
  10. age = nianLing;
  11. }
  12. }
  13. public int getAge(){
  14. return age;
  15. }
  16. public void setName(String xingMing){
  17. name = xingMing;
  18. }
  19. public String getName(){
  20. return name;
  21. }
  22. }
  1. public class Test {
  2. public static void main(String[] args) {
  3. Person person = new Person();
  4. //person.name = "狗剩";
  5. person.setName("狗剩");
  6. //person.age = 18;
  7. person.setAge(18);
  8. System.out.println(person.getName()+"..."+person.getAge());
  9. }
  10. }