/** * Exclude specific auto-configuration classes such that they will never be applied. * @return the classes to exclude */ Class<?>[] exclude() default {};
@RequestBody:用于将请求体中的数据绑定到控制器方法的参数上,通常用于接收 JSON 或 XML 数据。 @ResponseBody: 表示方法返回的对象应该直接写入HTTP响应体,而不是通过视图解析器进行渲染。
@Autowired 是 Spring 框架自带的注解用于进行依赖注入,将 Spring 托管的 bean 注入到需要它们的类中。 @Resource是 Java EE 提供的注解,用于实现依赖注入。它可以用于字段、setter 方法、构造函数等地方,用于告诉容器注入指定名称或类型的 bean。 @Bean: 用于定义Spring Bean,通常在 @Configuration 类中使用。 @Component 是 Spring 框架中用于声明一个类为 Spring 管理的组件(Bean)的注解。
@Service、@Repository、@Controller:这些注解分别用于标记服务类、仓库类和控制器类,以便 Spring Boot 可以自动扫描并创建这些组件。都属于 @Component 的衍生注解,用于更明确地表示类的职责。
Spring 是一个开源的轻量级框架,用于构建企业级 Java 应用程序。它提供了广泛的基础设施支持和许多可重用的库,以简化企业级应用程序的开发。Spring 框架的设计目标是促进松耦合、可维护性和可测试性的编码实践。 Spring的一个最大的目的就是使 JAVA EE 开发更加容易。同时,Spring之所以与Struts、Hibernate等单层框架不同,是因为Spring致力于提供一个以统一的、高效的方式构造整个应用,并且可以将单层框架以最佳的组合揉和在一起建立一个连贯的体系。可以说Spring是一个提供了更完善开发环境的一个框架,可以为POJO对象提供企业级的服务。
控制反转(IoC):Inversion of Control,指的是将对象的创建权交给 Spring 去创建。Spring 的 IoC 容器管理对象的生命周期和配置,开发者不再需要手动 new创建对象。这种反转控制的方式使得应用程序更加松散耦合、易于测试和维护。Spring 管理一切,管理项目中的对象和整合其他对象。
Spring 支持 Junit 和 TestNG 测试框架,而且还额外提供了一些基于 Spring 的测试功能,比如在测试 Web 框架时,模拟 Http 请求的功能。包含Mock Objects, TestContext Framework, Spring MVC Test, WebTestClient。
结合Spring历史版本和SpringBoot看发展
控制反转(IOC)
IoC Container管理的是Spring Bean, 那么Spring Bean是什么呢? Spring里面的bean就类似是定义的一个组件,而这个组件的作用就是实现某个功能的,这里所定义的bean就相当于给了你一个更为简便的方法来调用这个组件去实现你要完成的功能。
Ioc—Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想。 在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。
Java 线程:线程是操作系统中的基本执行单元(能够直接执行的最小代码块),是CPU调度和分派的基本单位。一个进程可包含多个线程,每个线程独立执行不同的任务,共享进程的资源。一个线程就是一个指令流,将指令流中的一条条指令以一定的顺序交给 CPU 执行。同一时刻一个CPU核心只能运行一线程,8核CPU同时可以执行8个线程代码。
join():在线程中调用另一个线程的 join() 方法,会将当前线程挂起,而不是忙等待,直到目标线程结束。 对于以下代码,虽然 b 线程先启动,但是因为在 b 线程中调用了 a 线程的 join() 方法,b 线程会等待 a 线程结束才继续执行,因此最后能够保证 a 线程的输出先于 b 线程的输出。
这里所设置的初始值通常情况下是数据类型默认的零值(如0、0L、null、false等),而不是被在Java代码中被显式地赋予的值。 假设一个类变量的定义为: public static int value = 3;那么变量value在准备阶段过后的初始值为0,而非3,因为这时候尚未开始执行任何Java方法,把value赋值为3的动作将在初始化阶段才会执行。
扩展类加载器被替换成了平台类加载器(Platform Class Loader) 平台类加载器遵循模块化方式加载字节码文件,所以继承关系从URLClassLoader变成了BuiltinClassLoader,BuiltinClassLoader实现了从模块中加载字节码文件。平台类加载器的存在更多的是为了与老版本的设计方案兼容,自身没有特殊的逻辑
空间分配担保:在发生 Minor GC 之前,虚拟机先检查老年代最大可用的连续空间是否大于新生代所有对象总空间,如果条件成立的话,那么 Minor GC 可以确认是安全的。 如果不成立的话虚拟机会查看 HandlePromotionFailure 设置值是否允许担保失败,如果允许那么就会继续检查老年代最大可用的连续空间是否大于历次晋升到老年代对象的平均大小,如果大于,将尝试着进行一次 Minor GC;如果小于,或者 HandlePromotionFailure 设置不允许冒险,那么就要进行一次 Full GC。
Full GC 的触发条件 对于 Minor GC,其触发条件非常简单:当 Eden 空间满时就将触发一次。而 Full GC 则相对复杂,有以下条件: 1.调用 System.gc() 2. 老年代空间不足 3. 空间分配担保失败 4. JDK 1.7及以前的永久代空间不足在 5. Concurrent Mode Failure
内存回收策略 Minor GC、Major GC、Full GC JVM 在进行 GC 时,并非每次都对堆内存(新生代、老年代,方法区)区域一起回收的,大部分时候回收的都是指新生代。针对 HotSpot VM 的实现,它里面的 GC 按照回收区域又分为两大类: 部分收集 (Partial GC),整收集(Full GC)。
部分收集: 不是完整收集整个 Java 堆的垃圾收集。其中又分为:
新生代收集 (Minor GC/Young GC) : 只是新生代的垃圾收集。
老年代收集 (Major GC/Old GC) : 只是老年代的垃圾收集 目前,只有 CMS GC 会有单独收集老年代的行为。很多时候 Major GC 会和 Full GC 混合使用,需要具体分辨是老年代回收还是整堆回收
左旋 对 x 进行左旋,意味着,将“x 的右孩子”设为“x 的父亲节点”;即,将 x 变成了一个左节点(x成了为 z 的左孩子)!因此,左旋中的“左”,意味着“被旋转的节点将变成一个左节点”。
右旋 对 x 进行右旋,意味着,将“x 的左孩子”设为“x 的父亲节点”;即,将 x 变成了一个右节点(x成了为 y 的右孩子)!因此,右旋中的“右”,意味着“被旋转的节点将变成一个右节点”。
添加 第一步: 将红黑树当作一颗二叉查找树,将节点插入。 第二步:将插入的节点着色为”红色”。 根据被插入节点的父节点的情况,可以将”当节点 z 被着色为红色节点,并插入二叉树”划分为三种情况来处理。 ① 情况说明:被插入的节点是根节点。处理方法:直接把此节点涂为黑色。 ② 情况说明:被插入的节点的父节点是黑色。处理方法:什么也不需要做。节点被插入后,仍然是红黑树。 ③ 情况说明:被插入的节点的父节点是红色。这种情况下,被插入节点是一定存在非空祖父节点的;进一步的讲,被插入节点也一定存在叔叔节点(即使叔叔节点为空,我们也视之为存在,空节点本身就是黑色节点)。理解这点之后,我们依据”叔叔节点的情况”,将这种情况进一步划分为 3种情况(Case) ,,, 第三步: 通过一系列的旋转或着色等操作,使之重新成为一颗红黑树。
删除 第一步:将红黑树当作一颗二叉查找树,将节点删除。这和”删除常规二叉查找树中删除节点的方法是一样的”。分 3 种情况: ① 被删除节点没有儿子,即为叶节点。那么,直接将该节点删除就 OK 了。 ② 被删除节点只有一个儿子。那么,直接删除该节点,并用该节点的唯一子节点顶替它的位置。 ③ 被删除节点有两个儿子。那么,先找出它的后继节点;然后把“它的后继节点的内容”复制给“该节点的内容”;之后,删除“它的后继节点”。 第二步:通过”旋转和重新着色”等一系列来修正该树,使之重新成为一棵红黑树。 因为”第一步”中删除节点之后,可能会违背红黑树的特性。所以需要通过”旋转和重新着色”来修正该树,使之重新成为一棵红黑树。 选择重着色 3 种情况。 ① 情况说明: x 是“红+黑”节点。处理方法:直接把 x 设为黑色,结束。此时红黑树性质全部恢复。 ② 情况说明: x 是“黑+黑”节点,且 x 是根。处理方法:什么都不做,结束。此时红黑树性质全部恢复。 ③ 情况说明: x 是“黑+黑”节点,且 x 不是根。处理方法:这种情况又可以划分为 4 种子情况。这 4 种子情况如下表所示: ,,,,
B树
B-tree 又叫平衡多路查找树。一棵 m 阶的 B-tree (m 叉树)的特性如下(其中 ceil(x)是一个取上限的函数) :
Java SE(标准版):是 Java 平台的基本版本,也是最基本的 Java 编程平台。提供了 Java 编程语言的核心功能,包括基本的语言结构、标准库、输入/输出、多线程支持等。Java SE 适用于通用的桌面应用程序、命令行工具、小型服务、移动应用程序等各种领域。
Java EE(企业版):是在 Java SE 的基础上构建的,专门用于开发和运行企业级应用程序的平台。它提供了一组扩展和 API,用于构建大型、分布式、可伸缩、高性能的应用程序,如企业级 Web 应用、电子商务系统等。Java EE 包括了 Servlet、JSP、EJB、JPA等各种技术和规范,以支持不同类型的企业级应用。
Java 是由 Sun Microsystems 公司于 1995 年 5 月推出的高级程序设计语言。Java 可运行于多个平台,如 Windows, Mac OS 及其他多种 UNIX 版本的系统。 移动操作系统 Android 大部分的代码采用 Java 编程语言编程。
概念:适配器模式就是将⼀个类的接⼝,转换成客户期望的另⼀个接⼝。 作用:可以让原本两个不兼容的接⼝能够⽆缝完成对接。 原理 or 实现:适配器实现了其中一个对象的接口, 并对另一个对象进行封装。
Java 各版本的新特性
New highlights in Java SE 8 Lambda Expressions,Pipelines and Streams,Date and Time API,Default Methods,Type Annotations,Nashhorn JavaScript Engine,Concurrent Accumulators,Parallel operations,PermGen Error Removed New highlights in Java SE 7 Strings in Switch Statement,Type Inference for Generic Instance Creation,Multiple Exception Handling,Support for Dynamic Languages,Try with Resources,Java nio Package,Binary Literals,Underscore in literals,Diamond Syntax
Java 与 C++ 的区别
Java 是纯粹的面向对象语言,所有的对象都继承自 java.lang.Object,C++ 为了兼容 C 即支持面向对象也支持面向过程。
Java 通过虚拟机从而实现跨平台特性,但是 C++ 依赖于特定的平台。
Java 没有指针,它的引用可以理解为安全指针,而 C++ 具有和 C 一样的指针。
Java 支持自动垃圾回收,而 C++ 需要手动回收。
Java 不支持多重继承,只能通过实现多个接口来达到相同目的,而 C++ 支持多重继承。
Java 不支持操作符重载,而 C++ 可以。虽然可以对两个 String 对象支持加法运算,但是这是语言内置支持的操作,非操作符重载
Java作为一门世界级主流编程语言,有一款高效易用的项目管理工具是java开发者共同追求的心原和目标。 2012年基于 Ant 和Maven产生的Gradle,弥补了不足,带来了一些更高效的特点。它使用种基于Groovy的特定领域语言(DSL)来声明项目设置,抛弃了基于XML的各种繁琐配置。面向Java应用为主。
Spring Boot 是 Spring 框架的一个扩展,旨在简化 Spring 应用程序的开发和部署。引入了 Starter 依赖的概念,这些 Starter是预配置的依赖项集合,用于快速启动特定类型的应用程序(例如,spring-boot-starter-web 是用于构建 Web 应用程序的 Starter 依赖,它包含了 Spring MVC、Tomcat 等依赖);可以根据项目需求选择性地引入 Starter 依赖,而不必手动添加一堆依赖项。
Spring全家桶:Spring Framework, Spring Boot, Spring Cloud 微服务, Spring Cloud Data Flow 客户端
Spring Framework: Spring Core - IoC, AOP 管理一切 Spring Data Access - Transactions, Spring MyBatis Web Servlet - Spring MVC Integration - Email, Scheduling, AMQP, Security
Thymeleaf(View层):模板文件 + Model -> 模板引擎(Thymeleaf) -> Html (但现在更多是前后端分离,会使用HTML+AJAX(异步请求),采用前端框架进行渲染会更好的解耦) 在controller中写一个函数,获取数据,用model封装返回给html,在html文件中链接Thymeleaf模板,将数据动态展现。
调度到主机:K8s 的调度器会根据资源需求、节点的可用资源以及调度策略(如反亲和性、亲和性等)来决定 Pod 部署到哪台主机上。你可以使用以下命令查看 Pod 所在的节点信息:kubectl get pod -n influxdb -o wide
通信调度:K8s 中,Pod 之间的通信通常通过 Service 来进行。Service 会为一组 Pod 提供一个稳定的 IP 地址和 DNS 名称。对于 InfluxDB 集群,可能会有一个或多个 Service 来管理数据节点和元数据节点之间的通信。你可以使用以下命令查看 InfluxDB 命名空间中的 Service:kubectl get svc -n influxdb
classSolution { publicintsearchInsert(int[] nums, int target) { intn= nums.length; intleft=0, right = n - 1; while (left <= right) { intmid= ((right - left) >> 1) + left; if (nums[mid] >= target) right = mid - 1; else left = mid + 1; } return l; } }
x 的平方根
1
双指针
原地移除 (快慢指针法)通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。(前后指针) 给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
1 2 3 4 5 6 7 8 9 10
intremoveElement(vector<int>& nums, int val){ int slow = 0; for (int fast = 0; fast < nums.size(); fast++) { if (nums[fast] != val) { // 此时快指针指向 新数组(原数组去除了val)中的元素 nums[slow] = nums[fast]; // 用慢指针,直接在原数组的基础上得到去除了 val 的新数组 slow++; } } return slow; }
盛最多水的容器:给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。 初始化:双指针 i, j 分列水槽左右两端;循环收窄:选定两板高度中的短板,向中间收窄一格,同时更新面积最大值 res,直至双指针相遇时跳出。
intminSubArrayLen(int target, vector<int>& nums){ int i = 0, j = 0, sum = 0, ans = INT_MAX ; // i 滑动窗口起始位置,j 滑动窗口结束位置,当前活动窗口内和 for (; j < nums.size(); j++) { sum = sum + nums[j]; // j 后移 while (sum >= target) { ans = (j - i + 1) < ans ? (j - i + 1) : ans; sum = sum - nums[i++]; // i 前移 } } // !!! O(n):不要以为for里放一个while就以为是O(n^2)啊,主要是看每一个元素被操作的次数,每个元素在滑动窗后进来操作一次,出去操作一次,每个元素都是被操作两次,所以时间复杂度是 2 × n 也就是O(n)。 return ans == INT_MAX ? 0 : ans; // 如果result没有被赋值的话,就返回0,说明没有符合条件的子序列 }
翻转字符串里的单词: 移除多余空格、将整个字符串反转、将每个单词反转 移除多余空格:参考快慢指针原地去除数组特定元素的方法(题目见) 翻转问题:考虑 部分翻转 + 整体翻转 同构字符串:需要我们判断 s 和 t 每个位置上的字符是否都一一对应,即 s 的任意一个字符被 t 中唯一的字符对应,同时 t 的任意一个字符被 s 中唯一的字符对应。这也被称为「双射」的关系。 因此,我们维护两张哈希表,第一张哈希表 s2t 以 s 中字符为键,映射至 t 的字符为值,第二张哈希表 t2s 以 t 中字符为键,映射至 s 的字符为值。从左至右遍历两个字符串的字符,不断更新两张哈希表,如果出现冲突(即遍历 s 当前下标 i 已经存在映射 s2t.get(s.charAt(i)) 且不为 t.charAt(i),或遍历 t 当前下标 i 已经存在映射 t2s.get(t.charAt(i)) 且不为 s.charAt(i))说明两个字符串无法构成同构,返回 false
int a = 65; string b = '9', s = "80"; char c = (char)a; // ASCII -> char: 65 -> '65' 类型强制转换或显式转换 char d = a + '0'; // int -> char: 65 + '0' -> '65' int e = b - '0'; // char -> int: '9' - '0' -> 9 int f = stoi(s); // string -> int string g = to_string(a); // int - > string
将短数扩展为机器处理的长度:参与算术运算的只有5种类型数据 char、short -> int,unsigned char、unsigned short -> unsigned int,float -> double、long、unsigned long
使运算符两端的操作数具有相同的类型: “向高看齐”,向表达能力强的类型转换;逐个算符转换
运算符的优先关系
单目运算符 > 乘除运算 > 加减运算 > 关系运算 > 逻辑与 > 逻辑或 > 赋值 > 逗号
i + 1 < j * 4 && ! P || Q 等价于 : ( ( ( i +1 ) < ( j * 4 ) ) && ( ! P ) ) || Q
P != i < j || Q && S 等价于 : ( P != ( i < j ) ) || ( Q && S )
自增、自减
前缀式:先增值后引用 例:x = ++ i 相当于 i = i + 1 ; x = i ;
后缀式:先引用后增值 例:x = i ++ 相当于 x = i ; i = i + 1 ;
自增、自减算符的运算对象只能是整型变量,不能为常量或表达式
位运算
16进制表示: 0xff -> 1111 1111
1 2 3 4 5 6 7
int a = 5, b = 3; // a 二进制: 0101, b 二进制: 0011 int andResult = a & b; // 0001 (1) 按位与 `&` int orResult = a | b; // 0111 (7) 按位或 `|` int xorResult= a ^ b; // 0110 (6) 按位异或 `^` int notA = ~a; // 1010 (-6 in two's complement representation) 按位取反 `~` int leftShift = a << 1; // 1010 (10) 左移<<:将操作数的每个位向左移动指定的位数,右侧用零填充 int rightShift= a >> 1; // 0010(2) 右移>>:每个位右移指定位数,左侧用符号位(对于有符号数)或零填充
程序控制结构
所有程序都只能包含三种控制结构:顺序结构、选择结构和循环结构
if 语句,while语句,do-while语句,for语句
switch语句:根据一个整型表达式的值决定程序分支
1 2 3 4 5 6
switch(表达式) { case 常量表达式 1 : 语句 1// case 标签是用来匹配 switch 后面表达式的值,执行相应的代码 … case 常量表达式 n : 语句 n default : 语句 n+1// 如果没有任何一个 case 匹配成功,用 default 标签来执行默认的操作 }