每日总结 Day 2 (不知道能坚持几天)


11.30


早上起来有点难受,去校医院发现有点发低烧,应该是宿舍交叉感染了,大伙要做好防护



Java八股文10:00-12:15

JDK、JRE、JVM


  1. JDK是java开发工具包,是功能齐全的JAVA SDK(软件开发工具包,能够帮助开发者快速进行开发,可以理解为Utils)里面包括了Java编译器(javac)、java调试器、JAVA核心API、JRE等开发工具,用于进行JAVA开发使用
  2. JRE是JAVA运行环境,提供在计算机上运行java程序所需的最小运行环境
  3. JVM是java虚拟机,作用是将javac编译生成的字节码文件转换为电脑能够识别的机器码,并且负责程序的执行
  4. Java开发⼯具包=Java 运⾏环境+Java开发⼯具
  5. Java 运⾏环境=Java虚拟机+Java核⼼类库
  6. 执行步骤
  7. 编写JAVA程序(.java)需要JDK
  8. 将编写好的.java程序编译成.class的字节码 需要JDK中的javac
  9. 字节码转换为机器能够识别和执行的机器码 需要JVM
  10. 操作系统执行机器码,则需要JRE



字节码


字节码是 Java 程序编译后的中间代码,是⼀种可移植的⼆进制代码,可以在任何⽀持 Java 虚拟机(JVM)的平台上运⾏。字节码通过将 Java 源代码编译为字节码指令序列,使得 Java 程序可以跨平台运⾏,即使是在不同的操作系统和硬件平台上也可以运⾏。


  1. 可移植性:Java程序通过编译形成的字节码(.java->.class),可以在任何的JVM上运行,使得程序有可移植性,这也是java跨平台的重要特征
  2. 安全性:由于字节码需要在JVM中运行转换,所以对字节码进行安全检查,即可确保程序不会对系统构成威胁
  3. 性能:字节码是一种紧凑的二进制格式,相比于直接编译为机器码,可以更快的加载和传输,同时可以在运行时进行动态优化,提高执行效率
  4. 可读性:相比于机器码更易读,可以进行反编译和调试



final的作用


  1. 对于修饰类:可以让类无法被继承,且该类的方法都是默认final关键字,所以无法对类的方法进行重写
  2. 对于修饰方法:表示该方法无法被子类进行重写
  3. 对于修饰变量:表示该变量只能被赋值一次,且不能再次修改,如果定义的时候没有进行赋值,那么只有在类的构造函数中才能初始化
  4. 具体作用
  5. 安全性:确保被final修饰的变量不会再次改变
  6. 可读性:将常量修饰为final可以提高可读性,因为常量的值也不会被修改
  7. 优化:final 变量在编译时被转换成常量,这可以提⾼程序的性能



equals、hashCode、==


  1. hashCode没有equals可靠,所以equals为true,hashCode一定相等,反之不能推导(有hash碰撞之类的)
  2. equals方法默认使用的是==操作符,所以要两个对象引用指向的是同一个对象的时候才会返回true,大部分情况下会重写对象的equals进行自定义比较
  3. ==操作符对于基本类型进行比较值是否相等,对于引用类型,用于比较两个对象的引用是否相等,即比较两个变量引用是否指向同一个对象。
  4. equals用于比较两个对象的值是否相等,对象的值⽐较往往需要根据对象的实际情况来定义,因此⼀般需要重写 equals ⽅法。如果不进行重写,那么本质上还是进行的==比较,因为每个类都继承了Object类,其中的equals方法就是进行的==比较。
  5. 总结:
  6. 如果两个对象equals相同,hashCode⼀定相同
  7. 如果两个对象equals不同,hashCode不⼀定不同
  8. 如果两个对象的hashCode相同,它们的equals并不⼀定相同
  9. 如果两个对象的hashCode不相同,它们的equals⼀定不相同
  10. 为什么要重写equals的时候要重写hashCode
  11. 重写equals是进行对象的内容的自定义比较,即两个内容相同的类要返回true
  12. 重写hashCode是为了保证内容相同的类返回相同的Hash值 Object.hash() 进行重写
  13. 因为在使用散列表数据结构的时候



public、private、protected、NULL



反射


Java反射(超详细!)_一个快乐的野指针~的博客-CSDN博客



力扣 13:10-14:55

1657. 确定两个字符串是否接近 中等


  1. 思路:对于第一个交换判断,直接把字符串变成字符数组,然后用Arrays.sort最后用Arrays.equals对数组内的元素进行比较是否相等。对于第二个判断,因为字符串中的都是小写字母,所以初始化两个new int[26]用于统计每一个字符串的具体字母的个数,然后进行一个遍历要是word1有的word2没有或者反过来,那么就返回false,然后再对数组进行排序,最后然后返回比较结果
  2. 注意点:第二个的判断可以抽象成为比较字母数量,也就是说一个字母的有2个,两个字母的有几个这意思,还需要额外判断两个集合所包含字母的种类是一样的。
