Skip to content

[TOC]

Java基础部分 ​

主要包括Java语法的:

  1. 基础语法
  2. 流程控制

这两个阶段的作业。

Scanner基础使用练习 ​

键盘输入某个学生的三门学科(数学,语文,英语)成绩,然后分别求出三科成绩的平均分,最低分,最高分,三科的总分。

注:

  1. 代码直接写在main()方法中即可,

  2. 注意录入数据的数据类型。

    java
    public static void main(String[] args) {
            System.out.println("依次输入语文、数学、英语成绩:");
            Scanner sc = new Scanner(System.in);
            Double sum = 0.0;
            Double scoreHighest = 0.0;
            Double scoreLowest = Double.MAX_VALUE;
            for (int i = 0; i < 3; i++) {
                double score = sc.nextDouble();
                sum += score;
                if(scoreHighest < score) scoreHighest = score;
                if(scoreLowest > score) scoreLowest = score;
            }
            System.out.printf("最高分:%f, 最低分:%f,平均分:%f",scoreHighest,scoreLowest,sum / 3);
        }

Scanner基础使用练习 &#8203;

使用Scanner依次接收以下三种数据类型的值:

  1. int类型
  2. String类型
  3. double类型

接收三个值后,再计算:

  1. 求和:int + double
  2. 拼接字符串:int + double + String

分别接收计算结果后,输出该计算结果。

注:

  1. 使用Scanner时,注意不要混用next系列和nextLine方法。(原因可以查看详细文档说明)

  2. 代码直接全部写在main方法中即可。

    java
    public static void main(String[] args) {
            System.out.println("依次输入int,String,double类型:");
            Scanner sc = new Scanner(System.in);
            String n = sc.nextLine();
            String s = sc.nextLine();
            String d = sc.nextLine();
            System.out.printf("%d\t%s\t%f\n",Integer.parseInt(n),s,Double.parseDouble(d));
        }

Scanner综合练习 &#8203;

模拟账号登录功能

1.用户名(String):admin

2.密码(String): 123456

3.使用scanner进行输入, 有3次机会可以重新输入, 用户名密码匹配成功提示登陆成功并结束, 否则提示登陆失败还剩几次机会 , 一旦3次都失败提示锁定账户结束程序.

java
public static void main(String[] args) {
    public static void main(String[] args) {
        for (int i = 0; i < 3; i++) {
            System.out.println("**********登录***********");
            System.out.println("输入用户名:");
            Scanner sc = new Scanner(System.in);
            String userName = sc.nextLine();
            System.out.println("输入密码:");
            String userPass = sc.nextLine();
            if(userName.equals("admin") && userPass.equals("123456")){
                System.out.println("登陆成功!");
                break;
            }else{
                if(i == 2){
                    System.out.println("输入错误!账户已被锁定");
                    break;
                }
                System.out.printf("输入错误!还剩%d次机会\n",3 - i - 1);
            }
        }
    }
}

switch练习 &#8203;

利用switch语句输出每个月份对应的季节:

  1. 12、1、2:冬季
  2. 3、4、5:春季
  3. 6、7、9:夏季
  4. 9、10、11:秋季

注:合理使用case穿越,注意命名规范

java
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int month = sc.nextInt();
        switch (month) {
            case 12:
            case 1:
            case 2:
                System.out.println("冬季");
                break;
            case 3:
            case 4:
            case 5:
                System.out.println("春季");
                break;
            case 6:
            case 7:
            case 8:
                System.out.println("夏季");
                break;
            case 9:
            case 10:
            case 11:
                System.out.println("秋季");
                break;
            default:
                break;
        }
    }
}

if多分支练习 &#8203;

键盘录入某个人的工资收入,求他应该缴纳的个人所得税以及最后得到的工资。

也就是说需要求两个值:

  1. 缴纳的个税
  2. 到手工资

个人所得税的计算方法是:

应纳税额 = 应纳税所得额 * 税率 - 速算扣除数 (速算扣除额已经扣除了重复计算的部分)

其中,应纳税所得额 = 工资薪金所得-2000(即工资超过2000的部分才需要缴税)

针对不同的收入人群,需要缴纳个税的税率是不同的,详参下列表格:

级数应纳税所得额税率(单位:%)速算扣除数
1不超过500元的50
2超过500元但是不超过2000的1025
3超过2000元但是不超过5000元的15125
4超过5000元但是不超过20000元的20375
5超过20000元但是不超过40000元的251375
6超过40000元但是不超过60000元的303375
7超过60000元但是不超过80000元的356375
8超过80000元但是不超过100000元的4010375
9超过100000元的4515375

注:

  1. 代码直接写在main()方法中即可,
image-20220606005339928
java
public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        double salary = sc.nextDouble();
        double taxAble = salary - 2000;//应纳税所得额
        double taxRate = 0;//税率
        double deduction = 0;//速算扣除数
        if (taxAble <= 0) {
            System.out.println("应该缴纳个税0,到手工资" + salary);
            return;
        }
        if (taxAble <= 500) {
            taxRate = 5;
            deduction = 0;
        } else if (taxAble <= 2000) {
            taxRate = 10;
            deduction = 25;
        } else if (taxAble <= 5000) {
            taxRate = 15;
            deduction = 125;
        } else if (taxAble <= 20000) {
            taxRate = 20;
            deduction = 375;
        } else if (taxAble <= 40000) {
            taxRate = 25;
            deduction = 1375;
        } else if (taxAble <= 60000) {
            taxRate = 30;
            deduction = 3375;
        } else if (taxAble <= 80000) {
            taxRate = 35;
            deduction = 6375;
        } else if (taxAble <= 100000) {
            taxRate = 40;
            deduction = 10375;
        } else {
            taxRate = 45;
            deduction = 15375;
        }
        double res1 = taxAble * taxRate * 0.01 - deduction;
        System.out.printf("应该缴纳个税%f,到手工资%f", res1, salary - res1);
    }

循环相关练习题 &#8203;

无论是for循环、while循环还是do...while循环,它们的本质都是一致的,使用时也没有特别的差异。下列给出几道简单的练习题,大致做一做。实际开发中,要根据实际需求,灵活使用循环。

  1. 计算 2 + 4 + 6 + … + 100 的值。
  2. 计算2000年1月1日到2008年1月1日相距多少天。(注意闰年)
  3. 循环输入一个不为0的数进行累加,直到输入的数字为0,结束循环并最后输出累加的结果。

注:

  1. 代码直接写在main()方法中即可,

  2. 使用什么循环都行,实现功能就行。

    java
    public static void main(String[] args) {
        //计算 2 + 4 + 6 + … + 100 的值。
        int sum = 0;
        for (int i = 2; i <= 100 ; i+=2) {
            sum += i;
        }
        System.out.println(sum);
    }
    java
    public static void main(String[] args) {
            //计算2000年1月1日到2008年1月1日相距多少天。(注意闰年)
            int sum = 0;
            for (int i = 2000; i < 2008; i++) {
                if(i % 400 == 0 || (i % 4 == 0 && i % 100 != 0)) {
                    //是闰年,366天
                    sum += 366;
                }else sum += 365;
            }
            System.out.println(sum);
        }
    java
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int sum = 0;
        while(true){
            int num = sc.nextInt();
            if(num == 0)
                break;
            sum += num;
        }
        System.out.println(sum);
    }

方法 &#8203;

主要包括Java语法的:

  1. 方法
  2. 方法的重载
  3. Junit
  4. Debug模式练习

基础语法练习 &#8203;

方法是Java代码中最常用的语法结构,这里对方法的语法做一下练习。

在使用方法或者想要写一个方法时,首先要考虑的是方法需要的参数是什么数据类型,需要几个(形式参数),再考虑方法需要返回什么结果(返回值类型)。在调用方法时,需要搞清楚具体传入什么数值(实际参数)。

