07.Java 编程入门学习笔记20210310-数组、面向对象(上)

1. 数组整体的概述

 - 数组的理解:多个相同数据类型的变量按照一定顺序组织起来的集合
 - 一维数组的使用
	① 数组的声明与初始化
	② 数组元素的调用
	③ 数组的长度
	④ 数组的遍历
	⑤ 数组元素默认初始化值
	⑥ 数组的内存解析
 - 二维数组的使用
	① 数组的声明与初始化
	② 数组元素的调用
	③ 数组的长度
	④ 数组的遍历
	⑤ 数组元素默认初始化值
	⑥ 数组的内存解析
 - 数组中常见算法的使用
 - Arrays工具类的使用
 - 数组中的常见异常
	> ArrayIndexOutOfBoundsException
	> NullPointerException

2. 数组中常见算法的使用

2.1 数组的定义及元素的赋值

  • 练习
package com.atguigu.exer;

/**
* 使用二维数组打印一个 10 行杨辉三角。
*  * 【提示】
*  1. 第一行有 1 个元素, 第 n 行有 n 个元素
*  2. 每一行的第一个元素和最后一个元素都是 1
*  3. 从第三行开始, 对于非第一个元素和最后一个元素的元素。即:
*   yanghui[i][j] = yanghui[i-1][j-1] + yanghui[i-1][j];
*  *  *   说明:笔试中数组是作为算法考察的一大门类(另一大门类就是考察String);
*        数组中的考察,其中一部分是创建特殊要求的数组。比如:杨辉三角,回形数等。
*  *   拓展1:
*   创建一个长度为6的int型数组,要求数组元素的值都在1-30之间,且是随机赋值。
*   同时,要求元素的值各不相同。
*   拓展2:
*   回形数
*/
public class YangHuiAngleTest {
   public static void main(String[] args) {
       //1. 创建一个二维数组
       int[][] yangHui = new int[10][];

       //2. 通过循环的方式,创建内层的数组
       for(int i = 0;i < yangHui.length;i++){
           yangHui[i] = new int[i + 1];
           //3. 给数组元素赋值
           //3.1 给每行的首末元素赋值为1
           yangHui[i][0] = yangHui[i][i] = 1;
           //3.2 给每行的非首末元素赋值:yanghui[i][j] = yanghui[i-1][j-1] + yanghui[i-1][j];
           //if(i > 1){
               for(int j = 1;j < yangHui[i].length - 1;j++){
                   yangHui[i][j] = yangHui[i-1][j-1] + yangHui[i-1][j];
               }
           //}
       }

       //4. 二维数组的遍历
       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的int型数组,要求数组元素的值都在1-30之间,且是随机赋值。同时,要求元素的值各不相同。
  • 回形数
从键盘输入一个整数(1~20) 
则以该数字为矩阵的大小,把1,2,3…n*n 的数字按照顺时针螺旋的形式填入其中。例如: 输入数字2,则程序输出: 1 2 4 3 
输入数字3,则程序输出: 1 2 3 8 9 4 7 6 5 
输入数字4, 则程序输出: 
1   2   3   4 
12  13  14  5 
11  16  15  6 
10   9  8   7
  • 代码实现
package Test1;

import java.util.Scanner;

/*
* 从键盘输入一个整数(1~20) 
则以该数字为矩阵的大小,把1,2,3…n*n 的数字按照顺时针螺旋的形式填入其中。例如: 输入数字2,则程序输出: 1 2 4 3 
输入数字3,则程序输出: 1 2 3 8 9 4 7 6 5 
输入数字4, 则程序输出: 
1   2   3   4 
12  13  14  5 
11  16  15  6 
10   9  8   7
*/
public class RectangleTest {
   public static void main(String[] args) {
   	Scanner scanner = new Scanner(System.in);
   	System.out.println("输入一个数字");
   	int len = scanner.nextInt();
   	int[][] arr = new int[len][len];
   	
   	int s = len * len;
   	/*
   	 * k = 1:向右
   	 * k = 2:向下
   	 * k = 3:向左
   	 * k = 4:向上
   	 */
   	int k = 1;
   	int i = 0,j = 0;
   	for(int m = 1;m <= s;m++){
   		if(k == 1){
   			if(j < len && arr[i][j] == 0){
   				arr[i][j++] = m;
   			}else{
   				k = 2;
   				i++;  
   				j--;
   				m--;
   			}
   		}else if(k == 2){
   			if(i < len && arr[i][j] == 0){
   				arr[i++][j] = m;
   			}else{
   				k = 3;
   				i--;
   				j--;
   				m--;
   			}
   		}else if(k == 3){
   			if(j >= 0 && arr[i][j] == 0){
   				arr[i][j--] = m;
   			}else{
   				k = 4;
   				i--;
   				j++;
   				m--;
   			}
   		}else if(k == 4){
   			if(i >= 0 && arr[i][j] == 0){
   				arr[i--][j] = m;
   			}else{
   				k = 1;
   				i++;
   				j++;
   				m--;
   			}
   		}
   	}
   	
   	//遍历
   	for(int m = 0;m < arr.length;m++){
   		for(int n = 0;n < arr[m].length;n++){
   			System.out.print(arr[m][n] + "\t");
   		}
   		System.out.println();
   	}
   }
}
/*
	01 02 03 04 05 06 07 
	24 25 26 27 28 29 08 
	23 40 41 42 43 30 09 
	22 39 48 49 44 31 10 
	21 38 47 46 45 32 11 
	20 37 36 35 34 33 12 
	19 18 17 16 15 14 13 
 */
public class RectangleTest1 {

	public static void main(String[] args) {
		int n = 7;
		int[][] arr = new int[n][n];
		
		int count = 0; //要显示的数据
		int maxX = n-1; //x轴的最大下标
		int maxY = n-1; //Y轴的最大下标
		int minX = 0; //x轴的最小下标
		int minY = 0; //Y轴的最小下标
		while(minX<=maxX) {
			for(int x=minX;x<=maxX;x++) {
				arr[minY][x] = ++count;
			}
			minY++;
			for(int y=minY;y<=maxY;y++) {
				arr[y][maxX] = ++count;
			}
			maxX--;
			for(int x=maxX;x>=minX;x--) {
				arr[maxY][x] = ++count;
			}
			maxY--;
			for(int y=maxY;y>=minY;y--) {
				arr[y][minX] = ++count;
			}
			minX++;
		}
		
		
		for(int i=0;i<arr.length;i++) {
			for(int j=0;j<arr.length;j++) {
				String space = (arr[i][j]+"").length()==1 ? "0":"";
				System.out.print(space+arr[i][j]+" ");
			}
			System.out.println();
		}
	}
}

2.2 数值类型数组中特殊值的计算

/**
 * 数组的常见算法一:求数值型数组中元素的最大值、最小值、平均数、总和等
 */
public class ArrayTest {
    public static void main(String[] args) {

        int[] arr = new int[]{3,42,2,53,65,24,65,87,-95,-84,0,45};

        //获取最大值
        int max = arr[0];
        for(int i = 1;i < arr.length;i++){
            if(max < arr[i]){
                max = arr[i];
            }
        }
        System.out.println("最大值为:" + max);

        //获取最小值
        int min = arr[0];
        for(int i = 1;i < arr.length;i++){
            if(min > arr[i]){
                min = arr[i];
            }
        }
        System.out.println("最小值为:" + min);

        //获取总和
        int sum = 0;
        for(int i = 0;i <arr.length;i++){
            sum += arr[i];
        }
        System.out.println("总和为:" + sum);

        //求平均数
        double avg = (double)sum / arr.length;
        System.out.println("平均数为:" + avg);
    }

}

2.3 数组的反转、复制、遍历、查找等

/**
 * 数组的常见算法二:复制、反转、查找、遍历
 */
public class ArrayTest1 {

    public static void main(String[] args) {
        int[] arr = new int[]{3,42,2,53,65,24,65,87,-95,-84,0,45};

        //复制
        int[] arrCopy = new int[arr.length];
        for (int i = 0; i < arrCopy.length; i++) {
            arrCopy[i] = arr[i];
        }


        //遍历
        for (int i = 0; i < arr.length; i++) {
            if(i == 0){
                System.out.print("{");
            }else if(i == arr.length - 1){
                System.out.print(arr[i] + "}");
                break;
            }
            System.out.print(arr[i] +",");
        }

        //反转方式一:
//        for(int i = 0,j = arr.length - 1; i < j ;i++,j--){
//            int temp = arr[i];
//            arr[i] = arr[j];
//            arr[j] = temp;
//        }

        //反转方式二:
        for(int i = 0;i < arr.length / 2;i++){
            int temp = arr[i];
            arr[i] = arr[arr.length - 1 - i];
            arr[arr.length - 1 - i] = temp;
        }

        System.out.println();
        //遍历arr1
        for (int i = 0; i < arr.length; i++) {
            if(i == 0){
                System.out.print("{");
            }else if(i == arr.length - 1){
                System.out.print(arr[i] + "}");
                break;
            }
            System.out.print(arr[i] +",");
        }

        //查找(或搜索):如果查找到了,打印其在数组中的索引;如果没找到,打印没有找到的提示
        //线性查找
        int target = 244;
        boolean isFlag = true;
        for(int i = 0;i < arr.length;i++){
            if(target == arr[i]){
                System.out.println("查找到了" + target +"元素,索引位置为:" + i);
                isFlag = false;
                break;
            }
        }

        if(isFlag){
            System.out.println("不好意思,没找到");
        }

        //二分法查找:了解
        //二分法查找:要求此数组必须是有序的。
        int[] arr3 = new int[]{-99,-54,-2,0,2,33,43,256,999};
        boolean isFlag1 = true;
        int number = 256;
        number = 25;
        int head = 0;//首索引位置
        int end = arr3.length - 1;//尾索引位置
        while(head <= end){
            int middle = (head + end) / 2;
            if(arr3[middle] == number){
                System.out.println("找到指定的元素,索引为:" + middle);
                isFlag1 = false;
                break;
            }else if(arr3[middle] > number){
                end = middle - 1;
            }else{//arr3[middle] < number
                head = middle + 1;
            }
        }
        if(isFlag1){
            System.out.println("未找打指定的元素");
        }
    }
}
  • 练习
使用简单数组
 * (1)创建一个名为ArrayTest的类,在main()方法中声明array1和array2两个变量,他们是int[]类型的数组。
 * (2)使用大括号{},把array1初始化为8个素数:2,3,5,7,11,13,17,19。
 * (3)显示array1的内容。
 * (4)赋值array2变量等于array1,修改array2中的偶索引元素,使其等于索引值(如array[0]=0,array[2]=2)。
 * 打印出array1。   array2 = array1;
public class ArrayTest {
    public static void main(String[] args) {
        int[] array1,array2;

        array1 = new int[]{2,3,5,7,11,13,17,19};

        //遍历array1
        for (int i = 0; i < array1.length; i++) {
            System.out.print(array1[i] + "\t");
        }

        //赋值array2变量等于array1
        array2 = array1;

        //修改array2中的偶索引元素,使其等于索引值(如array[0]=0,array[2]=2)
        for(int i = 0;i < array2.length;i++){
            if(i % 2 == 0){
                array2[i] = i;
            }
        }
        System.out.println("**************");
        //遍历array1
        for (int i = 0; i < array1.length; i++) {
            System.out.print(array1[i] + "\t");
        }
    }
}

对应的内存结构:
在这里插入图片描述

  • 拓展
 * 思考:array1和array2是什么关系? 两个数组变量指向了堆空间中同一个数组结构
 *
 * 拓展:修改题目,实现array2对array1数组的复制
public class ArrayTest1 {
    public static void main(String[] args) {
        int[] array1,array2;

        array1 = new int[]{2,3,5,7,11,13,17,19};

        //遍历array1
        for (int i = 0; i < array1.length; i++) {
            System.out.print(array1[i] + "\t");
        }

        //实现array2数组对array1数组的复制
        array2 = new int[array1.length];
        for(int i = 0;i < array2.length;i++){
            array2[i] = array1[i];
        }

        //修改array2中的偶索引元素,使其等于索引值(如array[0]=0,array[2]=2)
        for(int i = 0;i < array2.length;i++){
            if(i % 2 == 0){
                array2[i] = i;
            }
        }
        System.out.println("**************");
        //遍历array1
        for (int i = 0; i < array1.length; i++) {
            System.out.print(array1[i] + "\t");
        }
    }
}

对应的内存结构:
在这里插入图片描述

2.4 数组的排序

衡量排序算法的优劣:
1.时间复杂度:分析关键字的比较次数和记录的移动次数
2.空间复杂度:分析排序算法中需要多少辅助内存
3.稳定性:若两个记录A和B的关键字值相等,但排序后A、B的先后次序保持不变,则称这种排序算法是稳定的。

排序算法分类:内部排序和外部排序。
内部排序:整个排序过程不需要借助于外部存储器(如磁盘等),所有排序操作都在内存中完成。
外部排序:参与排序的数据非常多,数据量非常大,计算机无法把整个排序过程放在内存中完成,必须借助于外部存储器(如磁盘)。外部排序最常见的是多路归并排序。可以认为外部排序是由多次内部排序组成。
  • 十大经典排序算法
    在这里插入图片描述
  • 冒泡排序的实现
    在这里插入图片描述
public class BubbleSortTest {
   public static void main(String[] args) {

       int[] arr = new int[]{3, 42, 2, 53, 65, 24, 65, 87, -95, -84, 0, 45};
       //排序前的遍历
       for (int i = 0; i < arr.length; i++) {
           if (i == 0) {
               System.out.print("{");
           } else if (i == arr.length - 1) {
               System.out.print(arr[i] + "}");
               break;
           }
           System.out.print(arr[i] + ",");
       }

       //排序操作:冒泡排序
       for(int i = 0;i < arr.length - 1;i++){
           for(int j = 0;j < arr.length -1 - i;j++){
               if(arr[j] > arr[j + 1]){
                   int temp = arr[j];
                   arr[j] = arr[j + 1];
                   arr[j + 1] = temp;
               }
           }
       }


       System.out.println();
       //排序后的遍历
       for (int i = 0; i < arr.length; i++) {
           if (i == 0) {
               System.out.print("{");
           } else if (i == arr.length - 1) {
               System.out.print(arr[i] + "}");
               break;
           }
           System.out.print(arr[i] + ",");
       }
   }
}

快速排序的实现原理
在这里插入图片描述

  • 第一轮
    在这里插入图片描述
  • 后续n轮:
    在这里插入图片描述
  • 快速排序代码实现:
public class QuickSort {
	private static void swap(DataWrap[] data, int i, int j) {
		DataWrap temp = data[i];
		data[i] = data[j];
		data[j] = temp;
	}

	private static void subSort(DataWrap[] data, int start, int end) {
		if (start < end) {
			DataWrap base = data[start];
			int i = start;
			int j = end + 1;
			while (true) {
				while (i < end && data[++i].compareTo(base) <= 0)
					;
				while (j > start && data[--j].compareTo(base) >= 0)
					;
				if (i < j) {
					swap(data, i, j);
				} else {
					break;
				}
			}
			swap(data, start, j);
			subSort(data, start, j - 1);
			subSort(data, j + 1, end);
		}
	}
	public static void quickSort(DataWrap[] data){
		subSort(data,0,data.length-1);
	}
	public static void main(String[] args) {
		DataWrap[] data = { new DataWrap(9, ""), new DataWrap(-16, ""),
				new DataWrap(21, "*"), new DataWrap(23, ""),
				new DataWrap(-30, ""), new DataWrap(-49, ""),
				new DataWrap(21, ""), new DataWrap(30, "*"),
				new DataWrap(30, "") };
		System.out.println("排序之前:\n" + java.util.Arrays.toString(data));
		quickSort(data);
		System.out.println("排序之后:\n" + java.util.Arrays.toString(data));
	}
}

  • 各种排序算法的时间复杂度、空间复杂度、稳定性的情况
    在这里插入图片描述

2.5 其他的算法

待补充,

import java.util.Arrays;
/**
 *
 * 测试Arrays的使用
 *  * Arrays:操作数组的工具类,在java.util包下提供
 */
public class ArraysTest {
    public static void main(String[] args) {
        //1. boolean equals(int[] a,int[] b)
        int[] arr1 = new int[]{1,2,3,4,5};
        int[] arr2 = new int[]{1,2,4,3,5};
        System.out.println(Arrays.equals(arr1, arr2));

        //2. String toString(int[] a)
        System.out.println(arr1);//[I@1540e19d

        System.out.println(Arrays.toString(arr1));

        //3. void fill(int[] a,int val)
        Arrays.fill(arr1,10);
        System.out.println(Arrays.toString(arr1));

        //4. void sort(int[] a)
        int[] arr3 = new int[]{3, 42, 2, 53, 65, 24, 65, 87, -95, -84, 0, 45};
        Arrays.sort(arr3);
        System.out.println(Arrays.toString(arr3));

        //5. int binarySearch(int[] a,int key)
        System.out.println(Arrays.binarySearch(arr3, 53));
    }
}

4. 常见异常

  • ArrayIndexOutOfBoundsException
		//1. 数据角标越界的异常:ArrayIndexOutOfBoundsException
        //角标的合法范围为:[0,数组长度-1]
        int[] arr = new int[10];
//        System.out.println(arr[10]);
        //System.out.println(arr[-1]);
  • NullPointerException
//2. 空指针异常:NullPointerException
        //情况1:
        int[] arr1 = new int[10];
        arr1 =  null;
        //System.out.println(arr1[0]);

        //情况2:
        int[][] arr2 = new int[10][];
        //System.out.println(arr2[0][0]);

        //情况3:后面面向对象内容中最常见的情况
        String[] arr3 = new String[]{"AA","BB"};
        arr3 = new String[4];
        System.out.println(arr3[0].toString());

5. 面向对象的理解

  • 学习面向对象的三条主线
 * 面向对象部分内容学习的三条主线:
 * 1. 类及类的成员:属性、方法、构造器(或构造方法);代码块、内部类
 * 2. 面向对象的三大特征:封装性、继承性、多态性、(抽象性)
 * 3. 其它关键字的使用:this\super\static\final\package\import\abstract\interface...
  • 面向对象 vs 面向过程
 * 面向过程,强调的是功能行为,以函数为最小单位,考虑怎么做。
 * 面向对象,将功能封装进对象,强调具备了功能的对象,以类/对象为最小单位,考虑谁来做。
 *  *  * 举例:把大象装进冰箱。
 *  * 面向过程:
 * 1. 把冰箱门打开
 * 2. 拿起大象,放进冰箱
 * 3. 把冰箱门关住
 *  * 面向对象:
 *  *  冰箱{
 *      开开(){
 *  *      }
 *      合上(){
 *  *      }
 *  }
 *  * 大象{
 *      进入(冰箱){
 *  *      }
 *  * }
 *  * 人{
 *     打开(冰箱){
 *         冰箱.开开();
 *     }
 *     拿起(大象){
 *         大象.进入(冰箱);
 *     }
 *     关闭(冰箱){
 *         冰箱.合上();
 *     }
 * }

6. 类与对象

 * 类是对一类事物的描述,是抽象的、概念上的定义
 * 对象是实际存在的该类事物的每个个体,因而也称为实例(instance)

7. 类的内部设计

/**
 * 设计类,其实就是设计类的内部结构。
 *  * 1. 名词解释:
 *  属性 = 成员变量 = field = 域、字段
 *  *  方法 = 成员方法 = method = 函数(function)
 *  *  对象 = 实例
 *  *  创建对象 = 类的实例化
 */
  • 代码演示
class Person{ //类:人
    //设计类,就是设计类的内部成员
    //首当其中,就是设计类的属性、方法
    //成员一:属性
    String name;
    int age;

    //成员二:方法
    public void eat(){
        System.out.println("人吃饭");
    }
    public void sleep(){
        System.out.println("人睡觉");
    }

    public void think(){
        System.out.println("人思考");
    }
}

使用上述设计的类:

public class PersonTest {  //测试类

    public static void main(String[] args) { //程序的入口
        //创建Person类的对象
        //数据类型 变量名 = 变量值
        int num = 10;

        int[] arr = new int[10];
        Scanner scann = new Scanner(System.in);

        Person per = new Person();//创建了Person类的对象

        //通过对象调用属性:“对象.属性”
        //per.name = "江学振";
        System.out.println(per.name);

        per.age = 23;
        System.out.println(per.age);

        //通过对象调用方法:“对象.方法()”
        per.eat();
        per.sleep();
        per.think();

        Person per1 = new Person();
        per.age = 30;
        System.out.println(per1.age);//30

        Person per2 = per;//per 和 per2指向了堆空间中的同一个对象实体
        per2.age = 40;
        System.out.println(per2.age);//40
        System.out.println(per.age);//40
    }

}
  • 总结
如何由类创建对象以及实现功能的调用?
-  第1步:创建类,并设计类的内部成员。(属性、方法)
-  第2步:创建类的对象 (或类的实例化)
-  第3步:通过“对象.属性” 或 “对象.方法()” 的方式,完成功能的实现
  • 内存解析
    在这里插入图片描述
 - 总结:对象的内存解析
 -   1. 对象名的变量保存在栈空间中
 -       对象实体保存在堆空间中,对象的属性也保存在堆空间中。
 -   2. 如果创建类的多个对象,则每个对象拥有一套类的属性。如果修改其中一个对象的属性a的值,不会影响
 -     其它对象的属性a的值。

8. 类的成员变量

  • 代码演示
class Phone{
   //属性:成员变量
   String phoneName;
   double price;

   //方法
   public void call(){
       int hour = 1; //局部变量
       System.out.println("手机打了" + hour + "小时的电话");
   }
   public void sendMessage(String message){ //message:局部变量
       System.out.println("发送短信:" + message);
   }
   public void playGame(String game){//game:局部变量
       System.out.println("玩游戏:" + game);
   }
}

//测试类
public class PhoneTest {
   public static void main(String[] args) {
       Phone p1 = new Phone();
       System.out.println(p1.phoneName);
       System.out.println(p1.price);

       p1.sendMessage("有内鬼,终止交易");
   }
}
总结:
 * 1. 复习:变量的分类: ① 按照数据类型: 基本数据类型  vs 引用数据类型
 *                    ② 按照在类中声明的位置: 成员变量  vs 局部变量
 *
 * 2. 对比成员变量  vs 局部变量
 *     相同点:①声明的格式是相同的。格式:数据类型  变量  =  变量值
 * 					  ②变量,必须先声明后使用
             		  ③变量,都有作用域,在其声明的作用域内是有效的。
 *     不同点:
 *          ① 类中声明的位置不同
 *              成员变量:直接声明在类的内部
 *              局部变量:方法内部、方法的形参、构造器内部、构造器形参、代码块内部等
 *          ② 在内存中分配的位置不同
 *              成员变量:分配在堆空间中
 *              局部变量:分配在栈空间中
 *          ③ 成员变量声明以后,如果没显式赋值。可以有默认赋值。
 *                  整型:0
 *                  浮点型:0.0
 *                  字符型:0 或 \u0000
 *                  boolean型:false
 *                  引用类型:null
 *
 *            而局部变量在调用前,必须显式赋值(初始化),因为没有默认赋值。而对方法的形参而言,是在调用方法时,给形参赋值。
 *          ④ 成员变量可以在声明前,添加权限修饰符。
 *            而局部变量不能使用权限修饰符进行修饰。
 *            (此时的权限修饰符有:public \ private \ protected \缺省)
 * ——————————————————————————————----------------------------------------------
 * 补充:回顾变量的分类:

 * 方式一:按照数据类型:基本数据类型   vs 引用数据类型
 * 方式二:照声明的位置:
 * 		成员变量  :直接声明在类的内部
 * 			实例变量:不使用static修饰
 * 			全局变量:不使用static修饰
 * 		vs 
 * 
 * 		局部变量:
 * 			方法内声明的变量
 * 			方法的形参、构造器的形参
 * 			代码块内声明的变量
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值