package com.Ewan.每日一题;
/*
* @Author Ewan
* @Date 2023/11/30
* @Description:
*/
/**
* 1657. 确定两个字符串是否接近
* 提示 中等
*/
public class CloseStrings {
public boolean closeStrings(String word1, String word2) {
if (word1.length() != word2.length()) return false;
//第一种操作
char[] word1CharArray = word1.toCharArray();
char[] word2CharArray = word2.toCharArray();
Arrays.sort(word2CharArray);
Arrays.sort(word1CharArray);
if (Arrays.equals(word1CharArray, word2CharArray)) return true;
//第二种操作
int[] memo1 = new int[26];
int[] memo2 = new int[26];
for (int i = 0; i < word1CharArray.length; i++) {
int num1 = word1CharArray[i] - 'a';
memo1[num1]++;
int num2 = word2CharArray[i] - 'a';
memo2[num2]++;
}
for (int i = 0; i < memo1.length; i++)
if ((memo1[i] == 0 && memo2[i] != 0) || (memo1[i] != 0 && memo2[i] == 0)) return false;
Arrays.sort(memo1);
Arrays.sort(memo2);
return Arrays.equals(memo1, memo2);
}
}



121. 买卖股票的最佳时机 简单


  1. 只能买一次,因为有两个状态:持有,不持有,所以需要定义一个二维dp
package com.Ewan.动态规划.股票;
/*
* @Author Ewan
* @Date 2023/11/30
* @Description:
*/
/**
* 121. 买卖股票的最佳时机
* 简单
*/
public class MaxProfit {
public int maxProfit(int[] prices) {
int[][] dp = new int[prices.length][2];
//0表示不持有 1 表示持有
dp[0][0] = 0;
dp[0][1] = -prices[0];
for (int i = 1; i < prices.length; i++) {
dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i]);
//前一天持有的 或者 今天持有的 取一个最大的
//只能买卖一次!!所以取一个持有的最大值,也就是最便宜的时候买
//因为只能买卖一次 所以每次买入的时候的初始值是0 这就是和II的区别点
dp[i][1] = Math.max(dp[i - 1][1], 0 - prices[i]);
}
return dp[prices.length - 1][0];
}
}



122. 买卖股票的最佳时机 II 中等


  1. 这里和I的不同点就在于可以进行多次交易,所以在dp[i] [1]的递推公式上有点不一样,可以是前一天未买的状态 - 今天买入
package com.Ewan.动态规划.股票;
/*
* @Author Ewan
* @Date 2023/11/30
* @Description:
*/
/**
* 122. 买卖股票的最佳时机 II
* 中等
*/
public class MaxProfitII {
public int maxProfit(int[] prices) {
int[][] dp = new int[prices.length][2];
//0表示不持有 1 表示持有
dp[0][0] = 0;
dp[0][1] = -prices[0];
for (int i = 1; i < prices.length; i++) {
//昨天不持有 和 昨天持有今天卖出
dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i]);
//昨天不持有今天买入 和 昨天不持有
//这样就表示可以多次买入卖出 和这个就是和I的区别点
dp[i][1] = Math.max(dp[i - 1][0] - prices[i], dp[i - 1][1]);
}
return dp[prices.length - 1][0];
}
}



123. 买卖股票的最佳时机 III 困难


  1. 这道题拿到就是懵的,至多交易两次?不知道如何控制这个状态
  2. 后面看视频才晓得,就是多定义几个状态dp[i] [5]
  3. 0:不进行任何操作
  4. 1:第一次持有的最大利润
  5. 2:第一次卖出的最大利润
  6. 3:第二次持有的最大利润
  7. 4:卖出的最大利润
  8. 这样一分,思路就一下清晰了,和前两个题还是一样的套路,由于可以多次买入,所以要和前一天的比较取一个最大值
  9. dp[i] [1] 这个表示的不是非要在第i天持有,也可以是之前就买了的,一直传递过来的状态
  10. 初始化:初始化还是有点怪,一开始做的时候我就初始化了dp[0] [1]没有意识到可以当天买然后又当天卖这个点


今天的力扣就做到这里了捏 ~ ~ ~



写报告15:10-15:20


写个要交的作业报告



设计模式15:10-17:43 19:40-21:40

设计模式

设计模式的目的


  1. 代码重用性(重复功能的代码,不用重新编写)
  2. 可读性(程序员的统一规范,让别人也能看懂你的代码)
  3. 可扩展性(当出现新的需求的时候能够扩展功能)
  4. 可靠性(新扩展的功能不会对原有功能影响)
  5. 使程序呈现高内聚、低耦合的特性(低耦合:功能之间的依赖性不高不会互相影响。高内聚:模块外部是高内聚的)