完成如下练习题,要求提取出必要的方法,然后在main方法中调用测试:

  1. 使用for循环遍历n以内的奇数,并计算所有的奇数的和并输出。

    java
    public static int func(int num) {
            //使用for循环遍历n以内的奇数,并计算所有的奇数的和并输出。
            int sum = 0;
            for (int i = 1; i < num; i++) {
                if(i % 2 != 0){
                    sum += i;
                    System.out.println(i);
                }
            }
            return sum;
    }
  2. 打印倒三角形,并且行数(line)是可控制的。比如我想打印6行的倒三角形,则如下图:

    ******
    *****
    ****	
    ***	
    **	
    *
    java
    public static void func() {
            Scanner sc = new Scanner(System.in);
            int row = sc.nextInt();
            for (int i = 0; i < row; i++) {
                for (int j = row - i; j > 0; j--) {
                    System.out.print("*");
                }
                System.out.println();
            }
        }
  3. 根据键盘录入打印nn乘法表,n是可变的。

    java
    public static void func() {
            Scanner sc = new Scanner(System.in);
            int row = sc.nextInt();
            for (int i = 1; i <= row; i++) {
                for (int j = 1; j <= i; j++) {
                    System.out.printf("%d * %d = %d\t",j,i,i*j);
                }
                System.out.println();
            }
        }
  4. 键盘录入一个int数字,判断它是奇数还是偶数。

    java
    public static void func() {
            Scanner sc = new Scanner(System.in);
            int n = sc.nextInt();
            if(n % 2 == 0)
                System.out.println("偶数");
            else System.out.println("奇数");
        }
  5. 根据键盘录入打印n行m列井号,n和m是可变的。

    java
    public static void func() {
            Scanner sc = new Scanner(System.in);
            int row = sc.nextInt();
            int cul = sc.nextInt();
            for (int i = 0; i < row; i++) {
                for (int i1 = 0; i1 < cul; i1++) {
                    System.out.print("#");
                }
                System.out.println();
            }
        }
  6. (扩展题)输出前n个数当中的所有素数,并统计个数。

    java
    public static void func() {
            Scanner sc = new Scanner(System.in);
            int n = sc.nextInt();
            int count = 0;//素数的个数
            for (int i = 2; i < n; i++) {
                if(isPrime(i)){
                    System.out.println(i);
                    count++;
                }
            }
            System.out.println("前" + n + "个数中有" + count + "个素数");
        }
        public static boolean isPrime(int n){
            for (int i = 2; i <= Math.sqrt(n); i++) {
                if(n % i == 0){
                    return false;
                }
            }
            return true;
        }

完成控制台项目阶段一 &#8203;

详细说明,见文档说明。

Java数组 &#8203;

主要包括Java语法的:

  1. 数组的基本使用
  2. JVM内存模型
  3. 可变参数
  4. 值传递
  5. ....

数组基本使用练习 &#8203;

  1. 定义一个double数组用来存放学生成绩,然后键盘录入10位同学的成绩并存入数组,求这10位同学成绩的平均值。
  2. 定义一个String数组,输出该数组的长度,并用多种方式遍历打印数组元素(常见的方式遍历即可)

注:

  1. 请合理使用方法,不要胡子眉毛一把抓把代码全部写在main方法里。

    java
        public static void main(String[] args) {
            double[] scores = new double[10];
            System.out.println("输入10个成绩");
            Scanner sc = new Scanner(System.in);
            double sum = 0;
            for (int i = 0; i < 10; i++) {
                scores[i] = sc.nextDouble();
            }
            System.out.println("平均成绩:" + getAvg(scores));
        }
        static double getAvg(double[] scs){
            double sum = 0;
            for (double sc : scs) {
                sum += sc;
            }
            return sum / scs.length;
        }
  2. 数组遍历的方式,比如for、增强for或者使用工具类等等。

    java
        public static void main(String[] args) {
            String[] strs = {"one","two","three","four","five","six","seven","eight"};
            System.out.println("数组长度:" + getLength(strs));
            traverse1(strs);
            traverse2(strs);
            traverse3(strs);
            String[] strs1 = null;//null数组
            System.out.println("数组长度:" + getLength(strs1));
            traverse1(strs1);
            traverse2(strs1);
            traverse3(strs1);
            String[] strs2 = new String[]{};//空数组
            System.out.println("数组长度:" + getLength(strs2));
            traverse1(strs2);
            traverse2(strs2);
            traverse3(strs2);
        }
     static int getLength(String[] strs){
            if(strs == null) return -1;//表示null数组
            return strs.length;
        }
        //for循环
        static void traverse1(String[] strs){
            if(strs == null){
                System.out.println("null数组");
                return;
            }
            if(strs.length == 0){
                System.out.println("空数组");
                return;
            }
            for (int i = 0; i < 8; i++) {
                System.out.print(strs[i] + "\t");
            }
            System.out.println();
        }
        //增强for
        static void traverse2(String[] strs){
            if(strs == null){
                System.out.println("null数组");
                return;
            }
            for(String s : strs){
                System.out.print(s + "\t");
            }
            System.out.println();
        }
        //工具类
        static void traverse3(String[] strs){
            if(strs == null){
                System.out.println("null数组");
                return;
            }
            System.out.println(Arrays.toString(strs));
        }
    1. 数组的逆序

      java
          public static void main(String[] args) {
              int[] nums = {1,2,3,4,5,6,7,8};
              //数组的逆序
              reverse(nums);
              System.out.println(Arrays.toString(nums));
              reverse1(nums);
              System.out.println(Arrays.toString(nums));
          }
          static void swap(int[] nums,int i,int j){
              int tmp = nums[i];
              nums[i] = nums[j];
              nums[j] = tmp;
          }
          static void reverse(int[] nums){
              int len = nums.length;
              for (int i = 0; i < len / 2; i++) {
                  swap(nums,i,len - 1 - i);
              }
          }
          static void reverse1(int[] nums){
              int len = nums.length;
              for (int i = 0,j = len - 1; i < j; i++,j--) {
                  swap(nums,i,j);
              }
          }

数组基本使用练习 &#8203;

现在你去参加歌唱比赛。有10个评委打分,规则是去掉最高分和最低分,求平均分是最终成绩。请编码计算出你的最终成绩~

注:

  1. 请合理使用方法,不要胡子眉毛一把抓把代码全部写在main方法里。

  2. 最高分和最低分可能有多个,但只需要去掉其中一个即可(也就是说平均成绩要除以8)

  3. 建议给出下面的三个方法:

    1. 求数组中元素最大值的方法
    2. 求数组中元素最小值的方法
    3. 求数组中元素平均分的方法

    当然如果你有自己的想法,也可以用自己的方式去实现功能。

    java
    //思路想复杂了,直接求最大值最小值,sum减去最大值和最小值就行了
    public static void main(String[] args) {
            double[] scores = {90,90,90,90,90,90,90,90,90,90};
            System.out.println("平均分:" + getAverage(scores));
        }
        //得到最大值的下标
        static int getHIndex(double[] scs){
            double max = scs[0];
            int index = 0;
            for (int i = 1; i < scs.length; i++) {
                if(max < scs[i]){
                    max = scs[i];
                    index = i;
                }
            }
            System.out.println("最高分:" + max);
            return index;
        }
        //得到最小值的下标
        static int getLIndex(double[] scs){
            double min = scs[0];
            int index = 0;
            for (int i = 1; i < scs.length; i++) {
                if(min > scs[i]){
                    min = scs[i];
                    index = i;
                }
            }
            System.out.println("最低分:" + min);
            return index;
        }
        //得到平均分
        public static double getAverage(double[] scs){
            double sum = 0;
            int len = scs.length;
            int h = getHIndex(scs);
            int l = getLIndex(scs);
            //如果最高和最低一样,说明全一样
            if(h == l) return scs[h];
            for (int i = 0; i < len; i++) {
                if(i == h || i == l)
                    continue;
                sum += scs[i];
            }
            return sum / (len - 2);
        }

数组排序(扩展) &#8203;

随意给出一个长度为10的int数组,然后升序排列它。

注:

  1. 如果想自己写排序实现,可以使用最简单的冒泡排序或者选择排序。(不会就百度一下)

  2. 排序对于数组而言是非常常见的操作,Java源码工具类中,早有对应的实现。请百度查询一下,不需要了解它具体怎么实现的,会用即可。(百度并学习是非常重要的能力,我们不可能在课堂上学会所有的知识)

    java
        public static void main(String[] args) {
            int[] scores = {92,60,50,44,99,30,8,20,40,96};
            bubbleSort(scores);
            int[] scores2 = {9,60,232,44,99,55,2,23,49,964};
            selectionSort(scores2);
        }
        private static void swap(int[] nums, int m,int n){
            int tmp = nums[m];
            nums[m] = nums[n];
            nums[n] = tmp;
        }
        private static void selectionSort(int[] scs) {
            int len = scs.length;
            for (int i = 0; i < len - 1; i++) {//交换len - 1次
                int min = i;//最小元素的下标
                for (int j = i; j < len; j++) {//找[i,len)之间最小元素的下标
                    if(scs[min] > scs[j])
                        min = j;
                }
                //交换最小元素和第i个元素
                if (i != min) {
                    swap(scs,i,min);
                }
            }
            System.out.println(Arrays.toString(scs));
        }
        private static void bubbleSort(int[] scs) {
            int len = scs.length;
            for (int i = 0; i < len - 1; i++) {//冒泡多少趟
                for (int j = 0; j < len - i - 1; j++) {//每次冒泡交换的次数
                    if(scs[j] > scs[j + 1]){
                        swap(scs,j,j+1);
                    }
                }
            }
            System.out.println(Arrays.toString(scs));
        }

数组基础练习——除以首元素 &#8203;

定义一个double类型的数组,让数组中每个元素(包括首位元素)都除以首位元素,得到的结果过作为该位置上的新元素。请在原先数组数组上操作,并打印新数组。 例如数组[ 2.0 , 4.0 , 6.0 , 4.0 ] 经过方法运算得到新数组 [ 1.0 ,2.0 , 3.0 ,2.0 ]

注:注意元素取值的变化。

