一、系统温习------黑马程序员Java+AI智能辅助编程全套视频教程
程序流程控制
程序的三种执行顺序:顺序结构、分支结构、循环结构。
分支结构
If语句中如果只有一行代码,大括号可以省略不写。
If分支结构可以根据条件,选择执行某段程序。
Switch分支结构是通过比较值是否相等,来决定执行哪条分支。
Switch分支先执行表达式的值,再拿着这个值去与case后的值进行匹配。与哪个case后的值匹配为true就执行哪个case块的代码,遇到break就跳出switch分支。如果全部case后的值与之匹配都是false,则执行default块的代码。
If在功能上远远强大于switch。
当前条件是区间 的时候,建议使用if分支结构来实现。
当条件是与一个一个的值比较 的时候,建议用switch更合适。
Switch的表达式类型只能是byte、short、int、char、JDK5开始支持枚举,JDK7开始支持String。不支持double、float、long。
case给出的值不能重复,且只能是字面量,不能是变量。
正常使用switch时不要忘记break否则会出现穿透现象。
穿透性的作用:相同程序的case块,可以通过穿透性进行合并,从而减少重复代码。
循环结构
for循环控制一段代码反复执行很多次。减少代码的重复编写,灵活控制程序的执行。

while循环

for循环和while循环功能上是完全一样的。
使用规范:知道循环几次使用for;不知道循环几次使用while。
do-while循环:先执行后判断,一定会执行一次。

for和while循环都是先判断后执行 ,do...while循环时先执行后判断。
for循环中,控制循环的变量只在循环内 使用;while循环中,控制循环的变量在循环后还可以继续使用。
死循环的写法:
死循环的用途:服务器程序

循环嵌套的特点:外部循环每循环一次,内部循环会全部执行完一轮。
break和continue
break:跳出并结束当前所在循环的执行。
continue:用于跳出当前循环的当次执行,直接进入循环的下一次执行。
案例
计算器案例中接收用户输入的操作数和操作符,设计运算方法,其中采用switch分支结构单值匹配,根据不同操作符做不同的运算,返回结果。
猜数字游戏中先通过**(int)Math.random()** +1或者通过Random类得到一个随机数对象调用对象的nextInt(100) 方法+1得到一个1-100的随机整数。(random生成的随机数包前不包后 )然后设计猜数字的逻辑,通过死循环使得游戏在猜对之前一直不终止 。循环里根据if条件语句判断 用户猜的数字与真实数字的偏差,并给出过大或过小的提示 ,仅当猜对时才打印并break跳出循环结束游戏。 补充:生成65-91 之间的随机数èint num =r.nextInt(27)+65
开发验证码定义一个字符串变量用于记录生产的验证码。循环n次,每次生成一个验证码并连接到字符串变量中。循环中先生成一个随机的数字,0、1、2分别表示数字、大写字母、小写字母,使用switch单值判断来划分3种情况,数字可以直接随机生成只要限定0-9的范围即可,而大小写字母通过字符编号进行随机。如char ch =(char)('A'+(int)(Math.random()*26)) 'A' 65 -- 'Z' 65+25
找素数,素数是只有1和它本身两个正因数的自然数,大于1的自然数。先定义一个方法来判断是否为素数:用一个for循环,循环边界是参数的开平方,在循环体中判断从2到边界是否存在一个数满足参数与之取余等于0即参数可以整除其中的一个数,若存在则该数不为素数,如果循环结束仍未返回,则返回真表示该数是素数。最后遍历要求的区间并通过判断方法来筛选出素数并打印。
程序的数据存储
数组
对于类型相同的大批量数据,使用数组进行存储,明显优于用多个变量进行存储!
静态数组的定义:数据类型[ ] 数组名 = {元素1,元素2,...};
静态初始化数组,定义时已经确定了数据。
数组的访问:数组名[索引];数组的长度:数组名.length
数组变量存储的是数组对象的地址信息
动态初始化数组:只确定数组的类型和存储数据的容量,不事先存入具体的数据。
动态初始化数组格式:数据类型[ ] 数组名 = new 数据类型[长度];
动态初始化数组boolean数组的默认值是false ;类,接口,数组,String的默认值是null

此处每次遍历用一个变量来接收每次遍历的值有利于减少对数组的访问,否则每次使用到变量都要去访问数组,造成时间开销。
案例:简易斗地主的做牌和洗牌
做牌:动态初始化一个长度为54的数组准备存牌,准备4种花色以及12种点数存放到静态数组中,遍历点数再遍历花色进行牌的拼装,拼装后将牌放入起始动态初始化的数组中(需要定义一个变量来记录牌存储的索引位置),最后单独存放大小王。
洗牌:把数组中的牌打乱顺序。遍历54个位置,每次遍历随机生成两个索引,并将这两个随机索引对应数组位置的牌进行交换。交换时引入临时变量进行。
二维数组
数组中的每个元素都是一个一维数组,这个数组就是二维数组。
静态初始化:数据类型[ ][ ] 数组名 = {{ },{ },{ } ...};
动态初始化:数据类型[ ][ ] 数组名 = new 数据类型[长度1][长度2];
二维数组的访问:数组名称[行索引] 或 数组名称[行索引][列索引]
数组名.length访问行数。数组名[行索引].length访问某一行中的列数。
二维数组的遍历:

