public class Autoincrement {
public static void main(String[] args) {
int i = 1;
i = i++;
int j = i++;
int k = i + ++i * i++;
System.out.println("i="+i);//4
System.out.println("j="+j);//1
System.out.println("k="+k);//11
}
}
javap -c Autoincrement.class
F:\yygh\yygh_parent-master\Interview-questions\out\production\Interview-questions\com\frx01\interview\javase>javap -c Autoincrement.class
Compiled from "Autoincrement.java"
public class com.frx01.interview.javase.Autoincrement {
public com.frx01.interview.javase.Autoincrement();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: iconst_1
1: istore_1 // int i = 1; -------->int i = 1;
2: iload_1 //加载到栈
3: iinc 1, 1 //i自增---------------->i = i++;
6: istore_1 //把i赋给i --->i=1
7: iload_1 //加载1
8: iinc 1, 1 //i自增---------------->int j = i++;
11: istore_2 //赋值给第二个变量
12: iload_1 //加载i---------------->int k = i + ++i * i++; i=2
13: iinc 1, 1 //i自增 ++i ----------->i=3
16: iload_1 //加载i ---------->i=3
17: iload_1 //加载i
18: iinc 1, 1 //i自增为3 i++ ------->i=3
21: imul //把操作数栈中前两个弹出求乘积结果再压入栈 3*3
22: iadd //相加 2+3*3
23: istore_3 //赋值给k
24: getstatic #2 // Field
...
}
总结
++i先自增后赋值
; 后++:i++先赋值后运算
要点
几种常见形式
/**
* desc:
* 直接创建实例对象,不管你是否需要这个对象
* 1.把构造器私有化
* 2.自行创建,并且用静态变量保存
* 3.向外提供这个实例
* 4.强调这是一个单例,我们可以用final修饰
* */
public class Singleton1 {
public static final Singleton1 INSTANCE = new Singleton1();
private Singleton1() {
}
}
public class Singleton1Test {
public static void main(String[] args) {
Singleton1 s = Singleton1.INSTANCE;
System.out.println(s);//com.frx01.interview.javase.single.Singleton1@677327b6
}
}
/**
* desc:
* 枚举类型:表示该类型的对象有限几个
* 我们可以限定一个,就成了单例
*/
public enum Singleton2 {
INSTANCE
}
public class Singleton2Test {
public static void main(String[] args) {
Singleton2 s = Singleton2.INSTANCE;
System.out.println(s);//INSTANCE
}
}
public class Singleton3 {
public static final Singleton3 INSTANCE;
private String info;
static {
try {
Properties properties = new Properties();
properties.load(Singleton3.class.getClassLoader().getResourceAsStream("single.properties"));
INSTANCE = new Singleton3(properties.getProperty("info"));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private Singleton3(String info) {
this.info = info;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
@Override
public String toString() {
return "Singleton3{" +
"info='" + info + '\'' +
'}';
}
}
info=Hello
public class Singleton3Test {
public static void main(String[] args) {
Singleton3 s = Singleton3.INSTANCE;
System.out.println(s);//Singleton3{info='Hello'}
}
}
/**
* desc:
* 懒汉式:
* 延迟创建这个实例对象
*
* 1.构造器私有化
* 2.用一个静态变量保存这个唯一的实例
* 3.提供一个静态方法,获取这个实例对象
*/
public class Singleton4 {
private static Singleton4 instance;
private Singleton4(){
}
public static Singleton4 getInstance(){
if(instance == null){
instance = new Singleton4();
}
return instance;
}
}
public class Singleton4Test {
public static void main(String[] args) {
Singleton4 s1 = Singleton4.getInstance();
Singleton4 s2 = Singleton4.getInstance();
System.out.println(s1 == s2);//true
}
}
public class Singleton5 {
private static Singleton5 instance;
private Singleton5(){
}
public static Singleton5 getInstance(){
if(instance == null){
synchronized (Singleton5.class){
if(instance == null){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
instance = new Singleton5();
}
}
}
return instance;
}
}
public class Singleton5Test {
public static void main(String[] args) throws ExecutionException, InterruptedException {
Callable<Singleton5> c = () -> Singleton5.getInstance();
ExecutorService es = Executors.newFixedThreadPool(2);
Future<Singleton5> f1 = es.submit(c);
Future<Singleton5> f2 = es.submit(c);
Singleton5 s1 = f1.get();
Singleton5 s2= f2.get();
System.out.println(s1 == s2);//true
System.out.println(s1);
System.out.println(s2);
es.shutdown();
}
}
/**
* 在内部类被加载和初始化时,才创建INSTANCE实例对象
* 静态内部类不会自动随着外部类的加载和初始化而初始化,它是单独去加载和初始化的
* 因此是在内部类加载和初始化时,创建的,因此是线程安全的
*/
public class Singleton6 {
private Singleton6() {
}
private static class Inner {
private static final Singleton6 INSTANCE = new Singleton6();
}
public static Singleton6 getInstance(){
return Inner.INSTANCE;
}
}
public class Singleton6Test {
public static void main(String[] args) {
Singleton6 s1 = Singleton6.getInstance();
Singleton6 s2 = Singleton6.getInstance();
System.out.println(s1 == s2);//true
}
}
public class Father {
private int i = test();
private static int j = method();
static {
System.out.print("(1)");
}
Father(){
System.out.print("(2)");
}
{
System.out.print("(3)");
}
public int test(){
System.out.print("(4)");
return 1;
}
public static int method(){
System.out.print("(5)");
return 1;
}
}
public class Son extends Father{
private int i = test();
private static int j = method();
static {
System.out.print("(6)");
}
Son() {
System.out.print("(7)");
}
{
System.out.print("(8)");
}
public int test(){
System.out.print("(9)");
return 1;
}
public static int method(){
System.out.print("(10)");
return 1;
}
public static void main(String[] args) {
Son s1 = new Son();
System.out.println();
Son s2 = new Son();
}
}
(5)(1)(10)(6)(9)(3)(2)(9)(8)(7)
(9)(3)(2)(9)(8)(7)
Process finished with exit code 0
执行顺序:
<clinit>()
方法 <clinit>()
方法由静态类变量显示赋值代码和静态代码块组成<clinit>
方法只执行一次<init>()
方法 <init>
方法中就是正在创建的对象public class Exam4 {
public static void main(String[] args) {
int i = 1;
String str = "hello";
Integer num = 200;
int[] arr = {1,2,3,4,5};
MyData my = new MyData();
change(i,str,num,arr,my);
// arr my变了
System.out.println("i= " + i);
System.out.println("str= " + str);
System.out.println("num= " + num);
System.out.println("arr= " + Arrays.toString(arr));
System.out.println("my.a= " + my.a);
}
public static void change(int j, String s, Integer n, int[] a, MyData m) {
j += 1;
s += "world";
n += 1;
a[0] += 1;
m.a += 1;
}
}
class MyData {
int a = 10;
}
i= 1
str= hello
num= 200
arr= [2, 2, 3, 4, 5]
my.a= 11
Process finished with exit code 0
考点?
方法的参数传递机制
String、包装类等对象的不可变性
方法的参数传递机制
编程题:有n步台阶,一次只能上1步或2步,共有多少种走法?
public class TestStep {
@Test
public void test(){
long start = System.currentTimeMillis();
System.out.println(f(10));
long end = System.currentTimeMillis();
System.out.println("消耗时间:"+(end-start));
}
//实现f(n):求n步台阶 一共有几种走法?
public int f(int n){
if(n<1){
throw new IllegalArgumentException(n+"不能小于1");
}
if(n==1 || n==2){
return n;
}
return f(n-2)+f(n-1);
}
}
public class TestStep2 {
@Test
public void test(){
long start = System.currentTimeMillis();
System.out.println(loop(10));
long end = System.currentTimeMillis();
System.out.println("消耗时间:"+(end-start));
}
public int loop(int n){
if(n<1){
throw new IllegalArgumentException(n+"不能小于1");
}
if(n==1 || n==2){
return n;
}
int one = 2;//初始化为走到第二级台阶的走法
int two = 1;//初始化为走到第一级台阶的走法
int sum = 0;
for (int i = 3; i <= n; i++) {
//最后跨2步 + 最后跨1步的走法
sum = two + one;
two = one;
one = sum;
}
return sum;
}
}
小结:
public class Exam5 {
static int s;//成员变量,类变量
int i;//成员变量,实例变量
int j;//成员变量,实例变量
{
int i = 1;//非静态代码块的局部变量i
i++;
j++;
s++;
}
public void test(int j){//形参,局部变量j
j++;
i++;
s++;
}
public static void main(String[] args) {//形参,局部变量,args
Exam5 obj1 = new Exam5();//局部变量,obj1
Exam5 obj2 = new Exam5();//局部变量,obj2
obj1.test(10);
obj1.test(20);
obj2.test(30);
System.out.println(obj1.i+","+obj1.j+","+obj1.s);
System.out.println(obj2.i+","+obj2.j+","+obj2.s);
}
}
2,1,5
1,1,5
Process finished with exit code 0
考点
分析如图
局部变量与成员变量的区别
final
public
、protected
、private
、final
、static
、volatile
、transient
当局部变量与XX变量重名时,如何区分
在实例变量前面加 “this.”
在类变量前面加 “类名.”
BeanDefinition
;BeanDefinition
反射创建Bean
对象;Aware
接口的方法,如BeanNameAware
;BeanPostProcessor
的初始化前方法;init
初始化方法;BeanPostProcessor
的初始化后方法,此处会进行AOP
;Bean
对象放入一个Map
中;Bean
对象;DisposableBean
的destory()
方法;在 Spring 的配置文件中,给 bean 加上 scope 属性来指定 bean 的作用域如下:
TransactionDefinition 接口中定义了五个表示隔离级别的常量:
支持当前事务的情况:
不支持当前事务的情况:
其他情况:
修改项目中web.xml文件
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
修改tomcat中server.xml文件
<Connector URIEncoding="UTF-8" port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
流程说明(重要): 1、客户端(浏览器)发送请求,直接请求到 DispatcherServlet。 2、DispatcherServlet 根据请求信息调用 HandlerMapping,解析请求对应的 Handler。 3、解析到对应的 Handler(也就是我们平常说的 Controller 控制器)后,开始由 HandlerAdapter 适配器处理。 4、HandlerAdapter 会根据 Handler 来调用真正的处理器来处理请求,并处理相应的业务逻辑。 5、处理器处理完业务后,会返回一个 ModelAndView 对象,Model 是返回的数据对象,View 是个逻辑上的 View。 6、ViewResolver 会根据逻辑 View 查找实际的 View。 7、DispaterServlet 把返回的 Model 传给 View(视图渲染)。 8、把 View 返回给请求者(浏览器)
解决方案有三种如下: 1、写 SQL 语句的时候 写别名 2、在MyBatis的全局配置文件中开启驼峰命名规则,前提是符合驼峰命名规则
<!-- 开启驼峰命名规则,可以将数据库中下划线映射为驼峰命名
列如 last_name 可以映射为 lastName
-->
<setting name="mapUnderscoreToCameLCase" value="true" />
<!--
自定义映射
-->
<resultMap type="com.atguigu.pojo.Employee" id="myMap">
<!-- 映射主键 -->
<id cloumn="id" property="id"/>
<!-- 映射其他列 -->
<result column="last_name" property="lastName" />
<result column="email" property="email" />
<result column="salary" property="salary" />
<result column="dept_id" property="deptId" />
</resultMap>
Service ( centos6)
注册在系统中的标准化程序
有方便统一的管理方式(常用的方法)
service服务名start
service服务名stop
service服务名restart
service服务名reload
service服务名status
#查看服务的方法 /etc/init.d/ 服务名
#通过 chkconfig 命令设置自启动
#查看服务 chkconfig -list l grepXXX
chkconfig -level 5 服务名on
Linux系统有7种运行级别(runlevel): 常用的是级别3和5
运行级别0:系统停机状态,系统默认运行级别不能设为0,否则不能正常启动
运行级别1:单用户工作状态,root权限,用于系统维护,禁止远程登陆
运行级别2:多用户状态(没有NFS),不支持网络
运行级别3:完全的多用户状态(有NFS),登陆后进入控制台命令行模式
运行级别4:系统未使用,保留
运行级别5: X11控制台,登陆后进入图形GUI模式
运行级别6:系统正常关闭并重启,默认运行级别不能设为6,否则不能正常启动.
Systemctl ( centos7 )
注册在系统中的标准化程序
有方便统一的管理方式(常用的方法)
systemctl start 服务名(xxx.service
systemct restart 服务名(xxxx.service)
systemctl stop 服务名(xxxx.service)
systemctl reload 服务名(xxxx.service)
systemctl status 服务名(xxxx.service)
#查看服务的方法 /usr/lib/systemd/system
#查看服务的命令
systemctl list-unit-files
systemctl --type service
#通过systemctl命令设置自启动
自启动systemctl enable service_ _name
不自启动systemctl disable service_ name
创建分支
git branch <分支名>
git branch -v 查看分支
切换分支
git checkout <分支名>
一步完成: git checkout -b <分支名>
合并分支
先切换到主干 git checkout master
git merge <分支名>
删除分支
先切换到主干 git checkout master
git branch -D <分支名>
RDB ( Redis DataBase)
AOF (Append OF File)
在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是行话讲的Snapshot快照,它恢复时是将快照文件直接读到内存里。
备份是如何执行的
Redis会单独创建(fork) -个子进程来进行持款化,铣将数据写入到一个临时文件中,待玖化过程都结束了,再用这个临时文件替换上次持久化好的文件。整个过程中,主进程是不进行任何I0操作的,这就确保了极高的性能如果需要进行大规模数据的恢复,肘于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。RDB的缺点是最后一次持久化后的数据可能丢失。
rdb 的保存文件
在 redis.conf 中配置文件名称 默认为 dump.rdb
rbd 文件的保存路径,也可以修改,默认为 Redis启动命令行所在目录下
rdb 的备份
先通过 config get dir 查询 rdb文件的目录
将 *.rdb 的文件拷贝到别的地方
rdb 的恢复
关闭 Redis
先把备份文件拷贝到拷贝到工作目录下
启动 Redis,备份数据会直接加载
rdb 的优点
节省磁盘空间
恢复速度快
rdb 的缺点
虽然Redis在fork时使用了写时拷贝技术,但是如果数据庞大时还是比较消耗性能。
在备份周期在一定间隔时间做一-次备份, 所以如果Rediq意外down掉的话,就会丢失最后一-次快照后的所有修改。
以日志的形式来记录每个写操作,将Redis执行过的所有写指令记录下来(读操作不记录),只许追加文件但不可以改写文件,Redis启动之初会读取该文件重新构建数据,换言之,Redis重启的话就根据日志文件的内容将写指令从前到后执行一-次以完成数据的恢复工作。
Rewrite
AOF采文件追加方式,文件会越来越大为避免出现此种情况,新增了重写机制,当AOF文件的大小超过所设定的阈值时,Redis就会启动AOF文件的内容压缩,只保留可以恢复数据的最小指令集可以使用命令bgrewriteaof.
Redis 如何实现重写?
AOF文件持续增长而过大时,会fork出- 条新进程来将文件写(也是先写临时文件最后再rename),遍历新进程的内存中数据,条记录有一条的Set语句。 写af文件的操作,并没有读取旧的aof文件,醍将整个内存中的数据库内容用命令的方式写了一个新的aof文件, 这点和快照有点类似。
何时重写
写虽然可以节约大量磁盘空间,减少恢复时间。但是每次重写还是有一定的负担的,因此设定Redis要满足一条件才会进行重写。
auto- aof- rewrite- percentage 100
auto- aof- rewrite-min-size 64mb
統载入时或者上次重写完毕时, Redis会记录此时AOF大小,设为 base size ,如果Redis的AOF当前大小 >= base size + base_ size* 100% (默认)且当前大小 >=64mb (默认)的情况下, Redis会对AOF进行重写。
AOF 的优点
备份机制更稳健,丢失数据概率更低。
可读的日志文本,通过操作AOF稳健,可以处理误操作
AOF的缺点
比起RDB占用更多的磁盘空间。
恢复备份速度要慢。
每次读写都同步的话,有一定的性能压力。
存在个别Bug,造成不能恢复。
GC 发生在JVM的堆里面
数据类型 | 使用场景 |
---|---|
String | 比如说,我想知道什么时候封锁一个 IP 地址 Incrby 命令 |
Hash | 存储用户信息[ id, name , age]Hset( key ,field, value)Hset( key ,id, 101)Hset( key ,name, admin)Hset( key ,age, 23)修改案例---------Hget(userKev,jd)+Hset(userKey,id,102)为什么不使用String类型来存储 String拿到对象值之后需要反序列化,我们只需要更改id name, age 没有意义反序列化Set(userKey;用信息的字符串)Get(userKey)不建议使用String 类型。————————————————版权声明:本文为CSDN博主「Evan Guo」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 |
List | 实现最新消息的排行,还可以利用 List 的 push 命令,将任务存在list集合中,同时使用另-个命令,将任务从集合中取出[ pop ]。。Redis - List 数据类型来模拟消息队列。[电商中的秒杀就可以采用这种方式来完成一个秒杀活动]。 |
Set | 特殊之处:可以自动排重。比如说微博中将每个人的好友存在集合( Set) 中,+这样求两个人的共通好友的操作。我们只需要求交集即可。 |
Zset | 以某一个条件为权重,进行排序。京东:商品详情的时候,都会有一个综合排名,还可以按照价格进行排名 |
背景:他们都是基于 Lucene 搜索服务器基础上开发,一款优秀的,高性能的企业级搜索服务器,【是因为他们都是基于分词技术构建的倒排索引的方式进行查询】
开发语言:Java
诞生时间:
Solr:2004年诞生
ES:2010年诞生
ES 更新【功能越强大】
新技术的出现,会弥补老技术的缺点,吸取老技术的优点
区别:
Elasticsrarch :集群图
单点登录: 一处登录多处使用!
前提:单点登录多使用在分布式系统中
一处登录,处处运行
Demo:
参观动物园流程
检票员=认证中心模块
登录=买票
Token = piao
京东:单点登录,是将 token 放入到 cookie 中
案例:将浏览器的 cookie 禁用,则在登录京东则失效,无论如何登录不了
购物车:
背景: 在分布式系统中如何处理高并发的
由于在高并发的环境下,来不及同步处理用户发送的请求,则会导致请求发生阻塞,比如说,大量的 insert,update 之类的请求同时到达数据库 MySQL, 直接导致无数的行锁表锁,甚至会导致请求堆积过多,从而触发 too many connections ( 链接数太多 ) 错误,使用消息队列可以解决 【异步通信】
消息队列在电商中的使用场景
消息队列的弊端
消息的不确定性: 延迟队列 和 轮询技术来解决问题即可!
推荐大家使用 activemq ! 环境都是 Java 适环境而定