java
    public static void main(String[] args) {
        double[] nums = {2.0 , 4.0 , 6.0 , 4.0};
        int len = nums.length;
        double factor = nums[0];
        if(factor == 0) return;
        for (int i = 0; i < len; i++) {
            nums[i] = nums[i] / factor;
        }
        System.out.println(Arrays.toString(nums));
    }

数组综合练习——删除元素 &#8203;

举例,对于String数组["abc", "123", "123", "123", "666", "777"] 将其中的元素"123"全部去掉,就得到了新数组["abc","666", "777"],一共去掉了3个元素。

注:

  1. 这里说的去掉,不是指用0/null等默认值替代原先的元素,而是指真正的删除掉。

  2. 思考:同一个数组能不能实现这个功能?如果不能,应该怎么完成呢?

    java
        public static void main(String[] args) {
            String[] strs = {"abc", "123", "123", "123", "666", "777"};
            int len = strs.length;
            int[] index = new int[len];//记录符合目标的数组的下标
            int count = 0;//要保留的个数
            for(int i = 0;i < len;i++){
                if(strs[i].equals("123") == false){
                    index[count++] = i;
                }
            }
            String[] newStrs = new String[count];//最后符合要求的新数组
            for (int i = 0; i < count; i++) {
                newStrs[i] = strs[index[i]];
            }
            System.out.println(Arrays.toString(newStrs));
            System.out.println("一共去掉" + (len - count) + "个元素");
        }

数组元素的删除,修改,查找 &#8203;

根据提供的代码,完成人名数组的删除、修改和查找方法。

其中:

删除人名,给出一个要删除的目标元素,用null替换它,表示删除

修改人名,需要明确指出修改哪个人名,以及修改成什么。

查找人名,找到后返回目标人名在数组中的位置(下标)

可以直接在我的代码中,直接写完方法,直接测试。

也可以自己新写一个类,重新定义数组,定义方法,然后测试

java
    public static void main(String[] args) {
        String[] stus = {"杜梦颖","任晓宇","景天老师"};
        System.out.println(findStu(stus, "杜梦颖"));
        updateStu(stus,"杜梦颖","杜梦");
        System.out.println(Arrays.toString(stus));
        delStu(stus,"杜梦");
        System.out.println(Arrays.toString(stus));
    }

    private static void delStu(String[] stus, String target) {
        int index = findStu(stus,target);
        if(index == -1) return;
        stus[index] = null;
    }

    private static void updateStu(String[] stus, String target,String newName) {
        int index = findStu(stus,target);
        if(index == -1) return;
        stus[index] = newName;
    }

    private static int findStu(String[] stus, String target) {
        for (int i = 0; i < stus.length; i++) {
            if(stus[i].equals(target))
                return i;
        }
        return -1;//表示没找到
    }

数组元素添加(扩展) &#8203;

利用数组元素的拷贝,实现真正意义上的在一个int数组中新增一个元素。新增元素的位置可自由决定,不要求排序,实现功能即可。

java
    public static void main(String[] args) {
        int[] originalNums = {92,60,50,44,99,30,8,20,40,96};
        int len = originalNums.length;
        int[] newNums = new int[len + 1];
        System.out.println("在下标为几的位置上插入几");
        Scanner sc = new Scanner(System.in);
        int index = sc.nextInt();
        int target = sc.nextInt();
        for (int i = 0,j = 0; i < len; i++,j++) {
            if(j == index){//j控制newNums的下标,i控制original的下标
                newNums[j] = target;
                j++;
            }
            newNums[j] = originalNums[i];
        }
        System.out.println(Arrays.toString(newNums));
    }

数组综合练习——合并数组(扩展) &#8203;

首先准备两个数组(简单起见,用两个int数组即可)

然后写方法,将这两个数组合并。

注:

  1. 数组合并也是很常见的操作,实际开发中有很多现成的手段去完成它。由于有些手段是超纲的,所以这里不再细表。

  2. 如果后续工作中碰到了,可以再百度学习一下。目前就先考虑自己手写实现就可以了。

    java
        private static int[] mergeNums(int[] nums1, int[] nums2) {
            int len = nums1.length + nums2.length;
            int[] newNums = new int[len];
            int index = 0;
            for(int n : nums1){
                newNums[index++] = n;
            }
            for(int n : nums2){
                newNums[index++] = n;
            }
            return newNums;
        }

值传递练习 &#8203;

Java有且仅有值传递,Java中的方法不能直接改变实参本身。

对于下列代码:

public static void main(String[] args) {
 int a = 10;
 int b = 20;
 method(a, b);
 System.out.println("a = " + a);
 System.out.println("b = " + b);
}

public static void method(int a, int b) {
 a *= 2;
 b *= 2;
}

思考以下问题:

  1. 对于以上Java代码,method()方法可以把a,b的取值变为原先的2倍吗?如果不能,为什么?

    不能,因为基本数据类型传参只是值传递,不能改变实参

  2. 上述main方法不变,修改method方法实现,让程序输出:

    1. a = 20
    2. b = 40

    如何实现呢?

    注:这是个脑筋急转弯,不会的可以互相问问或者查一查。

    在method中添加打印语句

可变参数练习 &#8203;

可变参数的本质是数组,完成下列需求:

求不限定个数参数的最大值(要求使用可变参数,使用int类型即可)

```java
public static int getMax(int...nums) {
    int max = Integer.MIN_VALUE;
    for(int n : nums){
        if(max < n)
            max = n;
    }
    return max;
}
```

判断2个字符串对象相等 &#8203;

对于任意两个字符串对象的引用str1,str2。

怎么判断这两个字符串对象的内容相同呢?

注:如果有一个引用等于null,那么另一个引用也等于null,也可算内容相同

思考一下,写出你的答案。

java
    private static boolean comStr(String str1, String str2) {
        if(str1 == null && str2 == null) return true;
        int len = str1.length();
        if(len != str2.length()) return false;
        for (int i = 0; i < len; i++) {
            if(str1.charAt(i) != str2.charAt(i))
                return false;
        }
        return true;
    }

二维数组和递归 &#8203;

主要涵盖内容:

  1. 二维数组
  2. 递归

练习使用二维数组 &#8203;

二维数组不是必须要掌握的知识点,对于JavaWeb实际开发而言,它也没有太大的作用。

但就像嵌套for循环一样,二维数组毕竟比一维数组更复杂一些,但本质不变。练习二维数组,可以锻炼逻辑思维能力,建议大家去自学一下,并且在时间充裕的情况下,完成下列两道题。

题目1 &#8203;

某公司该年度,每个季度的销售额(单位:万元)如下: 第一季度:30,66, 48 第二季度:10, 33, 20 第三季度: 10,99,103 第四季度: 9,18,27 请使用二维数组存储数据 并计算: 1,每个季度平均销售额 2,年度销售总额

java
    public static void main(String[] args) {
        int[][] volume = new int[4][3];
        volume[0] = new int[]{30,66,48};
        volume[1] = new int[]{10,33,20};
        volume[2] = new int[]{10,99,103};
        volume[3] = new int[]{9,18,27};
        //可以放到for循环里
        System.out.println("季度平均销售额:"+ getAverage(volume[0]));
        System.out.println("季度平均销售额:"+ getAverage(volume[1]));
        System.out.println("季度平均销售额:"+ getAverage(volume[2]));
        System.out.println("季度平均销售额:"+ getAverage(volume[3]));
        System.out.println("年度销售总额:" + getSum(volume));
    }
    static double getAverage(int[] nums){
        int len = nums.length;
        int sum = 0;
        for(int n : nums)
            sum += n;
        return sum / 3.0;
    }
    static int getSum(int[][] matrix){
        int len = matrix.length;
        int sum = 0;
        for (int i = 0; i < len; i++) {
            for (int j = 0; j < matrix[i].length; j++) {
                sum += matrix[i][j];
            }
        }
        return sum;
    }

题目2 &#8203;

已知有3个班级(一班,二班,三班)分别有3人,2人,5人 键盘录入每个班级的学生的成绩,并使用二维数组存储数据 然后计算: 每个班级的平均成绩,每个班级中的最高成绩和最低成绩,并输出

java
    public static void main(String[] args) {
        int[][] scores = new int[3][];
        scores[0] = new int[3];
        scores[1] = new int[2];
        scores[2] = new int[5];
        Scanner sc = new Scanner(System.in);
        for (int i = 0; i < 3; i++) {
            int count = scores[i].length;
            System.out.printf("输入%d班%d人的成绩:\n",i + 1,count);
            for (int i1 = 0; i1 < count; i1++) {
                scores[i][i1] = sc.nextInt();
            }
        }
        for (int i = 0; i < 3; i++) {
            System.out.println(i + 1 + "班");
            System.out.println(Arrays.toString(scores[i]));
            System.out.println("平均成绩:" + getAverage(scores[i]));
            int[] hl = getHL(scores[i]);
            System.out.println("最高成绩" + hl[1]);
            System.out.println("最低成绩" + hl[0]);
        }
    }
    static double getAverage(int[] nums){
        int len = nums.length;
        int sum = 0;
        for(int n : nums)
            sum += n;
        return sum / 3.0;
    }
    static int[] getHL(int[] nums){
        int[] hl = new int[2];
        hl[0] = Integer.MAX_VALUE;
        hl[1] = Integer.MIN_VALUE;
        for (int i = 0; i < nums.length; i++) {
            if(hl[0] > nums[i]) hl[0] = nums[i];
            if(hl[1] < nums[i]) hl[1] = nums[i];
        }
        return hl;
    }

