ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Java进阶之路:第二阶段数组、排序与面向对象实战笔记

Java进阶之路:第二阶段数组、排序与面向对象实战笔记 记录一下学Java的第二阶段。上一篇写了环境搭建和第一个Hello World这阵子又啃了不少新东西数组、排序、面向对象这些基础核心总算摸到点门道了。这里把这段时间踩过的坑、琢磨明白的问题、还有个人觉得比较关键的实战经验都整理出来给同样在自学Java的朋友做个参考。1. 内容整体设计与思路拆解1.1 为什么说第二阶段是分水岭写Hello World的时候其实你还没真正进入编程的世界。变量、运算符、if/else这些更多是在熟悉语法脑子里还是原来代码长这样的朦胧感。到了第二阶段就不一样了。数组、循环嵌套、方法调用、类与对象这些知识点开始要求你用计算机的思维方式去思考问题。简单说你得学会把现实中的逻辑翻译成代码还得学会用抽象的方式描述事物。我自己的体会特别深写第一弹的时候跟着教程敲代码敲完运行出结果就完事了根本不理解为什么要这么写。到了数组排序、面向对象这块光靠抄代码已经行不通了因为你不理解内存里数据怎么存的不理解对象和类到底是什么关系后面的代码根本写不下去。所以如果你也是自学到了这个阶段一定要有心理准备不要追求敲了多少行代码而要追求想明白了几个问题。1.2 第二弹的学习目标拆解我给这一阶段定的目标是能独立写出一个包含多个方法、使用数组存储数据、体现基本面向对象思想的小程序比如学生成绩管理系统、图书管理小工具这类。听起来不难但真要实现需要这几个能力同时在线数组的创建、遍历、增删改查操作循环和条件判断的嵌套使用方法函数的定义和调用类和对象的基本概念属性和方法的编写异常处理的基础认识至少知道程序崩了去哪里看问题这五个能力点其实就是Java基础阶段的核心骨架。面试题里常考的Java基础翻来覆去也就是这些东西的变形。1.3 关于学习路线的一点个人建议很多人在网上找Java学习路线图我也找过经常被那种20天搞定Java的路线吓到。说实话我觉得对新手来说路线图真的不用太复杂关键是把一条线走通环境搭建JDK安装配置基础语法变量、数据类型、运算符、流程控制数组与字符串操作面向对象类、对象、封装、继承、多态常用类库集合框架、IO、时间处理数据库和JDBC能存数据了才叫程序框架入门Spring Boot这是目前最主流的企业级开发框架我目前卡在第4个的尾巴上后面路还长。但至少现在回头看第一阶段写的代码已经能看出很多问题了这就是进步。2. Java基础核心概念扫雷2.1 数据类型不只是int和double之前觉得Java数据类型就是int、double、char、boolean这些真学起来才发现里面戏挺多。首先要分清基本数据类型和引用类型。基本类型就是那8个byte、short、int、long、float、double、char、boolean。这里有个特别容易踩的坑整数运算溢出。举个例子int a 2000000000; int b 2000000000; int sum a b; System.out.println(sum); // 结果竟然是负数我第一次看到输出结果是负数时整个人都懵了。后来才明白int的最大值是2147483647两个20亿加起来超过了这个范围就发生了溢出结果变成了负数。解决办法就是用更大的类型比如long或者用Math.addExact(a, b)在溢出时直接抛异常。引用类型则是类、数组、接口这些。String就是典型的引用类型。新手在这里特别容易混淆的是赋值到底是拷贝值还是拷贝引用。看下面这段代码int x 10; int y x; y 20; System.out.println(x); // 还是10值类型赋值是拷贝 int[] arr1 {1, 2, 3}; int[] arr2 arr1; arr2[0] 999; System.out.println(arr1[0]); // 变成999了引用类型赋值拷的是地址这个区别不理解的话后面写代码会出现很多怎么这个变量莫名其妙被改了的灵异现象。2.2 流程控制与循环嵌套的思维转换if/else和switch相对好理解就是按条件分岔路。循环这块才是新手容易卡壳的地方尤其是嵌套循环。说个我的亲身经历用Java打印一个九九乘法表看似简单我整整折腾了半小时才弄对。for (int i 1; i 9; i) { for (int j 1; j i; j) { System.out.print(j x i (i * j) \t); } System.out.println(); }核心思路就一句话外层循环管行内层循环管列。你只要想清楚每一行要打印多少个内容循环条件就出来了。这类题别怕多画图把循环的每次执行过程在纸上写出来练几个就通了。2.3 标识符命名规则与开发习惯这部分的规则其实不复杂字母、数字、下划线、美元符号组成不能以数字开头不能是关键字大小写敏感。但我更想说的是命名习惯你以后会感谢现在的自己类名用大驼峰StudentInfoOrderManager方法名和变量名用小驼峰getUserNameorderList常量全大写加下划线MAX_COUNTDEFAULT_TIMEOUT不要用拼音缩写int xm 0这种代码过三天你自己都看不懂更别说别人了蓝桥杯这类算法竞赛对新手来说其实是很好的练习场它的入门题很多就是考循环、数组、字符串处理这些基本功而且数据规模一般不大不需要高深的算法就能过。刷几道蓝桥杯真题比对着教程敲一百遍Hello World有用得多。3. 冒泡排序与算法入门实操3.1 为什么第一个算法选择冒泡排序排序算法是Java基础阶段绕不开的内容。面试时候考排序项目里也许用得不多但排序算法是理解算法思维最好的入门材料。冒泡排序的基本思想重复地走访要排序的数列一次比较两个元素如果顺序错误就把它们交换过来。走访数列的工作是重复进行的直到没有需要交换的元素为止。看代码public static void bubbleSort(int[] arr) { int n arr.length; // 外层循环控制需要比较的轮数n个元素需要n-1轮 for (int i 0; i n - 1; i) { // 内层循环控制每轮比较的次数 // 每轮结束后最大的数会冒泡到最后面 for (int j 0; j n - 1 - i; j) { if (arr[j] arr[j 1]) { // 交换两个元素这里也可以不用临时变量的写法 int temp arr[j]; arr[j] arr[j 1]; arr[j 1] temp; } } } }这里有两个关键点需要理解第一外层循环为什么要n-1次因为n个元素只要排好n-1个最后一个自然就归位了。第二内层循环为什么是n-1-i因为每轮结束后最大的元素已经沉底了不需要再参与下一轮的比较所以每次循环的区间都在缩小。3.2 冒泡排序的优化与性能分析基础版的冒泡排序可以加一个优化如果某一轮没有任何交换发生说明数组已经有序直接结束。public static void bubbleSortOptimized(int[] arr) { int n arr.length; boolean swapped; for (int i 0; i n - 1; i) { swapped false; for (int j 0; j n - 1 - i; j) { if (arr[j] arr[j 1]) { int temp arr[j]; arr[j] arr[j 1]; arr[j 1] temp; swapped true; } } if (!swapped) { break; // 没有交换已有序 } } }时间复杂度方面最坏情况是数组完全逆序需要比较和交换n(n-1)/2次时间复杂度O(n²)。最好情况是已经有序加上优化后只需比较一轮时间复杂度降为O(n)。平均情况还是O(n²)。对于新手来说我不建议一开始就去抠各种排序算法的最优实现而是先吃透一个最简单的冒泡排序把比较-交换-循环这套思维模式建立起来后面再学快速排序、归并排序会顺手很多。注意蓝桥杯的比赛里大数据的题目用O(n²)的排序算法经常超时Java组一般建议在数据量超过10万时改用Arrays.sort()它底层用的是优化过的快速排序。3.3 数组越界异常——新手的第一个碰壁点这个必须单独拎出来说因为几乎每个人都遇过这个报错Exception in thread main java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 5意思就是你访问了数组中不存在的下标。Java的数组索引从0开始长度为5的数组合法下标是0到4。当你试图访问第5个位置下标5时就触发了这个异常。这个报错其实是好事因为Java做了数组越界检查能及时告诉你哪里出了问题。换到C语言数组越界不报错但你可能把内存里的其他数据改掉了问题更隐蔽。养成一个好习惯遍历数组时循环条件写成i arr.length不要写成i arr.length。前者是小于长度后者会在最后一次循环时越界。3.4 用Arrays工具类提升开发效率当你会手写排序之后再用Java自带的Arrays工具类效果完全不同。你会知道它帮你封装了什么逻辑出问题时也能猜到内部是怎么处理的。import java.util.Arrays; int[] arr {5, 2, 9, 1, 7, 3}; // 排序 Arrays.sort(arr); // 底层用的是双轴快排效率很高 // 二分查找前提是数组已有序 int index Arrays.binarySearch(arr, 7); // 数组转字符串方便打印调试 System.out.println(Arrays.toString(arr)); // 数组填充 Arrays.fill(arr, 0); // 数组拷贝扩容的底层就是这个 int[] newArr Arrays.copyOf(arr, arr.length * 2);Arrays类里面还有很多重载方法支持不同类型的数组用之前看下方法签名就行。idea里按住Ctrl点方法名就能跳到源码源码看不懂没关系至少看个大概。4. 面向对象编程从照着写到按我的方式写4.1 类与对象的关系用生活例子讲清楚类与对象这个概念教科书上的定义绕来绕去我自己的理解是类是图纸对象是按照图纸造出来的实物。比如学生是一个类它规定了每个学生都应该有学号、姓名、成绩这些属性成员变量以及上课、考试这些行为方法。而张三李四这些具体的学生就是学生这个类的实例对象。代码层面是这样的// 定义图纸 public class Student { // 成员变量属性 private String name; private int age; private double score; // 构造方法创建对象时调用完成初始化 public Student() { } public Student(String name, int age, double score) { this.name name; this.age age; this.score score; } // 成员方法行为 public void study() { System.out.println(name 正在学习Java); } // getter和setter public String getName() { return name; } public void setName(String name) { this.name name; } } // 使用图纸创建实物 Student stu1 new Student(小明, 18, 88.5); stu1.study();这段代码里有个新手很难理解的地方static关键字。记住一条规则static修饰的成员属于类本身不是static的成员属于每个实例对象。main方法之所以是static是因为程序启动的时候还没有创建任何对象JVM需要直接调用它。4.2 构造方法创建一个对象时发生了什么构造方法名字和类名相同没有返回值类型。它的作用是在new对象的时候完成初始化工作。Student stu new Student(小明, 18, 88.5);这行代码在JVM内部做的事情大致是这么几步在堆内存中为对象分配空间调用构造方法完成属性的初始化返回对象的引用地址给变量stu如果没写任何构造方法编译器会自动生成一个无参构造方法但如果你写了带参构造方法而不写无参的那么无参构造就不会自动生成了。这是个特别容易踩的坑很多情况下框架底层需要调用无参构造来创建对象比如Spring的Bean实例化到时候报No default constructor错误就麻烦了。所以我的习惯是只要写了带参构造就顺手把无参构造也写上。4.3 封装为什么不让外部直接改我的属性封装是面向对象三大特性之一封装、继承、多态。直观理解就是成员变量用private修饰对外提供public的getter和setter方法。public class Student { private int age; public void setAge(int age) { if (age 0 || age 150) { throw new IllegalArgumentException(年龄不合法); } this.age age; } public int getAge() { return age; } }如果直接让外部访问age属性谁也拦不住别人给你设置一个负数。但通过setter方法你可以在赋值前加校验逻辑保证数据的安全性和合理性。新手容易有一个误解封装就是加private和getter/setter。其实封装的核心思想是隐藏内部实现细节对外暴露稳定的访问接口。getter/setter只是实现封装的一种常见手段不是全部。4.4 这个阶段的花式报错与调试技巧这个阶段最常见的几个报错逐一列一下因为这些都是我实实在在踩过的空指针异常NullPointerException出现频率最高。原因就是你调用了null对象的方法或属性。排查思路很简单看报错日志里提示哪一行出了问题然后看那一行涉及的变量是不是null。可以在关键位置打印日志或者用断点调试。编译错误Compile Error比如少了个分号、中英文标点混用、括号不匹配。IDEA里会直接红色波浪线提示鼠标放上去就能看到原因。这些错不用慌照着提示改就行。这里提醒一下写代码时尽量用英文输入法中英文标点混用是新手编译错误的头号来源。类找不到异常ClassNotFoundException一般是项目里缺依赖了或者类名拼写错了。如果是Idea里的Maven项目右键项目-Maven-Reload Project刷新一下依赖。我的排查方法先看日志第一条异常不要被后面几十行堆栈吓住。异常堆栈是按调用顺序排的最后面的异常往往是最原始的原因从下往上找定位到第一个出现异常的地方基本就是问题所在了。5. 常见问题与排查技巧实录5.1 Java环境问题速查表问题现象可能原因解决方案javac 不是内部或外部命令环境变量没配好或没刷新检查JAVA_HOME、Path配置重开命令行窗口java -version正常但javac -version报错Path里只配了java.exe的路径没配javac把%JAVA_HOME%\bin加到Path程序运行时报UnsupportedClassVersionErrorJDK版本不匹配class文件编译版本高于运行版本升级JDK或降低编译版本Windows下端口被占用SpringBoot起不来8080端口被别的程序占用了netstat -ano查端口任务管理器结束进程或改配置里的端口5.2 定时任务框架怎么选学到后面做项目了几乎躲不开定时任务这个东西。Java里常见的方案有三种JDK自带的ScheduledExecutorService适合简单的场景比如定时清理临时文件代码量很少不需要额外依赖Spring框架里的Scheduled注解Spring Boot项目里最常用的方式一个注解搞定还支持cron表达式Quartz框架功能最强支持分布式调度、任务持久化适合企业级复杂场景新手阶段我建议先搞清楚JDK自带的ScheduledExecutorService因为它能帮你理解定时任务的核心机制。用熟了再学Spring的注解会非常快。ScheduledExecutorService scheduler Executors.newScheduledThreadPool(2); // 延迟5秒后执行一次 scheduler.schedule(() - System.out.println(任务执行), 5, TimeUnit.SECONDS); // 延迟1秒开始每3秒执行一次 scheduler.scheduleAtFixedRate(() - System.out.println(周期性任务), 1, 3, TimeUnit.SECONDS);5.3 Java怎么保证数据一致性这个问题面试常考实际做项目也会遇到。新手不用钻太深但要先建立一个概念框架。一是内存可见性问题。多个线程同时访问一个变量时一个线程修改了值另一个线程可能看不到因为CPU缓存和指令重排。基础方案是用volatile关键字保证可见性或者加synchronized同步块。二是数据库事务问题。多个操作要么全部成功要么全部回滚。Java里的典型做法是Spring的Transactional注解。但要注意事务不是万能的它只能保证数据库层面的数据一致性解决不了跨系统、跨服务的数据一致性问题那个就涉及分布式事务了。三是业务层面的幂等性。比如用户重复提交订单后端要保证只创建一笔订单。常见做法前端按钮置灰、后端用唯一索引约束、或者引入状态机机制。这些内容对于新手来说可能有点远但提前知道有这么回事等你以后做项目遇到并发问题时心里就有谱了。6. 自学路上的杂谈与心得6.1 关于免费学习资源的甄别网上关于Java的免费网站和教程非常多质量参差不齐。我的筛选经验是看三点视频时长超过30分钟一集的节奏容易拖沓适合调剂不适合主学、案例是否完整只讲代码片段的学完很难串联、是否有人维护更新过时内容会严重影响入门比如还在教老掉牙的JDK7写法。文本类教程我比较推荐官方文档配合中文笔记看Java官方文档在Oracle官网可以查阅全英文看着吃力也没关系先看示例代码就行。另外像Stack Overflow、GitHub上的一些开源项目配套文档也都是很好的参考。还有一个经验学会给教程编教材。看视频的时候不要跟着敲一遍就完了而是看完之后关掉视频自己从零写一遍。能默写出来的才是你的看了会、写了忘、过几天又不会这是常态不用沮丧再来一轮就好。我在学习每个知识点后都会尝试用这个知识点改写之前写的代码比如把写成绩管理程序改成面向对象版本这比多开新项目高效得多。6.2 每天怎么安排练习量我是上班族白天基本没时间每天晚上的学习时间大概两到三小时。我的安排是30分钟复习前一天内容把前一天的代码重新敲一遍60分钟看新教程、理解新概念60分钟独立编码尽量不看教程自己写剩下的时间用来复盘和做笔记有件事我想说新手学编程的终极问题不是看不懂而是坚持不下来。我自己的心态调整方式是不追求每天学很久追求每天都有产出。哪怕今天只弄明白了一个for循环和while循环的区别那也是收获。学习过程中感到痛苦是正常的正因为暂时还不会才需要反复练习和琢磨。6.3 Java和Python、C到底选哪个很多人在学Java之前都会纠结Java、Python、C到底选哪个我个人的理解是Java胜在生态和岗位数量尤其在企业级应用后端开发领域Java是绝对的主流语言。Spring Boot框架体系非常成熟电商、金融、物流等行业的后端系统大量使用Java。Python的优势是上手快、语法简洁在数据分析、人工智能、自动化脚本方向上很强势。C的优点是性能极致适合游戏引擎、操作系统、嵌入式这些对性能要求极高的领域。三者各有优势别听人吹XX语言无敌编程语言只是工具适合自己职业方向的就是最好的。我选了Java主要看中的是它严谨的语法带来的好习惯、跨平台能力以及后端开发岗位的广阔需求。但这不代表其他人也应该学Java兴趣和方向才是第一位的。6.4 下一步的学习计划与善用的工具我给自己规划的下一阶段目标是把面向对象学透然后用集合框架重写之前的程序。具体而言ArrayList、HashMap掌握增删改查和遍历理解泛型是什么、为什么需要它用集合替代数组重写一个学生管理系统了解Java 8的Stream和Lambda这两样在真实开发中几乎是必用我在前几个月的亲身经历中可以很负责地说这些内容不是进阶技巧而是Java日常开发的日用品。很多编程题和面试题表面上考的是API用法考察的却是你对这个语言设计思路的理解。最后再分享一个我自己觉得挺有用的习惯每天整理一条今日收获笔记格式就是一句话加一段示例代码。别小看这一条笔记坚持一个月你就会拥有一份属于自己的精华知识点合集。面试前复习这份合集比翻十本教程都高效。Java这条路很长但每一步都算数。第二阶段搞定继续往前。
返回列表