Java初学者零基础分章学习后续

第5章 程序控制结构

5.1 五种控制结构

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

    if(age>18){
        System.out.println("    ");
        
    } else {
        
    System.out.println("   ");
    }
    
    
  2. switch
    在这里插入图片描述

    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
      在这里插入图片描述

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

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

      循环变量初始化;

      do{

      ​ 循环体(语句);

      ​ 循环变量迭代;

      }while(循环条件);

      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

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 次。
    在这里插入图片描述

  • 九九乘法表

    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. 矩形
*****
*****
*****
*****
*****
    for(int i = 1;i <=5;i++){
        System.out.println("*****");
    }
  1. 打印半个金字塔
*    //第 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 层 有 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 层 有 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. 自己写的空心菱形
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

    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

    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

//自己写的
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)的结果
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 冒泡序列

  • 这样一层循环只是把最大的一个数排到了最后
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();
		}
	}
}

在这里插入图片描述

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

    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;

    int a=10;
    int b=a;
    
    b=80;
    System.out.println(a);//  10
    System.out.println(b);//  80
    
  2. 数组在默认情况下是引用传递,赋的值是地址。

    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

    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. 官方答案

    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}的基础上定义增加几个数值,然后录入,输入。(结束后内存里是两个数组,改进是一个)

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.第一行有 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. String foo = "blue";
    boolean[] bar = new booolean[2];//数组bar[]默认的都是false
    if(bar[0]){   //bar[0]为false,所以不进入
        foo="green";
    }
    System.out.println(foo);//  仍然为blue
    

3.在这里插入图片描述

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

    	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();

    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
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 基本数据类型的传参机制

在这里插入图片描述

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类方法:需要通过对象调用。比如 对象名.方法名(参数) )

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 对象,返回复制的对象。克隆对象, 注意要求得到新对象和原来的 对象是两个独立的对象,只是他们的属性相同。

    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 递归举例

  • 距离问题

  • 阶乘问题

    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. 基本语法:访问修饰符 返回类型 方法名(数据类型… 形参名) {

    }

    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.

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 作用域

在这里插入图片描述

在这里插入图片描述

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

    • 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的大小写,有点搞不懂

    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.在这里插入图片描述

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. 我们看一个案例来分析当子类继承父类,创建子类对象时,内存中到底发生了什么?提示:当子类对象创建好后,建立查找的关系
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. 向上转型
    在这里插入图片描述
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 属性没有重写之说!属性的值看编译类型
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 类型的子类型。

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 重要特性: 动态绑定机制

在这里插入图片描述

再看一种情况:

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 怎么调用?

    代码:

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. 多态参数

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

在这里插入图片描述

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,执行到下一个断点)

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值