练习使用递归 &#8203;

递归在实际开发中用途并不广泛,但我们仍有必要学习它的基本使用。

这道题目如果想不明白,那就百度一下吧。

使用递归,把十进制正整数(N>=0)转换成二进制数
java
    public static void main(String[] args) {
        int n = 128;
        StringBuilder s = new StringBuilder();
        getBinary(n,s);
        System.out.println(s);
    }
    static void getBinary(int n,StringBuilder s) {
        if (n == 0)
            return;
        getBinary(n / 2,s);
        s.append(String.valueOf(n % 2));
    }

OOP1——基础部分 &#8203;

主要包括面向对象第一部分知识点:

  1. 对象与类
  2. this关键字
  3. 构造器

构造器之前的知识。

对象与类基础语法练习题 &#8203;

设计物品(Item)类

它具有以下属性:

  1. 名字
  2. 价格
  3. 类别

它具有以下行为:

  1. 售卖。该方法需要传入一个参数表示购买使用的金钱,如果金钱足够则打印"xx物品被卖出"的信息,并将找零作为返回值。

    否则打印"金钱不足,购买失败",并将"-1"作为返回值表示购买失败。

类定义完毕后,试着创建三个对象并使用"对象名点"完成属性赋值:

  1. "手机类的Samsung Galaxy S21 8000元"
  2. "家具类的海尔冰箱 3000元"
  3. "日用品类的海飞丝洗发水 30元"

然后自行调用一下售卖方法,测试一下。

注:

  1. 建议用一个public class作为测试类,用于创建对象,调用方法,访问属性等。

  2. 具体类(比如本题中的Item)的定义,建议在public class下面定义非public class,这样比较方便快捷。

  3. java
    public class Main {
        public static void main(String[] args) {
            Item phone = new Item();
            Item fridge = new Item();
            Item shapoo = new Item();
            phone.catagory = "手机";
            phone.name = "Samsung Galaxy";
            phone.price = 8000;
            phone.buy(10000);
            fridge.catagory = "家具";
            fridge.name = "海尔冰箱";
            fridge.price = 3000;
            fridge.buy(10000);
    
            shapoo.catagory = "日用品";
            shapoo.name = "海飞丝洗发水";
            shapoo.price = 30;
            shapoo.buy(10);
        }

} class Item{ String name; double price; String catagory;

   double buy(double pay){
       if(pay >= price){
           System.out.println( name+"被卖出");
           return price - pay;
       }
       else System.out.println("金钱不足,购买失败");
       return -1;
   }

}




## 构造方法和this关键字练习题

> 定义一个Teacher类:
>
> 包含4个成员变量 String name, int age, String gender, int teacherId
>
> 然后定义5个构造方法:
>
> 1. 无参构造
> 2. name单参构造方法
> 3. name和teacherId双参构造方法
> 4. name,age和gender的三参构造器
> 5. name,age,gender和teacherId的四参构造器(要求用this调用已存在的三参构造器)
>
> 最后再定义一个成员方法:
>
> print():用于打印这个Teacher类对象的基本信息。
>
> 回答下列问题:
>
> 1. 在上面5个构造方法的基础上,再定义一个构造方法单独给gender赋值,能够做到吗?为什么?
>
>    不能
>
> 2. 定义完上述结构后,再定义一个成员方法setGender,用于给gender赋值。要求方法的形参就是String gender,这个方法如何写呢?
>
> 定义完这个类后,创建两个Teacher对象分别为t1和t2
>
> 1. 要求t1对象的四个成员变量name, age, gender, teacherId的值分别为"张三"、18、"男"、 1
>
> 2. 要求t2对象的四个成员变量name, age, gender, teacherId的值分别为"李四"、25、"女"、 2
>
>    <font color=red>**注意在使用构造器时,对应位置的实参和形参要一一对应。**</font>
>
> 最后分别用两个对象调用print方法,两次调用方法输出的结果相同吗?为什么?

