diff --git a/code/src/main/java/com/raorao/java/proxy/MyInvocationHandler.java b/code/src/main/java/com/raorao/java/proxy/MyInvocationHandler.java new file mode 100644 index 00000000..93bffc0c --- /dev/null +++ b/code/src/main/java/com/raorao/java/proxy/MyInvocationHandler.java @@ -0,0 +1,56 @@ +package com.raorao.java.proxy; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; + +/** + * . + * + * @author Xiong Raorao + * @since 2018-08-23-20:31 + */ +public class MyInvocationHandler implements InvocationHandler{ + + private Object object; + + public MyInvocationHandler(Object object){ + this.object = object; + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) + throws Throwable { + // TODO Auto-generated method stub + System.out.println("MyInvocationHandler invoke begin"); + System.out.println("proxy: "+ proxy.getClass().getName()); + System.out.println("method: "+ method.getName()); + for(Object o : args){ + System.out.println("arg: "+ o); + } + //通过反射调用 被代理类的方法 + method.invoke(object, args); + System.out.println("MyInvocationHandler invoke end"); + return null; + } + + public static void main(String [] args){ + //创建需要被代理的类 + Student s = new Student(); + //这一句是生成代理类的class文件,前提是你需要在工程根目录下创建com/sun/proxy目录,不然会报找不到路径的io异常 + System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true"); + //获得加载被代理类的 类加载器 + ClassLoader loader = Thread.currentThread().getContextClassLoader(); + //指明被代理类实现的接口 + Class[] interfaces = s.getClass().getInterfaces(); + // 创建被代理类的委托类,之后想要调用被代理类的方法时,都会委托给这个类的invoke(Object proxy, Method method, Object[] args)方法 + MyInvocationHandler h = new MyInvocationHandler(s); + //生成代理类 + Person proxy = (Person) Proxy.newProxyInstance(loader, interfaces, h); + //通过代理类调用 被代理类的方法 + proxy.sayHello("yujie.wang", 20); + proxy.sayGoodBye(true, 100); + System.out.println("end"); + } + +} diff --git a/code/src/main/java/com/raorao/java/proxy/Person.java b/code/src/main/java/com/raorao/java/proxy/Person.java new file mode 100644 index 00000000..09eefc96 --- /dev/null +++ b/code/src/main/java/com/raorao/java/proxy/Person.java @@ -0,0 +1,14 @@ +package com.raorao.java.proxy; + +/** + * . + * + * @author Xiong Raorao + * @since 2018-08-23-20:27 + */ +public interface Person { + + public void sayHello(String content, int age); + + public void sayGoodBye(boolean seeAgin, double time); +} diff --git a/code/src/main/java/com/raorao/java/proxy/StaticProxyTest.java b/code/src/main/java/com/raorao/java/proxy/StaticProxyTest.java new file mode 100644 index 00000000..f5d89269 --- /dev/null +++ b/code/src/main/java/com/raorao/java/proxy/StaticProxyTest.java @@ -0,0 +1,48 @@ +package com.raorao.java.proxy; + +/** + * 静态代理测试. + * + * @author Xiong Raorao + * @since 2018-08-23-20:29 + */ +public class StaticProxyTest implements Person { + + private Person o; + + public StaticProxyTest(Person o) { + this.o = o; + } + + public static void main(String[] args) { + // TODO Auto-generated method stub + //s为被代理的对象,某些情况下 我们不希望修改已有的代码,我们采用代理来间接访问 + Student s = new Student(); + //创建代理类对象 + StaticProxyTest proxy = new StaticProxyTest(s); + //调用代理类对象的方法 + proxy.sayHello("welcome to java", 20); + System.out.println("******"); + //调用代理类对象的方法 + proxy.sayGoodBye(true, 100); + + } + + @Override + public void sayHello(String content, int age) { + // TODO Auto-generated method stub + System.out.println("ProxyTest sayHello begin"); + //在代理类的方法中 间接访问被代理对象的方法 + o.sayHello(content, age); + System.out.println("ProxyTest sayHello end"); + } + + @Override + public void sayGoodBye(boolean seeAgin, double time) { + // TODO Auto-generated method stub + System.out.println("ProxyTest sayHello begin"); + //在代理类的方法中 间接访问被代理对象的方法 + o.sayGoodBye(seeAgin, time); + System.out.println("ProxyTest sayHello end"); + } +} diff --git a/code/src/main/java/com/raorao/java/proxy/Student.java b/code/src/main/java/com/raorao/java/proxy/Student.java new file mode 100644 index 00000000..2ec81d53 --- /dev/null +++ b/code/src/main/java/com/raorao/java/proxy/Student.java @@ -0,0 +1,20 @@ +package com.raorao.java.proxy; + +/** + * . + * + * @author Xiong Raorao + * @since 2018-08-23-20:28 + */ +public class Student implements Person { + + @Override + public void sayHello(String content, int age) { + System.out.println("student say hello" + content + " " + age); + } + + @Override + public void sayGoodBye(boolean seeAgin, double time) { + System.out.println("student sayGoodBye " + time + " " + seeAgin); + } +} diff --git a/interview/answer.md b/interview/answer.md index 087755ea..d6977b3c 100644 --- a/interview/answer.md +++ b/interview/answer.md @@ -6,9 +6,15 @@ - [java 四种引用及其应用场景](#java-四种引用及其应用场景) - [foreach与正常for循环效率对比](#foreach与正常for循环效率对比) - [java反射的作用于原理](#java反射的作用于原理) + - [java 动态代理](#java-动态代理) - [数据库](#数据库) - [truncate与 delete区别](#truncate与-delete区别) - [B+树索引和哈希索引的区别](#b树索引和哈希索引的区别) +- [Linux](#linux) + - [Top 查看系统信息](#top-查看系统信息) + - [Linux 内核空间和用户空间](#linux-内核空间和用户空间) +- [分布式](#分布式) + - [paxos 算法](#paxos-算法) @@ -63,12 +69,22 @@ Java 反射是可以让我们在运行时,通过一个类的Class对象来获 这种动态获取信息以及动态调用对象的方法的功能称为JAVA的反射。 +### java 动态代理 + + + # 数据库 ## truncate与 delete区别 -TRUNCATE TABLE 在功能上与不带 WHERE 子句的 DELETE 语句相同:二者均删除表中的全部行。但 TRUNCATE TABLE 比 DELETE 速度快,且使用的系统和事务日志资源少。 DELETE 语句每次删除一行,并在事务日志中为所删除的每行记录一项。 -TRUNCATE TABLE 通过释放存储表数据所用的数据页来删除数据,并且只在事务日志中记录页的释放。 TRUNCATE,DELETE,DROP 放在一起比较: +TRUNCATE TABLE 在功能上与不带 WHERE 子句的 DELETE 语句相同:二者均删除表中的全部行。但 TRUNCATE TABLE 比 DELETE 速度快,且使用的系统和事务日志资源少。 + +DELETE 语句每次删除一行,并在事务日志中为所删除的每行记录一项。 + +TRUNCATE TABLE 通过释放存储表数据所用的数据页来删除数据,并且只在事务日志中记录页的释放。 + +TRUNCATE,DELETE,DROP 放在一起比较: + TRUNCATE TABLE :删除内容、释放空间但不删除定义。 DELETE TABLE: 删除内容不删除定义,不释放空间。 DROP TABLE :删除内容和定义,释放空间 @@ -79,8 +95,72 @@ B+树是一个平衡的多叉树,从根节点到每个叶子节点的高度差 ![](https://mmbiz.qpic.cn/mmbiz_jpg/UtWdDgynLdYnMu5lfXNAYzW0PPSOB8Pss8E5IlpSXicQbuCj5p3fN1vGtKkdUgeZ4IvYBx4IlFMLI4peDFvTV2w/640?wx_fmt=jpeg&tp=webp&wxfrom=5&wx_lazy=1) -哈希索引就是采用一定的哈希算法,把键值换算成新的哈希值,检索时不需要类似B+树那样从根节点到叶子节点逐级查找,只需一次哈希算法即可,是无序的 +哈希索引就是采用一定的哈希算法,把键值换算成新的哈希值,检索时不需要类似B+树那样从根节点到叶子节点逐级查找,只需一次哈希算法即可立刻定位到相应的位置,速度非常快。是无序的 ![](https://mmbiz.qpic.cn/mmbiz_jpg/UtWdDgynLdYnMu5lfXNAYzW0PPSOB8PsAdicCricepbjicRIBIOlKdDPWlHroEiaYVgdDgicMMWbsuIlmmA4kOEVVog/640?wx_fmt=jpeg&tp=webp&wxfrom=5&wx_lazy=1) **优势对比:** + +- 如果是等值查询,那么哈希索引明显有绝对优势,因为只需要经过一次算法即可找到相应的键值;当然了,这个前提是,键值都是唯一的。如果键值不是唯一的,就需要先找到该键所在位置,然后再根据链表往后扫描,直到找到相应的数据; + +- 从示意图中也能看到,如果是范围查询检索,这时候哈希索引就毫无用武之地了,因为原先是有序的键值,经过哈希算法后,有可能变成不连续的了,就没办法再利用索引完成范围查询检索; + +- 同理,哈希索引也没办法利用索引完成排序,以及like ‘xxx%’ 这样的部分模糊查询(这种部分模糊查询,其实本质上也是范围查询); + +- 哈希索引也不支持多列联合索引的最左匹配规则; + +- B+树索引的关键字检索效率比较平均,不像B树那样波动幅度大,在有大量重复键值情况下,哈希索引的效率也是极低的,因为存在所谓的哈希碰撞问题。 + +说白了,等值查询的时候,Hash索引才有用武之地。 + +# Linux + +## Top 查看系统信息 + +参考文档: +- [Linux top命令的用法详细详解](https://www.cnblogs.com/zhoug2020/p/6336453.html) + +## Linux 内核空间和用户空间 + +通常32位Linux内核地址空间划分0~3G为用户空间,3~4G为内核空间。注意这里是32位内核地址空间划分,64位内核地址空间划分是不同的。 + +![](http://ilinuxkernel.com/wp-content/uploads/2011/09/091011_1614_Linux2.png) + +当内核模块代码或线程访问内存时,代码中的内存地址都为逻辑地址,而对应到真正的物理内存地址,需要地址一对一的映射,如逻辑地址0xc0000003对应的物理地址为0×3,0xc0000004对应的物理地址为0×4,… …,逻辑地址与物理地址对应的关系为 + +物理地址 = 逻辑地址 – 0xC0000000 + +处于用户态的程序只能访问用户空间,而处于内核态的程序可以访问用户空间和内核空间。那么用户态和内核态有什么区别呢? + +当一个任务(进程)执行系统调用而陷入内核代码中执行时,我们就称进程处于内核运行态(或简称为内核态)。此时处理器处于特权级最高的(0级)内核代码中执行。当进程处于内核态时,执行的内核代码会使用当前进程的内核栈。每个进程都有自己的内核栈。当进程在执行用户自己的代码时,则称其处于用户运行态(用户态)。即此时处理器在特权级最低的(3级)用户代码中运行。 + +内核态与用户态是操作系统的两种运行级别,Intel x86架构提供Ring0-Ring3四种级别的运行模式,Ring0级别最高,Ring3最低。Linux使用了Ring3级别运行用户态,Ring0作为 内核态,没有使用Ring1和Ring2。Ring3状态不能访问Ring0的地址空间,包括代码和数据。程序特权级别的不同,其所拥有的权力也不同。如下图所示。 + +![](img/20170610171008637.jpg) + +用户态切换到内核态的3种方式: + +a. 系统调用 + +这是用户态进程主动要求切换到内核态的一种方式,用户态进程通过系统调用申请使用操作系统提供的服务程序完成工作,比如fork()实际上就是执行了一个创建新进程的系统调用。而系统调用的机制其核心还是使用了操作系统为用户特别开放的一个中断来实现,例如Linux的int 80h中断。 + +b. 异常 + +当CPU在执行运行在用户态下的程序时,发生了某些事先不可知的异常,这时会触发由当前运行进程切换到处理此异常的内核相关程序中,也就转到了内核态,比如缺页异常。 + +c. 外围设备的中断 + +当外围设备完成用户请求的操作后,会向CPU发出相应的中断信号,这时CPU会暂停执行下一条即将要执行的指令转而去执行与中断信号对应的处理程序,如果先前执行的指令是用户态下的程序,那么这个转换的过程自然也就发生了由用户态到内核态的切换。比如硬盘读写操作完成,系统会切换到硬盘读写的中断处理程序中执行后续操作等。 + +这3种方式是系统在运行时由用户态转到内核态的最主要方式,其中系统调用可以认为是用户进程主动发起的,异常和外围设备中断则是被动的。 + +参考链接: +- [linux 用户空间与内核空间——高端内存详解](https://www.cnblogs.com/wuchanming/p/4360277.html) +- [内核态(内核空间)和用户态(用户空间)的区别和联系](https://blog.csdn.net/qq_34228570/article/details/72995997) + +# 分布式 + +## paxos 算法 + +[通俗易懂](https://www.cnblogs.com/endsock/p/3480093.html) + diff --git a/interview/img/20170610171008637.jpg b/interview/img/20170610171008637.jpg new file mode 100644 index 00000000..d61b8daf Binary files /dev/null and b/interview/img/20170610171008637.jpg differ diff --git a/interview/question.md b/interview/question.md index fe5281bc..996bb67b 100644 --- a/interview/question.md +++ b/interview/question.md @@ -125,6 +125,7 @@ ## HTTP - cookie和session的区别,分布式环境怎么保存用户状态; +- http 和 https 的区别,ssl加密过程; # 设计模式 @@ -147,7 +148,7 @@ # Linux -- +- top命令查看系统的参数 # 安全 @@ -158,7 +159,6 @@ ## Storm - storm 的 ACK机制 - storm 的tuple分组机制 -- ## Zookeeper