我是靠谱客的博主 清爽饼干,这篇文章主要介绍Java初学者零基础分章学习后续第5章 程序控制结构第 6 章 数组、排序和查找第 7 章 面向对象编程(基础部分)第8章 面向对象编程(中级部分),现在分享给大家,希望可以做个参考。

第5章 程序控制结构

5.1 五种控制结构

  1. if-else
    在这里插入图片描述

    复制代码
    1
    2
    3
    4
    5
    6
    7
    8
    9
    if(age>18){ System.out.println(" "); } else { System.out.println(" "); }
  2. switch
    在这里插入图片描述

    复制代码
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    switch(c1) { case 'a' : System.out.println("A"); break; case 'b' : System.out.println("B"); break; case 'c' : case 'd' : case 'e' : System.out.println("C,D,E"); break; default : System.out.println("你的输入有误~")
    1. for
      在这里插入图片描述

      复制代码
      1
      2
      3
      4
      for(int i= 0 , j = 0; i<100; i++,j++;){ System.out.println("i=" + i +"j="+ j); }
    2. while
      在这里插入图片描述

      • while 循环也有四要素
      • 只是四要素放的位置和for比一样
      复制代码
      1
      2
      3
      4
      5
      while(i<=10){ System.out.println(" "); i++; }
    3. do…while

      循环变量初始化;

      do{

      ​ 循环体(语句);

      ​ 循环变量迭代;

      }while(循环条件);

      复制代码
      1
      2
      3
      4
      5
      do{ System.out.println( ); i++; }while(i<=10);

5.2 switch 注意事项

在这里插入图片描述

例题

  1. 对学生成绩大于 60 分的,输出"合格"。低于 60 分的,输出"不合格"。(注:输入的成绩不能大于 100), 提示 成绩/60*

提示

这里我们需要进行一个转换, 编程思路 :

如果成绩在 [60,100] , (int)(成绩/60) = 1

如果成绩在 [0,60) , (int)(成绩/60) = 0

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
if( score >= 0 && score <= 100) { switch ((int)(score / 60)) { case 0 : System.out.println("不合格"); break; case 1 : System.out.println("合格"); break; // default : // System.out.println("输入有误"); } } else { System.out.println("输入的成绩在 0-100"); }

switch 和 if 的比较

  • 如果判断的具体数值不多,而且符合 byte、 short 、int、 char, enum[枚举], String 这 6 种类型。虽然两个语句都可 以使用,建议使用 swtich 语句
  • 其他情况:对区间判断,对结果为 boolean 类型判断,使用 if,if 的使用范围更广

5.3 for 注意事项

  • 循环条件是返回一个布尔值的表达式
  • for(;循环判断条件;) 中的初始化和变量迭代可以写到其它地方,但是两边的分号不能省略。
  • 循环初始值可以有多条初始化语句,但要求类型一样,并且中间用逗号隔开,循环变量迭代也可以有多条变量迭代 语句,中间用逗号隔开。

###5.83 while 注意事项

  • 循环条件是返回一个布尔值的表达式
  • while 循环是先判断再执行语句

5.4 do…while

  • 先执行,再判断,也就是说,一定会至少执行一次
  • 最后 有一个 分号 ;
  • while 和 do…while 区别举例: 要账

5.5 多重循环控制

  • 设外层循环次数为 m 次,内层为 n 次,则内层循环体实际上需要执行 m*n 次。
    在这里插入图片描述

  • 九九乘法表

    复制代码
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    public class Test { /** * java实现九九乘法 */ public static void main(String[] args) { //九九乘法 for(int i = 1;i <= 9;i++){ for(int j = 1;j <= i;j++){ System.out.print(j+"*"+ i +"="+i*j+" ");//此处用的print } System.out.println(); } }

5.6经典的打印的金字塔

  1. 矩形
复制代码
1
2
3
4
5
6
7
8
9
***** ***** ***** ***** ***** for(int i = 1;i <=5;i++){ System.out.println("*****"); }
  1. 打印半个金字塔
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
* //第 1 层 有 1 个* ** //第 2 层 有 2 个* *** //第 3 层 有 3 个* **** //第 4 层 有 4 个* ***** //第 5 层 有5个* public class Switch{ //编写一个main方法 public static void main(String[] args) { for(int i = 1;i <= 5;i++){//i表示层数 //控制打印每层的*的个数 for(int j = 1;j<=i;j++){ System.out.print("*"); } //每打印完一层的*后,就换行 System.out.println(""); //println本身会换行, //或者用System.out.print("n"); } } }
  1. 打印整个金字塔

    复制代码
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    * //第 1 层 有 1 个* 2 * 1 -1 有 4=(总层数-1)个空格 *** //第 2 层 有 3 个* 2 * 2 -1 有 3=(总层数-2)个空格 ***** //第 3 层 有 5 个* 2 * 3 -1 有 2=(总层数-3)个空格 ******* //第 4 层 有 7 个* 2 * 4 -1 有 1=(总层数-4)个空格 ********* //第 5 层 有 9 个* 2 * 5 -1 有 0=(总层数-5)个空格 public class Switch{ //编写一个main方法 public static void main(String[] args) { for(int i = 1;i <= 5;i++){//i表示层数 //在输出*之前,还要输出 对应空格 = 总层数-当层数 for(int k = 1;k <= 5-i;k++){ System.out.print(" "); } //控制打印每层的*的个数 for(int j = 1;j<=2*i-1;j++){ System.out.print("*"); } //每打印完一层的*后,就换行 System.out.println(""); //println本身会换行, //或者用System.out.print("n"); } } }
  2. 打印空心的金字塔 [最难的]

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
* //第 1 层 有 1 个* 当前行的第一个位置是*,最后一个位置也是* * *2 层 有 2* 当前行的第一个位置是*,最后一个位置也是* * *3 层 有 2* 当前行的第一个位置是*,最后一个位置也是* * *4 层 有 2* 当前行的第一个位置是*,最后一个位置也是* ********* //第 5 层 有 9 个* 全部输出* import java.util.Scanner; public class Switch{ public static void main(String[] args){ Scanner myScanner = new Scanner(System.in); System.out.println("输出几行星星:"); int line = myScanner.nextInt(); for(int i=1; i<=line;i++){ for(int k=1;k<=line-i;k++){ System.out.print(" ");//前边的空格数 } for(int j=1;j<=2*i-1;j++){ if(j==1||j==2*i-1||i==line){ //每行第一个和最后一个和最后一行输出* System.out.print("*"); }else{ System.out.print(" "); } } System.out.println(" ");//换行 } } }
  1. 自己写的空心菱形
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import java.util.Scanner; public class Switch{ public static void main(String[] args){ Scanner myScanner = new Scanner(System.in); System.out.println("输出上半部分为几行星星:"); int line = myScanner.nextInt(); //上半部分 for(int i=1; i<=line;i++){ for(int k=1;k<=line-i;k++){ System.out.print(" ");//前边的空格数 } for(int j=1;j<=2*i-1;j++){ if(j==1||j==2*i-1){ //每行第一个和最后一个和最后一行输出* System.out.print("*"); }else{ System.out.print(" "); } } System.out.println(" ");//换行 } //下半部分 for(int a =line-1; a>=1;a--){ for(int c = line-a;c>=1;c--){ System.out.print(" "); } for (int b=1;b<=2*a-1;b++){ if(b==1||b==2*a-1){ //每行第一个和最后一个和最后一行输出* System.out.print("*"); }else{ System.out.print(" "); } } System.out.println(" ");//换行 } } }

5.7 跳转控制语句break注意事项

在这里插入图片描述
(1)break 语句可以指定退出那层
(2)label1 是标签,名字由程序员指定。
(3)break 后指定到那个label 就退出到哪里。
(4)在实际的开发中,尽量不要使用标签。
(5)如果没有指定 break ,默认退出最近的循环体

  • 随机数 random

    复制代码
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    Math.random() //public static double random() 返回带正号的 double 值,该值大于等于 0.0 且小于 1.0。返回值是一个伪随机选择的数,在该范围内(近似)均匀分布。 //0.4749998761740407 0.41238696627546256 0.08495914852873843 0.034277645140542545 0.3654206938068364 0.45168695756836974 0.6727095226947664 0.4550512902464454 0.810014052676977 0.04461491267967932 0.12219404584351146 (int)(Match.random()*100)+1 //加一是因为,前边乘以100范围是0~99,加1之后范围就到了0~100了。
  • 字符串比较 equals

    复制代码
    1
    2
    3
    4
    5
    if("丁真".equals(name) && "666".equals(passwd)) { System.out.println("恭喜你,登录成功~"); break; }

    判断“丁真”和name这两个字符串是否相等。

5.8 跳转控制语句continue

  1. continue 语句用于结束本次循环,继续执行下一次循环。
  2. continue 语句出现在多层嵌套的循环语句体中时,可以通过标签指明要跳过的是哪一层循环 , 这个和前面的标签的 使用的规则一样.

###5.13 跳转控制语句retuen

  • return 使用在方法,表示跳出所在的方法,如果 return 写在 main 方法,退出程序。

5.9本章作业

  • 求出1-1/2+1/3-1/4…1/100的和

    注意1.0/j中的数字1.0不能写成1

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
//自己写的 public class Switch{ public static void main(String[] args){ double sum=0; int a=1; for(int j=1;j<=100;j++){ if(j%2==0){ a=-1; }else{ a=1; } sum=sum+(1.0/j)*a;//这的1.0不能写成1 //写成1的话这个除法1/j得到的就是0了! } System.out.println("sum="+sum); } } //老师的 public class Homework08 { //编写一个main方法 public static void main(String[] args) { /* 求出1-1/2+1/3-1/4…..1/100的和 思路分析 1. 1-1/2+1/3-1/4…..1/100 = (1/1)-(1/2)+(1/3)-(1/4)...1/100 2. 从上面的分析我们可以看到 (1) 一共有100数 , 分子为1 , 分母从1-100 (2) 还发现 当分母为奇数时,前面是 +, 当分母是偶数时,前面是- 3. 我们可以使用 for + 判断即可完成 4. 把结果存放到 double sum 5. 这里有一个隐藏的陷阱,要把 公式分子 1 写出1.0 才能得到精确的小数 */ double sum = 0; for(int i = 1; i <= 100; i++) { //判断是奇数还是偶数,然后做不同的处理 if( i % 2 != 0) {//分母为奇数 sum += 1.0/i; } else { //分母我偶数 sum -= 1.0/i; } } System.out.println("sum=" + sum); } }
  • 求1+(1+2)+(1+2+3)+(1+2+3+4)+…+(1+2+3+…+100)的结果
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
public class Switch{ public static void main(String[] args){ int sum=0; for(int i=1;i<=100;i++){ for(int j=1;j<=i;j++){ sum+=j; } } System.out.println("sum="+ sum); } }

第 6 章 数组、排序和查找

6.1 冒泡序列

  • 这样一层循环只是把最大的一个数排到了最后
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class BubbleSort{ public static void main(String[] args){ int[] arr={24,68,-2,1,6}; int max=0; for(int i=0;i<arr.length-1;i++){ if(arr[i]>arr[i+1]){ max=arr[i]; arr[i]=arr[i+1]; arr[i+1]=max; } System.out.println("第"+(i+1)+"轮"); for(int j=0;j<arr.length;j++){ System.out.print(arr[j]+"t"); } System.out.println(); } } }

在这里插入图片描述

  • 双重循环最后一下把所有的数从小排到大

    复制代码
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    public class BubbleSort{ public static void main(String[] args){ int[] arr={24,68,-2,1,6}; int max=0; for(int i=0;i<arr.length-1;i++){ for(int j=0;j<arr.length-i-1;j++) if(arr[j]>arr[j+1]){ max=arr[j]; arr[j]=arr[j+1]; arr[j+1]=max; } System.out.println("第"+(i+1)+"轮"); for(int j=0;j<arr.length;j++){ System.out.print(arr[j]+"t"); } System.out.println(); } } }

在这里插入图片描述

6.2 数组的使用

  1. 使用方式1-动态初始化

    数组的定义: 数组类型 数组名[] = new 数据类型[大小]

    int a[] = new int[5];

  2. 使用方式2-动态初始化

    数据类型 数组名[]; 也可以 数据类型[] 数组名;

    int a[]; 或者 int[] a; //声明数组,这时 a 是 null

    数组名 = new 数据类型[大小];

    a = new int[10] //分配内存空间,可以存放数据

  3. 使用方式3-静态初始化

    数据类型 数组名[] = {元素值,元素值…}

    int a[]={2,5,6,90,65,33}

  • 注意:

    • 数组创建后,如果没有赋值,有默认值

      int 0,short 0, byte 0, long 0, float 0.0,double 0.0,char u0000,boolean false,String null

    • 数组属引用类型,数组型数据是对象(object)

6.3 数组赋值机制

  1. 基本数据类型赋值,这个值就是具体的数据,而且相互不影响。

    ​ int n1 = 2; int n2 = n1;

    复制代码
    1
    2
    3
    4
    5
    6
    7
    int a=10; int b=a; b=80; System.out.println(a);// 10 System.out.println(b);// 80
  2. 数组在默认情况下是引用传递,赋的值是地址。

    复制代码
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    public class ArrayDetail{ public static void main(String[] args){ int[] a={1,2,3}; int[] b=a; b[1]=9; for (int i=0;i<a.length;i++){ System.out.print(a[i]+" ");//1 9 3 } System.out.println(); for(int i=0;i<b.length;i++){ System.out.print(b[i]+ " ");//1 9 3 } } }
    • 这样数组a和数组b就互不干扰了

      重新定义一个数组b

    复制代码
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    public class ArrayDetail{ public static void main(String[] args){ int[] a={1,2,3}; int[] b=new int[a.length]; for(int i = 0; i < a.length; i++) { b[i] = a[i]; } b[1]=9; for (int i=0;i<a.length;i++){ System.out.print(a[i]+" ");//1 2 3 } System.out.println(); for(int i=0;i<b.length;i++){ System.out.print(b[i]+ " ");//1 9 3 } } }

6.4 数组的增加

  • 用户可以通过如下方法来决定是否继续添加,添加成功,是否继续?y/n
  1. 官方答案

    复制代码
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    import java.util.Scanner; public class ArrayDetail{ public static void main(String[] args){ Scanner myScanner=new Scanner(System.in); int[] arr={1,2,3}; do{ int[] arr2=new int[arr.length +1]; for(int i=0;i<arr.length;i++){ arr2[i]=arr[i]; } System.out.println("请输入你要增加的元素:"); int num=myScanner.nextInt(); arr2[arr2.length - 1]=num; arr=arr2;// 让 arr 指向 arr2; arr = arr2; 那么 原来 arr 数组就被销毁 System.out.println("===arr扩容后元素的情况===="); for(int i=0;i<arr.length;i++){ System.out.print(arr[i]+" "); } //问用户是否继续 System.out.println(); System.out.println("是否继续添加 y/n"); char key = myScanner.next().charAt(0); if(key=='n'){//如果输入n,就结束 break; } }while(true); System.out.println("你退出了增加..."); } }
  2. 自己写的,在数组int[] arr={1,2,3}的基础上定义增加几个数值,然后录入,输入。(结束后内存里是两个数组,改进是一个)

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import java.util.Scanner; public class ArrayDetail{ public static void main(String[] args){ Scanner myScanner=new Scanner(System.in); int[] arr={1,2,3}; System.out.println("请输入要加入的个数:"); int n = myScanner.nextInt(); int[] arr2=new int[arr.length+n]; for(int i=0;i<arr.length;i++){ arr2[i]=arr[i]; } System.out.println("请输入:"); for(int i=0;i<n;i++){ int m=myScanner.nextInt(); arr2[arr.length+i]=m; } //1. arr=arr2; 用这个销毁原来的数组arr for(int i=0;i<arr2.length;i++){ //2. 再把这的arr2换成arr就行了 System.out.print(arr2[i]+" "); // 这种方法比自己的好,能减少一个数组。 } } }

6.5 二维数组

  1. 使用方式 1: 动态初始化

    语法: 类型[][] 数组名=new 类型【大小】【大小】

    比如: int a[][]=new int[2] [3];

  2. 使用方式 2: 动态初始化

    先声明:类型 数组名[][];

    再定义(开辟空间) 数组名 = new 类型[大小] [大小]

    赋值(有默认值,比如 int 类型的就是 0)

  3. 使用方式 3: 动态初始化-列数不确定

    int[][] arr = new int[3] [];

  4. 使用方式 4: 静态初始化

    定义 类型 数组名[][] = {{值 1,值 2…},{值 1,值 2…},{值 1,值 2…}}

    int[] [] arr = {{1,1,1}, {8,8,9}, {100}};

6.6 杨辉三角形

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
规律 1.第一行有 1 个元素, 第 n 行有 n 个元素 2. 每一行的第一个元素和最后一个元素都是 1 3. 从第三行开始, 对于非第一个元素和最后一个元素的元素的值. arr[i][j] arr[i][j] = arr[i-1][j] + arr[i-1][j-1]; //必须找到这个规律 public class ArrayDetail{ public static void main(String[] args){ int[][] yangHui = new int[12][]; for(int i=0;i<yangHui.length;i++){ yangHui[i]=new int[i+1];//给每个一维数组(行)开空间 for(int j= 0;j<yangHui[i].length;j++){ if(j==0 || j==yangHui[i].length-1){ yangHui[i][j]=1; }else{ yangHui[i][j] = yangHui[i-1][j]+yangHui[i-1][j-1]; } } } //输出杨辉三角形 for(int i=0;i<yangHui.length;i++){ for(int j =0;j<yangHui[i].length;j++){ System.out.print(yangHui[i][j]+"t"); } System.out.println(); } } }

6.7 二维数组使用细节和注意事项

  1. 一维数组的声明方式有:

    int[] x 或者 int x[]

  2. 二维数组的声明方式有:

    int[] [] y 或者 int[] y[] 或者 int y[] []

  3. 二维数组实际上是由多个一维数组组成的,它的各个一维数组的长度可以相同,也可以不相同。
    在这里插入图片描述

6.8 本章作业

  1. 下面数组定义正确的有 B,D

    在这里插入图片描述

  2. 复制代码
    1
    2
    3
    4
    5
    6
    7
    String foo = "blue"; boolean[] bar = new booolean[2];//数组bar[]默认的都是false if(bar[0]){ //bar[0]为false,所以不进入 foo="green"; } System.out.println(foo);// 仍然为blue

3.在这里插入图片描述

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
public class Homework04 { //编写一个main方法 public static void main(String[] args) { /* 已知有个升序的数组,要求插入一个元素,该数组顺序依然是升序, 比如: [10, 12, 45, 90], 添加23 后, 数组为 [10, 12,23, 45, 90] 思路 本质数组扩容 + 定位 1. 我们先确定 添加数应该插入到哪个索引 2. 然后扩容 */ //先定义原数组 int[] arr = {10, 12, 45, 90}; int insertNum = 111; int index = -1; //index就是要插入的位置 //遍历 arr数组, 如果发现 insertNum<=arr[i], 说明 i 就是要插入的位置 //使用 index 保留 index = i; //如果遍历完后,没有发现 insertNum<=arr[i], 说明 index = arr.length //即:添加到arr的最后 for(int i = 0; i < arr.length; i++) { if(insertNum <= arr[i]) { index = i; break; //找到位置后,就退出 } } //判断index 的值 if(index == -1) { //说明没有还没有找到位置 index = arr.length; } //扩容 //先创建一个新的数组,大小 arr.length + 1 int[] arrNew = new int[arr.length + 1]; //下面老师准备将arr的元素拷贝到 arrNew ,并且要跳过 index位置 /* 分析: int[] arr = {10, 12, 45, 90}; arrNew = { } */ //i 控制arrNew的下标 , j用来控制arr数组的下标 for(int i = 0, j = 0; i < arrNew.length; i++) { if( i != index ) { //说明可以把 arr的元素拷贝到 arrNew arrNew[i] = arr[j]; j++; } else { //i这个位置就是要插入的数 arrNew[i] = insertNum; } } //让arr 指向 arrNew , 原来的数组,就成为垃圾,被销毁 arr = arrNew; System.out.println("======插入后,arr数组的元素情况======"); for(int i = 0; i < arr.length; i++) { System.out.print(arr[i] + "t"); } } }
  1. 随机生成10个整数(1-100)保存到数组; 在数组中找是否有8

    复制代码
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    for(int i = 0; i < arr.length; i++) { arr[i] = (int)(Math.random() * 100) + 1; } int findNum = 8; int index = -1; //如果找到,就把下标记录到 index for(int i = 0; i < arr.length; i++) { if(findNum == arr[i]) { System.out.println("找到数" + findNum + " 下标=" + i); index = i; break; } } if(index == -1) { System.out.println("没有找到数" + findNum ); }

第 7 章 面向对象编程(基础部分)

7.1 类与对象

  • 类和对象的区别
    • 类是抽象的,概念的,代表一类事物,比如人类,猫类…, 即它是数据类型.
    • 对象是具体的,实际的,代表一个具体事物, 即 是实例.
    • 类是对象的模板,对象是类的一个个体,对应一个实例

7.2对象在内存中存在形式(重要的)必须搞清楚。

在这里插入图片描述

7.3 如何创建对象

  1. 先声明再创建

    Cat cat ; //声明对象 cat

    cat = new Cat(); //创建

  2. 直接创建 Cat cat = new Cat();

    复制代码
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    public class Object{ public static void main(String[] args){ Cat cat1 = new Cat(); cat1.name="小白"; cat1.age=3; cat1.color="白色"; System.out.println("第一只猫的信息"+cat1.name+" "+cat1.age +" "+cat1.color); } } class Cat{ int age; String name; String color; }

7.4 类和对象的内存分配机制

Java 内存的结构分析

  1. 栈: 一般存放基本数据类型(局部变量)
  2. 堆: 存放对象(Cat cat , 数组等)
  3. 方法区:常量池(常量,比如字符串), 类加载信息

Java 创建对象的流程简单分析

  1. 先加载 Person 类信息(属性和方法信息, 只会加载一次)
  2. 在堆中分配空间, 进行默认初始化(看规则)
  3. 把地址赋给 p , p 就指向对象
  4. 进行指定初始化, 比如 p.name =”jack” p.age = 10
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
Person a=new Person(); a.age=10; a.name="小明"; Person b; b=a; System.out.println(b.name); //小明 b.age=200; b=null; //把b的地址null,b现在谁也不指向了 System.out.println(a.age); //200 System.out.println(b.age); //异常

在这里插入图片描述

7.5 基本数据类型的传参机制

在这里插入图片描述

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class MethodParameter01 { //编写一个 main 方法 public static void main(String[] args) { int a = 10; int b = 20; //创建 AA 对象 名字 obj AA obj = new AA(); obj.swap(a, b); //调用 swap System.out.println("main 方法 a=" + a + " b=" + b); //a=10 b=20 } } class AA { public void swap(int a,int b){ System.out.println("na 和 b 交换前的值na=" + a + "tb=" + b);//a=10 b=20 //完成了 a 和 b 的交换 int tmp = a; a = b; b = tmp; System.out.println("na 和 b 交换后的值na=" + a + "tb=" + b);//a=20 b=10 } }

7.6 引用数据类型的传参机制

看一个案例 MethodParameter02.java

B 类中编写一个方法 test100,可以接收一个数组,在方法中修改该数组,看看原来的数组是否变化?会变化

B 类中编写一个方法 test200,可以接收一个 Person(age,sal)对象,在方法中修改该对象属性,看看原来的对象是否变化?会变化.(注意看一个类中怎样调用另一个类。跨类中的方法A类调用B类方法:需要通过对象调用。比如 对象名.方法名(参数) )

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
public class Object{ public static void main(String[] args){ B b=new B(); int arr[]={1,2,3}; b.test100(arr); System.out.println("主方法中的"); for(int i=0;i<arr.length;i++){ System.out.print(arr[i]+"t"); } Ren mo = new Ren(); mo.name="jack"; mo.age=20; b.test200(mo); //注意看这一点 System.out.println(mo.age); } } class Ren{ String name; int age; } class B{ public void test200(Ren mo){ //注意看 mo.age=10000; } public void test100(int arr[]){ arr[0]=123; System.out.println("类中的"); for(int i=0;i<arr.length;i++){ System.out.print(arr[i]+"t"); } } }

7.7成员方法返回类型是引用类型应用实例

  • 编写一个方法 copyPerson,可以复制一个 Person 对象,返回复制的对象。克隆对象, 注意要求得到新对象和原来的 对象是两个独立的对象,只是他们的属性相同。

    复制代码
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    public class MethodExercise02 { //编写一个main方法 public static void main(String[] args) { Person p = new Person(); p.name = "milan"; p.age = 100; //创建tools MyTools tools = new MyTools(); Person p2 = tools.copyPerson(p); //到此 p 和 p2是Person对象,但是是两个独立的对象,属性相同 System.out.println("p的属性 age=" + p.age + " 名字=" + p.name); System.out.println("p2的属性 age=" + p2.age + " 名字=" + p2.name); //这里老师提示: 可以同 对象比较看看是否为同一个对象 System.out.println(p == p2);//false } } class Person { String name; int age; } class MyTools { //编写一个方法copyPerson,可以复制一个Person对象,返回复制的对象。克隆对象, //注意要求得到新对象和原来的对象是两个独立的对象,只是他们的属性相同 // //编写方法的思路 //1. 方法的返回类型 Person //2. 方法的名字 copyPerson //3. 方法的形参 (Person p) //4. 方法体, 创建一个新对象,并复制属性,返回即可 public Person copyPerson(Person p) { //创建一个新的对象 Person p2 = new Person(); p2.name = p.name; //把原来对象的名字赋给p2.name p2.age = p.age; //把原来对象的年龄赋给p2.age return p2; } }

7.8 递归举例

  • 距离问题

  • 阶乘问题

    复制代码
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    public class Recursion01 { //编写一个 main 方法 public static void main(String[] args) { T t1 = new T(); t1.test(4);//输出什么? n=2 n=3 n=4 int res = t1.factorial(5); System.out.println("5 的阶乘 res =" + res); } } class T { //分析 public void test(int n) { if (n > 2) { test(n - 1); } System.out.println("n=" + n); } } //factorial 阶乘 public int factorial(int n) { if (n == 1) { return 1; } else { return factorial(n - 1) * n; } } }

在这里插入图片描述

(老鼠迷宫,汉诺塔,八皇后例子没有写,有空注意一下,很有意思)

7.9 方法重载

  1. java 中允许同一个类中,多个同名方法的存在,但要求 形参列表不一致!
  2. 方法名必须相同,形参列表必须相同(形参类型或个数或顺序,至少有一样不同,参数名无要求),返回类型无要求。

7.10 可变参数

  1. java 允许将同一个类中多个同名同功能但参数个数不同的方法,封装成一个方法。 就可以通过可变参数实现。

  2. 基本语法:访问修饰符 返回类型 方法名(数据类型… 形参名) {

    }

    复制代码
    1
    2
    3
    4
    5
    6
    7
    8
    9
    public int sum(int... nums) {//可以任意多个数相加 int res = 0; for(int i = 0; i < nums.length; i++) { res += nums[i]; } return res; } }
  3. 可变参数的实参可以为0个活任意多个。

  4. 可变参数色实参可以为数组。

  5. 可变参数的本质就是数组

  6. 可变参数可以和普通类型的参数一起放在有形参列表,但必须保证可变参数在最后

  7. 一个形参列表中只能出现一个可变参数

    • 里边有一个public String showScore(String name ,double… scores)

      注意string.

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class VarParameterExercise { //编写一个 main 方法 public static void main(String[] args) { HspMethod hm = new HspMethod(); System.out.println(hm.showScore("milan" , 90.1, 80.0 )); System.out.println(hm.showScore("terry" , 90.1, 80.0,10,30.5,70 )); } } class HspMethod { /* 有三个方法,分别实现返回姓名和两门课成绩(总分), 返回姓名和三门课成绩(总分),返回姓名和五门课成绩(总分)。 封装成一个可变参数的方法 */ //分析 1. 方法名 showScore 2. 形参(String ,double... ) 3. 返回 String public String showScore(String name ,double... scores){ double totalScore = 0; for(int i = 0; i < scores.length; i++) { totalScore += scores[i]; } return name + " 有 " +scores.length + "门课的成绩总分为=" + totalScore; } }

7.11 作用域

在这里插入图片描述

在这里插入图片描述

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
public class VarScopeDetail{ //编写一个 main 方法 public static void main(String[] args) { Person p1 = new Person(); /* 属性生命周期较长,伴随着对象的创建而创建,伴随着对象的销毁而销毁。 局部变量,生命周期较短,伴随着它的代码块的执行而创建, 伴随着代码块的结束而销毁。即在一次方法调用过程中 */ //p1.say();//当执行 say 方法时,say 方法的局部变量比如 name,会创建,当 say 执行完毕后 //name 局部变量就销毁,但是属性(全局变量)仍然可以使用 // T t1 = new T(); t1.test(); //第 1 种跨类访问对象属性的方式 t1.test2(p1);//第 2 种跨类访问对象属性的方式 } } class T { //全局变量/属性:可以被本类使用,或其他类使用(通过对象调用) public void test() { Person p1 = new Person(); System.out.println(p1.name);//jack } public void test2(Person p) { System.out.println(p.name);//jack } } class Person { //细节: 属性可以加修饰符(public protected private..) // 局部变量不能加修饰符 public int age = 20; String name = "jack"; public void say() { //细节 属性和局部变量可以重名,访问时遵循就近原则 String name = "king"; System.out.println("say() name=" + name); } public void hi() { String address = "北京"; //String address = "上海";//错误,重复定义变量 String name = "hsp";//可以 } }

7.12 构造器

  1. 基本语法

    [修饰符] 方法名(形参列表){

    ​ 方法体;

    }

  • 构造器的修饰符可以默认, 也可以是 public protected private
  • 构造器没有返回值
  • 方法名 和类名字必须一样
  • 参数列表 和 成员方法一样的规则
  • 构造器的调用, 由系统完成
  1. 基本介绍
  • 构造方法又叫构造器(constructor),是类的一种特殊的方法,它的主要作用是完成对新对象的初始化。它有几个特点:
    • 方法名和类名相同
    • 没有返回值
    • 在创建对象时,系统会自动的调用该类的构造器完成对象的初始化
  1. 注意事项

在这里插入图片描述

7.13 this关键字

  1. 案例
    在这里插入图片描述

在这里插入图片描述

  1. this 的注意事项和使用细节

    • this 关键字可以用来访问本类的属性、方法、构造器
    • this 用于区分当前类的属性和局部变量
    • 访问成员方法的语法:this.方法名(参数列表);
    • 访问构造器语法:this(参数列表); 注意只能在构造器中使用(即只能在构造器中访问另外一个构造器, 必须放在第一 条语句)
    • this 不能在类定义的外部使用,只能在类定义的方法中使用。
  2. this案例
    定义 Person 类,里面有 name、age 属性,并提供 compareTo 比较方法,用于判断是否和另一个人相等,提供测试类 TestPerson 用于测试, 名字和年龄完全一样,就返回 true, 否则返回 false

    • 复制代码
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      public class TestPerson { //编写一个 main 方法 public static void main(String[] args) { Person p1 = new Person("mary", 20); Person p2 = new Person("mary", 20); System.out.println("p1 和 p2 比较的结果=" + p1.compareTo(p2)); } } /* 定义 Person 类,里面有 name、age 属性,并提供 compareTo 比较方法, 用于判断是否和另一个人相等,提供测试类 TestPerson 用于测试, 名字和年龄完全一样,就返回 true, 否则返回 false*/ class Person { String name; int age; //构造器 public Person(String name, int age) { this.name = name; this.age = age; } //compareTo 比较方法 public boolean compareTo(Person p) { //名字和年龄完全一样 // if(this.name.equals(p.name) && this.age == p.age) { // return true; // } else { // return false; // } return this.name.equals(p.name) && this.age == p.age; } }

7.14 课后作业

  1. 编程创建一个Cale计算类,在其中定义2个变量表示2个操作数,定义4个方法实现求和、差、乘、商(要求除数为0的话,要提示)并创建2个对象,分别测试。(注意除数中Double的大小写,有点搞不懂

    复制代码
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    public class Homework06 { //编写一个main方法 public static void main(String[] args) { Cale cale = new Cale(2, 10); System.out.println("和=" + cale.sum()); System.out.println("差=" + cale.minus()); System.out.println("乘=" + cale.mul()); Double divRes = cale.div(); if(divRes != null) { System.out.println("除=" + divRes); } } } /* 编程创建一个Cale计算类,在其中定义2个变量表示两个操作数, 定义四个方法实现求和、差、乘、商(要求除数为0的话,要提示) 并创建两个对象,分别测试 */ class Cale { double num1; double num2; public Cale(double num1, double num2) { this.num1 = num1; this.num2 = num2; } //和 public double sum() { return num1 + num2; } //差 public double minus() { return num1 - num2; } //乘积 public double mul() { return num1 * num2; } //除法 // public Double div() { //判断 if(num2 == 0) { System.out.println("num2 不能为0"); return null; } else { return num1 / num2; } } }

7.在这里插入图片描述

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class Test { //公有类 int count = 9; //属性 public void count1() { //Test类的成员方法 count=10;//这个count就是属性 改成 10 System.out.println("count1=" + count); //10 } public void count2() { //Test类的成员方法 System.out.println("count1=" + count++); } //这是Test类的main方法, 任何一个类,都可有main public static void main(String args[]) { //老韩解读 //1. new Test() 是匿名对象, 匿名对象使用后,就不能使用 //2. new Test().count1() 创建好匿名对象后, 就调用count1() new Test().count1(); Test t1= new Test(); t1.count2();//9 t1.count2();//10 } }

10.在这里插入图片描述

第8章 面向对象编程(中级部分)

8.1 IDEA 常用快捷键

  1. 删除当前行, 默认是 ctrl + Y

  2. 复制当前行,默认是crtl + D

  3. 补全代码 alt + /

  4. 添加注释和取消注释 ctrl + / 【第一次是添加注释,第二次是取消注释】

  5. 导入该行需要的类 先配置 auto import , 然后使用 alt+enter 即可

  6. 快速格式化代码 ctrl + alt + L

  7. 快速运行程序 自己定义 alt + R

  8. 生成构造器等 alt + insert [提高开发效率]

  9. 查看一个类的层级关系 ctrl + H [学习继承后,非常有用]

  10. 将光标放在一个方法上,输入 ctrl + B , 可以定位到方法 [学继承后,非常有用]

  11. 自动的分配变量名 , 通过 在后面假 .var [老师最喜欢的]
    在这里插入图片描述

8.2 包

8.2.1 包的三大作用
  1. 区分相同名字的类
  2. 当类很多时,可以很好的管理类【看Java API文档】
  3. 控制访问范围
8.2.2 包的基本语法

package.com.student;

  1. package 关键字,表示打包。
  2. com.student 表示包名。
8.2.3 包的基本分析

在这里插入图片描述

8.2.4 包的命名
  1. 命名规则:

    只能包含数字、字母、下划线、小圆点,但不能用数字开头,不能是关键字或者保留字。

  2. 命名规范:

    一般是小写字母+小圆点

    一般是com.公司名.项目名.业务板块名

8.2.5 常用的包

一个包下,包含很多的类,java中常用的包有:

  1. java.lang.* //lang包是基本包,默认引入,不需要再引入。
  2. java.util.* //util 包,系统提供的工具包,工具类,使用 Scanner
  3. java.net.* //网络包,网络开发
  4. java.awt* //是做java的界面开发,GUI
8.2.6 如何引入包

在java中,为了装载已编译好的包,通常可使用以下三种方法。

  1. 在要引用的类名前带上包名作为修饰符。

    Animals.Cat cat = new Animals Cat();

    其中,Animals是包名,Cat是包中的类,cat是类的对象。

  2. 在文件开头使用 import 引用包中的类。

    import Animals.Cat;

    class Check{

    ​ Cat cat = new Cat( );

    }

    同样,Animals是包名,Cat是包中的类,cat是创建的Cat类对象。

  3. 在文件前使用 import 引入整个包。

    import Animals. *;

    Animals整个包被引入。(在引入包时,可以用点“ . ”表示出包所在的层次结构,如经常使用的:

    import java.io.*;

    import java.applet.* ;

    实际是引入了/java/io/或/java/applet/这样的目录结构下的所有内容。)

8.2.7 注意事项和使用细节
  1. package 的作用是声明当前类所在的包,需要放在类的最上面,一个类中最多只有一句package。
  2. import 指令位置放在package的下面,在类定义前面,可以有多句且没有顺序要求。

8.3 访问修饰符

8.3.1基本介绍

java 提供四种访问控制修饰符号,用于控制方法和属性(成员变量)的访问权限(范围):

  1. 公开级别:用 public 修饰,对外公开
  2. 受保护级别:用 protected 修饰,对子类和同一个包中的类公开
  3. 默认级别:没有修饰符号,向同一个包的类公开
  4. 私有级别:用 private 修饰,只有类本身可以访问,不对外公开
8.3.2 4种访问修饰符的访问范围

在这里插入图片描述

8.3.3使用的注意事项
  1. 修饰符可以用来修饰类中的属性,成员方法以及类
  2. 只有默认的和public才能修饰类!并且遵循上述访问权限的特点。
  3. 成员方法的访问规则和属性一样

8.4 面向对象编程三大特征

8.4.1基本介绍

面向对象编程有三大特征:封装、继承和多态。

8.4.2封装介绍

在这里插入图片描述

8.4.3封装的理解和好处在这里插入图片描述
8.4.4 封装的实现步骤 (三步)

在这里插入图片描述

8.5 面向对象编程-继承

8.5.1 继承基本介绍和示意图

继承可以解决代码复用,让我们的编程更加靠近人类思维.当多个类存在相同的属性(变量)和方法时,可以从这些类中 抽象出父类,在父类中定义这些相同的属性和方法,所有的子类不需要重新定义这些属性和方法,只需要通过 extends 来 声明继承父类即可。画出继承的示意图在这里插入图片描述

8.5.2 继承的基本语法

在这里插入图片描述

8.5.3 继承给编程带来的便利
  1. 代码的复用性提高了
  2. 代码的扩展性和维护性提高了
8.5.4继承的深入讨论/细节问题
  1. 子类继承了所有的属性和方法,非私有的属性和方法可以在子类直接访问, 但是私有属性和方法不能在子类直接访 问,要通过父类提供公共的方法去访问
  2. 子类必须调用父类的构造器, 完成父类的初始化
  3. 当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器,如果父类没有提供无 参构造器,则必须在子类的构造器中用 super 去指定使用父类的哪个构造器完成对父类的初始化工作,否则,编译不会通过
  4. 如果希望指定去调用父类的某个构造器,则显式的调用一下 : super(参数列表)
  5. super 在使用时,必须放在构造器第一行(super 只能在构造器中使用)
  6. super() 和 this() 都只能放在构造器第一行,因此这两个方法不能共存在一个构造器
  7. java 所有类都是 Object 类的子类, Object 是所有类的基类
  8. 父类构造器的调用不限于直接父类!将一直往上追溯直到 Object 类(顶级父类)
  9. 子类最多只能继承一个父类(指直接继承),即 java 中是单继承机制。
  10. 不能滥用继承,子类和父类之间必须满足 is-a 的逻辑关
8.5.5 继承的本质分析(重要)
  1. 我们看一个案例来分析当子类继承父类,创建子类对象时,内存中到底发生了什么?提示:当子类对象创建好后,建立查找的关系
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package com.whwedu.extend_; /** * 讲解继承的本质 */ public class ExtendsTheory { public static void main(String[] args) { Son son = new Son();//内存的布局 //?-> 这时请大家注意,要按照查找关系来返回信息 //(1) 首先看子类是否有该属性 //(2) 如果子类有这个属性,并且可以访问,则返回信息 //(3) 如果子类没有这个属性,就看父类有没有这个属性(如果父类有该属性,并且可以访问,就返回信息..) //(4) 如果父类没有就按照(3)的规则,继续找上级父类,直到 Object... System.out.println(son.name);//返回就是大头儿子 //System.out.println(son.age);//返回的就是 39 //System.out.println(son.getAge());//返回的就是 39 System.out.println(son.hobby);//返回的就是旅游 } } class GrandPa { //爷类 String name = "大头爷爷"; String hobby = "旅游"; } class Father extends GrandPa {//父类 String name = "大头爸爸"; private int age = 39; public int getAge() { return age; } } class Son extends Father { //子类 String name = "大头儿子"; }
  1. 子类创建的内存布局
    在这里插入图片描述
8.5.6 案例分析

在这里插入图片描述

8.6 super 关键字

8.6.1基本介绍

super 代表父类的引用,用于访问父类的属性、方法、构造器

8.6.2基本语法

在这里插入图片描述

8.6.3 super 给编程带来的便利/细节

在这里插入图片描述

8.6.4 super 和 this 的比较

在这里插入图片描述

8.7 方法重写/覆盖(override)

8.7.1基本介绍

在这里插入图片描述

8.7.2 注意事项和使用细节

方法重写也叫方法覆盖,需要满足下面的条件

在这里插入图片描述

8.7.3 对方法的重写和重载做一个比较

在这里插入图片描述

8.8 面向对象编程-多态

8.8.1 多[多种]态[状态]基本介绍

方法或对象具有多种形态。是面向对象的第三大特征,多态是建立在封装和继承基础之上的。

8.8.2 多态的具体体
  1. 方法的多态

    重写和重载就体现多态

  2. 对象的多态 (核心,困难,重点)
    在这里插入图片描述
    在这里插入图片描述

多态的前提是:两个对象(类)存在继承关系

8.8.3 多态的向上转型和向下转型
  1. 向上转型

在这里插入图片描述

  1. 向上转型
    在这里插入图片描述
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
package com.whwedu.poly_.detail_; public class Animal { String name = "动物"; int age = 10; public void sleep(){ System.out.println("睡"); } public void run(){ System.out.println("跑"); } public void eat(){ System.out.println("吃"); } public void show(){ System.out.println("hello,你好"); } } package com.whwedu.poly_.detail_; public class Cat extends Animal { public void eat(){//方法重写 System.out.println("猫吃鱼"); } public void catchMouse(){//Cat 特有方法 System.out.println("猫抓老鼠"); } } package com.whwedu.poly_.detail_; public class Dog extends Animal {//Dog 是 Animal 的子类 } package com.whwedu.poly_.detail_; public class PolyDetail { public static void main(String[] args) { //向上转型: 父类的引用指向了子类的对象 //语法:父类类型引用名 = new 子类类型(); Animal animal = new Cat(); Object obj = new Cat();//可以吗? 可以 Object 也是 Cat 的父类 //向上转型调用方法的规则如下: //(1)可以调用父类中的所有成员(需遵守访问权限) //(2)但是不能调用子类的特有的成员 //(#)因为在编译阶段,能调用哪些成员,是由编译类型来决定的 //animal.catchMouse();错误 //(4)最终运行效果看子类(运行类型)的具体实现, 即调用方法时,按照从子类(运行类型)开始查找方法 //,然后调用,规则我前面我们讲的方法调用规则一致。 animal.eat();//猫吃鱼.. animal.run();//跑 animal.show();//hello,你好 animal.sleep();//睡 //我希望,可以调用 Cat 的 catchMouse 方法 //多态的向下转型 //(1)语法:子类类型 引用名 =(子类类型)父类引用; //问一个问题? cat 的编译类型 Cat,运行类型是 Cat Cat cat = (Cat) animal; cat.catchMouse();//猫抓老鼠 //(2)要求父类的引用必须指向的是当前目标类型的对象 Dog dog = (Dog) animal; //可以吗? 不可以 System.out.println("ok~~"); } }
8.8.4 属性没有重写之说!属性的值看编译类型
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class PolyDetail02 { public static void main(String[] args) { //属性没有重写之说!属性的值看编译类型 Base base = new Sub();//向上转型 System.out.println(base.count);// ? 看编译类型 10 Sub sub = new Sub(); System.out.println(sub.count);//? 20 } } class Base { //父类 int count = 10;//属性 } class Sub extends Base {//子类 int count = 20;//属性 }
8.8.5 instanceOf 比较操作符

instanceOf 比较操作符,用于判断对象的运行类型是否为 XX 类型或 XX 类型的子类型。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class PolyDetail03 { public static void main(String[] args) { BB bb = new BB(); System.out.println(bb instanceof BB);// true System.out.println(bb instanceof AA);// true //aa 编译类型 AA, 运行类型是 BB //BB 是 AA 子类 AA aa = new BB(); System.out.println(aa instanceof AA);// true System.out.println(aa instanceof BB);// true Object obj = new Object(); System.out.println(obj instanceof AA);//false String str = "hello"; //System.out.println(str instanceof AA);//直接报错,字符串和AA没有任何关系 System.out.println(str instanceof Object);//true } } class AA {} //父类 class BB extends AA{} //子类
8.8.6 java 的动态绑定机制(非常非常重要.)

Java 重要特性: 动态绑定机制

在这里插入图片描述

再看一种情况:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class DynamicBinding { public static void main(String[] args) { //a 的编译类型 A, 运行类型 B A a = new B();//向上转型 System.out.println(a.sum());// 30 System.out.println(a.sum1());// 20 } } class A {//父类 public int i = 10; //动态绑定机制: public int sum() {//父类 sum() return getI() + 10;//20 +10 } public int sum1() {//父类 sum1() return i + 10;//10 + 10 } public int getI() {//父类 getI return i; } } class B extends A {//子类 public int i = 20; public int getI() {//子类 getI() return i; } }
8.8.7 多态的应用
  1. 多态数组

    数组的定义类型为父类类型,里面保存的实际元素类型为子类类型

    应用实例:现有一个继承结构如下:要求创建 1 个 Person 对象、2 个 Student 对象和 2 个 Teacher 对象, 统一放在数组 中,并调用每个对象 say 方法.

    应用实例升级:如何调用子类特有的方法,比如 Teacher 有一个 teach , Student 有一个 study 怎么调用?

    代码:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package com.whwedu.houserent.view; class Person { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String say() {//返回名字和年龄 return name + "t" + age; } } class Student extends Person { private double score; public Student(String name, int age, double score) { super(name, age); this.score = score; } public double getScore() { return score; } public void setScore(double score) { this.score = score; } //重写父类 say @Override public String say() { return "学生 " + super.say() + " score=" + score; } //特有的方法 public void study() { System.out.println("学生 " + getName() + " 正在学 java..."); } } class Teacher extends Person { private double salary; public Teacher(String name, int age, double salary) { super(name, age); this.salary = salary; } public double getSalary() { return salary; } public void setSalary(double salary) { this.salary = salary; } //写重写父类的 say 方法 @Override public String say() { return "老师 " + super.say() + " salary=" + salary; } //特有方法 public void teach() { System.out.println("老师 " + getName() + " 正在讲 java 课程..."); } } public class PloyArray { public static void main(String[] args) { //应用实例:现有一个继承结构如下:要求创建 1 个 Person 对象、 // 2 个 Student 对象和 2 个 Teacher 对象, 统一放在数组中,并调用每个对象 say 方法 Person[] persons = new Person[5]; persons[0] = new Person("jack", 20); persons[1] = new Student("mary", 18, 100); persons[2] = new Student("smith", 19, 30.1); persons[3] = new Teacher("scott", 30, 20000); persons[4] = new Teacher("king", 50, 25000); for (int i = 0; i < persons.length; i++) { //老师提示: person[i] 编译类型是 Person ,运行类型是是根据实际情况有 JVM 来判断 System.out.println(persons[i].say());//动态绑定机制 //这里大家聪明. 使用 类型判断 + 向下转型. if (persons[i] instanceof Student) {//判断 person[i] 的运行类型是不是 Student Student student = (Student) persons[i];//向下转型 student.study(); //小伙伴也可以使用一条语句 ((Student)persons[i]).study(); } else if (persons[i] instanceof Teacher) { Teacher teacher = (Teacher) persons[i]; teacher.teach(); } else if (persons[i] instanceof Person) { //System.out.println("你的类型有误, 请自己检查..."); } else { System.out.println("你的类型有误, 请自己检查..."); } } } }
  1. 多态参数

    方法定义的形参类型为父类类型,实参类型允许为子类类型

在这里插入图片描述

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
package com.whwedu.houserent.view; public class Employee { private String name; private double salary; public Employee(String name, double salary) { this.name = name; this.salary = salary; } //得到年工资的方法 public double getAnnual() { return 12 * salary; } public String getName() { return name; } public void setName(String name) { this.name = name; } public double getSalary() { return salary; } public void setSalary(double salary) { this.salary = salary; } } package com.whwedu.houserent.view; public class Manager extends Employee { private double bonus; public Manager(String name, double salary, double bonus) { super(name, salary); this.bonus = bonus; } public double getBonus() { return bonus; } public void setBonus(double bonus) { this.bonus = bonus; } public void manage() { System.out.println("经理 " + getName() + " is managing"); } //重写获取年薪方法 @Override public double getAnnual() { return super.getAnnual() + bonus; } } package com.whwedu.houserent.view; public class Worker extends Employee { public Worker(String name, double salary) { super(name, salary); } public void work() { System.out.println("普通员工 " + getName() + " is working"); } @Override public double getAnnual() { //因为普通员工没有其它收入,则直接调用父类方法 return super.getAnnual(); } } package com.whwedu.houserent.view; public class PloyParameter { public static void main(String[] args) { Worker tom = new Worker("tom", 2500); Manager milan = new Manager("milan", 5000, 200000); PloyParameter ployParameter = new PloyParameter(); ployParameter.showEmpAnnual(tom); ployParameter.showEmpAnnual(milan); ployParameter.testWork(tom); ployParameter.testWork(milan); } //showEmpAnnual(Employee e) //实现获取任何员工对象的年工资,并在 main 方法中调用该方法 [e.getAnnual()] public void showEmpAnnual(Employee e) { System.out.println(e.getAnnual());//动态绑定机制. } //添加一个方法,testWork,如果是普通员工,则调用 work 方法,如果是经理,则调用 manage 方法 public void testWork (Employee e){ if (e instanceof Worker) { ((Worker) e).work();//有向下转型操作 } else if (e instanceof Manager) { ((Manager) e).manage();//有向下转型操作 } else { System.out.println("不做处理..."); } } }

8.9 Object 类详解

8.9.1 equals方法

==和 equals 的对比 [面试题]

== 是一个比较运算符

  1. == :既可以判断基本类型,又可以判断引用类型
  2. == :如果判断基本类型,判断的是值是否相等。实例: int i = 10; doublt d = 10.0;
  3. == :如果判断引用类型,判断的是地址是否相等,即判定是不是同一对象。
  4. equals :是Object类中的方法,只能判断引用类型。(可以查看Jdk源码)
  5. 默认判断的是地址是否相等,子类中往往重写该方法,用于判断内容是否相等。比如:Integer,String【看看String 和 Integer的 equals 源代码】
8.9.2 hashCode 方法

在这里插入图片描述

几个小结:

  1. 提高具有哈希结构的容器的效率!
  2. 两个引用,如果指向的是同一个对象,则哈希值肯定是一样的!
  3. 两个引用,如果指向的是不同对象,则哈希值是不一样的
  4. 哈希值主要根据地址号来的!, 不能完全将哈希值等价于地址
8.9.3 toString 方法
  1. 基本介绍

    默认返回:全类名+@+哈希值的十六进制,【查看 Object 的 toString 方法】

    子类往往重写 toString 方法,用于返回对象的属性信息

  2. 重写 toString 方法,打印对象或拼接对象时,都会自动调用该对象的 toString 形式

  3. 当直接输出一个对象时,toString 方法会被默认的调用, 比如 System.out.println(monster); 就会默认调用 monster.toString()

8.9.4 finalize 方法
  1. 当对象被回收时,系统自动调用该对象的 finalize 方法。子类可以重写该方法,做一些释放资源的操作
  2. 什么时候被回收:当某个对象没有任何引用时,则 jvm 就认为这个对象是一个垃圾对象,就会使用垃圾回收机制来 销毁该对象,在销毁该对象前,会先调用 finalize方法
  3. 垃圾回收机制的调用,是由系统来决定(即有自己的 GC 算法), 也可以通过 System.gc() 主动触发垃圾回收机制

8.10 断点调试(debug)

8.10.1 一个实际需求

在这里插入图片描述

8.10.2 断点调试介绍

在这里插入图片描述

8.10.3 断点调试的快捷键

F7(跳入) F8(跳过) shift+F8(跳出) F9(resume,执行到下一个断点)

最后

以上就是清爽饼干最近收集整理的关于Java初学者零基础分章学习后续第5章 程序控制结构第 6 章 数组、排序和查找第 7 章 面向对象编程(基础部分)第8章 面向对象编程(中级部分)的全部内容,更多相关Java初学者零基础分章学习后续第5章内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(67)

评论列表共有 0 条评论

立即
投稿
返回
顶部