```java
public class Main {
 public static void main(String[] args) {
     Teacher te1 = new Teacher("张三",18,"男",1);
     Teacher te2 = new Teacher("李四",25,"女",2);
     te1.print();
     te2.print();
 }
}

class Teacher{
 String name;
 int age;
 String gender;
 int teacherId;
 public Teacher(){
 }
 public Teacher(String name){
     this.name = name;
 }
 public Teacher(String name,int id){
     this.name = name;this.teacherId = id;
 }
 public Teacher(String name,int id,String gend){
     this.name = name;this.teacherId = id;
     this.gender = gend;
 }
 public Teacher(String name,int id,String gend,int age){
     this.name = name;this.teacherId = id;
     this.age =age;this.gender = gend;
 }
 public void setGender(String gender){
     this.gender = gender;
 }
 public void print() {
     System.out.println("name='" + name  + "\nage=" + age +
             "\ngender='" + gender + '\'' +
             "\neacherId=" + teacherId);
 }
}

对象数组练习 &#8203;

定义一个Student类:

成员变量:String name,int stuId,String gender,int age,double score(表示学生Java考试成绩)

构造器:无参构造器,全参构造器等,自由发挥。

成员方法:print(),打印对象所有属性的取值。

类定义完毕后,创建五个Student对象存入Student对象数组中,完成以下两个操作:

  1. 遍历输出每个学生的属性信息(遍历对象调用print()方法)
  2. 求成绩平均值。

注:

  1. 数组既可以存储基本数据类型(的值),也可以存储引用数据类型(的引用)。它们的使用没有本质区别。
  2. 可以考虑提取方法实现功能,不要把所有代码一股脑写在main方法中。
java
public class Main {
    public static void main(String[] args) {
        Student stu1 = new Student("小明", 1, "男", 3, 90);
        Student stu2 = new Student("小红", 2, "女", 5, 77.5);
        Student stu3 = new Student("小黄", 3, "男", 3, 88.88);
        Student stu4 = new Student("小绿", 4, "男", 7, 60);
        Student stu5 = new Student("小花", 5, "女", 9, 80);

        Student[] stus = {stu1,stu2,stu3,stu4,stu5};
        for (Student stu : stus) {
            stu.print();
        }
        getAvg(stus);
    }
    static void getAvg(Student...stus){
        int len = stus.length;
        double sum = 0;
        for (Student stu : stus) {
            sum+=stu.score;
        }
        System.out.println("平均分:" + sum / len);
    }
}

class Student {
    String name;
    int stuId;
    String gender;
    int age;
    double score;

    public Student() {
    }

    public Student(String n, int id, String gen, int a, double sc) {
        name = n;
        stuId = id;
        gender = gen;
        age = a;
        score = sc;
    }

    public void print() {
        System.out.println("Student{" +
                "name='" + name + '\'' +
                ", stuId=" + stuId +
                ", gender='" + gender + '\'' +
                ", age=" + age +
                ", score=" + score +
                '}');
    }
}

OOP1——高级部分 &#8203;

主要包括面向对象第一部分知识点:

  1. static
  2. 代码块
  3. 访问权限修饰符
  4. ...

包含OOP1后部分所有知识点

static基础语法练习 &#8203;

当类中的成员变量被static修饰时,那么它就是一个静态成员变量。当类中的成员方法被static修饰时,那么它就是一个静态成员方法。

普通成员(变量和方法)必须创建对象才能够访问,它们是属于对象的的。静态成员(变量和方法) 属于类,通过"类名点"就可以访问,它们是属于类的。

静态成员变量还有一个非常重要特性:由于类加载只有一次,所以静态成员变量在类全局都是唯一的!

现在你需要完成以下基础语法练习:

编写一个类模拟银行账户(Account)的功能,包含的属性有"账户名(ID)"、"密码"、"账户余额"、"储蓄年利率"等。 其中:

  1. 账号名:要求每个账户的账户名都是唯一的,且按照固定格式自动生成:
    • 第一位账户的账户名是"10001"
    • 其后账户的账户名依次加1。比如第二位账户的账户名就是"10002",第三位就是"10003".....
  2. 密码:新建账户时,可以选择自定义密码,也可以选择使用默认密码:"000000"(6个0)
  3. 账户余额:可以选择在新建账户时预设一个值,也可以保持默认值0
  4. 储蓄年利率:由银行设置,和账户本身没有关系。你可以将它设置为"0.3%"(活期年利率一般都非常低,聊胜于无)

定义完属性后,再给出两个成员方法:

  1. 打印账户所有属性。

  2. 根据传入的年限和储蓄年利率,计算本息合计后的余额。

    注:计算利息时简单点,不考虑利滚利。即利息 = 利率 * 时间 * 本金

提示:

  1. 账户ID是独属于某个账户的,它肯定是一个成员变量。但是它的赋值却是在一个初始值的基础上,创建一个对象就+1,这需要一个不受创建对象影响的变量。

  2. 储蓄年利率肯定不是属于账户对象的。

    java
    public class test2 {
        public static void main(String[] args) {
            Account ac1 = new Account();
            Account ac2 = new Account();
            ac1.print();
            ac2.print();
            ac1.getRemain(1, 0.3);
        }
    }
    
    class Account {
        static int defaultId = 10000;
        int id = 0;
        String pwd = "000000";
        double remain = 0;//余额
        static final double PERCENT = 0.3;//0.3%
    
        public Account() {
            id = ++defaultId;
            System.out.println("账户名:" + id);
            Scanner sc = new Scanner(System.in);
    
            System.out.println("输入密码(没有输入则设置为默认值):");
            String pass = sc.nextLine();
            if (pass.length() != 0)
                pwd = pass;
    
            System.out.println("设置余额(没有输入则设置为默认值):");
            String rem = sc.nextLine();
            if (rem.length() != 0)
                remain = Double.parseDouble(rem);
        }
    
        public void print() {
            System.out.println("Account{" +
                    "id=" + id +
                    ", pwd='" + pwd + '\'' +
                    ", remain=" + remain +
                    ", PERCENT=" + PERCENT +
                    '}');
        }
    
        public void getRemain(int year, double percent) {
            //计算利息时简单点,不考虑利滚利。即利息 = 利率 * 时间 * 本金
            //余额 = 本金 + 利息
            double interest = percent * year * remain * 0.01;
            double total = remain + interest;
            System.out.println("total = " + total);
        }
    }

猜数小游戏 &#8203;

百度和各种搜索引擎就是生产力,尝试自己解决以下问题:

先生成一个随机数(1~100之间的整数),再键盘输入猜测的数 如果猜的数大了或者小了,给出提示,继续猜,直到猜中为止。

注:Java如何生成随机数,自己百度查一下非常简单。这点学习能力还是需要具备的。

java
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        Random rd = new Random();
        int target = rd.nextInt(100) + 1;//[0,100) + 1
        while(true){
            int guess = sc.nextInt();
            if(guess == target){
                System.out.println("恭喜你,猜对了!");
                break;
            }else if(guess > target){
                System.out.println("猜大了");
            }else System.out.println("猜小了");
        }
    }

自己编写数组工具类 &#8203;

工具类:指的是类中方法全部是静态方法的类,工具类在使用时无需创建对象(静态方法无需对象调用)

以下方法的实现,都是我们上课写过的代码,如果觉得自己很熟练了,直接抄代码即可

如果觉得不熟悉或者想再练习一遍,再写一遍也可以~

写一个数组的工具类ArrayTool, 要求提供如下方法:
	遍历,求最大值,最小值,逆置数组元素
	查询(在数组中查找指定元素,若不存在,待查找元素返回-1,若存在返回元素在数组中首次出现的位置)
	查询(在数组中查找指定元素,若不存在,待查找元素返回-1,若存在返回元素在数组中最后一次出现的位置)
java
public class Main {
    public static void main(String[] args) {
        int[] nums = {1, 2, 3, 4, 5, 6, 2, 7};
        ArraysTool.traversal(nums);
        System.out.println("ArraysTool.getMax(nums) = " + ArraysTool.getMax(nums));
        System.out.println("ArraysTool.getMin(nums) = " + ArraysTool.getMin(nums));
        ArraysTool.reverse(nums);
        ArraysTool.traversal(nums);
        System.out.println("ArraysTool.findFirst(nums,2) = " + ArraysTool.findFirst(nums,2));
        System.out.println("ArraysTool.findLast(nums,2) = " + ArraysTool.findLast(nums, 2));
    }
}
class ArraysTool{
    static void traversal(int[] nums){
        System.out.print("[");
        for (int n : nums) {
            System.out.print(n + ",");
        }
        System.out.println("\b]");
    }
    static int getMax(int[] nums){
        int res = Integer.MIN_VALUE;
        for(int i = 0;i < nums.length;i++){
            res = Math.max(res,nums[i]);
        }
        return res;
    }
    static int getMin(int[] nums){
        int res = Integer.MAX_VALUE;
        for(int i = 0;i < nums.length;i++){
            res = Math.min(res,nums[i]);
        }
        return res;
    }
    static void reverse(int[] nums){
        int len = nums.length;
        for (int i = 0; i < len / 2; i++) {
            int tmp = nums[i];
            nums[i] = nums[len - 1 - i];
            nums[len - 1 - i] = tmp;
        }
    }
    static int findFirst(int[] nums,int target){
        for (int i = 0; i < nums.length; i++) {
            if(nums[i] == target){
                return i;
            }
        }
        return -1;
    }
    static int findLast(int[] nums,int target){
        for (int i = nums.length - 1; i >= 0;i--) {
            if(nums[i] == target){
                return i;
            }
        }
        return -1;
    }
}

导包相关练习 &#8203;

导包是很基本的操作,某些细节也需要注意,请完成以下练习:

Java
// 在com.cskaoyan.a包下,定义一个名为MyClazz的类如下
     public class  MyClazz {
        public void hello() {
        System.out.println("a包");
       }
     }
     
// 同时,在com.cskaoyan.b包下,一个类名也为MyClazz
     public class  MyClazz {
       public void hello() {
       System.out.println("b包");
       }
     }

// 同时在com.cskaoyan.b包下定义一个Test类如下:
     public class Test {
       public static void main(String[] args) {
       MyClazz myClazz = new MyClazz();
       myClazz.hello();
       }
     }

首先根据上述注释,将三个类定义出来

毫无疑问,直接执行Test中的main方法会输出的是b包,思考以下问题:

  1. 不改变Test类中main方法的基础上,让main方法运行之后输出“a包”,应该怎么做?

    导包

  2. 不做任何导包操作的基础上,修改main方法,让main方法运行之后同时输出“a包”和“b包”,应该怎么做?

  3. 在Test类中添加导包语句import com.cskaoyan.a.*,不修改任何代码,执行main方法,输出的是什么?为什么?

工具类禁止创建对象 &#8203;

普遍来说,工具类不应该创建对象,应该私有化构造方法

需求一:在昨天自己的作业,数组工具类的基础上,私有化它的构造方法
需求二:
定义一个Scanner工具类ScannerUtils,提供以下方法:
	1,键盘录入字符串
	2,键盘录入int整数
	3,键盘录入一个Person对象(Person类中有age和name属性)
	不要忘记私有化构造器

注:录入对象,无非就是先录入成员变量取值,然后构造器创建对象。

java
public class Main {
    public static void main(String[] args) {
        System.out.println(ScannerUtils.inputeStr());
        System.out.println(ScannerUtils.inputeInt());

        Person p = ScannerUtils.inputePerson();
        System.out.println(p.toString());
    }
}
class ScannerUtils{
    private ScannerUtils(){

    }
    static Scanner sc = new Scanner(System.in);
    static String inputeStr(){
        return sc.nextLine();
    }
    static int inputeInt(){
        return sc.nextInt();
    }
    static Person inputePerson(){
        System.out.println("分别输入Person对象的名字和年龄:");
        String name = sc.nextLine();
        int age = sc.nextInt();
        return new Person(name, age);
    }
}
class Person{
    String name;
    int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

禁止创建对象 &#8203;

综合访问权限修饰符,static等知识点,做一个综合的练习。

定义一个Student类,并要求在其他类中,最多只能创建10个Student类的对象。
	分析:
		1,如果允许外部直接创建对象,显然无法控制创建对象的个数
		2,需要计数器指示外部创建对象的个数
java
class Student{
    static int countObj = 0;
    private Student(){
        countObj++;
    }
    public static Student createObj(){
       if(countObj >= 10){
           return null;
       }
       return new Student();
    }
}

设计一个员工类 &#8203;

设计一个员工类(Staff),要求该类:
     属性: 姓名,性别,工号,工资
     构造器:
     姓名的单参构造器、姓名和性别的双参构造器、姓名、性别和工资的三参构造器
其中员工的工号要求(每一位员工都必须有工号):
     第一个员工对象的工号是10001
     第二个员工对象的工号是10002
     第三个员工对象的工号是10003
     ....
现在每位员工都要缴纳一个固定额的公积金(比如2000),要求在员工类中设计一个方法求员工的到手工资。(除了扣除这个固定额度的公积金,不考虑诸如扣税等其余问题)
最后再定义一个方法用于打印员工对象的各种属性取值,其中在打印工资时,要打印实际到手工资。
将该类定义完毕后,尝试创建对象,测试一下代码。
java
public class Test {
    public static void main(String[] args) {
 	    Staff stf1 = new Staff("小红");
        Staff stf2 = new Staff("小白","男");
        Staff stf3 = new Staff("小黑","男",10000);
        stf1.print();
        stf2.print();
        stf3.print();
    }
}
class Staff{
    String name;
    String gender;
    int id;
    double salary;
    static int defaultId = 1000;
    static final double FUND = 2000;
    {
        id = ++defaultId;
    }
    public Staff(String name){
        this.name = name;
    }

    public Staff(String name, String gender) {
        this.name = name;
        this.gender = gender;
    }

    public Staff(String name, String gender, double salary) {
        this(name, gender);
        this.salary = salary;
    }
    public double getHomeSalary(){

        return 0.0;
    }

    public void print() {
        System.out.println("Staff{" +
                "name='" + name + '\'' +
                ", gender='" + gender + '\'' +
                ", id=" + id +
                ", salary=" + (salary - FUND) +
                '}');
    }
}

OOP2——封装 &#8203;

主要针对OOP2阶段的:

面向对象第一个特征——封装

Getter/Setter方法 &#8203;

当属性私有化,又有外界访问需求时,提供Getter/Setter方法

创建两个类,分别用来表示长方形和正方形。
同时定义所需的成员变量(边长),代表长方形或者正方形的边长(私有化成员变量,并提供相应的Getter/Setter方法,获取以及改变长方形和正方形的边长。)
然后在两个类中分别定义两个成员方法,用于求对应图形的面积和周长。
最后,写代码测试一下创建对象,方法调用等。

注:Getter/Setter方法可以选择手写一个,其余的用快捷键自动生成。

java
class Square{
    private double side;
    public double perimeter(){
        return 4 * getSide();
    }
    public double area(){
        return Math.pow(getSide(), 2);
    }

    public double getSide() {
        return side;
    }
    public void setSide(double side) {
        this.side = side;
    }
}
class Rectangle{
    private double length;
    private double width;
    public double perimeter(){
        return 2 * (getWidth() + getLength());
    }
    public double area(){
        return getLength() * getWidth();
    }
    public double getLength() {
        return length;
    }

    public void setLength(double length) {
        this.length = length;
    }

    public double getWidth() {
        return width;
    }

    public void setWidth(double width) {
        this.width = width;
    }
}

OOP2——继承 &#8203;

主要针对OOP2阶段中面向对象第二个特征——继承

包含:

  1. 继承的基本概念
  2. 继承中两个类的关系
  3. protected
  4. 子类对象初始化
  5. 方法覆盖
  6. final
  7. ....

继承基础语法练习 &#8203;

明确记住,继承中的两个类应该有is-a关系

提供以下两个动物需要描述,请用你的知识来编写代码
猫:姓名,年龄,颜色,可以叫,可以抓老鼠
狗:姓名,年龄,性别,可以叫,可以看门
分析这个案例,设计出合适的继承体系。

最后思考:人类研究出来了机器人,它们也有姓名,年龄,颜色等属性,可以套用本题中的继承体系吗?
java
class Animal {
    protected String name;
    protected int 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;
    }

    protected void sound() {

    }
}

class Cat extends Animal {
    private String color;

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public Cat(String n, int a, String color) {
        this.name = n;
        this.age = a;
        this.color = color;
    }

    public void sound() {
        System.out.println("喵喵喵");
    }

    public void mice() {
        System.out.println("抓老鼠");
    }
}

class Dog extends Animal {
    String gender;

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public Dog(String n, int a, String g) {
        this.name = n;
        this.age = a;
        this.gender = g;
    }

    public void sound() {
        System.out.println("汪汪汪");
    }

    public void watch() {
        System.out.println("看门");
    }
}

练习继承中的构造器使用 &#8203;

使用alt + insert快捷键可以快速生成各种类中结构。子类继承父类后,在子类中按alt + insert快捷键快速创建构造方法时,第一步会让你选择父类构造器(也就是super(参数))

随后才是选择子类自身的成员变量,生成子类构造器。

当然如果选择使用父类无参构造器,这时super()是隐藏的,即子类对象隐式初始化。

当选择使用子类有参构造器时,这时super(参数)必须写在子类构造器第一行,这是子类对象的显式初始化。

给出三个层级的继承关系
顶层父类Grandfather,Father继承Grandfather,Son继承Father
成员变量:
Grandfather:gA,a
Father:fA,a
Son:sA,a

成员方法:
Grandfather:testGrand,test
Father:testFather,test
Son:testSon,test

使用快捷键在Son中生成不同的构造方法,调用不同的父类构造器(需要先生成父类相应的构造器)
随后使用多种方式创建Son对象(思考有几种),测试对象名访问成员的机制,理解属性隐藏和方法覆盖
java
public class test2 {

    public static void main(String[] args) {
        Son s = new Son();
        System.out.println(s.a); //2
        Father f = new Son();
        System.out.println(f.a); //1
        GrandFather gf = new Son();
        System.out.println(gf.a); //0

        s.test();
        f.test();
        gf.test();

//        f.testSon();
//        gf.testFather();
    }


}
class GrandFather{
    int gA;
    int a;

    public void testGrand() {
        System.out.println("testGrand");
    }
    public void test() {
        System.out.println("GrandFather.test");
    }
    public GrandFather(int gA, int a) {
        this.gA = gA;
        this.a = a;
    }
    public GrandFather() {
    }
}
class Father extends GrandFather{
    int fA;
    int a = 1;
    public void testFather() {
        System.out.println("testFather");
    }
    public void test() {
        System.out.println("Father.test");
    }
    public Father(int fA, int a) {
        this.fA = fA;
        this.a = a;
    }
    public Father() {
    }
    public Father(int gA, int a, int fA, int a1) {
        super(gA, a);
        this.fA = fA;
        this.a = a1;
    }
}
class Son extends Father{
    int sA;
    int a = 2;
    public void testSon() {
        System.out.println("testSon");
    }
    public void test() {
        System.out.println("Son.test");
    }
    public Son(int gA, int a, int fA, int a1, int sA, int a2) {
        super(gA, a, fA, a1);
        this.sA = sA;
        this.a = a2;
    }

    public Son(int sA, int a) {
        this.sA = sA;
        this.a = a;
    }

    public Son(int gA, int a, int fA, int a1) {
        super(gA, a, fA, a1);
    }

    public Son() {

    }
}

final语法练习 &#8203;

final修饰成员/静态成员变量,表示一个常量,必须明确地赋值。

自定义一个类,类中定义三个成员变量a,b,c,用final修饰这三个成员变量
再定义两个静态成员变量staticA和staticB,也用final修饰这两个静态成员变量
然后:
	1,请用三种不同的方式,分别为成员变量a,b,c赋值
	2,请用两种不同的方式,分别为静态成员变量staticA和staticB赋值
java
class Test{
    final int a = 1;
    final int b;
    final int c;
    {c = 3;}//构造代码块
    static final int A = 4;
    static final int B;
    static{B = 5;}
    public Test(int bb) {
        b = bb;
    }
}

多态语法基础练习 &#8203;

牢记多态发生的条件

请根据题目,作出合理设计,定义如下类:
父类Person
	属性:String name,int age
	行为:eat();
	
子类SouthPerson
	属性:String name,int age,double salary
	行为:eat(),swim()

子类NorthPerson
	属性:String name,int age,double height
	行为:eat(),drink()

写代码实现,eat()方法的多态效果
	1,人都要吃饭
	2,南方人喜欢吃米饭
	3,北方人喜欢吃面食

最后,在测试类中,编写测试代码,要求进行如下测试:
	1,编写测试方法,	
		要求该方法允许传入SouthPerson对象和NorthPerson对象,并在方法体中调用它们的eat()方法
		方法调用的结果一致吗?
	2,用父类引用指向子类对象的方式创建SouthPerson对象,能否直接访问salary属性和swim()方法?
		如果不能,应该怎么写代码让它能够正常调用?
	3,用父类引用指向子类对象的方式创建NorthPerson对象,能否(直接或写代码)访问salary属性和swim()方法?
		如果不能,将该对象引用强转为SouthPerson引用,能否成功?为什么?
java
public class ExerciseBlock {
    public static void main(String[] args) {
        Person p = new Person();
        p.eat();
        Person sp = new SouthPerson();
        sp.eat();
        Person np = new NorthPerson();
        np.eat();
        personEat(p);
        personEat(sp);
        personEat(np);
        ((SouthPerson) sp).swim();
        double d = ((SouthPerson) sp).salary;
        if(np instanceof SouthPerson){
            double salary = ((SouthPerson) np).salary;
            ((SouthPerson) np).swim();
        }else System.out.println("np不能强转为SouthPerson");

    }
    public static void personEat(Person ps){
        ps.eat();
    }
}
class Person{
    String name;
    int age;
    public void eat() {
        System.out.println("人都要吃饭");
    }
}
class SouthPerson extends Person{
    double salary;
    public void eat(){
        System.out.println("南方人爱吃米饭");
    }
    public void swim(){
        System.out.println("南方人会游泳");
    }
}
class NorthPerson extends Person{
    double height;
    public void eat(){
        System.out.println("北方人爱吃面食");
    }
    public void drink(){
        System.out.println("北方人爱喝酒");
    }
}

OOP3——抽象类和接口 &#8203;

主要针对OOP3阶段:

包含:

  1. 抽象类
  2. 接口

抽象类基础语法练习 &#8203;

完成抽象类的基础语法练习,按照说明操作即可。

定义抽象类A,抽象类B继承A,普通类C继承B。
A类中,定义成员变量a赋值为10,抽象showA方法
B类中,定义成员变量b赋值为20,抽象showB方法
C类中,定义成员变量c赋值为30,重写showA方法打印a,重写showB方法打印b,定义showC方法,打印c

然后在测试类中,创建C类的对象,调用showA方法,showB方法,showC方法。
然后查看方法调用结果,思考为什么会出现这种现象。
java
public class Test {
    public static void main(String[] args) {
        C c = new C();
        c.showA();
        c.showB();
        c.showC();
    }
}

abstract class A {
    int a = 10;

    abstract void showA();
}

abstract class B extends A {
    int b = 20;

    abstract void showB();
}

class C extends B {
    int c = 30;

    @Override
    void showA() {
        System.out.println(a);
    }

    @Override
    void showB() {
        System.out.println(b);
    }

    void showC() {
        System.out.println(c);
    }
}

接口与抽象类基础语法练习 &#8203;

从实际角度出发,接口和抽象类的差异是十分明显的。可以参考完成以下案例:

学生和老师都有共同的属性: name、gender、age
共同的行为:eat() sleep() 
	注:虽然行为一致,但实现会不同。
现在为了提升自身素质,大家都需要额外进行技能的学习:学生需要增强实践动手能力,老师需要增强语言能力。
请定义抽象类和接口,描述以上体系。

然后用以下方式进行测试:
	1,用不同的父类指向不同的子类对象,理解方法调用时“编译时看左边”
	2,用这些引用调用方法,理解方法调用时“运行时看右边”
java
public class Test {
    public static void main(String[] args) {
        Study stu = new Teacher();
        Study sty = new Student();
        stu.learnEnglish();
        sty.learnEnglish();
    }
}
abstract class Person{
    String name;
    String gender;
    int age;
    abstract public void eat();
    abstract public void sleep();
}
interface Study{
    public void learnEnglish();
}
class Student extends Person implements Study{
    @Override
    public void learnEnglish() {
        System.out.println("学生增强动手实践");
    }

    @Override
    public void eat() {
        System.out.println("学生吃饭");
    }

    @Override
    public void sleep() {
        System.out.println("学生睡觉");
    }
}
class Teacher extends Person implements Study{
    @Override
    public void learnEnglish() {
        System.out.println("老师增强语言能力");
    }

    @Override
    public void eat() {
        System.out.println("老师吃饭");
    }

    @Override
    public void sleep() {
        System.out.println("老师睡觉");
    }
}

OOP3——内部类 &#8203;

主要针对OOP3阶段:

包含:

  1. 成员内部类、静态内部类、局部内部类
  2. 匿名内部类、Lambda表达式

填代码题 &#8203;

成员内部类,静态内部类的区别实际上时非常明显的,对象的创建和使用都有很大差异。请完成下列题目:

根据注释填写(1),(2),(3)处的代码:

public class Test{
 public static void main(String[] args){
        //(1)创建并初始化Bean1类对象bean1
        bean1.i++;
        //(2)创建并初始化Bean2类对象bean2 
        bean2.j++;
        //(3)创建并初始化Bean3类对象bean3
        bean3.k++;
 }
 class Bean1{
        public int i = 0;
 }
 static class Bean2{
        public int j = 0;
 }
}
class Bean{
 class Bean3{
        public int k = 0;
 }
}
java
public class Test{
    public static void main(String[] args){
        //(1)创建并初始化Bean1类对象bean1
        Bean1 bean1 = new Test().new Bean1();
        bean1.i++;
        //(2)创建并初始化Bean2类对象bean2
        Bean2 bean2 = new Bean2();
        bean2.j++;
        //(3)创建并初始化Bean3类对象bean3
        Bean.Bean3 bean3 = new Bean().new Bean3();
        bean3.k++;
    }
    class Bean1{
        public int i = 0;
    }
    static class Bean2{
        public int j = 0;
    }
}
class Bean{
    class Bean3{
        public int k = 0;
    }
}

用内部类来实现接口 &#8203;

定义一个接口Compute,用来完成计算器的功能,比如最简单的加减乘除功能。
请用以下两种方式测试:
	1,编写实现类进行测试
	2,用局部内部类进行测试
	3,使用匿名内部类进行测试
java
public class Test{
    public static void main(String[] args){
        ComputeImpl com = new ComputeImpl();
        System.out.println("add(1,2) = " + com.add(1, 2));
        //局部内部类
        class InnerComp implements Compute{
            @Override
            public int add(int op1, int op2) {
                return op1 + op2;
            }

            @Override
            public int sub(int op1, int op2) {
                return op1 - op2;
            }

            @Override
            public int mul(int op1, int op2) {
                return op1 * op2;
            }

            @Override
            public int div(int op1, int op2) {
                if(op2 == 0) return 0;
                return op1 / op2;
            }
        }
        System.out.println("sub(4,3) = " + new InnerComp().sub(4,3));
        //匿名内部类
        int res = new Compute() {
            @Override
            public int add(int op1, int op2) {
                return op1 + op2;
            }

            @Override
            public int sub(int op1, int op2) {
                return op1 - op2;
            }

            @Override
            public int mul(int op1, int op2) {
                return op1 * op2;
            }

            @Override
            public int div(int op1, int op2) {
                if (op2 == 0) return 0;
                return op1 / op2;
            }
        }.mul(4, 5);
        System.out.println("mul(4,5) = " + res);
    }
}
//实现类
class ComputeImpl implements Compute{

    @Override
    public int add(int op1, int op2) {
        return op1 + op2;
    }

    @Override
    public int sub(int op1, int op2) {
        return op1 - op2;
    }

    @Override
    public int mul(int op1, int op2) {
        return op1 * op2;
    }

    @Override
    public int div(int op1, int op2) {
        if(op2 == 0) return 0;
        return op1 / op2;
    }
}
interface Compute{
    int add(int op1, int op2);

    int sub(int op1, int op2);

    int mul(int op1, int op2);

    int div(int op1, int op2);
}

成员内部类练习 &#8203;

成员内部类对象依赖于它的外围类对象

定义一个类Dog
属性:age,name
除此之外,Dog类中需要定义一个成员内部类Body,Body类中有属性color
请私有化该成员内部类,然后将该成员内部类对象作为外围类的成员变量私有化。
然后在Dog类提供一个方法,展示Dog类的全部属性(包括成员内部类中的)。

最后在一个外部类中,创建Dog对象,让外界感知不到成员内部类的存在。
思考一下如何做这个需求?

成员内部类练习 &#8203;

成员内部类题目:

定义一个外部类Car,在外部类中定义一个成员内部类Engine(发动机)。

Car类包含私有成员变量brand,price,model等。
然后提供构造器给成员变量赋值,以及一个成员方法startEngine(),
该方法创建一个Engine对象并调用其run()方法表示启动发动机。

成员内部类Engine当中提供一个run成员方法,要打印汽车的信息,并提示发动机已启动。
java
public class Test{
    public static void main(String[] args) {
        Car car = new Car("奔驰",100000,"e300");
        car.startEngine();
    }
}
class Car{
    private String brand;
    private double price;
    private String model;

    public Car(String brand, double price, String model) {
        this.brand = brand;
        this.price = price;
        this.model = model;
    }
    void startEngine(){
        new Engine().run();
    }
    class Engine{
        void run(){
            System.out.println("品牌:" + brand + " 价格:" + price
                    + " 型号:" + model + " 的汽车发动机启动");
        }
    }
}

静态内部类练习 &#8203;

创建一个名为Library的外部类,其中包含一个名为Book的静态内部类。

Book类包含两个私有成员变量:String title和String author,
以及一个构造函数用于初始化这些变量。

Library类存在一个Book对象数组作为成员变量,用于存储Book对象。
再定义一个成员方法addBook,该方法需要传入书名和作者作为参数,
然后将这个Book对象添加到成员变量的Book数组中
(找null的位置,进行插入,可以考虑将Book数组的长度初始值给大一点)

Library类包含一个名为displayBooks的方法,用于打印Book对象数组中所有书籍的详细信息。

Book类还包含一个名为displayInfo的方法,用于打印书籍的详细信息。

最后,在测试类当中创建Library对象并调用方法,进行代码测试。
java
public class Test{
    public static void main(String[] args) {
        Library lib = new Library();
        lib.addBook("红楼梦", "曹雪芹");
        lib.addBook("西游记", "吴承恩");
        lib.addBook("水浒传", "施耐庵");
        lib.addBook("三国演义", "罗贯中");
        lib.displayBooks();
    }
}
class Library{
    static class Book{
        private String title;
        private String author;

        public Book(String title, String author) {
            this.title = title;
            this.author = author;
        }

        @Override
        public String toString() {
            return "Book{" +
                    "title='" + title + '\'' +
                    ", author='" + author + '\'' +
                    '}';
        }
    }

    private Book[] books = new Book[10];

    boolean addBook(String t, String a) {
        Book newBook = new Book(t, a);
        for (int i = 0; i < books.length; i++) {
            if (books[i] == null) {
                books[i] = newBook;
                return true;
            }
        }
        return false;
    }
    void displayBooks(){
        for (Book b : books) {
            if(b == null) continue;
            System.out.println(b.toString());
        }
    }
}

lambda表达式的练习 &#8203;

lambda表达式的书写,除了注意格式外,最重要的是关注类型推断

  • 提供以下6个功能接口,请用lambda表达式分别创建对象,调用test()方法
  • 自由发挥lambda表达式的书写
java
//无返回值无参数的功能接口
@FunctionalInterface
interface INoReturnNoParam {
    void test();
}

//无返回值有一个参数的功能接口
@FunctionalInterface
interface INoReturnOneParam {
    void test(int a);
}

//无返回值两个参数的功能接口
@FunctionalInterface
interface INoReturnTwoParam {
    void test(int a, int b);
}

//有返回值无参数的功能接口
@FunctionalInterface
interface IHasReturnNoParam {
    int test();
}

//有返回值一个参数的功能接口
@FunctionalInterface
interface IHasReturnOneParam {
    int method(int a);
}

//有返回值两个参数的功能接口
@FunctionalInterface
interface IHasReturnTwoParam {
    int test(int a, int b);
}
java
public class Demo {
    public static void main(String[] args) {
        INoReturnNoParam nrnp = () -> System.out.println("NoReturnNoParam");
        nrnp.test();
        INoReturnOneParam nrop = a -> System.out.println("INoReturnOneParam " + a);
        nrop.test(3);
        INoReturnTwoParam nrtp = (a, b) -> System.out.println("INoReturnTwoParam " + (a + b));
        nrtp.test(50, 2);
        //IHasReturnNoParam hrnp = () -> { return 2; };
        IHasReturnNoParam hrnp = () -> 2;
        System.out.println("hrnp.test() = " + hrnp.test());
        IHasReturnOneParam hrop = (a) -> a;
        System.out.println("hrop.method(1) = " + hrop.method(1));
        IHasReturnTwoParam hrtp = (a, b) -> a + b;
        System.out.println("hrtp.test(2, 4) = " + hrtp.test(2, 4));
    }
}


//无返回值无参数的功能接口
@FunctionalInterface
interface INoReturnNoParam {
    void test();
}

//无返回值有一个参数的功能接口
//功能接口并不是只能由一个抽象方法
@FunctionalInterface
interface INoReturnOneParam {
    void test(int a);
    boolean equals(Object o);
}

//无返回值两个参数的功能接口
@FunctionalInterface
interface INoReturnTwoParam {
    void test(int a, int b);
}

//有返回值无参数的功能接口
@FunctionalInterface
interface IHasReturnNoParam {
    int test();
}

//有返回值一个参数的功能接口
@FunctionalInterface
interface IHasReturnOneParam {
    int method(int a);
}

//有返回值两个参数的功能接口
@FunctionalInterface
interface IHasReturnTwoParam {
    int test(int a, int b);
}

今天先学会使用匿名内部类和lambda表达式,具体详细的有哪些用途,后面会碰到

  • 如果实在感兴趣想知道,你也可以自己搜一搜,Java对象数组的排序

Lambda表达式的练习 &#8203;

定义一个计算(compute)接口,接口中有加减乘除四个抽象方法。
然后使用匿名内部类去实现加减乘除并测试

上述功能,昨天已经实现了,今天考虑用lambda改进它,如下:

  • 用以下功能接口,实现一个计算器的工具类
  • 在工具类中,只需要一个工具方法,就能够实现所有的计算功能
Java
@FunctionalInterface
interface Compute {
    double compute(double a, double b);
}

工具类和工具方法如下:

java
//需要提供一个使用功能接口的方法完成需求
class ComputeTool {
    private ComputeTool() {
    }

    public static void calc(Compute com, double a, double b) {
        //...
    }
}

你知道如何使用吗?联系一下,今天讲解的String数组的过滤,

java
public class Demo {
    public static void main(String[] args) {
        System.out.println(ComputeTool.calc((op1, op2) -> op1 + op2, 90, 32));
        System.out.println(ComputeTool.calc((op1, op2) -> op1 - op2, 90, 32));
        System.out.println(ComputeTool.calc((op1, op2) -> op1 * op2, 90, 32));
        System.out.println(ComputeTool.calc((op1, op2) -> op1 / op2, 90, 32));
    }
}
@FunctionalInterface
interface Compute{
    double calc(double op1, double op2);
}
class ComputeTool {
    private ComputeTool() {
    }

    public static double calc(Compute com, double a, double b) {
        return com.calc(a, b);
    }
}

Object类 &#8203;

主要包含内容是Object类的成员方法:

  1. getClass()
  2. toString()
  3. equals()
  4. hashCode()
  5. finalize()
  6. clone()

getClass()方法练习 &#8203;

定义两个类,然后分别创建对象,调用getClass方法

用“==”号比较它们的运行时Class对象是否相等,并说明原因

理解运行时类对象、类加载、类的对象的区别

java
public class Demo {
    public static void main(String[] args) {
        A a = new A();
        A a1 = new A();
        B b = new B();
        Class aClass = a.getClass();
        Class aClass1 = a1.getClass();
        Class bClass = b.getClass();
        System.out.println(aClass==aClass1);
        System.out.println(aClass==bClass);
        System.out.println(classEqual(a, b));
    }
    public static boolean classEqual(Object a,Object b){
        return (a.getClass()==b.getClass());
    }
}
class A{

}
class B{

}

equals方法练习 &#8203;

定义一个Animal类
成员变量:
	int age,String name,double price
手写它的equals方法,比较getClass和instanceof的区别
java
public class Demo {
    public static void main(String[] args) {
        Animal a = new Animal(3, "二哈", 99.8);
        Animal a1 = new Animal(3, "二哈", 99.8);
        System.out.println(a1.equals(a1));
        //Animal2中重写equals方法用了instanceof取代getClass
        Animal2 a2 = new Animal2(3, "二哈", 99.8);
        Dog dog = new Dog(3, "二哈", 99.8);
        System.out.println(a2.equals(dog));
    }
}
class Animal{
    private int age;
    private String name;
    private double price;

    public Animal(int age, String name, double price) {
        this.age = age;
        this.name = name;
        this.price = price;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Animal animal = (Animal) o;
        return age == animal.age &&
                Double.compare(animal.price, price) == 0 &&
                Objects.equals(name, animal.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(age, name, price);
    }
}
class Animal2{
    private int age;
    private String name;
    private double price;

    public Animal2(int age, String name, double price) {
        this.age = age;
        this.name = name;
        this.price = price;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || !(o instanceof Animal2)) return false;
        Animal2 animal2 = (Animal2) o;
        return age == animal2.age &&
                Double.compare(animal2.price, price) == 0 &&
                Objects.equals(name, animal2.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(age, name, price);
    }
}
class Dog extends Animal2{

    public Dog(int age, String name, double price) {
        super(age, name, price);
    }
}

深度克隆练习 &#8203;

String虽然也是引用数据类型,但无需考虑它的深度克隆。

分别定义以下类:
教师类Teacher
属性:int age;String name;Student stu
学生类Student
属性:int age;String name;Star s
明星类Star
属性:int age,String name

尝试完成Teacher对象的深度克隆,并写代码进行测试
java
public class Demo {
    public static void main(String[] args) throws CloneNotSupportedException {
        Teacher t1 = new Teacher(28, "王老师",
                new Student(14, "小明", new Star(36, "刘亦菲")));
        Teacher clone = t1.clone();
        System.out.println(clone.name.equals(t1.name));
        System.out.println(clone.stu == t1.stu);//浅克隆true,深克隆false
        System.out.println(clone.stu.s == t1.stu.s);//浅克隆true,深克隆false
        t1.stu.s.name = "张靓颖";
        System.out.println(clone.stu.s);
        System.out.println(t1.stu.s);
    }

}
class Teacher implements Cloneable{
    int age;
    String name;
    Student stu;

    @Override
    public Teacher clone() throws CloneNotSupportedException {
        Teacher ct = (Teacher) super.clone();
        ct.stu = ct.stu.clone();
        return ct;
    }

    public Teacher(int age, String name, Student stu) {
        this.age = age;
        this.name = name;
        this.stu = stu;
    }
}
class Student implements Cloneable{
    int age;
    String name;
    Star s;

    public Student(int age, String name, Star s) {
        this.age = age;
        this.name = name;
        this.s = s;
    }

    @Override
    public Student clone() throws CloneNotSupportedException {
        Student cs = (Student) super.clone();
        cs.s = cs.s.clone();
        return cs;
    }
}
class Star implements Cloneable{
    int age;
    String name;

    public Star(int age, String name) {
        this.age = age;
        this.name = name;
    }

    @Override
    protected Star clone() throws CloneNotSupportedException {
        return (Star) super.clone();
    }

    @Override
    public String toString() {
        return "Star{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}