算法,八股
Contents
算法
美团技术岗笔试
python
输入输出
|
|
https://blog.csdn.net/m0_72538340/article/details/131012294
map:在Python中,map()
是一个内置函数,它可以将一个函数应用于一个序列(例如列表或元组)的每个元素,并返回一个新的序列,其中包含每个元素应用函数后的结果。
|
|
https://blog.csdn.net/guan022/article/details/115293946
输入一行:input(),str类型
输入的一行有多个信息:input().split(),一个接收是list元素是str,多个接收是每个str
有多组测试用例(多组同时输入):
while true:
try:
xxx
except:
break
for line in sys.stdin: #多行用例 print(line)# 键盘输入,包含回车 a = line.split()# 列表,str
list a[0]第一位,a[-1]最后一个
lower():str中大写变小写、upper()变大写
https://www.bilibili.com/video/BV1144y1c7ef?p=2&vd_source=ad42090d7d6fcdfc144126ae0e2884ac
前缀和的思想?
**strip()
**是Python中字符串对象的一个内置函数。它用于去除字符串开头和结尾的指定字符(默认情况下是空格字符)。
Python的内置函数**abs()
**。该函数返回一个数的绝对值。
二维前缀和,二维前缀和的作用就是快速计算区块和,行列的下标都从1开始
|
|
矩阵联通块:上下左右四个方向相邻阳的相同字符是连通的。
请在所有可能的矩阵种找到一个权值最小的矩阵,并输出权值。
枚举+bfs广度优先搜索
|
|
deque
是一个双端队列(double-ended queue)的实现,具有在两端高效地进行插入和删除操作的特性。通过使用 deque
,可以方便地实现需要在两端频繁插入和删除元素的场景,例如队列、栈等数据结构的实现。
append(x)
:将元素x
添加到双端队列的右侧。appendleft(x)
:将元素x
添加到双端队列的左侧。pop()
:从双端队列的右侧移除并返回一个元素。popleft()
:从双端队列的左侧移除并返回一个元素。extend(iterable)
:在双端队列的右侧追加可迭代对象iterable
中的所有元素。extendleft(iterable)
:在双端队列的左侧追加可迭代对象iterable
中的所有元素。clear()
:清空双端队列中的所有元素。len(d)
:返回双端队列d
的长度。
树上染色 树形DP动态规划
dp*[*i][0] 表示以 i 为子树,不选择 i 这个节点进行染色,i 这棵子树可以染色的结点最大数量
dp*[*i][1] 表示以 i 为子树,对 i 这个节点进行染色,i 这棵子树可以染色的结点最大数量
|
|
美团笔试
笔试:题型和上述题型类似,但只做出来了1和26.6-2 和16.6-3
不知道后续会不会有面试,也不清楚我通过笔试是因为内推还是真的就是都有
如果没面试机会,希望春招的时候可以再次参与笔试。
关于笔试,有朋友帮助,但是我还是自己做,按自己的思路进行,再辅以答案
一向如此,可能有答案在我面前,我也会按自己的思路取走,然后再去修正或者是执拗的去继续按照自己的思路,我觉得这是 我的妥协中的小倔强吧,我认为是。
接下来就是同步进行考公和刷题和面经
加油
在人才市场成为人才。
中国铁塔笔试
\1. 写一个程序,输入一个数字n,然后输出1到n的所有整数。 2. 写一个程序,输入一个数字n,然后计算并输出1到n的所有整数的和。 3. 编写一个函数,接受一个整数列表作为参数,并返回其中最大的数。 4. 写一个程序,输入一个英文字符串,然后将该字符串中的每个单词反转并输出。 5. 编写一个函数,接受一个长度为n的整数数组,然后返回该数组中的所有元素之和。
|
|
|
|
|
|
|
|
|
|
for (int num : arr)
是 Java 中的增强型 for 循环,也被称为 for-each 循环。它用于遍历数组或集合中的元素,可以在不知道数组或集合长度的情况下方便地对其中的元素进行访问。具体来说,
for (int num : arr)
中的int num
表示对数组arr
中的每个元素进行迭代访问,并将当前迭代的元素赋值给num
。这样,在循环体内就可以直接使用num
来访问数组中的元素,而不需要使用索引来访问。
"\\s+"
表示一个或多个空白字符(空格、制表符、换行符等)。因此,split("\\s+")
的作用是将句子分割成多个单词,并将这些单词存储在words
数组中。
1.在一个1到100之间的整数序列中,除了一个数字出现了两次外,其他数字都只出现了一次。请写一个算法,找出那个重复出现的数字。 2. 给定一个数组arr,其中包含1到100之间的无重复整数,现在将其中一个数字删除,然后将剩下的数字重新排序,得到新的数组arr'。请找出被删除的数字。 3. 给定一个有序数组arr,其中包含1到100之间的无重复整数,现在要求将其中其中一数字替换成另一个数字,并且保持数组有序。请设计一个算法来实现这个要求。 4. 给定一个整数数组arr,其中包含重复数字,要求使用最少的额外空间来找出这些重复数字。 5.在一个1到100之间的整数序列中,有两个数字出现了两次,其他数字都只出现了一次。请写一个算法,找出这两个重复出现的数字。 6. 给定一个整数数组arr,其中包含重复数字,要求找出所有重复数字并且统计它们的出现次数。 7.给定一个字符串s,其中包含大小写字母、数字和特殊字符。请编写一个函数,对s进行加密,将其转换成一个新的字符串。加密规则为将每个字符的ASCII码加上一个固定值,然后再将结果转换成对应的ASCII字符。 8.给定一个字符串s,其中包含大小写字母、数字和特殊字符,请编写一个函数,将s中的英文单词逆序排列。 9. 给定一个整数数组arr和一个目标值target,要求从arr中找到两个数字,使得它们的和等于target。请设计一个算法来实现这个要求,并返回这两个数字的下标。 10. 给定一个整数数组arr,其中包含若干个数字,要求找出其中出现次数最多的数字。如果有多个数字出现次数相同,则返回其中任意一个数字。
\1. 什么是栈?栈的特点是什么? 2. 什么是队列?队列的特点是什么? 3. 什么是链表?链表和数组有什么不同? 4. 什么是树?树的几个重要概念是什么? 5. 什么是哈希表?哈希表的特点是什么?
|
|
\1. 什么是虚拟内存?它的作用是什么? 2. 什么是死锁?死锁的原因是什么? 3. 什么是进程?进程和线程有什么区别? 4. 什么是文件系统?文件系统有哪些重要概念? 5. 什么是虚拟机?虚拟机的作用是什么?
|
|
|
|
笔试真题
美团
1、小美拿到了一个大小为n的数组,她希望删除一个元素,使得剩余元素之和不小于x。 小美想知道,有多少种不同的删除方案? 输入描述 第一行输入两个正整数n和x。第二行输入n个正整数ai,代表数组的元素。 1≤n≤105 1≤a≤104 1≤x≤10 输出描述 一个整数,代表删除的方案数。
3 7
3 4 3
2 说明 删除第一个或者第三个元素都可以。
|
|
–
2、小美拿到了一个数组,她可以进行最多一次操作:选择两个元素 ai和aj,使得ai加1,aj减1 小美希望最终数组所有元素的乘积尽可能大。你能帮帮她吗? 输入描述 第一行输入一个正整数n,代表数组的大小。 第二行输入n个正整数ai,代表数组的元素。 输出描述
输出描述 最终的最大乘积 由于答案过大,请对10^9+7取模
3
3 1 6
30
|
|
–
3、小美拿到了一个字符串s,她准备按以下的规则生成一个字符串t 1.首先令t等于s 2.若s不为空,删除s最后一个字符,然后将剩下的字符加入t的后缀。 3.若s不为空,删除s第一个字符,然后将剩下的字符加入t的后缀。 4.若s不为空,回到第二步,否则结束。 操作结束后,小美有若干次询问,每次查询t的第x个字符是多少。
输入描述 第一行输入两个正整数n,q,代表字符串s的长度,以及询问次数。
第二行输入一个长度为n的、仅由小写字母组成的字符串,代表字符 s 接下来的q行,每行输入一个正整数x,代表一次查询。 1≤n,q≤105 输出描述 输出q行,每行输出一个小写字母代表查询的答案。 输入 32
abc
2
5
输出
b
b
说明:输出的字符串为abcabb
|
|
中华财险技术笔试
java
1、java中哪些类型的变量不能被赋值为null
基本数据类型不能赋值为null;只有引用类型,如对象数组,可以被赋值为null
静态变量(类变量)和成员变量(实例变量)都是引用类型(Reference types),因此它们可以被赋值为null。
2、super,this关键字
用于引用对象的特定类型
super:引用父类的成员使用 super
关键字可以在子类中引用父类的成员(方法、属性),包括在子类中被隐藏的同名属性或方法。
调用父类构造函数在子类构造函数中,可以使用 super()
来调用父类的构造函数。这通常用于子类需要在构造过程中执行父类特定的初始化操作。
this:引用当前对象使用 this
关键字可以在类的成员方法中引用当前对象。
解决命名冲突,this
可以用来区分成员变量和局部变量,当它们同名时,使用 this
可以指代当前对象的成员变量。
总的来说,super
用于与父类有关的操作,包括引用父类的成员和调用父类的构造函数,而 this
则用于当前对象的操作,包括引用当前对象的成员和解决成员变量与局部变量之间的命名冲突。
最佳实践是将 super()
或 this()
调用放在构造函数的第一行,以确保正确的对象初始化。
super()
和 this()
可以同时出现在一个构造函数中。这种情况通常发生在需要调用另一个构造函数或者需要引用当前对象的情况下。
当两者同时出现时,需要注意以下几点:
- 构造函数中只能出现一个显式的调用:在一个构造函数中,只能显式调用
super()
或this()
中的一个,因为它们都需要作为构造函数的第一条语句。 - 隐式调用:如果在构造函数中没有显式调用
super()
或this()
,Java会在构造函数的第一行自动插入一个无参的super()
调用。 - 先调用super(),再调用this():如果在一个构造函数中显式调用了
this()
,那么它必须是构造函数的第一条语句,而在**this()
**调用的构造函数中也可能含有**super()
**调用。
|
|
在上述示例中,无参的构造函数中显式调用了有参的构造函数 this(0)
,而有参的构造函数中又显式调用了 super()
,这种情况是允许的。
在Java中,super
和 this
关键字在静态环境中(例如静态方法和静态语句块)是不允许使用的。这是因为这两个关键字是用来引用对象实例的,而在静态环境中,并不存在具体的对象实例,因此无法使用 this
和 super
。
3、java classloader
Java中的ClassLoader是Java虚拟机(JVM)的一个子系统,它的主要作用是动态加载Java类到JVM中。
作用:
- 加载类文件:ClassLoader负责将类文件加载到内存中,使得Java程序能够使用这些类。
- 类隔离:不同的ClassLoader加载的类相互隔离,每个ClassLoader都有自己的命名空间,从而避免类名冲突。
- 动态更新:允许在运行时动态地加载新的类,这在一些框架和应用程序中具有重要作用,比如插件系统。
特点:
- 层级结构:ClassLoader以层级结构组织,形成父子关系,当子ClassLoader需要加载类时,会先委托给父ClassLoader来尝试加载,只有在父ClassLoader无法加载时,子ClassLoader才会尝试加载类。
- 双亲委派模型:基于双亲委派模型,每个类加载请求都会被委托给父ClassLoader,只有在父ClassLoader无法完成加载时,子ClassLoader才会尝试加载。这样做可以保证类加载的一致性和避免重复加载。
- 自定义ClassLoader:允许开发人员自定义ClassLoader,以满足一些特殊的加载需求,比如从网络中加载类,或者对类进行加密保护等。
ClassLoader在Java中起着至关重要的作用,它不仅实现了Java程序的动态性,同时也保证了类的安全性和隔离性。
在Java中,默认提供了三个主要的ClassLoader,Bootstrap ClassLoader,Extension ClassLoader,System ClassLoader。
当JVM判定两个class是否相同时,不仅要判断类名是否相同,还要考虑类加载器。在Java中,类的唯一性是由类加载器和类的全限定名(包括类的包名)共同决定的。
4、sleep()方法和wait()方法
- 所属类:
- **
sleep()
方法属于Thread
类,而wait()
方法属于Object
**类。
- **
- 调用方式:
- **
sleep()
方法是静态方法,可以直接通过Thread.sleep()
**调用。 - **
wait()
方法则需要在同步上下文(即synchronized
**块或方法)中调用。
- **
- 释放锁:
- 当线程调用**
sleep()
**方法时,它不会释放持有的任何锁。 - 当线程调用**
wait()
**方法时,它会释放对象上的锁,并进入等待状态。
- 当线程调用**
- 唤醒条件:
- 线程调用**
sleep()
**方法后会在指定时间后自动唤醒,或者可以通过**interrupt()
**方法提前唤醒。 - 线程调用**
wait()
**方法后,需要通过其他线程调用对象上的**notify()
**或**notifyAll()
**方法来唤醒它。
- 线程调用**
- 它们都涉及线程的暂停和恢复操作,用于线程之间的协调和同步。
5、抽象类
抽象类是用于包含抽象方法的类,无法被实例化。抽象类使用**abstract
**关键字来定义,它可以包含抽象方法和具体方法。子类必须实现抽象类中的所有抽象方法才能实例化。
抽象类的主要作用是作为其他类的父类,提供一组通用的方法和属性,并定义一些抽象方法,让子类去实现这些抽象方法。
抽象类可以有构造方法,但是它们不能被用来实例化抽象类本身。构造方法在抽象类中的作用是初始化实例变量或执行其他必要的操作。子类在实例化时会调用父类的构造方法来初始化父类的实例变量。
抽象类必须提供至少一个抽象方法。抽象方法是在抽象类中声明但没有实现的方法,它不包含方法体。抽象方法的存在使得抽象类本身无法被实例化,因为抽象类中的抽象方法必须由子类实现后才能使用。
有抽象方法的类不一定是抽象类(抽象类的子类),但是只有抽象类才能包含抽象方法。一般类可以包含抽象方法,但它必须标记为抽象类。抽象类可以包含抽象方法,也可以包含具体方法。另一方面,普通类不能包含抽象方法,因为抽象方法必须在抽象类中。
6、ThreadLocal
ThreadLocal
是 Java 中的一个类,它提供了线程局部变量的支持。使用 ThreadLocal
可以让每个线程都拥有自己独立的变量副本,互不影响。这在多线程环境下非常有用,可以避免线程间的数据共享问题。
通过 ThreadLocal
,每个线程可以像使用普通变量一样操作自己的局部变量,而不必担心线程安全性。
ThreadLocal 采用线程隔离的方式存放数据。每个 ThreadLocal 实例都为每个线程提供了一个独立的变量副本,这意味着每个线程都可以独立地操作自己的局部变量,而不会受到其他线程的影响。当一个线程访问 ThreadLocal 的 get()
方法或set()
方法时,实际上是操作了当前线程的局部变量,这种方式实现了线程之间数据的隔离,从而避免了线程安全性问题。
在Java 9中,引入了 ThreadLocal
的 remove
方法,它可以用来删除当前线程的局部变量值。调用 remove()
方法后,当前线程对应的局部变量会被清除,这样可以帮助减少内存泄漏的风险。
7、权限修饰符
操作修饰符 | 本类内部 | 本包内 | 其他包的子类 | 其他包非子类 |
---|---|---|---|---|
private | √ | |||
缺省(default) | √ | √ | ||
protected | √ | √ | √ | |
public | √ | √ | √ | √ |
8、==
和 equals
在Java中,==
和 equals
是用于比较对象的两种不同方式。
==
比较的是对象的引用,即判断两个对象是否指向同一个内存地址。如果比较的是基本数据类型,则比较它们的值。equals
是用于比较对象的内容是否相等,它是一个方法,可以被重写。在**Object
**类中,**equals
**方法默认是使用**==
**比较对象的引用
9、多线程
多线程是指在同一个进程内同时执行多个线程的能力。每个线程都可以独立执行不同的任务,但它们共享同一个进程的内存空间和资源。多线程可以提高程序的并发性能和响应速度,常用于并发处理、异步编程和提升系统性能等方面。
10、str.substring()的取值范围
str.substring()
方法用于从指定的开始索引到结束索引截取字符串。其取值范围是从开始索引处的字符(包括)到结束索引前的字符(不包括)
11、java object默认的基本方法
Java中,**Object
**类默认包含以下基本方法:
equals(Object obj)
: 用于判断对象是否相等。hashCode()
: 返回对象的哈希码值。toString()
: 返回对象的字符串表示。getClass()
: 返回对象的运行时类。clone()
: 用于创建并返回对象的副本。finalize()
: 当对象被垃圾回收器回收时调用。notify()
,notifyAll()
,wait()
: 用于实现线程间的通信。wait()导致当前线程等待,直到其他线程调用此对象的notify(),notifyall().- 不包含copy()方法
12、nginx.log
nginx.log通常是Nginx Web服务器生成的日志文件,记录了服务器的访问日志、错误日志等信息。
|
|
13、String框架的持久化支持方法
Java中的String类是不可变的,因此并不需要专门的持久化支持方法。如果您需要将String对象持久化到文件或数据库中,您可以使用常规的持久化技术,如文件I/O或数据库操作。
在JDBC中,通常会使用String来表示和处理数据库中的文本数据,但String并不是JDBC的一部分,也没有直接封装JDBC的数据操作
Spring对各种持久化技术提供了统一的编程方式
14、CMS垃圾回收器
CMS垃圾回收器通常指的是内容管理系统的垃圾回收机制,用于清理不再需要的或过时的内容和资源,以节省存储空间和优化系统性能。不过,这与编程语言中的垃圾回收器不同,后者用于自动回收不再使用的内存。
15、JVM堆内存
JVM(Java Virtual Machine)中的堆内存被分为两个主要区域:新生代(Young Generation)和老年代(Old Generation)。这种分区的目的是为了更有效地管理内存和进行垃圾回收。
新生代主要用来存放新创建的对象。由于大多数对象在创建后不久就会变为不可达(即成为垃圾),因此新生代是垃圾收集发生最频繁的区域。新生代又进一步细分为三个区:Eden区、SurvivorFrom区和SurvivorTo区。
老年代主要存放那些经历了多次GC仍然存活的对象,或者是在新生代中分配空间不足而直接分配到老年代的大对象。由于老年代中的对象生命周期较长,因此Major GC(也称作Full GC)在老年代中发生的频率相对较低。但每次Full GC都会暂停所有的应用线程,因此其执行时间相对较长,对系统性能的影响也较大。
JVM(Java Virtual Machine)中的HotSpot是Oracle JDK和OpenJDK的默认虚拟机,也是目前使用最广泛的JVM实现之一。HotSpot虚拟机通过即时编译(JIT,Just-In-Time)技术,将热点代码(即频繁执行的代码)编译成机器码,从而提高了Java程序的执行效率。
新生代与老年代的比例是1:2。新生代内部又被细分为Eden区和两个Survivor区(通常命名为S0和S1)。在HotSpot虚拟机中,Eden区与Survivor区的默认比例是8:1:1。
16、?三元运算符
条件 ? 表达式1 : 表达式2
int max = (a > b) ? a : b;
17、ArrayList
在Java中,当你使用ArrayList
并初始化其指定容量为10时,这并不意味着ArrayList
只能存储10个元素。实际上,这个容量只是ArrayList
的内部数组的初始大小。当你试图添加第11个元素时,ArrayList
会自动进行扩容。
添加元素导致当前容量不足时,ArrayList
通常会将其内部数组的大小增加大约50%。它会创建一个新的更大的数组,将原数组的内容复制到新数组中,然后丢弃原数组,以便为新的元素腾出空间。这个过程被称为数组的扩容或再分配。
在创建 ArrayList
时,虽然不强制要求指定初始化容量,但根据实际应用场景,有时指定一个合适的初始化容量可以提高性能。当你预计 ArrayList
将存储大量元素,并且你知道大致的数量时,指定初始化容量可以避免在添加元素过程中频繁的扩容操作,这可以减少内存分配和数组复制的开销。
|
|
18、元注解:
Java元注解(Meta-Annotation)是用于修饰其他注解的注解。它们提供了定义注解时的一些通用属性和行为。
@Target
用于指定注解的使用范围,即该注解可以被用于哪些Java元素上,例如类、方法、字段等
@Retention
用于指定注解的生命周期,即该注解会被保留到哪个阶段。
RetentionPolicy.SOURCE
:注解只在源码阶段存在,编译时会被丢弃。RetentionPolicy.CLASS
:注解在类文件中可用,但会被JVM丢弃。RetentionPolicy.RUNTIME
:注解在运行时也保留,因此可以通过反射读取。
@Documented
表示使用该注解的元素应该被javadoc或类似工具文档化。简单来说,如果一个注解类型被声明为@Documented,那么使用了此注解的Java元素在使用javadoc生成API文档时,注解将被包含在生成的文档中。
@Inherited
元注解是一个标记注解,如果它存在于一个被用于类的注解类型上,那么这个注解将被自动继承给子类的成员。但是要注意,继承性并不具备传递性,如果一个类使用了一个有@Inherited注解的注解类型,这个类的子类将继承这个注解,但是这个类的孙子类不会继承这个注解。
注解:
Java的注解(Annotation)是Java 5开始引入的一种用于为代码提供元数据的机制。注解本质上是一种接口,它提供了一种为程序元素(类、方法、变量、参数和包等)附加信息的方式,而这些信息并不会直接影响代码的执行,但可以被编译器用来生成代码、进行编译检查,或者在运行时由JVM或其他工具读取并进行相应的处理。
- 元数据:注解为代码提供了额外的信息,这些信息并不直接参与程序的执行逻辑,但可以被其他工具或框架用来生成代码、检查代码或执行其他任务。
- 与注释的区别:注解与Java的注释不同,注释是给程序员看的,而注解是给编译器或其他工具看的。编译器会处理注解,而忽略注释。
- 定义:注解使用
@interface
关键字定义
19、锁升级:
在Java中,锁升级通常与synchronized
关键字以及Java HotSpot JVM的实现相关。synchronized
关键字在Java中用于提供线程同步,它背后的机制依赖于JVM的实现。在某些JVM实现(如Java HotSpot VM)中,为了优化性能,当synchronized
块或方法被争用时,锁的状态可能会经历一个“升级”过程。
Java HotSpot VM的锁升级通常涉及以下状态:
- 无锁状态:这是锁的初始状态,当没有线程持有锁时,锁处于无锁状态。
- 偏向锁:这是锁的第一次优化状态。偏向锁的目标是减少无竞争情况下的同步开销。当一个线程首次访问同步块并获取锁时,JVM会记录锁的持有者,并在后续访问中偏向这个线程,从而避免不必要的锁获取和释放操作。如果其他线程尝试获取偏向锁,偏向锁就会被撤销并升级到轻量级锁。
- 轻量级锁:当多个线程试图同时访问同一个同步块时,锁可能会升级到轻量级锁状态。轻量级锁通过自旋等待(busy-waiting)的方式尝试获取锁,而不是立即阻塞线程。如果自旋等待一段时间后仍然无法获取锁,轻量级锁会升级为重量级锁。
- 重量级锁:当轻量级锁的自旋等待无法解决问题时,锁会最终升级为重量级锁。重量级锁通常涉及操作系统层面的同步机制(如互斥锁),并且当线程无法获取锁时会阻塞。重量级锁的开销相对较大,因为它涉及到线程的挂起和恢复。
互斥锁(Mutex,全称Mutual Exclusion Lock)是一种基本的同步原语,用于在并发编程中保护共享资源,防止多个线程同时访问同一资源,从而导致数据不一致或其他并发问题。当一个线程获得互斥锁时,其他尝试获取该锁的线程将会被阻塞,直到持有锁的线程释放该锁。
互斥锁通常具有以下特性:
- 互斥性:在任何时刻,只有一个线程可以持有互斥锁。这确保了同一时间只有一个线程能够访问被保护的共享资源。
- 原子性:锁的获取和释放操作是原子的,即这些操作不会被其他线程中断。这保证了线程安全地获取和释放锁。
- 非忙等待:当一个线程试图获取一个已被其他线程持有的互斥锁时,该线程通常会被阻塞(即进入等待状态),而不是忙等待(即持续检查锁是否可用)。这允许线程在等待期间释放CPU资源,从而提高了系统的整体效率。
- 可重入性:某些互斥锁实现允许同一个线程多次获取同一把锁而不会引起死锁,这种锁被称为可重入锁或递归锁。
- 公平性:某些互斥锁实现会确保等待时间最长的线程优先获得锁,这被称为公平锁。然而,并非所有的互斥锁实现都是公平的,有些实现可能采用非确定性策略来分配锁。
20、支持反射:
Java是一种支持反射(Reflection)的语言。反射是Java语言的一个强大特性,它允许程序在运行时检查类、接口、字段和方法的信息,并且允许程序动态地创建和操作对象。这种动态性为Java提供了极大的灵活性和扩展性。
- 获取类的信息:通过反射,可以获取一个类的Class对象,进而获取该类的名称、父类、实现的接口、声明的字段和方法等信息。
- 动态创建对象:使用反射,可以在运行时动态地创建类的实例,而无需提前编写具体的类名。
- 调用方法:通过反射,可以获取一个类的方法信息,并动态地调用该方法,传递参数并获取返回值。
- 操作字段:反射允许程序获取类的字段信息,并可以动态地读取和修改字段的值。
反射虽然强大,但也有一些缺点。比如性能开销较大,因为反射涉及到动态类型解析和内存分配等操作;另外,反射破坏了封装性,因为它允许程序直接访问类的内部结构和成员。
JAVA反射主要涉及的类包括Class
、Field
、Method
和Constructor
。这些类都位于特定的包下,以便有效地组织和使用。通过这些类,Java的反射机制能够在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够动态调用它的任意方法和属性。这为Java提供了丰富的动态性支持,使得程序能够在运行时根据需要进行灵活的调整。虽然反射机制提供了很大的灵活性,但它也有一些缺点,比如性能开销较大,破坏了封装性等。
- Class类:这是反射的核心类,它位于
java.lang
包下。通过Class
类,我们可以获取类的属性、方法等信息,这是实现反射机制的关键。 - Field类:这个类位于
java.lang.reflect
包下。它表示类的成员变量,通过Field
类,我们可以获取和设置类中的属性值。 - Method类:同样,
Method
类也位于java.lang.reflect
包下。它表示类的方法,通过Method
类,我们可以获取类中的方法信息或者执行方法。 - Constructor类:这个类也位于
java.lang.reflect
包下。它表示类的构造方法,通过Constructor
类,我们可以获取类的构造方法信息,并在运行时动态地创建对象。
Java反射机制本身并不提供字节码修改技术。Java反射机制主要允许程序在运行时检查类、接口、字段和方法的信息,并且可以动态地创建和操作对象。它提供了对类和对象的内部结构的访问能力,但并不涉及对字节码的修改。Java反射机制本身不能直接动态地实现一个接口并形成一个新的类。反射主要用于在运行时检查和操作已经存在的类、接口、字段和方法。虽然反射能够获取接口的信息,但它不能用来动态地创建实现该接口的新类。
设计模式
Java设计模式是一套被广泛接受和应用于Java编程的解决方案。这些设计模式是针对常见问题的通用解决方案,通过它们可以更容易地编写出易于理解、可维护和可扩展的代码。Java设计模式通常可以分为以下几种类型: 1. 创建型模式:这些模式关注对象的创建机制,包括如何实例化对象或者将对象组合成更复杂的结构。典型的创建型模式包括工厂模式、抽象工厂模式、建造者模式、原型模式和单例模式。 2. 结构型模式:这些模式处理类和对象的组合,从而形成更大的结构。它们帮助确保在系统中更容易地识别对象之间的关系。结构型模式包括适配器模式、桥接模式、组合模式、装饰器模式、外观模式、享元模式和代理模式。 3. 行为型模式:这些模式涉及对象之间的交互,包括如何分配职责以及如何实现通信。行为型模式包括模板方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式、状态模式、策略模式、职责链模式和访问者模式。 这些设计模式为解决特定类型的问题提供了指导,使得开发人员可以更容易地编写出高质量、易于理解和可维护的代码。在实际的软件开发中,设计模式通常被视为一种最佳实践,有助于提高代码的灵活性、可重用性和可扩展性。
1、模版模式和策略模式
模板模式和策略模式都属于行为型设计模式,它们都关注对象之间的交互,但它们的应用场景和解决问题的方式略有不同。
模板模式
- 特点:
- 模板模式定义了一个算法的骨架,将某些步骤的具体实现延迟到子类中。它允许子类为一个或多个步骤提供其自己的实现,同时保持算法的结构不变。
- 模板模式通常由一个抽象类和一组实现类组成,抽象类中定义了算法的框架,而具体实现类提供了算法中具体步骤的实现。
- 在模板模式中,算法的结构由父类决定,具体步骤的实现则由子类决定。
- 应用场景:
- 当有一个算法的整体结构是固定的,但是其中某些步骤的具体实现可能不同的时候,可以考虑使用模板模式。
策略模式
- 特点:
- 策略模式定义了一系列的算法,并将每一个算法封装起来,使它们可以相互替换。这使得算法可以独立于使用它们的客户而变化。
- 在策略模式中,算法被视为一个可替换的行为,并且客户可以在运行时动态地选择所需的算法。
- 应用场景:
- 当一个问题有多种解决方案,或者一个系统需要动态地在几种算法中选择一种的时候,可以考虑使用策略模式。
联系
-
联系:
- 模板模式和策略模式都涉及到算法的封装和替换,但它们的关注点不同。
- 模板模式关注的是算法的整体结构,提供一个固定的算法框架,允许子类提供特定步骤的实现。
- 策略模式关注的是多个算法的替换和动态选择,使得客户可以在运行时选择合适的算法。
虽然它们的关注点不同,但是在实际应用中,这两种模式可能会相互结合,比如模板模式可以使用策略模式来实现某些具体步骤的替换。
在某些情况下,策略模式和模板模式确实可以在一定程度上互换使用,特别是在涉及算法的封装和替换方面。虽然它们的主要关注点不同,但在一些情况下可以进行相互转换或结合使用。
模板模式使用的是集成关系实现,策略模式使用的是组合关系实现
模板模式倾向于将解决问题的过程定义为一个完整的框架,其中具体的步骤由子类来实现。策略模式中,通常会定义一个策略接口或抽象类,具体的算法实现则通过这个接口或抽象类来实现。
2、单例模式:
Java中的单例模式是一种创建对象的设计模式,它保证在一个应用程序中,某个类只有一个实例存在。单例模式通常用于那些只需要一个对象的场景,比如配置文件的读取、线程池、缓存等。
单例模式并不是Java特有的。单例模式是一种设计模式,它的主要目的是确保一个类仅有一个实例,并提供一个全局访问点来访问这个唯一实例。这种设计模式可以应用于任何面向对象的编程语言,包括Java、C++、C#、Python等。
3、观察者模型
对象间存在一对多关系,当一个对象被修改时,自动通知其依赖对象,这种设计模式通常采用的是观察者模式(Observer Pattern)。
观察者模式是一种行为设计模式,它允许对象之间定义一对多的依赖关系,当一个对象状态发生改变时,它的所有依赖者都会收到通知并自动更新。
这种设计模式有助于实现模块化、可复用和可扩展的代码,因为它降低了对象之间的耦合度,使得各个对象可以独立地改变和演进。虽然观察者模式在处理一对多关系时非常有效,但在某些情况下,如果依赖关系过于复杂,可能会导致性能问题或难以维护
数据结构
1、二叉树遍历 前序,中序,后序。
后序遍历从后开始看,最后一个是根节点,然后根据中序遍历区分左右子树。
2、循环队列
循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首以形成一个循环。它也被称为“环形”队列。循环队列在内存中是一个环形空间,当存储空间被填满后,就从第一个元素开始覆盖。
循环队列的主要优势在于,它可以更有效地利用存储空间,因为当一个元素被移除后,其位置可以被新的元素立即占用,而不需要进行任何额外的数据移动。此外,循环队列的入队和出队操作都是 O(1) 复杂度,即常数时间复杂度,这使得循环队列在处理大量数据时非常高效。
循环队列的实现通常需要两个指针,一个指向队头(front),另一个指向队尾(rear)。当元素入队时,rear 指针向前移动;当元素出队时,front 指针向前移动。当 front 和 rear 相遇时,队列为空;当 rear 到达队列的末尾并准备再次回到队首时,队列为满。
在实现中,我们预留了一个数组位置来区分队列满和队列空的情况。当rear
指针追上front
指针时,队列是满的;当front
和rear
都指向同一个位置且队列大小为0时,队列是空的。
数据库
1、MySQL数据库四种隔离级别
MySQL 数据库提供了四种标准的事务隔离级别,分别是:
- READ UNCOMMITTED(读取未提交的数据):最低的隔离级别,事务可以读取未提交的数据,可能会导致脏读、不可重复读和幻读问题。
- READ COMMITTED(读取提交的数据):事务只能读取已提交的数据,可以避免脏读问题,但仍可能出现不可重复读和幻读问题。
- REPEATABLE READ(可重复读):确保在事务执行期间多次读取的数据保持一致,可以避免脏读和不可重复读问题,但仍可能出现幻读问题。
- SERIALIZABLE(可串行化):最高的隔离级别,确保事务之间的数据读写操作彼此之间完全隔离,可以避免脏读、不可重复读和幻读问题,但会降低并发性能。
2、数据库设计范式:
数据库设计范式是数据库设计中所需要满足的规范,这些规范确保数据库结构清晰、简洁,并避免数据冗余和异常操作。范式是一系列逐级递增的规范,越高的范式数据库冗余越小。关系数据库中有六种范式,分别是第一范式(1NF)、第二范式(2NF)、第三范式(3NF)、巴斯-科德范式(BCNF)、第四范式(4NF)和第五范式(5NF,又称完美范式)。
第一范式(1NF)要求数据库表中的每个字段都是不可分割的原子数据项,即每个字段都是单一属性的,不可再分。这意味着每个字段只能包含一个值,而不能包含多个值或者数组。第一范式(1NF)是所有关系型数据库的最基本要求
第二范式(2NF)是在第一范式的基础上建立的,它要求数据库表中的每个非主键字段必须完全依赖于整个主键。换句话说,如果表中有复合主键,那么任何非主键字段不能仅依赖于主键的一部分。
第三范式(3NF)则进一步要求数据库表中的每个非主键字段不能依赖于其他非主键字段。这确保了数据表中的字段之间不存在传递依赖关系。
遵循数据库设计范式可以确保数据库结构的合理性,减少数据冗余,提高数据的一致性和可维护性。同时,它也有助于避免在数据库操作(如插入、删除和更新)时出现异常。
数据库设计并不必须完全遵守所有的范式。虽然范式理论为数据库设计提供了有价值的指导原则,但在实际应用中,完全遵守所有范式可能会导致数据库设计过于复杂,影响性能,甚至与业务需求相悖。
- 业务需求:首先,数据库设计的最终目标是满足业务需求。在某些情况下,为了满足特定的业务需求,可能需要适当地牺牲某些范式规则。例如,在某些数据仓库或数据分析场景中,为了提高查询性能,可能会选择保留一些冗余数据。
- 性能考虑:完全遵守高级范式(如4NF和5NF)可能导致数据库结构过于复杂,增加查询的复杂性,从而影响性能。在某些情况下,为了提高性能,可能会选择保留一些低级别的冗余数据。
- 维护成本:过于严格的范式遵守可能导致数据库结构过于复杂,增加维护成本。在某些情况下,简化数据库结构以降低维护成本可能是一个合理的选择。
- 数据一致性:虽然范式理论有助于确保数据一致性,但在实际应用中,还需要通过其他手段(如触发器、存储过程等)来维护数据的一致性。
设计范式之间确实有一定的独立性,因为每个范式都是针对特定问题或场景提出的解决方案。然而,这些范式之间也存在一定的关联和交互。
计网
1、tcp/ip网络中,为各种公共服务保留的端口范围是 0-1023
大于1023的端口则可供用户级应用程序使用
2、tcp/ip协议
TCP/IP协议集分为四层,分别是:
-
应用层:包括诸如HTTP、FTP、SMTP等协议,用于应用程序之间的通信和数据交换。
HTTP(超文本传输协议),SMTP(简单邮件传输协议),FTP(文件传输协议),DNS(域名系统)
-
传输层:主要有TCP(传输控制协议)和UDP(用户数据报协议),负责在网络中传输数据并提供端到端的通信服务。
-
网络层:主要有IP(网际协议),负责数据包的路由和转发,实现不同网络之间的通信。
-
数据链路层:包括以太网、WiFi等,负责在物理网络中传输数据帧,并提供了物理寻址、错误检测和纠正等功能。
HTTP(Hypertext Transfer Protocol)位于TCP/IP协议集中的应用层。 HTTP协议用于在网络中传输超文本文档,是Web应用程序的基础,通过HTTP,客户端(如浏览器)可以向服务器请求资源,并接收服务器返回的数据。
TFTP(Trivial File Transfer Protocol)位于TCP/IP协议集中的传输层。 TFTP是一个简单的文件传输协议,用于在计算机网络中进行文件传输,它基于UDP协议进行数据传输,通常用于在局域网内进行简单的文件传输操作。
TCP在建立连接时使用三次握手,断开连接时使用四次挥手。
- 三次握手:
- 第一次握手:客户端发送连接请求报文段,服务端收到请求后,进入到 LISTEN(监听)状态。
- 第二次握手:服务端接收到连接请求后,发送确认报文段,并进入到 SYN-RECEIVED 状态。
- 第三次握手:客户端收到服务端的确认后,发送一个确认报文段,双方进入 ESTABLISHED(已建立连接)状态。
- 四次挥手:
- 第一次挥手:客户端发送连接释放报文段,并进入 FIN-WAIT-1 状态。
- 第二次挥手:服务端接收到释放报文段后,发送确认报文段,自己进入 CLOSE-WAIT 状态,等待数据传输完成。
- 第三次挥手:服务端完成数据传输后,向客户端发送连接释放报文段,并进入 LAST-ACK 状态。
- 第四次挥手:客户端接收到释放报文段后,发送确认报文段,双方进入 CLOSED(连接关闭)状态。
3、TCP超时重传:
在TCP中,当发送端的数据到达接收主机时,接收端主机会返回一个确认应答消息,表示已收到消息。对于在传输过程中丢失的数据包,TCP使用重传机制来解决。这种机制包括设定一个定时器,在超过指定的时间后没有收到对方的ACK确认应答报文时,就会重发该数据,即超时重传。
git
1、哪个命令可以查看git所有分支git branch
如果想要查看远程仓库的分支,可以加上 -r
选项,或者使用 -a
选项来查看所有本地和远程跟踪的分支。-d
是删除本地分支的命令
Author kong
LastMod 2023-11-28