java笔记记录
本文最后更新于:2022年6月19日 下午
Java题目笔记
2022-06-19更新
Mysql(版本8.0.25)不支持full join, 执行full join 语句会报错。
2022-06-17更新
Java权限修饰符:
private 和 public很容易理解,分别是只能类内部访问和任何地方都可以访问。
比较让人容易分不清楚的,默认default的和protected的,默认的权限是类内部和在同一个包下可以访问;保护的权限是类内部、同一个包下和不在同一个包中的子类中可以访问。
hashCode()和equals()
hashCode()方法并不完全可靠,有时不同对象的hashCode()生成的hash值也是相同的,所以这时候需要再使用equals()来进行比较。
那为什么不直接都使用equals()进行比较呢?因为重写的equals()方法往往比较复杂,为了提高程序的效率,一般先使用hashCode()进行比较,如果两个对象的hash值不相等,则两个对象肯定不相等,直接返回false;如果hash值相等,则需要再使用equals()进行比较。
所以,做个总结:
- equals()相等的两个对象,它们的hashCode()肯定相等,使用equals()对比是绝对可靠的。
- hashCode()相等的两个对象,它们的equals()不一定相等。hashCode()不是绝对可靠的。
正因为hashCode()不是绝对可靠的,所以需要再使用equals()来进行对比。
关于try、catch、finally的执行顺序
1 |
|
最终的顺序是:
- 先打印try中的1,temp加1变为2,保存当前这个值2
- 转去执行finally中的语句,temp加1变为3,打印3
- 执行完finally后,返回到try中的return语句,返回第1步保存的值2.
所以最终的打印顺序是:1, 3, 2
try中的return的值会被保存到临时空间中,执行完finally后,方法结束,再返回临时空间中保存的值;
如果finally中有return temp+10;的话,则会刷新临时空间的值,最后仍返回临时空间的值。
类的私有变量,本类的方法可以访问,通过反射也可以访问到。
abstract和final可以同时作为一个类的修饰符吗?
abstract表示该类是一个抽象类。抽象类本身不能实例化,必须需要有子类继承它并实现抽象类中的所有抽象方法,子类才能实例化。
而final表示该类不能被继承。
因此这两个关键字的作用:前者表示该类必须被继承,后者表示该类不能被继承,是相克的,不能同时使用。
当把来自客户机的HTTP请求委托给servlet时,会调用HttpServlet的(service)方法
HttpServlet容器响应Web客户请求流程如下:
1)Web客户向Servlet容器发出Http请求;
2)Servlet容器解析Web客户的Http请求;
3)Servlet容器创建一个HttpRequest对象,在这个对象中封装Http请求信息;
4)Servlet容器创建一个HttpResponse对象;
5)Servlet容器调用HttpServlet的service方法,这个方法中会根据request的Method来判断具体是执行doGet还是doPost,把HttpRequest和HttpResponse对象作为service方法的参数传给HttpServlet对象;
6)HttpServlet调用HttpRequest的有关方法,获取HTTP请求信息;
7)HttpServlet调用HttpResponse的有关方法,生成响应数据;
8)Servlet容器把HttpServlet的响应结果传给Web客户。
doGet() 或 doPost() 是创建HttpServlet时需要覆盖的方法.
抽象类和接口不能实例化
抽象类 a = new 子类(); 是可以的。
字符流和字节流
如图
字节流:InputStream, OutputStream
字符流:多用于处理字符串和文本。面向字符的输入流类都是Reader的子类,面向字符的输出流类都是Writer的子类。一般以 reader 或 writer 结尾。
JVM的内存结构
- PC寄存器
- 虚拟机栈
- 堆
- 方法区 (常量池)
- 本地方法栈
2022-06-18
垃圾回收不能确定具体的回收时间
GC是完全自动的,不能被强制执行。
将某个局部变量置为null,只是表示可能会被回收,但是后面可能还会使用。
静态代码块、构造代码块和构造方法的执行时期
1.静态代码块 2.构造代码块3.构造方法的执行顺序是1>2>3;明白他们是干嘛的就理解了。
1.静态代码块:是在类的加载过程的第三步初始化的时候进行的,主要目的是给类变量赋予初始值。
2.构造代码块:是独立的,必须依附载体才能运行,Java会把构造代码块放到每种构造方法的前面,用于实例化一些共有的实例变量,减少代码量。
3.构造方法:用于实例化变量。
1是类级别的,2、3是实例级别的,自然1要优先23.
在就明白一点:对子类得主动使用会导致对其父类得主动使用,所以尽管实例化的是子类,但也会导致父类的初始化和实例化,且优于子类执行。
Java程序初始化工作可以在许多不同的代码块中来完成,它们的执行顺序如下:
父类的静态变量、父类的静态代码块、子类的静态变量、子类的静态代码块、
父类的非静态变量、父类的非静态代码块、父类的构造函数、
子类的非静态变量、子类的非静态代码块、子类的构造函数。
Java构造方法不能被static、final、synchronized、abstract、native修饰,但可以被public、private、protected修饰;
识别合法的构造方法;
1:构造方法可以被重载,一个构造方法可以通过this关键字调用另一个构造方法,this语句必须位于构造方法的第一行;
重载:方法的重载(overload):重载构成的条件:方法的名称相同,但参数类型或参数个数不同,才能构成方法的重载。
2 当一个类中没有定义任何构造方法,Java将自动提供一个缺省构造方法;
3 子类通过super关键字调用父类的一个构造方法;
4 当子类的某个构造方法没有通过super关键字调用父类的构造方法,通过这个构造方法创建子类对象时,会自动先调用父类的缺省构造方法
5 构造方法不能被static、final、synchronized、abstract、native修饰,但可以被public、private、protected修饰;
6 构造方法不是类的成员方法;
7 构造方法不能被继承。
8 java构造方法中的this关键字: 构造器的this指向同一个类中,用于调用同一个类中不同参数列表的另外一个构造器,必须放在第一行,否则会引起编译错误!
9 java构造方法中的super关键字:构造方法的super关键字用于调用其父类的构造方法,子类默认调用父类的构造方法,也就是说super()是默认调用的,显示调用必须放在构造方法第一行!
基本数据类型
整数型变量:byte, short, int ,long
浮点型:float, double
逻辑型:boolean
字符型:char
静态方法中不能直接调用非静态方法和非静态变量
会在编译时报错:
Non-static field ‘a’ cannot be referenced from a static context
1 |
|
Java的反射
- 反射涉及的类如:Class在lang包下,Method, Filed 在java.lang.reflet包下。
- 通过反射可以动态的实现一个接口,形成一个新的类,并可以用这个类创建对象,调用对象方法。即通过反射实现动态代理。
- 通过反射,可以突破Java语言提供的对象成员、类成员的保护机制,访问一般方式不能访问的成员。例如:通过反射访问私有成员时,Field调用
setAccessible
可解除访问符限制。 - 反射不能实现对字节码的修改
- Java的反射机制会带来效率问题,使用cache和禁止安全检查等都可以提升反射的效率,但即使再怎么优化也不可能达到和直接调用类一样的效率,因为无论是通过字符串获取Class、Method还是Field,都需要JVM的动态链接机制动态的进行解析和匹配(即告诉JVM该如何去找这个类),而直接调用则不必。
8、面向对象
this
- this修饰成员属性
- this修饰成员函数
- this可以在同一个类中调用构造器,this调用构造器必须放在第一行。
static
- 修饰属性
- 修饰方法:类的静态方法中不能访问非静态方法和非静态属性。
- 修饰代码块:执行顺序,静态块–》构造块–》构造器–》成员方法中的普通块。注意:静态块只在类加载的时候执行一次。静态块中只能访问静态成员变量和静态成员方法,不能访问非静态成员方法和非静态成员方法。
- 修饰内部类:
三大特性
封装
提高代码的安全性
继承
提高代码的复用性
父类private修饰的内容,子类实际上也继承,只是因为封装的特性阻碍了直接调用,但是提供了间接调用的方式,可以间接调用。
内存分析
权限修饰符
总结:
属性,方法:修饰符:四种:private,缺省,protected,public
类:修饰符:两种:缺省,public以后写代码
一般属性:用private修饰 ,方法:用public修饰
重载和重写的区别:
重载:在同一个类中,当方法名相同,形参列表不同的时候 多个方法构成了重载
重写:在不同的类中,子类对父类提供的方法不满意的时候,要对父类的方法进行重写。
super
Object类
toString方法
equals方法
多态
提高代码的扩展性
final
修饰基本数据类型,变量值不能改变,是一个常量。
修饰引用数据类型,对象的引用,也就是对象的指向不能改变,对象的属性可以修改。
修饰方法,该方法不能被该类的子类重写。
修饰类,表示该类不能被继承,也就是没有子类。
抽象类,抽象方法
- 抽象类是否可以创建对象?
不可以
- 抽象类中是否有构造器?
有的。子类创建对象初始化时调用子类的构造器,会先使用super调用抽象类的构造器。
- 抽象类是否可以被
final
修饰?
不能,因为抽象类就是用于被继承的,final
修饰的类不能被继承,就没有子类了。
需要被子类重写的方法加上abstract
,去除函数体,就是抽象方法了,抽象方法必须要被子类重写。
子类如果没有重写父类的全部抽象方法,那么子类也可以变成一个抽象类。
接口
抽象类与接口的区别
抽象类 | 接口 |
---|---|
使用abstract修饰 | 使用interface修饰 |
不能实例化 | 不能实例化 |
有构造方法 | 无构造方法 |
含有抽象方法的类是抽象类,必须使用abstract修饰 | 一个类只能继承一个类,但是可以实现多个接口 |
可以含有抽象方法,也可以不包含抽象方法,抽象类中可以有具体的方法 | 接口中的方法均为抽象方法 |
若子类实现了抽象类的所有抽象方法,则子类不是抽象类;否则子类是抽象类 | 接口中不能包含实例域或静态方法(静态方法必须实现,而接口中都是抽象方法,不能实现) |
Package ‘com.xxx.demo12’ clashes with class of same name
爆红:包名与类名冲突
JDK1.8前后接口的变化
JDK1.8前,接口仅包含常量和抽象方法 | JDK1.8后,接口新增非抽象方法(可以有函数体) |
---|---|
常量:public static final | 常量:public static final |
抽象方法:public abstract | 抽象方法:public abstract |
非抽象方法:public default | |
实现类要想重写非抽象方法,那么default修饰符不能加 | |
静态方法:public static | |
static不能省略;静态方法不能在实现类重写 |
为什么要在接口中加入非抽象方法?
Java 8新增了default方法,它可以在接口添加新功能特性,而且还不影响接口的实现类。
Q:在面向接口编程的过程中,如果发现原有的接口中,都需要添加一个相同的方法,有两种实现方案:
- 把接口换成抽象类,在抽象类中添加该方法(需要改动代码)
- 在接口中添加该抽象方法,在每一个接口的实现类中,都要添加相同的实现方法,代码的改动是相当大的。
两种方法对代码的改动都是很大的。如果使用接口的默认方法,是接口本身就拥有某些功能的实现,就很好的解决了问题。
内部类
成员内部类:静态成员内部类,非静态成员内部类
局部内部类:(方法中,块中,构造器中)
匿名内部类
9、异常
Error:错误
Exception:
- 检查异常
- 运行时异常
10、常用类
包装类
自动装箱,自动拆箱
日期类
Math类
Random类
String类
不可变的,底层实现是final char value[]
也是数组,不过是final的。
StringBuider类,StringBuffer类
StringBuider的底层实现是数组char value = new char[capacity];
,可变数组,可以动态扩容,最初数组容量为16,一旦向里面加入的字符串的长度大于16时,就会扩容,扩容规则为
1 |
|
StringBuider类,StringBuffer类的区别?
底层都是可变char数组,区别是StringBuilder是线程不安全的,效率高;StringBuffer是线程安全的,效率低。
StringBuffer的大多数方法都加了synchronized
关键字,上了锁,所以效率低,一般优先考虑使用StringBuilder。
11、集合
1、Collection接口
——List接口:实现类有,ArrayList,LinkedList
——Set接口:实现类有, HashSet, TreeSet
ArrayList实现类:
在jdk1.7中,数组初始默认容量为10,
数组的扩容;
1 |
|
扩容1.5倍。原容量为10,新容量为15;
在jdk1.8中,调用空构造器,底层数组初始化为{},数组容量最初为0,然后变为10;
1 |
|
Vector容器,底层扩容数组长度为原来2倍。
1 |
|
泛型
元素的类型参数叫做泛型
2、Map接口
HashMap原理及内部存储结构
https://juejin.cn/post/6844903763715555336#comment
HashMap源码线程安全性问题(1.8)
1 多线程的map.put()方法可能导致元素的丢失:
实验代码:
1 |
|
触发此问题的场景:
1 |
|
两个线程t1和t2同时执行到上述代码的注释#1
处,然后一起向下执行,
t1线程执行map.put(“key2”, “value2”),t2线程执行map.put(“key3”, “value3”),
假设t1先执行p.next = newNode(hash, key, value, null)
,那么会新建节点key2,并追加链表;
然后t2也执行p.next = newNode(hash, key, value, null)
, 就会将p.next
重新指向一个新的节点key3,
p.next原来指向的节点key2就丢失了。
这样就产生了线程安全问题。
2 put和get并发时,可能导致get为null
场景:
当线程1执行put方法时,如果元素个数超出threshold需要扩容导致rehash,
线程2此时执行get方法,就由可能导致get得到的值为null。
扩容resize()方法源码:
先计算出扩容后的容量和threshold,然后根据新容量创建新hash表,然后将旧hash表中的元素rehash到新的hash表中。
重点在于创建新hash表和hash表赋值的两句代码。
1 |
|
在代码#1位置,使用新的容量newCap创建新hash表newTab,
然后在#2的位置将新hash表赋值给变量table。
赋值完后,table是空的!
如果此时,有线程使用get方法获取值,会得到null。
TreeMap
Collections工具类
Stack
Queue
Deque
并发容器
ConcurrentMap
多线程 并发
线程常见方法:
join方法:当一个线程调用了join方法,这个线程就会先被执行,它执行结束以后才可以去执行其余的线程。
注意:必须先start,再join才有效。setDaemon(true)方法; 将子线程设置为主线程的伴随线程,主线程停止,子线程也停止执行
线程安全问题:
竞争资源引发的,加锁
1、同步代码块
2、同步方法
3、Lock
数据库
项目:
spring 原理
spring mvc 原理
项目名称:仿牛客论坛项目
技术选型:SpringBoot+MySQL+Redis +Kafka+Elasticsearch
项目描述:本项目采用微服务架构的思想,主要涉及模块有权限模块、核心模块、性能模块、通知模块、搜素模块和其他模块。完成了xx模块后台代码的编写,解决了帖子审核、评论、异常等功能的开发,从中学习到了xx技术栈等【这里可以挑选几个自己比较熟悉的模块写上去】
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!