2023菜鸟物流一面.社招.Java后端开发
1.手写一个StringBuilder
public class MyStringBuilder {
/**
* 可变长度的字符串——字符数组
*/
char value[];
/**
* 定义数据长度
*/
int count;
public MyStringBuilder() {
this.value = new char[16];
}
public MyStringBuilder(int s) {
this.value = new char[s];
}
public MyStringBuilder(String s) {
value = new char[16 + s.length()];
this.count = s.toCharArray().length;
}
public int capacity() {
return this.value.length;
}
public int length() {
return this.count;
}
/**
* @param
* @return com.stringbuilder.MyStringBuilder
* @description //添加
* @param: s
* @date 2023/2/24 14:41
* @author wty
**/
public MyStringBuilder append(String s) {
if (null == s) {
value[this.count++] = 'n';
value[this.count++] = 'u';
value[this.count++] = 'l';
value[this.count++] = 'l';
} else {
// TODO this.ensureCapacityInternal(var5);
int length = s.length();
ensureCapacityInternal(this.count + length);
value = Arrays.copyOf(this.value, this.count + length);
for (int i = 0; i < length; i++) {
value[this.count++] = s.charAt(i);
}
}
return this;
}
public MyStringBuilder append(Object o) {
return append(String.valueOf(o));
}
/**
* @param
* @return com.stringbuilder.MyStringBuilder
* @description //删除
* @param: begin
* @param: end
* @date 2023/2/24 14:42
* @author wty
**/
public MyStringBuilder delete(int begin, int end) {
rangeCheck(begin, end);
// a b c d e
// 需要删除c和d
// a b e d e
// 截取前三位
// a b e
// 新加字符的长度
int length = end - begin;
if (length > 0) {
System.arraycopy(this.value, end, this.value, begin, this.count - end);
this.count -= length;
}
return this;
}
/**
* @param
* @return com.stringbuilder.MyStringBuilder
* @description //修改
* @param: start
* @param: end
* @param: s
* @date 2023/2/24 14:42
* @author wty
**/
public MyStringBuilder replace(int start, int end, String s) {
rangeCheck(start, end);
if (end > this.count) {
end = this.count;
}
int length = s.length();
/**
* 替换字符串后,value[]数组的length
*/
int countEnsure = this.count + length - (end - start);
// TODO this.ensureCapacityInternal(var5);
ensureCapacityInternal(countEnsure);
// a b c 中间的b替换成d 1 2 d
// a d c
// value, 2, value, 2,1
//System.arraycopy(this.value, end, this.value, start + length, this.count - end);
// s.getChars(this.value, start);
char charsNew[] = s.toCharArray();
System.arraycopy(charsNew, 0, this.value, start, charsNew.length);
this.count = countEnsure;
return this;
}
/**
* @param
* @return int
* @description //查询
* @param: findStr
* @date 2023/2/24 14:43
* @author wty
**/
public int indexOf(String findStr) {
return indexOf(findStr, 0);
}
/**
* @param
* @return int
* @description //查询
* @param: findStr 需要查询哪个字段
* @param: order 从第几位开始查询
* @date 2023/2/24 14:46
* @author wty
**/
public int indexOf(String findStr, int order) {
boolean flag = false;
rangeCheck(order);
if (order > 0) {
if (findStr.length() >= this.count) {
return -1;
}
} else if (order == 0) {
if (findStr.length() > this.count) {
return -1;
}
}
// ab
char[] findChars = findStr.toCharArray();
for (int i = order; i < this.count; i++) {
// b == abc ?
if (findChars[0] == this.value[i]) {
flag = true;
for (int j = 1; j < findChars.length; j++) {
if (findChars[j] != this.value[i + j]) {
flag = false;
break;
}
}
if (flag == true) {
return i;
}
}
}
return -1;
}
public int lastIndexOf(String findStr) {
return lastIndexOf(findStr, 0);
}
public int lastIndexOf(String findStr, int beginIndex) {
boolean flag = false;
rangeCheck(beginIndex);
int length = findStr.length();
if (beginIndex > 0) {
if (length >= this.count) {
return -1;
}
} else if (beginIndex == 0) {
if (length > this.count) {
return -1;
}
}
char[] charsStr = findStr.toCharArray();
for (int i = this.count - 1; i >= beginIndex; i--) {
if (charsStr[length - 1] == this.value[i]) {
flag = true;
for (int j = length - 2; j >= 0; j++) {
if (charsStr[j] != this.value[i + j - length + 1]) {
flag = false;
break;
}
}
if (flag == true) {
return i - length + 1;
}
}
}
return -1;
}
/**
* @param
* @return void
* @description //数组是否越界
* @param: begin 开始
* @param: end 结束
* @date 2023/2/24 13:23
* @author wty
**/
public void rangeCheck(int begin, int end) {
if (begin > end || begin < 0) {
throw new StringIndexOutOfBoundsException("beginIndex:" + begin + "endIndex" + end);
}
}
private void rangeCheck(int beginIndex) {
if (beginIndex < 0 || beginIndex > this.count - 1) {
throw new StringIndexOutOfBoundsException("offset beginIndex: " + beginIndex + ",length " + count);
}
}
private void ensureCapacityInternal(int countNew) {
if (countNew - this.length() > 0) {
this.value = Arrays.copyOf(this.value, this.newCapacity(countNew));
}
}
private int newCapacity(int countNew) {
int countCompare = (this.length() << 1) + 2;
if (countCompare - countNew < 0) {
countCompare = countNew;
}
return countCompare > 0 && Integer.MAX_VALUE - countCompare >= 0 ? countCompare : this.hugeCapacity(countCompare);
}
private int hugeCapacity(int countNew) {
if (Integer.MAX_VALUE - countNew < 0) {
throw new OutOfMemoryError();
} else {
return countNew > Integer.MAX_VALUE ? countNew : Integer.MAX_VALUE;
}
}
@Override
public String toString() {
/**
* 截取有效数据的长度
*/
return new String(this.value, 0, this.count);
}
}
2.介绍分布式锁
3.介绍高并发经验
4.介绍项目的吞吐量
5.Mysql的行级锁
这里引用一下作者:IT利刃出鞘 的文章
MySQL–行级锁与表级锁
也用我自己的话概括一下:
Mysql数据库分为行级锁和表级锁。
锁类型 | 死锁 | 锁定粒度(并发性) | 适用场景 |
---|---|---|---|
表级锁 | 不会死锁 | 最大,发生锁冲突的概率最大(并发性低) | 场景1:读多写少; 场景2:写特别多。若用行锁,会导致事务执行效率低,可能造成其他事务长时间锁等待和锁冲突。 |
行级锁 | 会死锁 | 最小,发生锁冲突的概率最低(并发性最高) | 并发量大。 |
页面锁 | 会死锁 | 居中,并发一般 |
不同数据库引擎的锁机制
存储引擎 | 支持的锁 | 说明 |
---|---|---|
InnoDB | 表级锁、行级锁(默认)。 | InnoDB行级锁基于索引实现。若查询字段无索引或索引失效,则使用表锁。 |
MyISAM | 表级锁 | |
MEMORY | 表级锁 | |
BDB | 表级锁、页面锁 |
(1) 行级锁
从数据库的角度看,行级锁又分为:独占锁和共享锁。
锁名称 | 别名 | select锁形式 | update、delete、insert锁形式 | 是否造成死锁 |
---|---|---|---|---|
独占锁(Exclusive Lock) | 写锁、排他锁、X锁 | SELECT … FOR UPDATE | 对于UPDATE、DELETE和INSERT语句,InnoDB会自动给涉及数据集加排他锁 | 不会造成死锁 |
共享锁(Share Lock) | 读锁 | SELECT … LOCK IN SHARE MODE | 会造成死锁 |
注意:
一个事务在一行加上了独占锁,那么其余事务不可以在该行上加入任何锁。只能通过select查询数据。
(2) 表级锁
锁名称 | 别名 | 显示加锁 | update、delete、insert锁形式 |
---|---|---|---|
独占锁(Exclusive Lock) | 写锁、排他锁、X锁 | lock table tableName write; | 对于UPDATE、DELETE和INSERT语句会自动给涉及数据集加排他锁,对InnoDB表加锁时要注意,要将AUTOCOMMIT设为0 |
共享锁(Share Lock) | 读锁 | lock table tableName read; |
对InnoDB表加锁时要注意,要将AUTOCOMMIT设为0,否则MySQL不会给表加锁。
例如,如果需要写表t1并从表t2读,可以按如下做:
SET AUTOCOMMIT=0;
LOCK TABLES t1 WRITE, t2 READ;
COMMIT;
UNLOCK TABLES;
6.单一职责和接口隔离区别
定义:
单一职责:类或者接口要实现职责单一。
接口隔离:接口的设计要求精度单一。
区别:
相同点:都是都是为了提高类的内聚性、降低它们之间的耦合性,体现了封装的思想。
不同点:
- 单一职责中,“职责”两个字比较宽泛,可以是业务上的单一也可以是功能上的单一,而接口隔离中,指的只是接口中的依赖隔离。
- 单一职责的范围可以是类,接口隔离只能约束接口。