打乱二维数组中元素的顺序:遍历二维数组,内层遍历中每次生成一个随机数当作随即行,再生成一个随机数当作随机列,再借助一个临时变量将i行j列位置的数据与随机行随机列所指定位置的数据进行交换。
二、刷选择题------牛客网Java题组
集合类ArrayList、LinkedList、HashMap描述
ArrayList是基于数组 实现的,在中间位置插入或删除元素时需要移动后续元素。
LinkedList是基于链表 实现的,只需要改变相关节点的引用即可。
HashMap实现了Map接口,它的键和值都可以是任意类型的对象 ,且允许null作为键或值 。一个HashMap最多只能有一个键为null的映射。
ArrayList适合随机访问和遍历操作 ,LinkedList适合频繁的插入和删除操作。
注释嵌套
/*....*/注释中不能再嵌套/*...*/注释。
/*...*/注释中可以包含//注释。
字符串比较和对象引用

equals方法比较的是字符串的内容而不是引用。
==比较引用
String类型的equals方法只能用来比较String对象,不能直接与char数组比较。
"hello"是字符串字面量 ,Java会将其存入字符串常量池 。s和t都指向常量池中的同一个对象 ,所以地址相同。
Java多线程编程---ThreadLocal

ThreadLocal确实是线程局部变量 ,为每个使用该变量的线程提供独立的变量副本 。这种机制确保了线程之间的数据隔离 ,每个线程只能访问自己的变量副本。
ThreadLocal的set()方法的工作机制:
-
首先获取当前线程对象
-
从线程对象中获取ThreadLocalMap
-
如果map存在则更新 值
-
如果map不存在则创建 新的ThreadLocalMap并设置初始值
ThreadLocal并不会随着线程的结束自动销毁 。如果不正确处理ThreadLocal,可能会导致内存泄露 。主要原因是ThreadLocalMap中的Entry是弱引用,而Value是强引用 ,如果不主动调用remove()方法清理,即使线程结束,这些对象也可能无法被垃圾回收。
过度使用ThreadLocal确实会带来较大的内存开销 ,因为:
-
每个线程都会维护一份变量副本
-
线程数量越多 ,内存占用就越大
-
ThreadLocal数量过多会降低程序性能
Java的严格面向对象特性

Java是纯面向对象语言,所有代码必须定义在类中,不存在独立的"过程"或"函数"。
方法必须隶属于类或对象,不能单独存在。
非静态方法属于实例成员(对象),而静态方法才属于类成员。
Java需通过类名(静态方法)或对象(实例方法)调用。
三、刷面试陈述题------面试鸭
Java面向对象编程与面向过程编程的区别是什么?
面向过程是一步一步的执行,以过程作为基本单元来组织代码,函数和数据分离。关注逻辑的分步实现。
面向对象是先抽象,把事物分类得到不同的类。把类或对象作为基本单元来组织代码。划分每个类的职责,暴露出每个类所能执行的工作,执行时调用每个类的方法即可不必关心内部的逻辑。关注对象之间的关系和交互。运用封装、继承和多态作为代码设计指导。
面向对象优点:高复用性、扩展性、维护性强、适合复杂系统的开发。
面向对象缺点:开发和理解成本较高,对于简单项目比较繁琐。
面向过程优点:开发简单,代码执行速度块,适合小型项目。
面向过程缺点:可维护性查,代码复用性低,扩展性差。
Java方法重载和方法重写之间的区别
方法重载在同一个类 中,允许有多个同名方法 ,只要参数列表不同 。适用于同一类中同一操作的不同实现 。定义不同场景下的行为(不同类型输入的不同处理) 。返回类型可以不同 ,不受访问修饰符影响。
方法重写:子类在继承父类时,可以重写父类的某个方法 。适用于子类改变父类方法的实现,实现运行时多态性 。子类方法的访问修饰符不能比父类更严格。
什么是Java内部类?它有什么作用?
Java内部类指在一个类的内部定义的类。包括成员内部类、局部内部类、匿名内部类和静态内部类。内部类可以访问外部类的成员变量和方法。
内部类的作用:封装性(将逻辑相关的类封装在一起,提高类的内聚性);访问外部类成员、简化代码(减少冗余代码)、事件处理(匿名内部类广泛用于实现回调函数或事件监听,简化代码结构)

内部类是一个编译层面的概念,编译后内部类会提升为外部顶级类,在JVM中没有内部类的概念。
class Main {
// 外部类的private成员
private int num = 10;
public static void main(String[] args) {
// 先创建外部类Main的实例(匿名内部类依赖外部类实例)
Main outer = new Main();
// 真正的匿名内部类:嵌套在main方法里,实现Runnable接口
Runnable r = new Runnable() {
@Override
public void run() {
// 匿名内部类访问外部类Main的private成员 → 编译通过!
System.out.println(outer.num);
}
};
r.run(); // 输出10
}
}