设计模式的七大原则

单一职责原则


  1. 概念:对类来说,每个类只负责某一个职责。如果A类即负责A1这个职责又负责A2这个职责,那么当职责1需求变动的时候可能会影响到A2,所以这里要细分职责,分为A1和A2两个类,遵循单依职责原则。
  2. 注意事项:
  3. 降低类的复杂度,每个类只负责一个职责
  4. 提高类的可读性和课维护性
  5. 降低变更带来的风险(每个类只负责一个职责所以在修改的时候不会影响到其他的类)
  6. 通常情况下应当遵守单一职责原则,只有在某些情况逻辑足够简单,才能在代码层面违反单一职责原则;只要类中的方法足够少,那么可以在类方法中实行单一职责原则



接口隔离原则


  1. 概念:客户端不应该依赖他不需要的接口,即一个类对另一个类的依赖(使用)应该建立在最小的接口上
  2. 即一个类对接口的使用时,只会用到这个接口的几个方法,那么这时候就把这个接口拆分
  3. 场景引入


依赖倒转原则


  1. 概念
  2. 高层模块不应该依赖低层模块,二者都应该依赖其抽象
  3. 抽象不应该依赖细节,细节应该依赖抽象
  4. 依赖倒转(倒置)的中心思想是面向接口编程
  5. 依赖倒转原则是基于这样的设计理念:相对于细节的多变性,抽象的东西要稳定的多。以抽象为基础搭建的架 构比以细节为基础的架构要稳定的多。在 java 中,抽象指的是接口或抽象类,细节就是具体的实现类
  6. 使用接口或抽象类的目的是制定好规范,而不涉及任何具体的操作,把展现细节的任务交给他们的实现类去完成
  7. 依赖关系的三种传递方式
  8. 接口传递
  9. 构造函数传递
  10. setter传递
  11. 情景1:传统的模式,人要接受QQ调用QQ的发送信息功能。这种设计扩展性不高,需要改动的多,如果现在要用WX来发送消息,这种模式就得创建一个WX的类,然后又需要在Person类中重新定义一个方法
static class QQ {
public void getInfo() {
System.out.println("this message is from qq");
}
}
static class Person {
public void receive(QQ qq) {
qq.getInfo();
}
}
public static void main(String[] args) {
Person person = new Person();
person.receive(new QQ());
}
  1. 解决方法:引入一个抽象的接口 IReceiver, 表示接收者, 这样 Person 类与接口 IReceiver 发生依赖
static interface IReceiver {
void getInfo();
}
static class QQ implements IReceiver {
@Override
public void getInfo() {
System.out.println("this message is from qq");
}
}
static class WX implements IReceiver {
@Override
public void getInfo() {
System.out.println("this message is from WX");
}
}
static class Person {
public void receive(IReceiver receiver) {
receiver.getInfo();
}
}
public static void main(String[] args) {
Person person = new Person();
person.receive(new QQ());
person.receive(new WX());
}
  1. 从这个情景中可见在拓展WX这个业务的时候,并没有多原有的代码进行更改,而是直接写了一个WX的类去实现IReceiver
  2. IReceiver这个接收器就是抽象出来的,他并不管你用什么东西来发送,不管你是如何实现细节的
  3. 即抽象(IReceiver)不依赖细节(QQ、WX),细节(QQ、WX)依赖抽象(IReceiver)


  1. 注意事项
  2. 层模块尽量都要有抽象类或接口,或者两者都有,程序稳定性更好
  3. 变量的声明类型尽量是抽象类或接口, 这样我们的变量引用和实际对象间,就存在一个缓冲层,利于程序扩展 和优化
  4. 继承时遵循里氏替换原则



总结


今天还是学到挺多东西的,发现自己很多比较基础的东西都忘记了,是要得好好补一补

本来是打算寒假试试找实习了,仔细想了想,我感觉目前还是得以学技术为主要的(而且大家都说寒假实习挺少机会的),很多东西都不了解比如并发编程、JVM、Netty、设计模式这种,然后就是很多东西学过的都忘记了比如Spring的AOP、反射这类的知识,当时学就没有太过于认真,导致遗忘的挺多的,以后学习新知识还是得做做笔记,一来可以巩固记忆,二来可以打起精神(纯看视频的话是真的很不容易吸收)

明日计划

  1. 继续做股票的动态规划部分
  2. 设计模式剩余四个原则的学习
  3. 锻炼(今天有点烧没去,明天一定去!)


好了今天就这样了 睡觉了


0个评论
点击登录,快来和大家讨论吧~
表情
图片
暂无评论
EWAN
下载 APP