2020/08/31
1、逻辑或、逻辑与运算只能针对布尔类型的条件表达式进行运算。
2、计算机定义了两种小数:定点数和浮点数
3、IEEE754浮点数标准,规定了4种浮点数类型:单精度、双精度、延伸单精度、延伸双精度
4、浮点数使用:
在使用浮点数的时候推荐使用双精度,使用单精度由于表示区间的限制,计算结果会出现微小的误差。
在要求绝对精确表示的业务场景下,比如金融行业的货币表示,推荐使用整型存储器最小单位的值,展示时可以转换成该货币的常用单位,比如人命币使用分存储,美元使用美分存储。在要求精确表示小数点n位的业务场景下,比如圆周率要求存储小数点后1000位数字,使用单精度和双精度浮点数类型保存都是难以做到的,这时推荐使用数组保存小数部分的数据。
在比较浮点数时,会存在误差。禁止通过判断两个浮点数是否相等来控制业务流程。在数据库中保存小数时,推荐使用decimal类型,禁止使用float和double类型,因为这两种类型在存储的时候会有精度损失。
综上所述,在要求绝对精度表示的业务场景中,在小数保存、计算、转型过程中要谨慎对待。
5、cpu由控制器和运算器组成,内部寄存器使这两者协同更加高效。
2020/09/01
TCP三次握手创建连接(二次会导致脏连接)
TCP四次挥手断开连接
从经验来看,数据库层面的请求应答时间必须在100ms内,秒级sql查询通常存在巨大的性能提升空间。有如下应对方案:
1)建立高效且合适的索引
2)排查连接资源未显式关闭的情形
3)合并短请求
4)合理拆分多个表join的SQL,若是超过三个表则禁止join
5)使用临时表
6)应用层优化
7)改用其他数据库
SQL注入解决办法:
1)过滤用户输入参数中的特殊字符
2)禁止通过字符串拼接的SQL语句,严格使用参数绑定传入的sql参数
3)合理使用数据库访问框架提供的防止注入机制,mybatis禁止使用${}
防范XSS攻击:前端使用innerText 而不是innerHtml
防范CSRF漏洞主要通过以下方式:
1)CSRF token验证
2)人机交互,比如短信验证
2020/09/02:
1、安全套接字层:Secure socket layer - SSL
2、HTTPS ->HTTP OVER SSL
3、对称加密算法:DES
4、非对称加密算法:RSA
5、优秀的程序员至少需要掌握3门语言,这有助于知晓不同语言的各自特性,更重要的是洞悉语言共性和编程语言思想,跨域语言的抽象思维和架构掌控力。但是掌握不等于精通,真正的大师,需要醉心于某种语言,不断研究、不断打磨、不断回炉,才能达到炉火纯青、登峰造极的境界。我们写的每一行代码都是站在巨人的肩膀上,使我们看得更远。虽然任何编程语言的结构都是顺序、条件、循环,任何编程语言的本质都是输入输出,但是0与1的世界一定会因为编程变得更智能,更美好。
6、慎用object的clone()方法,因为对象的clone()方法是浅拷贝,若想实现深拷贝,则需要覆写clone()方法实现引用对象的深度遍历式拷贝。
7、设计模式七大原则之一的迪米特法则就是对于封装的具体要求,即A模块使用B模块的某个接口行为,对B模块中除此之外的其他信息知道得尽可能少。
8、继承的is-a判断标准:是否符合里氏代换原则(LSP)任何父类能出现的地方子类都能够出现。
9、提倡组合优先的原则来扩展类的能力,即优先采用组合或者聚合的类关系来复用其他类的能力,而不是继承。
10、JDK5~JDK8的重要特性:
JDK5新特性:foreach迭代方式,可变参数,枚举,自动拆装箱,泛型,注解等重要特性(历史意义的版本)
JDK6新特性:。。。
JDK7新特性:switch支持字符串作为匹配条件、泛型类型自动推断、try-with-resource资源关闭技巧,Objects工具类,ForkJoinPool等重要类与特性。
JDK8新特性:lambda表达式、函数式编程、引入Optional避免空指针
11、抽象类是模版式设计,接口是契约式设计。
12、定义包内可见静态内部类的方式很常见,这样做的好处是:
1)作用域不会扩散到包外
2)可以通过“外部类.内部类”的方式直接访问
3)内部类可以访问外部类中所有的静态属性和方法
13、在定义类时,推荐访问控制级别从严处理:
1)如果不允许外部直接通过new创建对象,构造方法必须是private
2)工具类不允许有public和default构造方法
3)类非static成员变量并且与子类共享,必须是protected
4)类非static成员变量并且仅在本类使用,必须是private
5)类static成员变量,如果仅在本类使用,必须是private
6)若是static成员变量必须考虑是否为final
7)类成员方法只供类内部调用,必须是private
8)类成员方法只对继承类公开,那么限制为protected
14、访问权限控制符:无 不为default
2020/09/21
1、尽量不使用可变参数。如果一定要使用,则只有相同参数类型,相同业务含义的参数才可以。并且一个方法只能有一个可变参数,且为该方法的最后一个参数。不推荐使用Object作为可变参数类型。
2、正确使用参数,参数预处理,包含两种情况:
1)入参保护。常见于批量接口。如:数据量过多导致内存占满。
2)参数校验
3、构造方法:
1)构造方法名称必须与类名相同。
2)构造方法没有返回类型,void也不能有。它返回对象地址,并赋值给引用变量。
3)不能继承,不能覆写,不能被直接调用。调用途径有三种:new、super、通过反射方式获取并调用。
4)定义类时提供了无参的构造方法。如果定义了有参数构造方法,还需要原始构造方法,则需要显式定义。
5)构造方法可以私有
注意:构造方法应遵循单一职责原则,不应在构造方法中引入业务逻辑。
4、类对象创建:
先执行父类和子类的静态代码块,然后再执行父类和子类的构造方法,静态代码块只运行一次,在第二次对象实例化时不会运行。
2020/10/17:
1、类内方法
除构造方法外类中还可以有三类方法:实例方法、静态方法、静态代码块
2、静态方法:
1)静态方法中不能使用实例成员变量和实例方法
2)静态方法不能使用this和super关键字,这两个关键字指代的都是需要被创建出来的对象
3、静态代码块
1)静态代码块是先于构造方法执行的特殊代码块
2)不能存在于任何方法体内,包括类静态方法和属性变量
4、getter和setter
一般不包含任何业务逻辑
好处:
1)满足面向对象语言封装的特性
2)有利于统一控制。如对对象属性修改作权限控制可在setter处做处理
易出错点:
1)在setter/getter中添加业务逻辑很难排查
2)同时定义iSXxxx()和getXxxx(),两者同时存在会在iBATIS和Json序列化引起冲突
3)相同的属性名容易带来歧义
非getter/setter参数名不能语成员变量相同
5、覆写-动态绑定
如果父类的方法不能满足子类的期望,那么子类可以重新实现方法覆盖父类的实现,因为有些子类是延迟加载,甚至是网络加载的,所以最终的是现实需要在运行期判断,这就是-动态绑定
通过父类执行子类方法时需要注意以下两点:
1)无法调用到子类中存在而父类本身不存在的方法
2)可以调用到子类中覆写了父类的方法,这是一种多态实现
想要成功覆写父类方法,需要满足4个条件(转型满足LSP李氏替换原则):
1)访问权限不能变小
2)返回类型能够向上转型为父类的返回类型
3)异常也要能向上转型为父类的异常
4)方法名和参数列表必须完全一致
总结为“一大两小两同”
6、重载-静态绑定
1)在编译器眼里,方法名+参数列表组成一个唯一键,称为方法签名
2)JVM在重载方法中选择合适的目标方法的顺序如下:
a、 精确匹配
b、如果是基本数据类型,自动转换为更大表示范围的基本类型
c、通过自动拆箱与装箱
d、通过子类向上转型继承路线依次匹配
e、通过可变参数匹配(优先级最低)
2020/10/15:
1、Java 9种基本数据类型:
boolean,byte,char,short,int,long,float,double,refvar(引用变量,也叫引用句柄)
2、不能用双引号的方式对char类型进行赋值
3、引用分为两种数据类型:引用变量本身,和引用指向的对象
4、基本数据类型int占用4个字节,而对应的包装类Integer实例对象占用16个字节
5、类定义中的方法代码不占用实例对象的任何空间
1)对象头:对象头最小占用12字节空间(包括对象标记8字节和类元信息)4字节
2)实例数据:实例成员变量和所有可见的父类成员变量
3)对齐填充:对象的存储空间分配单位是8个字节,如果需要占用的内存不为8的倍数,则补充为相近最小8的倍数
6、各个包装类的缓存区间:
Boolean:使用静态final变量定义,valueOf就是返回这两个静态值
Byte:表示范围是-128~127,全部缓存
Short:表示范围是-32767~32767,缓存范围是-128~127
Character:表示范围是0~65535,缓存范围是0~127
Long:表示范围是-2的63次方~2的63次方-1,缓存范围是-128~127
Integer:表示范围是-2的31次方~2的31次方-1,缓存范围是-128~127。在VM options加入参数-XX:AutoBoxCacheMax=7777即可设置最大缓存值为7777
7、在选择使用包装类还是基本数据类型时,推荐使用如下方式:
1)所有的POJO类属性必须使用包装类型
2)RPC方法的返回值和参数必须使用包装数据类型
3)所有的局部变量推荐使用基本数据类型
8、命名规约
1)命名符合本语言特性
2)命名体现代码元素特征
3)最好望文知意
9、常量:常量是在作用域内保持不变的值,一般使用final关键字进行修饰。根据作用域区分为3类:
1)全局常量:指的是类的公开静态属性,使用public static final 修饰
2)类内常量:是私有静态属性,使用private static final 修饰
3)局部常量:分为方法常量和参数常量,前者是在方法或者代码块内部定义的常量,后者是在定义形式参数时,增加final标志,表示此参数值不能被修改
10、一般类型用枚举表示,状态可用枚举也可用不能被实例化的抽象类的全局常量来表示,从而避免魔法值。
11、控制语句:
1)在if,else,for,while,do-while等语句中必须使用大括号
2)在条件表达式中不能有赋值操作,也不要在判断表达式中出现复杂的逻辑组合
3)多层嵌套不能超过3层
4)避免采用反逻辑运算符
JVM
1、类加载过程:
1)Load-加载:读取类文件产生的二进制流,并转化为特定的数据结构,初步校验cafe babe魔法数、常量池、文件长度、是否有父类等,然后创建对应的java.lang.Class实例
2)link-链接:包括验证、准备、解析三个步骤。验证是更加详细的校验,比如final是否合规、类型是否正确、静态变量是否合理等;准备阶段是为静态变量分配内存,并设置默认值,解析类和方法确保类与类之间的额相互引用正确性,完成内存结构布局
3)Init-初始化:执行类构造器<clinit>方法,如果赋值运算是通过其他类的静态方法来完成的,那么马上会解析另外一个类,在虚拟机栈中执行完毕后通过返回值进行赋值。
2、在什么情况下需要自定义类加载器?
1)隔离加载类
2)修改类加载方式
3)扩展加载源
4)防止代码泄露
3、内存布局:堆、元空间、虚拟机栈、本地方法栈、程序计数器
1)堆是OOM的主要产生地,分为两大块:新生代和老年代
2)栈帧在整个JVM体系中地位颇高,包括局部变量表、操作栈、动态连接、方法返回地址等
总结:从线程共享的角度来看,堆和元空间是所有线程共享的,而虚拟机栈、本地方法栈、程序计数器是线程内部私有的。
2020/11/09:
并发与多线程:
1、线程状态:NEW (新建状态)、RUNNABLE(就绪状态)、 RUNNING (运行状态)、BLOCKED(阻塞状态) DEAD(终止状态)五种状态
(1)、NEW 新建状态,是线程被创建且未启动的状态。创建线程的方式有3种:
第一种是继承自Thread类,第二种是实现Runnable接口,第三种是实现Callable接口。相比第一种推荐第二种方式,因为继承自Thread类往往不符合里氏代换原则。而实现Runnable接口可以使编程更加灵活,对外暴露的细节比较少,让使用者专注于实现线程的run()方法上。
Callable与Runnable有两点不同:第一可以通过call()返回值,前两种方式都不能在任务执行完成后,直接获取执行结果,需要借助共享变量等来获取,而Callable和Future则很好地解决了这个问题,第二,call()可以抛出异常,而Runnable只有通过setDefaultUncaughtExceptionHandler()的方式才能在主线程中捕捉到子线程异常。
(2)、Runnable,就绪状态,是调用start()之后运行之前的状态。
(3)、RUNNING,运行状态,是run()正在执行时线程的状态。
(4)、BLOCKED,进入此状态,有以下三种情况:
同步阻塞:锁被其他线程占用
主动阻塞:调用THread的某些方法,主动让出CPU执行权,比如sleep(), join()等
等待阻塞:执行了wait()
(5)DEAD,终止状态,是run()执行结果,或因异常退出后的状态,此状态不可逆转
2、为保证线程安全,在多个线程并发地竞争共享资源时,通常采用同步机制协调各个线程的执行,以确保得到正确的结果。
3、线程安全问题只在多线程环境下才出现,单线程串行执行不存在此问题。保证高并发场景下的线程安全,可以从以下四个维度考量。
(1)、数据单线程内可见
(2)、只读对象
(3)、线程安全类
(4)、同步与锁机制
4、线程安全的核心理念就是“要么只读,要么加锁”
5、Java并发包(Java.util.concurrent,JUC)主要分成以下几个类族:
(1)线程同步类
(2)并发集合类
(3)线程管理类
(4)锁相关类
6、计算机锁也是从开始的悲观锁,发展到后来的乐观锁、偏向锁、分段锁等。锁主要提供了两种特性:互斥性和不可见性
7、Java中实现锁的方式有两种
(1)用并发包中的锁类
Lock是JUC包的顶层接口,它的实现逻辑并未使用synchronized而是利用了volatile的可见性
(2)是利用同步代码块
同步代码块一般使用Java的synchronized关键字来实现,有两种方式对方法进行加锁操作:
第一在方法签名处加synchronized关键字
第二使用synchronized(对象或者类)进行同步。
这里的原则是锁的范围尽可能小,锁的时间尽可能短,即能锁对象就不要锁类,能 锁代码块就不要锁方法。
8、JDK6以后不断优化使得synchronized提供三种锁的实现,包括偏向锁、轻量级锁、重量级锁,还提供了自动的降级和升级机制。JVM就是利用CAS在对象头上设置线程ID,表示这个对象偏向于当前线程,这就是偏向锁。
9、偏向锁是为了在资源没有被多线程竞争的情况下尽量减少锁带来的性能开销。在锁对象的对象头重有一个ThreadId字段,当第一个线程访问锁时,如果该锁没有被其他线程访问过,即ThreadId字段为空,那么JVM让其持有偏向锁,并将ThreadId字段的值设置为该线程的ID,当下一次获取锁时,会判断它们是否一致,如果一致,那么该线程不会重新获取锁,从而提高了程序的运行效率。如果出现锁的竞争情况,那么偏向锁会被撤销,并被升级为轻量级锁,如果竞争非常激烈会升级为重量级锁。偏向锁可以减低无竞争开销,它不是互斥锁,不存在线程竞争的情况,省去再次同步判断的步骤,提升了性能。
10、资源共享的两个原因是资源紧缺和共建需求。线程共享cpu是从资源紧缺的维度来考虑的,而多线程共享同一变量,通常是从共建需求的维度来考虑的。
11、原子性:指不可分割的一系列操作指令,在执行完毕前不会被其他任何操作中断,要么全部执行,要么全部不执行。
2020/11/10:
线程池:
1、线程池的好处
线程使应用能够更加充分合理地协调利用CPU、内存、网络、I/O等系统资源。
线程池的作用包括:
(1)利用线程池管理并复用、控制最大并发数等。
(2)实现任务线程队列缓存策略和拒绝机制。
(3)实现某些与时间相关的功能,如定时执行、周期执行等
(4)隔离线程环境
2020/11/11:
ThreadPoolExecutor的构造方法如下:
特别提示:本信息由相关企业自行提供,真实性未证实,仅供参考。请谨慎采用,风险自负。