笔记--Java零散小知识--1.19更2.15w字

2021.9

for循环的结构可以为:
for(//;布尔/;//)
单:单表达式
多:多表达式
第二个表达式为空则是死循环
在Java里,for(;;)等价于while(true)
foreach循环 例:for(int x:array)

1B=8bit 1KB=1024B
bit:比特 位
byte:字节 也就是B
boolean 1位
byte 1字节 8位
char 2字节 16位
short 2字节 16位
int 4字节 32位
float 4字节 32位
long 8字节 64位
double 8字节 64位

默认情况下,如果输入法没有切换到全角,你点击的space键默认输出的是半角空格。
在Java中,可以使用“ ”直接输出空格,也可以通过unicode代码表示空格

1.不间断空格\u00A0,主要用在office中,让一个单词在结尾处不会换行显示,快捷键ctrl+shift+space ;
2.半角空格(英文符号)\u0020,代码中常用的;
3.全角空格(中文符号)\u3000,中文文章中使用;

String转换为char

  1. 使用String.charAt(index)(返回值为char)可以得到String中某一指定位置的char。
  2. 使用String.toCharArray()(返回值为char[])可以得到将包含整个String的char数组。

char转换为String

char[ ] charArr={“a”,“b”}

  1. String s = String.valueOf({“a”,“b”}); //效率最高的方法

  2. String s = String.valueOf(charArr); //将一个char数组转换成String

  3. String s = " " + charArr; // 效率最低的方法 // Java中的String Object的值实际上是不可变的,是一个final的变量。 // 所以我们每次对String做出任何改变,都是初始化了一个全新的String Object并将原来的变量指向了这个新String。 // 而Java对使用+运算符处理String相加进行了方法重载。
    字符串直接相加连接实际上调用了如下方法: // new
    StringBuilder().append(“”).append(charArr).toString();

  4. String s = new String(charArr);

do while循环中,while里面的运算也会对值产生影响(Java是值传递)

float数后面要加f,例如float x=3.6f

switch每个case(包括没有放在最后的default)后面都要加break要不然就会执行完当前case后继续执行本case后面的case直到执行完或者遇到break;default放在哪里都可以,但是只要不放在最后就失去了原本的意义,default意为缺省,即前面的条件都不满足的时候运行default

Java标识符 字母、数字、“_”、“&”,数字不能为首位

x%y 算x里面有几个y 然后返回余下的x

派生是在继承了一些东西的基础上增添了新的东西

根据 W3C 的 HTML DOM 标准,HTML 文档中的所有内容都是节点:
整个文档是一个文档节点
每个 HTML 元素是元素节点
HTML 元素内的文本是文本节点
每个 HTML 属性是属性节点
注释是注释节点

windows cmd创建指定大小的文件 (3221225472KB=3G)
fsutil file createnew test.txt 3221225472

继承JpaRepository,传入泛型,第一个参数为要操作的实体类,第二个参数为该实体类的主键类型

例:XXXRepository extends JpaRepository<XXXEntity,String>

在这里插入图片描述

1.HTTP Request 第一部分是包含的头信息 HttpContent 里面包含的是数据,可以后续有多个 HttpContent 部分
2.LastHttpContent 标记是 HTTP request 的结束,同时可能包含头的尾部信息
3.完整的 HTTPrequest,由1,2,3组成

在这里插入图片描述

1.HTTP response 第一部分是包含的头信息 HttpContent 里面包含的是数据,可以后续有多个 HttpContent 部分
2.LastHttpContent 标记是 HTTP response 的结束,同时可能包含头的尾部信息 完整的 HTTP
3.response,由1,2,3组成

三元运算符需要三个操作数。
语法为:条件表达式?表达式1:表达式2。
问号前面的位置是判断的条件,判断结果为bool型,为true时调用表达式1,为false时调用表达式2

length–数组的属性
length()–String的方法
size()–List,Set,Map等集合的方法

dao,dto,vo,po,pojo,bo的区别:
参考小张的博客:un1queyan.github.io

HashMap:
一个key-value构成一个entry
允许key和value值为null
HashMap和HashSet存储自定义类时,需要在key所在的类(自定义类)对hashcode()和equals()进行重写(非自定义类已内置对这两个方法的重写,例如String),避免存储相同值的不同实例时出现重复的情况。Object原生的equals()和hashcode()都是根据实例的地址进行运算,如果不重写的话,存储值相同的不同实例时,因为地址的不同,被认为是不同的值进行存储。

泛型通配符:本质上不同的泛型通配符其实没什么区别,可以随意替换,只不过是约定俗成地用不同的字母或者符号代替不同的含义。

?无界通配符: 表示不确定的 Java 类型
T :代表Type,表示具体的一个Java类型
K和V : 分别代表Java键值中的Key和Value
E :代表Element(元素),常用在集合类中表示集合中的元素

 位运算符
 & 按位与
 |按位或
 ^按位异或 (相同为0,不同为1)
 ~取反
 <<左移
 >>右移
在这里插入图片描述

2022.3

Maven的< scope> XXX< scope>标签
compile
默认的scope,表示 dependency 都可以在生命周期中使用。而且,这些dependencies 会传递到依赖的项目中。适用于所有阶段,会随着项目一起发布
provided
跟compile相似,但是表明了dependency 由JDK或者容器提供,例如Servlet AP和一些Java EE APIs。这个scope 只能作用在编译和测试时,同时没有传递性。
runtime
表示dependency不作用在编译时,但会作用在运行和测试时,如JDBC驱动,适用运行和测试阶段。
test
表示dependency作用在测试时,不作用在运行时。 只在测试时使用,用于编译和运行测试代码。不会随项目发布。
system
跟provided 相似,但是在系统中要以外部JAR包的形式提供,maven不会在repository查找它

@ControllerAdvice
在Spring里,我们可以使用@ControllerAdvice来声明一些全局性的东西,最常见的是结合@ExceptionHandler注解用于全局异常的处理。
@ControllerAdvice是在类上声明的注解,其用法主要有三点:
@ExceptionHandler注解标注的方法:用于捕获Controller中抛出的不同类型的异常,从而达到异常全局处理的目的;
@InitBinder注解标注的方法:用于请求中注册自定义参数的解析,从而达到自定义请求参数格式的目的;
@ModelAttribute注解标注的方法:表示此方法会在执行目标Controller方法之前执行

Linux命令 (CentOS 8.2)

sudo su root 切换root用户
命令后加 -y 遇到(y/n) 自动选择yes

ps -ef|grep XXX 查看XXX进程

clear 清除命令行

vim

:wq保存退出
:q退出

@RequestMapping 默认method是get,post方式都支持
@GetMapping,处理get请求
@PostMapping,处理post请求
@PutMapping,处理put请求
@DeleteMapping,处理delete请求

@GetMapping是一个组合注解,是@RequestMapping(method = RequestMethod.GET)的缩写。
@PostMapping是一个组合注解,是@RequestMapping(method = RequestMethod.POST)的缩写。
@RequestMapping是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。

最常用的post和get
post请求,如果是接收json格式(要求传输参数是json(application/json;charset=utf-8),接收参数要是一个参数或者是一个对象并且参数前加上@RequestBody注解);如果是表单提交(application/x-www-form-urlencoded),接收参数没有要求即可以是对象也可以是多个参数的接收方式
get请求,参数不能是json(application/json;charset=utf-8)格式,只能是表单(application/x-www-form-urlencoded)格式

详细请看https://www.hangge.com/blog/cache/detail_2485.html
以及https://www.hangge.com/blog/cache/detail_2484.html

Json和Gson

JSON: 是javascript对象的一种形态,是一种轻量级的数据交换格式。一般用来在JavaEE后台服务和Android或者IoS、H5之间进行通信的一种数据传递的格式
Gson: 是谷歌推出的一个用于生成和解析JSON数据格式的工具

从一个XXX json字符串生成一个Java对象

例:Gson gson = new Gson();
Request req = gson.fromJson(XXX, Request.class);  【方法参数:(Json对象,对应实体类)】

这时候会有问题,需要验证输入的json字符串是否是从当前的Request这个类序列化过去的,这个时候就需要用serialVersionUID来判断了

序列化和反序列化(serial翻译为序列、串行,所以序列化和串行化的的意思是一样的)

Java是面向对象的语言,与其他语言进行交互(比如与前端js进行http通信),需要把对象转化成一种通用的格式比如json(前端显然不认识Java对象),从对象到json字符串的转换,就是序列化的过程,反过来,从json字符串转换成Java对象,就是反序列化的过程

serialVersionUID是什么

serialVersionUID:序列版本用户标识符
UID:user identification用户标识符

Java的序列化机制通过判断类的serialVersionUID来验证版本一致性。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地对应实体类的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常,即InvalidCastException (无效强转异常)
serialVersionUID有两种显示的生成方式:
一是默认的1L,例:private static final long serialVersionUID = 1L;
二是根据类名、接口名、成员方法及属性等来生成一个64位的哈希字段
当一个类实现了java.io.Serializable接口,并且没有显示的定义serialVersionUID的时候,Java序列化机制会根据类信息编译的Class文件自动生成一个serialVersionUID,如果Class文件没有发生变化,就算重复编译,serialVersionUID也不会变。
如果我们不希望通过编译文件来强制划分软件版本,想让实现序列化接口的实体能够兼容先前版本,就需要显式地定义一个类型为long的serialVersionUID变量,变量值相等的序列化实体都可以相互进行序列化和反序列化

System.currentTimeMillis() 获取时间戳

哈希算法又叫散列算法,指的不是某一种算法,是某一类算法,将任意长度的二进制值转换为固定长度的二进制值,常用哈希算法有:MD、SHA、SM3
哈希值:通过哈希运算,从而映射成的二进制的值称为哈希值
无论输入是什么数字格式、文件有多大,输出都是固定长度的比特串。以Sh256算法为例,无论输入是什么数据文件,输出就是256bit,用16进制数字表示的话是64位
例:00740f40257a13bf03b40f54a9fe398c79a664bb21cfa2870ab07888b21aaba8

全局变量(成员变量)与局部变量
在这里插入图片描述
成员变量:

直接在类中声明的变量叫成员变量(又称全局变量)

初始化(自动赋初始值):
如果创建成员变量后未设置初始值,系统会根据类型自动设置初始值:int类型初始值0、boolean类型初始值false,而自定义类型初始值null

作用范围:
成员变量定义后作用域是其所在的整个类。且成员变量的定义没有先后顺序,但是最好将成员变量的定义集中在类的顶部

static
加了static的成员变量属于类,不加static的成员变量属于类对象,也就是类的实例

局部变量:

方法的参数、方法中定义的变量和代码块中定义的变量统称为局部变量。

初始化:
①局部变量在使用以前必须显式初始化赋值,局部变量没有默认值。
②声明局部变量时,除final外不允许有其他关键字,即其定义格式为[final] 数据类型 变量名 = 初始值;

作用范围:
从定义的位置开始到其所在语句块结束。

注意:
①如果局部变量的名字与全局变量的名字相同,则在局部变量的作用范围内全局变量被隐藏,即这个全局变量在同名局部变量所在方法内暂时失效。
②所以如果在局部变量的作用域范围内访问该成员变量,则必须使用关键字this来引用成员变量。

修饰符:修饰符分为访问修饰符和非访问修饰符
访问控制修饰符

访问范围修饰范围
public所有包类、接口、变量、方法
protected当前包或子类变量、方法【不能修饰类(外部类)】
default (即默认,什么也不写当前包类、接口、变量、方法
private当前类变量、方法【不能修饰类(外部类)】
  • public:如果几个相互访问的 public 类分布在不同的包中,需要导入相应 public 类所在的包。由于类的继承性,类所有的公有方法和变量都能被其子类继承。
  • protected:若子类与基类在同一包中,被声明为 protected 的变量、方法和构造器能被同一个包中的任何其他类访问;若子类与基类不在同一包中,那么在子类中,子类实例可以访问其从基类继承而来的 protected 方法(也就是加了static关键字的基类成员方法),而不能访问基类实例的protected方法。详细看【这里】(加了static的成员方法属于类的成员方法,没加的属于类的实例的成员方法)
  • default:接口里的变量都隐式声明为 public static final,而接口里的方法默认情况下访问权限为 public
  • private:类和接口不能声明为 private。声明为私有访问类型的变量只能通过类中公共的 getter方法被外部类访问。private的使用主要用来隐藏类的实现细节和保护类的数据

非访问控制修饰符:

为了实现一些其他的功能,Java 也提供了许多非访问修饰符。

  • static 修饰符,用来修饰类方法和类变量。
  • final 修饰符,用来修饰类、方法和变量,final 修饰的类不能够被继承,修饰的方法不能被继承类重新- 定义,修饰的变量为常量,是不可修改的。
  • abstract 修饰符,用来创建抽象类和抽象方法。
  • synchronized 和 volatile 修饰符,主要用于线程的编程

static 修饰符
加了static的成员变量/方法,都是属于类的。没加static的是属于类的实例(类对象)的成员变量/方法
静态成员方法可以只能访问静态变量,成员方法可以访问静态和非静态变量,原因是静态变量和静态方法在类加载时就加载出来了,但此时成员方法和成员变量还没有加载出来,因此无法调用。

静态变量:
static 关键字用来声明独立于对象的静态变量,无论一个类实例化多少对象,它的静态变量只有一份拷贝。 静态变量也被称为类变量。局部变量不能被声明为 static 变量。

静态方法:
static 关键字用来声明独立于对象的静态方法。静态方法不能使用类的非静态变量。静态方法从参数列表得到数据,然后计算这些数据。

final 修饰符

final 变量:
final变量一旦赋值后,不能被重新赋值
被 final 修饰的实例变量必须显式指定初始值
final 修饰符通常和 static 修饰符一起使用来创建类常量
对类变量和方法的访问可以直接使用 类名.变量名类名.方法名 的方式访问

final 方法:
父类中的 final 方法可以被子类继承,但是不能被子类重写。
声明 final 方法的主要目的是防止该方法的内容被修改。
如下所示,使用 final 修饰符声明方法

final 类:
final 类不能被继承,没有类能够继承 final 类的任何特性。

abstract 修饰符

抽象类:
抽象类不能用来实例化对象,声明抽象类的唯一目的是为了将来对该类进行扩充。
一个类不能同时被 abstract 和 final 修饰。如果一个类包含抽象方法,那么该类一定要声明为抽象类,否则将出现编译错误。
抽象类可以包含抽象方法和非抽象方法

抽象方法:
抽象方法是一种没有任何实现的方法,该方法的具体实现由子类提供。
抽象方法不能被声明成 final 和 static。
任何继承抽象类的子类必须实现父类的所有抽象方法,除非该子类也是抽象类。
如果一个类包含若干个抽象方法,那么该类必须声明为抽象类。抽象类可以不包含抽象方法。
抽象方法的声明以分号结尾,例如:public abstract sample();。

synchronized 修饰符

synchronized 关键字声明的方法同一时间只能被一个线程访问。synchronized 修饰符可以应用于四个访问修饰符。

transient 修饰符

序列化的对象包含被 transient 修饰的实例变量时,java 虚拟机(JVM)跳过该特定的变量。

volatile 修饰符

volatile
修饰的成员变量在每次被线程访问时,都强制从共享内存中重新读取该成员变量的值。而且,当成员变量发生变化时,会强制线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。
一个 volatile 对象引用可能是 null。
该修饰符包含在定义变量的语句中,用来预处理类和变量的数据类型。
通常情况下,在一个线程调用 run() 方法(在 Runnable 开启的线程),在另一个线程调用 stop() 方法。 如果 第一行 中缓冲区的 active 值被使用,那么在 第二行 的 active 值为 false 时循环不会停止。

但是以上代码中我们使用了 volatile 修饰 active,所以该循环会停止

继承与多态:https://www.runoob.com/w3cnote/java-extends.html
子类只可以直接访问父类中的非私有的属性和行为
继承让类与类之间产生了关系,是多态的前提
Java只支持单继承,不支持多继承;Java支持多层继承
注意:如果类之间存在着:is a 的关系,就可以考虑使用继承,不要为了继承部分功能,而去使用继承
super是一个关键字,代表父类的存储空间标识,代表当前子类对父类的引用
this代表对象的引用(谁调用就代表谁)

变量构造器方法
当前类this.变量this()this.方法名()
父类super.变量super()super.方法名()
方法的重写:
子类方法的返回值类型方法名参数列表和父类方法都一模一样,会出现覆盖操作,也称为重写或者复写。

注意:
子类方法访问权限大于等于父类方法的访问权限(注:private修饰的父类方法子类看不到所以无法被继承)
静态只能覆盖静态

重写的使用场景:
子类需要既沿袭了父类的功能,又在功能主体定义了子类特有的内容

方法重写、重载的区别?通俗来讲就是重写要一模一样,只是在方法内部将功能更加具体化。重载就是一个方法在不同情况下的不同使用方式,针对不同情况有不同的处理方式。
重写的子类方法与父类方法除了权限修饰符可能不一样,其他必须一模一样
重载是在同一个类中方法名相同,参数列表不同的一些方法(重载与否忽视返回值类型这个条件,只有返回值类型不同不算重载

子父类中构造方法的用法:
子类的初始化过程中,首先执行父类的初始化,后执行子类初始化。因为子类的构造方法第一行默认有一个super(),子类要使用父类的成员变量,这个初始化,必须在子类初始化之前完成。

如果父类没有无参构造方法:
使用super调用父类的带参构造(推荐)
使用this调用当前列的其他构造,但是被调用的当前类的其他构造器还是要有对父类构造的调用

this和super关键字

  • this.变量和super.变量:this.参数代表当前类对象的成员属性,一般来说参数名重复时使用this(例如形参和实参),而参数名称不重复时省略this;super.参数代表父类成员属性,其中父类的私有属性无法调用 ,因为子类根本看不到
  • this.方法和super.方法:this.方法代表当前类对象的成员方法,一般来说方法名不会重复,一般都会把方法前的this省略掉;super.方法是指父类的成员方法,其中父类的私有方法无法调用,因为子类根本看不到
  • this()构造和super()构造:子类构造必须都要有一个出口指向父类构造,子类的各种构造器第一行都默认是super(),也可以指定为this(有参),this(无参),或super(有参),但是最终每一个子类构造都要有一个出口最终指向父类构造

静态代码块、构造代码块,构造方法的执行顺序:【静态代码块static{},代码块{}】

父类静态代码块→子类静态代码块→父类构造代码块→父类构造方法→子类构造代码块→子类构造方法

Git 基础操作看https://blog.csdn.net/tufhgddty/article/details/124192657

2022.4.15

Java的值传递,视频讲解看这里
对于基本数据类型,值传递的值是指实参的基本数据类型的值,实参传递给形参的是基本类型值的副本,而不是实参本身。被调函数对形参怎么改跟实参都没有关系。
对于引用类型,值传递中的值是指实参对引用类型的引用地址,实参传递给形参的是地址的副本,而不是实参本身。被调函数内改变形参所对应的对象,也就是堆中的对象本身,并不会改变形参本身(引用地址副本),也不会改变实参本身(引用地址);被调函数内改变形参本身(引用地址副本),也不会对实参产生影响,因为改变的是副本,跟实参没有关系。

值传递(pass by value)是指在调用方法时将实参复制一份传递到方法中,这样当方法对形参进行修改时不会影响到实参。(把这个东西的克隆给你拿去玩)
引用传递(pass by reference):是指在调用方法时将实参的地址直接传递到方法中,那么在方法中对形参所进行的修改,将影响到实参。(直接把这个东西本身给你拿去玩)

  • 形参出现在函数定义中,在整个函数体内都可以使用,离开该函数则不能使用。形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只在函数内部有效。函数调用结束返回主调用函数后则不能再使用该形参变量。

  • 实参出现在主调函数中,进入被调函数后,实参变量也不能使用。形参和实参的功能是作数据传送。发生函数调用时,主调函数把实参的值传送给被调函数的形参从而实现主调函数向被调函数的数据传送。
     
    在调用函数时,实参将赋值给形参。因而,必须注意实参的个数,类型应与形参一一对应,并且必须要有确定的值。

成员变量与局部变量的区别有哪些?

  1. 从语法形式上看:成员变量是属于类的,⽽局部变量是在⽅法中定义的变量或是⽅法的参数;成员变量可以被 public , private , static 等修饰符所修饰,⽽局部变量不能被访问控制修饰符及 static 所修饰;但是,成员变量和局部变量都能被 final 所修饰。
  2. 从变量在内存中的存储⽅式来看:如果成员变量是使⽤ static 修饰的,那么这个成员变量是属于类的,如果没有使⽤ static 修饰,这个成员变量是属于实例的。
  3. 生命周期:从变量在内存中的⽣存时间上看:成员变量是对象的⼀部分,它随着对象的创建⽽存在,⽽局部变量随着⽅法的调⽤⽽⾃动消失。
  4. 自动赋值:成员变量如果没有被赋初值:则会⾃动以类型的默认值⽽赋值(⼀种情况例外:被 final 修饰的成员变量也必须显式地赋值),⽽局部变量则不会⾃动赋值。

Java的对象拷贝(浅拷贝、深拷贝)以及引用拷贝

  • 引用拷贝:B对象只拷贝A对象的引用地址,两个对象指向的还是堆中的同一个对象地址
  • 浅拷贝:B对象使用clone()方法对A对象进行克隆,即在堆中创建出来一个和A对象一样的新对象,但是浅拷贝存在一个问题:在堆中clone()出来的B对象中的引用类型还是和之前的A对象公用的,并没有创建一个新的引用类型出来
  • 深拷贝:改写clone()方法,在堆中对A对象中的基本类型和引用类型都克隆出一个新的出来,实现在堆中真正意义上的完全独立的两个对象

在这里插入图片描述
clone()方法:

Object类中的
protected native Object clone() throws CloneNotSupportException;

子类需要实现Cloneable接口并重写该方法并声明为public,外部才能调用这个方法
在重写时直接调用Objectclone()方法即可
浅拷贝
public class Person implements Cloneable{
	public int age;
	public Person(int age){
	this.age=age;
	}
	@Override
	public Person clone(){
	try{
		 return (Person) super.clone();
		 }catch(CloneNotSupportException e) {
		 return null;
		 }
	}
}

深拷贝
public class Person implements Cloneable{
	public int age;
	public int[] arr=new int[]{1,2,3};

	public Person(int age){
	this.age=age;
	}
	@Override
	public Person clone(){
	try{
		 Person person=(Person) super.clone();
		 person.arr=this.arr.clone();
		 return person;
		 }catch(CloneNotSupportException e) {
		 return null;
		 }
	}
}

2022.4.16

左值和右值
定义:左值与右值的定义在于一个赋值等号,赋值等号左边成为左值,等号右边成为右值
左值(L-value):表示存储在计算机内存的对象,可寻址,相当于地址值
右值(R-value):代表的为真实值,可读,即数据值
因为左值是一个地址值,因此可以对左值进行赋值操作,而右值本身就是同一个数据值,就不存在对一个数据值就行赋值的操作。
例如:

int a,b;
a=5;//为合法的操作,因为a是个地址值;
b=a;//这个也是个合法操作,在这里b为地址值,a取其数据值即5(注意这里不是取地址值,因为a是作为一个右值)
5=5;//这是一个非法操作,因为左值是个数据值,右值也是个数据值

++i和i++的区别
++i是左值,可以直接对++i赋值,例如++i=3。
i++是右值,不能直接对i++赋值,例如i++=3会报错。
++i是指被加1之后的i,而i++是指i被加1的这一个操作表达式,虽然两者的结果都为1,但是++i的结果是直接返回的加1后的i,而i++返回的是一个新的变量,值为i+1。++i和i++的结果都为1,因为这两者本身在汇编语言中没有任何区别,但是涉及到赋值操作的时候,i++会比++i多一行指令。

i++;  
++i;   //在汇编语言中二者完全相同

a=++i,直接对a赋值++i

i=i+1;
return i;

a=i++,会申请一个临时空间存储运算之后的值,然后将这个临时值赋值给i。

汇编语言的逻辑大概类似于:
int x;
x=i+1;
i=x;  
return i;
但是为什么不能作为左值呢,因为作为左值时没有申请临时空间这一步,左值需要直接就是内存地
址,不能有额外的相关操作

在这里插入图片描述

char和varchar
char是一种固定长度的类型,无论储存的数据有多少都会固定长度,如果插入的长度小于定义长度,则可以用空格进行填充。而varchar是一种可变长度的类型,当插入的长度小于定义长度时,插入多长就存多长。如果你把一个超过列最大长度的值赋给一个CHAR或VARCHAR列,值被截断以适合它。

最大长度: char最大长度是255字符,varchar最大长度是65535个字节。
定长:char是定长的,不足的部分用隐藏空格填充,varchar是不定长的。
空间使用: char会浪费空间,varchar会更加节省空间。
查找效率: char查找效率会很高,varchar查找效率会更低。
尾部空格:char插入时可省略,vaechar插入时不会省略,查找时省略。

事务管理
在这里插入图片描述

脏读 脏写 幻读 幻写 不可重复读

  • 脏读:假设数据库一条原始数据值为x,被事务A进行写操作,修改为了y但是还没有提交,此时事务B进来进行对数据库查询,查到了修改后的y,但是查到y之后,事务A进行了回滚,使得数据库中的数据又变回了x。因此就会出现事务B查询到的数据和当前数据库真实的x数据不一样,这就是脏读。
    脏写:假设数据库一条原始数据值为x,被事务A进行写操作,修改为了y但是还没有提交,此时事务B进来进行对数据库查询,查到了修改后的y,但是查到y之后,事务A进行了回滚,使得数据库中的数据又变回了x。因此就会出现事务B查询到的数据和当前数据库真实的x数据不一样,也就是事务B读出了一条数据库并不存在的数据,这就是脏读。
  • 脏写:假设数据库有一天原始数据值为x,被事务A操作写为了x+1但是还没有提交,此时事务B进来对这条数据写为了x+2,但是在事务B的写之后,事务A进行了回滚,使得数据恢复为了x,这样事务B对数据的操作效果就消失了,也就是事务B的写被事务A的回滚抹除了,这就是脏写。
    思考:如果事务B的提交是在事务A的回滚之后呢?根据推测应该是将数据库中的数据写为了x+2,就是事务A的回滚效果被事务B抵消了,事务B写入的是先事务A操作后事务B操作的共同结果。这个就不是脏写了,这个叫做幻写,后面会对幻写进行描述。
    脏读/脏写的【脏】字到底是什么意思:事务A的操作被视为是脏的东西,要擦干净(回滚),因此,在脏东西事务A基础上的读和写就被视为脏读和脏写,脏东西A被擦掉时(也就是回滚),事务B进行的脏读或脏写结果会出错。
  • 幻读:
  • 不可重复读:事务A对一条数据的多次重复读取结果不一样,比如事务A对一个原始数据x进行多次读取,事务B把这个x修改为x+1,并且规定事务B提交前,他对x的修改无法被外界读取到,因此就避免了脏读的问题,但是此时出现了另外一个问题,事务A对这条数据多次查询结果不一样,一次是x,一次是x+1,这就叫做不可重复读。

事务隔离级别【】【】【】【】【】
读未提交(Read uncommitted)
读已提交(Read committed)
可重复读(Repeatable read)
可序列化/可串行化读(Serializable)

数组是对象吗?
数组是对象,使用instanceof Object结果为true,数组和普通对象不一样的地方是:数组由JVM直接创建,而不是通过某个类来实例化,除了Object外,数组不是任何一个类的实例。(Array类时reflect包下的一个工具类,不是指数组)

静态代码块、构造代码块,构造方法是什么

静态代码块、构造代码块,构造方法的执行顺序:【静态代码块static{},代码块{}】

父类静态代码块→子类静态代码块→父类构造代码块→父类构造方法→子类构造代码块→子类构造方法

String、StringBuffer、StringBuilder
String是private final char value[]
StringBuffer和StringBuilder是继承于AbstractStringBuilder类,是非final的,AbstractStringBuilder父类定义了一些对字符串操作的方法:例如append,getindex,insertbyindex。其中StringBuilder对父类的一些方法添加了Sychronized关键字,也就是同步锁,实现了线程安全,而StringBuilder是线程不安全的
在少数据量时使用String
在大数据量多线程时使用StringBuffer
在大数据量单线程时使用StringBuilder
其中StringBuilder比StringBuffer的性能多了百分之十几,也不是很明显

Sychronized关键字:Sychronized是java的内置的同步锁,是重量级锁,Sychronized关键字可以把方法或者对象标记为同步,被Sychronized修饰的方法或对象是线程安全的,在线程进入方法或者获取对象时会先将其上锁再进入。其中修饰静态方法时是全局锁,锁的是当前的Class类对象,修饰非静态方法时锁的是当前实例对象。Sychronize的实现,其实在JVM中每一个对象都是内置一把锁的,叫做监视器锁(Monitor),监视器锁默认都是打开的,Sychronized的实现就是去争夺Monitor锁,如果争取到了就会将Monitor的计数器加1,此时其他线程无法再获取到这个Monitor锁,但是当前线程依然可以获取到这个Monitor锁,然后使得计数器再+1,实现了Sychronized同步锁的可重入,可以避免一些死锁问题。如果释放一个Monitor锁就会将计数器-1,直到为0的时候才能被其他线程获取。Sychronized的典型实现为悲观锁,即每次写数据时都认为会出现并发操作,从而会在每次写操作之前上锁,让其他线程无法进入。

内存溢出 JVM剩余内存小于当前线程申请的内存,就会导致线程无法正常执行,这就叫做内存溢出。
内存泄漏 死锁或者程序异常并且无法正常退出释放内存,因此导致JVM可用内存减少,叫做内存泄漏

2022.4.19

常见异常Execption:
空指针异常(NullPointExecption)
类转换异常(ClassCastException)
算数异常(ArithmeticException) Arithmetic 算术 [əˈrɪθmətɪk]
数组下标异常(ArrayIndexOutOfBoundsException) bounds:界限
文件未找到异常(FileNotFoundException)
操作数据库异常(SQLException)
I/O异常类(IOException)
线程终止异常(InterruptedException) Interrupted 中断 [ˌɪntəˈrʌptɪd]

HashMap和HashTable区别
HashTable是线程安全的,HashMap是线程不安全的。就是因为HashTable内部加了Sychronized关键字保持数据同步。HashTable默认大小11,每次扩容,大小×2+1;HashMap默认大小16,每次扩容,大小×2,他们两者的扩容/加载/负载因子都是0.75,都是下标+1>大小×扩容因子时会进行扩容。其中HashMap支持一个Null键和多个Null值(因为键不能重复,Entry的key是Set,value是Collection),HashTable不支持Null键和Null值。

HashMap最大容量是230,最小容量是16

hashcode()重写:初始值17,递归乘以31并加上哈希相关字段的hashcode()
在这里插入图片描述

ArryList是线程不安全的,Vector是线程安全的,Vector给所有方法都加了锁。

Automic类,计数器原子类

2022.4.25

创建线程方式

  • 继承Thread,继承Thread类,重写run()方法,调用Thread.start()方法启动
  • 实现Runnable接口,重写run()方法,调用Thread.start()方法启动
  • Callable和Future,重写call()方法,调用Thread.start()启动线程

run()方法不带返回值,可以通过在run方法里把最后的结果传递给实例变量,然后通过getXX方法获取该实例变量的值
run()方法不能抛异常,call()可以抛异常

Callable接口创建线程:
①实现Callable接口并重写call()方法,注意call方法返回类型是<T>,run方法是没有返回值的void
class XXX implements Callable<T> {
    @Override 
    public <T> call() throws Exception { 注意call方法可以抛异常,run方法是不能抛异常的
        return T; 
    } 
}
②创建FutureTask对象,并传入第一步编写的实现了Callable的类对象 
FutureTask<返回结果类型> future = new FutureTask<>(callable);
③通过Thread启动线程
new Thread(future).start()
//或者 Thread thread=new Thread(future);  thread.start();

创建对象的五种方式

  • new关键字
  • Class.newInstance
  • Constructor.newInstance
  • Clone方法
  • 反序列化

其中前三种调用了构造器,后两种Clone和反序列化没有调用构造器

LinkedHashMap就是每个Entry加了左右指针(前后指针)的HashMap,按照插入顺序连接起来,方便遍历
JDK1.8后把HashMap的头插入改为了尾插入(为了避免死锁)

缓存穿透:缓存没有,透过缓存直接去持久层

  • 即 。查询数据库不存在的数据,会导致无法缓存,每次都去持久层查询,
  • 解决
    ①缓存空对象
    ②布隆过滤器

缓存击穿:访问力量太大把缓存层打穿了

  • 当前key是一个热点key(例如一个秒杀活动),并发量非常大。
    缓存重建不能在短时间内完成,可能是一个复杂计算,例如复杂的SQL、多次IO、多个依赖等。在缓存失效的瞬间,有大量线程来重建缓存,造成后端负载加大,甚至可能会让应用崩溃

  • 解决
    ①永不过期
    ②分布式互斥锁:只允许一个线程重建缓存,其他线程等待重建缓存的线程执行完,重新从缓存获取数据即可

缓存雪崩:集中穿透,所有的小雪花(指单个穿透)同时崩掉,发生雪崩

  • 缓存在一段时间内集中失效,发生大量的缓存穿透,所有的查询都落在数据库上,造成了缓存雪崩。

  • 解决:
    ①分布式高可用,使用哨兵或者集群,使得一个服务器宕机还有其他服务器提供服务
    ②多级缓存,在redis和本地都设置缓存,使得一个过期还有另外一个兜底
    ③过期时间,离散过期时间,过期时间加随机数或者按照其他规律把过期时间分散开来,避免雪崩
    ④服务熔断:停止对不可用或超时服务的调用
    服务熔断的作用类似于我们家用的保险丝,当某服务出现不可用或响应超时的情况时,为了防止整个系统出现雪崩,暂时停止对该服务的调用。
    ⑤服务降级:只提供核心请求,降低符合,非核心请求返回错误
    服务降级是从整个系统的负荷情况出发和考虑的,对某些负荷会比较高的情况,为了预防某些功能(业务场景)出现负荷过载或者响应慢的情况,在其内部暂时舍弃对一些非核心的接口和数据的请求,而直接返回一个提前准备好的fallback(退路)错误处理信息。这样,虽然提供的是一个有损的服务,但却保证了整个系统的稳定性和可用性

缓存击穿和缓存雪崩:穿透缓存层去持久层
缓存穿透:热点key高并发或大量缓存重建请求

Redis
Redis是c语言开发的基于内存存储的数据库,常用作缓存,也可用作分布式锁或消息队列。
支持多种数据类型,而且支持事务、持久化(灾难恢复机制、重启重载入内存)、多种集群方式,Lua脚本,有过期策略,性能非常高,单线程多路复用
Redis支持的数据类型:k/v键值对 list(类似Java的双向链表) set(HashSet) zset hash(HashMap,多用于存储对象)

ACID
A 原子性 事务是最小单位,事务中的操作要么全部成功,要么全部失败回滚
C 一致性 事务执行前后数据是一致的
I 隔离性,事务不被其他事务干扰,不同并发事务之间数据库是独立的
D 持久性 事务提交后,事务对数据库中的数据的改变是持久的

2022.8.5

MySQL4.0和Oracle数据库的varchar(30)代表30个字节,可以存放10个UTF-8编码(3字节大小)汉字
MySQL5.0的varchar(30)代表30个字符,不管字母数字还是汉字,都能存30个

2022.8.31

  1. windows查看某个端口占用,查看占用进程的pid:
    netstat -ano|findstr “8080”
  2. 查看pid为9088的进程
    tasklist|findstr “9088”
  3. 强制杀掉pid为9088的进程
    taskkill /T /F /PID 9088

第2和第3步有更方便的操作就是直接去任务管理器里面结束掉对应pid的进程

2022.9.19

@Transactional
同一个方法进行多个sql操作最好加上事务注解,然后try catch抓异常,然后在catch里面throw new异常,可以使事务操作回滚

字符串占位符
进行输出或者日志打印最好使用占位符{}而不是拼串+,因为拼串需要新建对象去拼接,而用占位符的String对象数量是固定的,数据量大时拼串会导致内存消耗。可以从两方面来分析:
方法调用次数:拼串是用到StringBuilder的append()方法,不管参数存不存在都会调用append()方法进行拼串,占位符是用到了String的format()方法,只调用一次
对象数量:进行拼串时,例如a+“b”+c,具体流程是a “b” c三个对象,a拼"b"生成第四个对象"ab",“ab"拼c又生成第四个对象"abc”。而用占位符的具体操作是,例如对于String.format(“{}b{}”,a,c),对象数量是固定的3个,也就是 “{}b{}”、a、c这三个。 String.format()可以省略,直接写为"{}b{}",a,c

split方法分割字符串,返回字符数组String[]
特殊字符加\转义 匹配多个字符使用 | 号

String add1="南京*建邺区";
String[] splitAdd1=add1.split("\\*");

String address="南京1^南京2*南京3#南京4|南京5";
String[] splitAddress=address.split("\\^|\\*|#|\\|");

分布式系统的CAP原则
CAP原则又称CAP定理,指的是在一个分布式系统中,一致性(Consistency)、可用性(Availability)、分区容错性(Partition tolerance)。CAP 原则指的是,这三个要素最多只能同时实现两点,不可能三者兼顾。

正则表达式

//匹配第一位为1,后面再跟上10个数字
String regex="^1\\d{10}$";
Boolean b = Pattern.matches(regex,XXX)  ///XXX为被正则匹配的字符串

ip地址:主机身份地址的标志
子网掩码:分为网络位和主机位,二进制中1是网络位,0是主机位。可以和ip地址一块确定一个主机的网段
网关:父网和子网(不一定非要是公网和内网)中间的一道门,网关地址也就是路由器地址,默认网关就是默认路由器地址
DNS:Domain Name Server 静态域名解析服务器 解析静态主机ip(不一定非要是公网ip)与域名的映射
DDNS:Dynamic Domain Name Server 是动态域名服务器,解析动态的主机ip(不一定非要是公网ip)与域名的映射 例如对ISP动态分配的公网IP的域名解析
内网穿透:即NAT穿透,内网端口映射。内网IP端口映射外网访问的实现和过程。主要用于内网发布外网,外网连接访问内网,解决无公网IP问题
端口映射:即地址转换,一个地址端口映射到另一个地址端口。从实现角度看,跟内网穿透类型目的。在实现过程操作看,包括了路由器端口映射和软件端口映射。路由映射需要公网IP,软件映射则可以内网IP映射到自己域名
路由映射:直接由外网到路由器的公网ip再到路由器下的内网的主机ip形成端口映射。例如:

本地计算机(外网)映射到服务器内网ip:127.0.0.1的6666端口(服务器用户uuu,服务器公网ip:x.x.x.x,映射端口6666) 
ssh -L 6666:127.0.0.1:6666 uuu@x.x.x.x

软件映射:例如花生壳软件。在一个可以访问公网的服务器上部署内网映射程序服务端,在不能访问外网的内网服务器上部署内网映射程序客户端,建立两个服务器的连接,从而实现外网到服务端服务器再到客户端服务器的端口映射,也就是内网穿透

DDNS或DNS:IP和域名的映射解析,重点在于映射
内网穿透:内网到外网的端口映射,重点在于穿透

求网段:ip和子网掩码转为二进制 按位取与
服务器的内网和公网是相对于防火墙来说的,防火墙外是公网,防火墙内是内网

map遍历

for(string key:map.keyset())
Iterator<Map.Entry<string,object>> iterator=map.EntrySet<string,object>.iterator
for(map.entry<string,object> e:map.EntrySet())
for(Object v:map.values())

stream().filter.collect()
foreach
optional
枚举类
JDBC数据库连接

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

在外面要叫头哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值