2027届_怀瑾
技术栈测试
1、学Java看的哪个资料:学校的资料
- 重载,重写,泛型懂吗?前两个学过但是忘了
- Java集合这块学过了吗?
- HashMap源码,JVM,JUC是否看过:
2、数据结构与算法看的哪个资料: 学校的资料
- 链表,栈,队列,二叉树能自己手写吗: 学过但是不扎实
- AVL树,红黑树,线段树学过吗:
- 冒泡,快速,归并排序能手写吗: 学过
- 递归,二分,贪心,回溯,动规,枚举这几种算法学过哪几种: 学过前两个
- LeetCode 大概刷了多少题: 123道,断断续续的来回刷,但是每次都会忘记
3、框架与中间件
- servlet,cookie,session学过吗:
- SSM学过了吗:
- redis 学过吗:
- SpringBoot项目做过几个:
4、MySQL看的哪些资料:学校的资料
– sql 熟练吗: **leetcode关于sql初始的题刷过33道,但是忘了
– 索引底层原理懂吗:
5、计算机基础
- 计算机网络看什么资料:学校的书籍(计算机网络谢希仁第八版)
- 操作系统看什么资料:学校的书籍
- 计算机组成原来看的什么资料:学校的书籍
学习规划
一些链接入口
课程大纲: 所有课程大纲入口 ,PS:你要的东西,课程大纲基本都会有哈,需要学啥记得来课程大纲看看。
你的大致情况分析与规划
首先你拥有的时间非常多,但是你的目标其实不是很明确,不过帅地作为过来人,先帮你铺垫一下以后工作相关的东西,未来无论你是要去银行国企,去开发岗,去数据分析,去卷大厂,都来得及。
也就是说,平时学业上你就跟着学业,业余时间想学什么可以和我商量,然后挪出一部分时间,来学习我这边安排的内容。
近期总体规划:语言上选择 Java + Python,就是Python你应该会经常用到,但是得深入掌握一门开发语言,一般就是C++,Go,Java,这里推荐Java,可以干的事情多。
未来一年目标:跟着刷算法,学习 Java,跟着做一些项目,以及过一过核心八股文原理。
研0阶段具体学习计划安排(2023.10.10)
接下来系统学习一下各方面内容
1、Java理论:学校的Java讲的太浅了,咱们学深入一点,直接学习Java基础 ,懂的跳过即可,然后学习 Java进阶吧,Java进阶那里,源码分析有点难,可以跳过哈,问题不大的,。
划重点:为了学习更快,请学习的时候,按照我网站的说明来,每个目录都会说明需要掌握哪些,该跳过的就跳过哈,按照最低的要求来学就行,项目实战可以做一下哦。
配套练习(必做比做):你学到对应模块的时候,可以在牛客网这里刷刷题:Java语法刷题,相当于熟悉一下基本语法。视频的练习你可做可不做,但是这个配套练习必须做哈。
时间安排:这个课程比较系统和深入,推荐 2 个月完成。
2、刷算法:就按照 我这个课程刷就行:拿捏算法面试课程,这个可以好好刷一下,无论哪个岗位都会考察。
时间推荐:每周 10+题。
3、做一做项目:学完 1之后,你可以直接跟着这个路线学:web学习路线整合(框架+项目),做一做项目,就是先过一下技术栈,后面你想做其他的,也方便你做抉择。
时间推荐:推荐去读研之前,把这些过一遍吧,这样有个大概的认知。
学习顺序
学习顺序:两条线学,1=》3一条线,2是一条线。
就行先安排这么多,然后记得来每周打卡学习进度哈,也可以星球每天打卡哦,我会看的,比如像他们这样:0. 每周打卡做的比较好的成员示例,你也可以每天打卡或者星球打卡吧,我会看的
有什么问题记得随时私聊帅地
每周学习记录
2023.10.18 这一个周看了Java基础4节视频并做了总结,按顺序依次刷了10道算法题,将其算法思想以及时空复杂度也做了总结。因为有三个大的课程设计作业需要完成,所以这周完成的内容较少,下一个周会全身心投入计划当中。
2023.11.2 打算先以毕业论文为主,目前在大佬的指导下正在调研;计划两周看完Java基础后,完成一个Web项目(赶上同一起跑线上的同学的步伐)。
2024.11.13
break、continue、return
- break结束外层循环,开始执行循环之后的代码;
- continue跳过本次循环,接着开始下一次循环;
- return 退出所在方法;
数组
// 创建 赋值
int[] arr1 = {7, 5, 6};
// 未赋值
int[] arr2 = new int[3];
数组在创建后就不能修改大小
long[] arr = new long[10];
arr = new long[25]; //arr在栈区先指向一个大小为10的内存空间,后指向重新创建的一个大小为20的内存空间
排序
冒泡排序
// 遍历数组的过程中将当前顺序下的最大值调换至末尾;
// 外层循环每执行一次说明数组需要排序的次数减一
int[] arr = {3, 1, 4, 9, 2};
for(int i = 0; i < arr.length - 1; i++){
for(int j = 0; j < arr.length - i; j++){
if(arr[i] > arr[i+1]){
int temp = arr[i+1];
arr[i+1] = arr[i];
arr[i] = temp;
}
}
}
11.14
类与对象
关系
类:涵盖对象的所有属性和行为(方法)
对象:具体实例
内存分配
内存布局
- 类的具体实例(对象)存储在栈,属性中基本数据类型的内存分配在堆;引用类型(如字符串)的数据空间内存实际存储在方法区的常量池中,其地址存储在堆。
-
对象被创建时,就会在方法区加载其属性和行为信息
方法
调用机制
主函数存储在栈空间,当执行到方法时,就会在栈中开辟一个独立空间:基本数据类型采用值拷贝传递。当方法执行到return语句时返回到主函数调用方法的地方,继续执行之后的语句。
传参机制
场景:主函数中调用一个交换基本数据类型的函数,主函数中的基本数据类型值不变。
形参的任何改变不会影响到实参
12.9
克隆
浅克隆与深克隆的区别
浅克隆:拷贝了原来的对象中的变量,但是仍然存在引用变量是同一个并未独立的关联;
深克隆:新对象和原来的对象是两个独立的对象,只是属性相同。
递归
// 阶乘
public int fac(int n){
if(n == 1){
return 1;
}
else return fac(n - 1) * n;
}
//斐波那契求和
public int fibo(int n){
if(n == 1 || n == 2){
return 1;
}
else {
return fibo(n - 1) + fibo(n - 2);
}
}
public static void main(String[] args) {
int sum =0;
for(int i = 1; i <= n; i++){
sum += fibo(n);
}
printf("fibo前n项的和为:"+sum);
return 0;
}
方法重载
方法名称可以相同但要求形参列表不一致。
可变参数
是为了简化同名同功能仅参数个数不同的方法设置的。
public int varparameters(int length, int... nums);
// nums的本质数组;
// 其中形参列表只能出现一个可变参数;
// 可变参数可以和普通类型的参数一起放在形参列表,但可变参数需要放在末尾
作用域
全局变量和局部变量的区别
- 全局变量(属性)有默认值,可以不赋值直接使用;
- 局部变量没有默认值,必须先赋值再使用。
- 全局变量(属性)可以加修饰符;局部变量不可以。
变量的作用范围
- 局部变量和全局变量重名时,遵循就近原则;
- 全局变量通过对象调用既能被本类使用,又能被其他类使用;
- 局部变量只能在本类中对应的方法中使用;
变量的生命周期
- 全局变量(属性)生命周期随着对象的创建而创建,随着对象的销毁而销毁;
- 局部变量生命周期在一次方法的调用过程中创建、销毁。
构造器
作用
在创建对象时,系统会自动调用构造器完成对新对象的初始化
class Person{
String name;
int age;
public Person(String name, int age){ // 与类名同名
this.name = name;
this.age = age;
}
}
this
含义
对象调用构造器时this就代表该对象的全局变量(属性),与局部变量区分开来。
1.9
this和super的比较
- this访问本类的属性和方法,若本类没有则从父类中继续查找;super访问父类中的属性和方法;
- this调用本类的构造器,super调用父类的构造器,二者都必须放在构造器的首行;
- this表示当前对象;super是在子类中访问父类对象。
包
作用
- 区分相同名字的类
- 控制访问范围
- 便于管理类
封装
定义:将属性设置为私有,只能通过内部定义的getter和setter方法来获取
继承
定义:当多个类(子类)中存在相同属性和方法时,将这些提出到单独的一个类(父类)中,子类只需extends(继承)父类即可,无需定义
多态
定义:
方法的多态:即重写和重载;
对象的多态:同一个方法,使用不同的对象来执行不同的操作。
Animal animal = new Dog();//编译类型不可改变,为Animal
animal.cry();
Animal animal = new Cat();//运行类型可以改变,用以实现多态
animal.cry();
注意:
- 向上转型:多态在遵守访问权限的情况下,可以调用父类的所有成员,但不能调用子类的特有的成员(过不了编译阶段,因为在编译阶段,能调用哪些成员,是由编译类型来决定的)。
- 向下转型:
// 子类类型 引用名 = (子类类型) 父类引用;
Cat cat = (Cat) animal; // 向下强转后,此时对象可以调用特有的成员
属性的多态:属性没有“重写”,其值只跟编译类型有关
instanceof //判断运行类型是否是该类或该类的子类
面向对象的三大特性
封装、继承、多态
和equals的对比
- 可判断基本类型的值是否相等,也可判断引用类型是否是同一个对象
- equals 只能判断引用类型
equals和HashCode的对比
- HashCode只需利用公式将内存地址转换为一个hash值就能比较,效率较高,但不完全可靠(不同对象生成的hashcode可能会重复);
- equals在HashCode判断为true后作进一步判断来使用
讲一下equals()与hashcode(),什么时候重写,为什么重写,怎么重写?
2025.2.25
类变量
int count = 0; //实例变量,对象独享
public static count = 0; //类变量(静态变量),对象共享
类方法
注意事项
- 不允许使用和对象有关的关键字,比如this和super;
- 只能访问静态变量/方法
- 普通变量/方法只能通过对象来访问
代码块
定义
可以对构造器进行初始化,后执行构造器的内容,但优先级低于super();
public class Code {
public static void main(String[] args){
Hi hi = new Hi("你好"); // 每创建一个对象就执行一次代码块
}
}
class Hi {
private String name;
}
{
System.out.println("didadida");
}
public Hi(String name){
System.out.println("判断代码块是否可以先对构造器进行初始化");
this.name = name;
}
单例模式
饿汉式步骤
- 私有化构造器
- **随着类的加载,在其内部创建一个static对象 **
- 提供一个public的static方法,返回static对象
懒汉式
只有当用户使用getInstance时才创建并返回static对象,后面再次调用时会返回首次创建的static对象,从而保证单例模式。
final
注意事项
- 可重新赋值的位置有:定义时、代码块中、构造器中
- 若final修饰的是静态属性,那么初始化的位置只能是前两个,
- final + static 搭配创建对象,可以避开类的加载
抽象类abstract
出现原因
方便设计者后续对没有实现的方法
(抽象方法)进行实现
注意事项
- 不能被实例化,即不能创建对象;
- 不一定要包含abstract方法;
- 一旦类中包含了abstract方法,该类必须被声明为abstract;
- 只能用于修饰类和方法;
- 方法被abstract修饰后,不能被实现;
- 当一个类继承了abstract类,则必须实现所有abstract方法,除非该类也声明为abstract类
9、抽象类和接口的区别;
11、抽象方法能不能加final;
接口
可包含
- 抽象方法
- 默认实现方法
- 静态方法
alt+enter 快捷实现普通类实现接口所有public方法(抽象)
细节
- 一个类可以实现多个接口
- 接口中的属性只能是final,而且是 public static final 修饰符
- 接口不能继承类,但是可以继承多个接口
- 接口的修饰符只能是public 和 默认, 这点和类的修饰符是一样的(???)
- 具有多态特性
接口与继承的比较
1. 继承是为了解决代码的复用性和可维护性,子类继承后,就可拥有父类的功能;
1. 接口是设计好各种抽象方法,便于让其他类去实现,更加灵活;是对单继承机制的一种补充。
内部类
局部内部类
细节
- 是定义在外部类的局部(如方法中),因此可以直接访问外部类的所有成员;
- 不能添加访问修饰符,因为其类似于局部变量,但可以用final修饰(不可被继承);
- 作用域仅在定义局部内部类的方法或代码块中(???)
- 如果外部类和局部内部类的成员重名时,访问时默认遵循就近原则,如果想访问外部类的成员,可以使用外部类名.this.成员去访问;
匿名内部类
细节
- 是一个没有类名的定义在外部类的局部(如方法中)的类,同样也是一个对象;
- 其余细节见上述四条;
f1(new IL() {
@override
public void show(){
System.out.println("当作实参传递,更加简洁高效");
}
});
// 传统方法是创建一个类后,再创建一个对象去调用方法;
成员内部类
细节
- 是定义在外部类的成员位置上的类,没有static修饰;
- 可以添加修饰任意访问修饰符,因其类似于成员;
- 可以直接访问外部类的所有成员;
- 如果外部类和成员内部类的成员重名时,访问时默认遵循就近原则,如果想访问外部类的成员,可以使用外部类名.this.成员去访问;
- 外部其他类访问成员内部类的两种方式:
// First--利用外部类声明的对象去声明成员内部类
Outer outer new Outer();
Outer.Inner inner = outer.new Inner();
// Second--外部类返回成员内部类的对象
public Inner getInnerInstance(){
return new Inner();
}
静态内部类
细节
- 是定义在外部类的成员位置,并且有static修饰;
- 可以直接访问外部类的所有静态成员;
- 可以添加任意访问修饰符,其类似于成员;
- 作用域是整个类
枚举
定义
一组常量的集合
Enum Week{
Monday("星期一"), Tuesday("星期二"), Wederday("星期三");
private Week(String name){
this.name = name;
}
private String name;
public String getName(){
return name;
}
}
注解
三种基本的Annotation
- @Override:表明该方法是重写的父类方法;
- @Deprecated:表明某个程序元素已过时;
- @SuppressWarnings:抑制编译器警告
异常
五种运行时异常
- NullPointerException 空指针异常
- ArithmeticException 数字运算异常
- ArrayIndexOutBoundsException 数组下标越界异常
- ClassCastException 类型转换异常
- NumberFormatException 数字格式不正确异常
掌握异常种类,比如一种是 error,一种是 exception,知道他们的区别,以及能够举例对应的例子
异常处理
- 编译异常,在程序中必须使用try-catch或throws进行处理;
- 运行异常,如果程序不处理,那么默认是throws处理;
throw与throws的区别
- throws是异常处理的一种方式,位于方法声明处,后面紧跟异常类型;
- throw是手动生成异常对象的关键字,位于方法体中,后面紧跟异常对象;
包装类 — 八种基本数据类型相应的引用类型;
装箱
Object obj = true ? new Integer(1) : new DOuble(2.0);
// 三元运算符,须看作一个整体,因此obj的值为1.0(当前最高精度是double)
Integer缓存的数值范围是[-128,127]
String类
StringBuffer — 多线程
与String的相互转换
String str = "halo";
// First 构造器
StringBuffer stringbuffer = new StringBuffer(str);
// Second append
StringBuffer stringbuffer = new StringBuffer();
stringbuffer.append(str);
StringBuffer stringbuffer = new StringBuffer("哈喽");
// First 构造器
String str = new String(stringbuffer);
// Second toString
String str = stringbuffer.toString();
StringBulider — 单线程
线程不安全的原因
append方法中没有限定synchronized,致使程序可以并行操作。
String、StringBuffer、StringBuilder的区别
- String:不可变字符序列,效率低(做大量修改时,会导致大量副本字符串对象因丢弃而存留在内存中,影响程序性能),但复用率高(变量存放在常量池中,值相同的变量指向同一处);
- StringBuffer:可变字符序列,效率较高(增删),线程安全;
- StringBuilder:可变字符序列,效率最高,线程不安全。
Vector 和 ArrayList的比较
- Vector属于可变数组,线程安全,但效率不高(synchronized),其扩容倍数有两种方式:使用无参构造器创建数组时,默认容量是10,满后2倍扩容;使用有参构造器创建指定大小数组时,按2倍扩容;
- ArrayList属于可变数组,线程不安全,但效率高,其扩容倍数有两种方式:使用无参构造器创建数组时,默认容量为,第一次扩容到10,从第二次起1.5倍扩容;使用有参构造器创建指定大小数组时,按1.5倍扩容。
Arraylist和LinkList的比较
- ArrayList由于需要扩容的原因致使在增删的效率较低,但其改查的效率较高(索引定位);
- LinkList是双向链表,线程不安全,增删上可通过链表追加而效率较高,但其改查的效率较低(从头追查)。
HashSet
HashSet的底层维护了一个HashMap。
HashSet hashSet = new HashSet();
// 底层
public HashSet() {
map = HashMap<>();
}
扩容机制
第一次添加,扩充table容量为16,阈值(threshold)为12(16*0.75);超过阈值后2倍扩容。
Map
Map map = new HashMap();
四大遍历方式
- 先取出所有的Key,通过Key取出对应的Value;
Set keyset = map.keySet();
for(Object key : keyset) {
System.out.println(key + "-" + map.get(key));
}
- 迭代器
Iterator iterator = keyset.iterator();
while(iterator.hasNext()) {
Object key = iterator.next();
System.out.println(key + "-" + map.get(key));
}
- 通过EntrySet来获取
Set entrySet = map.entrySet();
for (Object entry : entrySet) {
Map.Entry m = (Map.Entry) entry;
System.out.println(m.getKey() + "-" + m.getValue());
}
- 迭代器
Iterator iterator = entrySet.iterator();
while(iterator.hasNext()) {
Object next = iterator.next();
Map.entry m = (Map.Entry) next;
System.out.println(m.getKey() + "-" + m.getValue());
}
public classHashMapSource2 {
public static void main(stringl args)
HashMaphashMap=new HashMap();
for(inti=1;i<=12;i++){
hashMap.put(new A(i),"hello");
}
}
}
classA{
private int num;
public A(int num) {
this.num = num;
}
@Override
public int hashCode(){
return 100;
}
}
HashTable
细节
- 键和值不能为null,否则会抛出NullPointerException;
- 线程安全(synchronized),而HashMap是线程不安全的;
- 初始容量为11,阈值为8(11*0.75),超过阈值后2倍+1进行扩容。
应用场景
- 判断存储类型(一组对象(单列)或一组键值对(双列));
- 单列:Collection接口
2.1 允许重复:List
2.1.1 增删多:LinkedList(底层是双向链表);
2.1.2 改查多:ArrayList(底层是Object类型的可变数组);
2.2 不允许重复:Set
2.2.1 无序:HashSet(底层是HashMap — 数组+链表+红黑树)
2.2.2 排序:TreeSet(底层是TreeMap,将比较器传入有参构造器中,指定排序规则)
2.2.3 插入和取出顺序一致:LinkedHashSet(底层是LinkedHashMap -- 数组+双向链表)
- 双列: Map
3.1 键无序:HashMap(底层是哈希表 — 数组+链表+红黑树)
3.2 键排序:TreeMap
3.3 键插入和取出顺序一致:LinkHashMap(底层是HashMap)
3.4 读取文件:Properties
泛型
List<Integer> list = new ArrayList<>();
细节
- 给泛型指向的数据类型必须是引用类型,不能是基本数据类型;
- 给泛型指定具体类型后,可以传入该类型或者其子类类型(extends);
- 使用泛型的数组不能被初始化;
- 静态方法不能使用类的泛型。(在类加载时对象尚未创建,因此JVM不能确定,不能初始化)
互斥锁
细节
- 同步方法(非静态的)的锁可以是this,也可以是其他对象(要求是同一个对象);
// First
public synchronized void sell(){}
// Second
public void sell(){
synchronized(this){}
}
// Third 针对同一个对象创建的多线程
Object object = new Object();
public void sell(){
synchronized(object);
}
- 同步方法(静态的)的锁为当前类本身。
class Sell implements Runnable {
// First
public synchronized static void m1() {}
// Second
public static void m2() {
synchronized (Sell.class){}
}
}