java笔记 - XiaoMeimei/Notes GitHub Wiki
初始化如下的一个字符串时,程序所做的工作如图所示:
String s = new String("Hello World!");

- for循环中,千万不要使用 "+" 进行字符串拼接。这样每次都会new StringBuilder(),导致性能很慢
a. equals()方法 (如果一个类没有重写equals方法,那么.equals()和==比较的结果一致,都是比较内存地址)
b. hashcode方法
c. toString()方法
d. clone()方法
除了ArrayList外,Java中还有几个容器类拥有线性存储结构:
LinkedList:链式存储结构,以链表的形式存储列表元素;
Vector:向量,方法与ArrayList非常类似,但列表操作都是同步的,线程安全。
LinkedList与ArrayList的主要区别如下:
(1)存储结构不同。LinkedList以链表的形式存储元素,ArrayList以数组的形式存储元素;
(2)使用场景不同。LindedList随机访问性能差,但插入和删除效果较高;ArrayList随机访问性能高,但插入和删除性能较差,两者正好互补。
Vector与ArrayList的主要区别如下:
(1)Vector是线程安全的,ArrayList不是线程安全的;
(2)扩容方式不同。ArrayList按照新的数组大小=(老的数组大小*3)/2 + 1的公式进行扩容;Vector则可以指定每次扩容的增量,若不指定, 则每次扩为为原有大小的2倍。
-
hashMap 底层是是一个数组+链表的结构。
hashMap装载长度默认是16,装载因子是0.75f,每次扩容为原来的两倍,之所以需要装载因子是为了减少哈希碰撞,哈希碰撞的解决方式有3种:1.开放定地址发 2.链地址法 3.再哈希法;hashmap采用的是链地址法。 key在数组上的位置是通过key的哈希值和hashmap的length,根据indexFor()来确定是table[i]的。 hashMap的key值可以为null;hashMap线程不安全。

5.反射中,Class.forName和classloader的区别。
Class.forName返回的对象可以决定是否初始化,而classloader返回的对象是绝对不会被初始化,只有调用newInstance()方法才能初始化,但可以决定是否要进行连接。
Class.forName可以决定由哪个classloader来加载类,而classloader.loadClass()只能用当前的classloader去加载。
- Class.forName两个重载方法:
name:类的全限定名
initialize:如果为true,则会在返回Class对象之前,对该类型做连接,校验,初始化操作。(如:执行static块中的代码),initialize默认需要初始化。
loader:用自定义的类加载器来请求这个类型;当然,你也可以传入null,用bootstrap加载器
public static Class<?> forName(String name, boolean initialize,
ClassLoader loader)
throws ClassNotFoundException
public static Class<?> forName(String className)
throws ClassNotFoundException
- ClassLoader.loadClass两个重载方法:
name:类的全限定名
resolve:表示是否需要连接该类型。 仅仅是连接(这里面包括校验class文件,准备分配内存,类型常量池的替换),并不会初始化该类型。
protected synchronized Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
public Class<?> loadClass(String name) throws ClassNotFoundException
-
1.父类【静态成员】和【静态代码块】,按在代码中出现的顺序依次执行。
-
2.子类【静态成员】和【静态代码块】,按在代码中出现的顺序依次执行。
-
3.父类的【普通成员变量被普通成员方法赋值】和【构造代码块】,按在代码中出现的顺序依次执行。
-
4.执行父类的构造方法。
-
5.子类的【普通成员变量被普通成员方法赋值】和【构造代码块】,按在代码中出现的顺序依次执行。
-
6.执行子类的构造方法。
7.反射机制的优缺点
- 静态编译
在编译时就确定了类型,绑定了对象,即通过
- 动态编译
在运行时动态的加载需要的类确定类型,绑定对象。
-
优点:实现动态的创建对象和编译,灵活性很高;当一个j2ee的项目发布有问题时,不需要卸载重装进行重新编译运行,只需要在运行时做动态的创建和编译就可以实现维护。
-
缺点:性能比较慢,反射是一种解释性操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求。这类操作总是慢于只直接执行相同的操作。
-
session 在服务器端,cookie 在客户端(浏览器)
-
session 存在在服务器的一个文件里(默认),不是内存。服务器使用一种类似于散列表的结构(也可能就是使用散列表)来保存信息。
-
session 的运行依赖 session id,而 session id 是存在 cookie 中的,也就是说,如果 浏览器禁用了 cookie ,同时 session 也会失效(当然也可以用URL重写,表单隐藏字段传递回服务器端)
-
用户验证这种场合一般会用 session。因此,维持一个会话的核心就是客户端的唯一标识,即 session id
-
cookie的生命周期可以通过cookie.setMaxAge(2000);来设置,如果没有设置setMaxAge,则cookie的生命周期当浏览器关闭的时候,就消亡了;如果设置了,就会把cookie信心存储在硬盘上,可以被多个同类型的浏览器共享。
11.Java中的队列都有哪些,有什么区别。
12.Java的内存模型以及GC算法。
13.Java内存泄露的问题调查定位:jmap,jstack的使用等等。
14.Java7、Java8的新特性(baidu问的,好BT)。
1.Java创建线程之后,直接调用start()方法和run()的区别
- 调用start()方法会创建一个新的线程,而run()方法使用的还是当前线程。
2.线程的生命周期

-
newCachedThreadPool 核心线程数为0;阻塞队列为1,当有任务来时进入SynchronousQueue同步队列,因此会在池中寻找可用线程来执行,若有可以线程则执行,若没有可用线程则创建一个线程来执行该任务;若池中线程空闲时间超过指定大小,则该线程会被销毁。
-
适用:执行很多短期异步的小程序或者负载较轻的服务器
-
newFixedThreadPool 创建固定个数线程的线程池,阻塞队列 LinkedBlockingQueue无限大,线程存活时间无限大
-
适用:执行长期的任务,性能好很多
-
newSingleThreadExecutor 创建只有一个线程的线程池,且线程的存活时间是无限的;当该线程正繁忙时,对于新任务会进入阻塞队列中(无界的阻塞队列)
-
适用:一个任务一个任务执行的场景
-
NewScheduledThreadPool 创建一个固定大小的线程池,线程池内线程存活时间无限制,线程池可以支持定时及周期性任务执行,如果所有线程均处于繁忙状态,对于新任务会进入DelayedWorkQueue队列中,这是一种按照超时时间排序的队列结构
-
适用:周期性执行任务的场景
4.newFixedThreadPool此种线程池如果线程数达到最大值后会怎么办,底层原理。
- 新任务会进入到LinkedBlockingQueue这个无限大的阻塞队列。
5.了解可重入锁的含义,以及ReentrantLock 和synchronized的区别
6.同步的数据结构,例如concurrentHashMap的源码理解以及内部实现原理,为什么他是同步的且效率高
7.atomicinteger和volatile等线程安全操作的关键字的理解和使用
8.线程间通信,wait和notify
9.定时线程的使用
10.场景:在一个主线程中,要求有大量(很多很多)子线程执行完之后,主线程才执行完成。多种方式,考虑效率。
1.Spring DI 和 Ioc
https://blog.csdn.net/xyh820/article/details/7303330/
-
IoC和DI由什么关系呢?其实它们是同一个概念的不同角度描述。相对IoC 而言,“依赖注入”明确描述了“被注入对象依赖IoC容器配置依赖对象”。
-
依赖注入:将本来由对象自己管理依赖关系转为由框架来创建和管理它们的依赖关系,实现了松耦合。
如何装配bean来实现依赖注入: 1.隐式的bean发现机制和自动装配; 2.java中显示的配置; 3.XML中显示的配置
1.自动化装配:组件扫描(component scanning)<@component,@componentScan>, 自动装配(autowiring)<@autowired>应用最多
2.java中显示的配置:创建javaConfig类,添加@Configuration注解,简单声明bean和实现注入
(将第三方库中的组件配置到当前应用的时候可以用到)
//简单声明bean
@bean
public CompactDisc a() {
return new A();
}
//实现注入(构造器注入或setter或其他)
@bean
public CDPlayer(CompactDisc compactDisc){
return new CDPlayer(compactDisc );
}
3.XML中显示的配置:创建一个xml文件,并以为根元素。
<beans>
<bean id="compactDisc" class="xxx.xxx"/>
<bean id="CDPlayer" class="xxx.xxx">
<construstor-arg ref="compactDisc" />
</bean>
</beans>
- 控制反转:Ioc不是一种技术而是一种编程思想,传统应用程序都是由我们在类内部主动创建依赖对象,从而导致类与类之间高耦合,难于测试;有了IoC容器后,把创建和查找依赖对象的控制权交给了容器,由容器进行注入组合对象,所以对象与对象之间是 松散耦合,这样也方便测试,利于功能复用,更重要的是使得程序的整个体系结构变得非常灵活。
-
将与业务逻辑无关的功能抽离出来形成可重用的组件,以横切面的形式应用到程序中。如:日志、事物、安全等。
-
术语:Advice, Join point, Pointcut, Aspect, Introduction, Weaving.
采用动态代理机制和字节码生成技术实现。
动态代理只能对实现了相应Interface的类使用,如果某个类没有实现任何的Interface,就无法使用动态代理对其产生相应的代理对象!因此:在默认情况下,如果Spring AOP发现目标实现了相应的Interface,则采用动态代理为其生成代理对象实例;而如果目标对象没有实现任何的Interface,Spring AOP会尝试使用CGLIB动态字节码生成类库,为目标对象生成代理对象实例!
动态字节码生成 > 对目标类进行继承扩展 (缺点,不适用于被定义成final的类)
1). 使用CGLIB类库,实现一个net.sf.cglib.proxy.Callback,或者使用net.sf.cglib.proxy.MethodInterceptor(继承自Callback),即写一个横切面类。
2). 通过Enhancer为目标对象动态生成一个子类,将RequestCallback的横切逻辑附加到该子类
import net.sf.cglib.proxy.Enhancer;
public class Client {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
//设置父类
enhancer.setSuperclass(Requestable.class);
//设置Callback
enhancer.setCallback(new RequestCallback());
Requestable proxy = (Requestable) enhancer.create();
proxy.request();
}
}
3.代理模式:为对象创建一个代理类,用户通过代理对象对委托对象进行操作,而不是直接操作委托对象。
静态代理:委托对象和代理对象实现同一个接口,实现相同的方法,并在代理类中对原对象进行操作。
动态代理:
* 1).定义需要被代理的类,和公共的接口
* 2).定义一个调用处理器,实现 InvocationHander 接口;该类主要是定义代理类需要完成的具体任务
* 3).生成代理对象(当然也会生成代理类),需要为他指定(1)委托对象(2)实现的一系列接口(3)调用处理器类的实例。
生成的代理对象以$ProxyN命名;构造函数需要传进来一个InvocationHander的实例;实现与委托类相同的方法,
并在方法中调用invoke()方法,从而实现代理。
1.单例模式:饱汉、饿汉。以及饿汉中的延迟加载
2.工厂模式、装饰者模式、观察者模式。
1.MySql的存储引擎的不同
2.单个索引、联合索引、主键索引
3.Mysql怎么分表,以及分表后如果想按条件分页查询怎么办(如果不是按分表字段来查询的话,几乎效率低下,无解)
4.分表之后想让一个id多个表是自增的,效率实现
5.MySql的主从实时备份同步的配置,以及原理(从库读主库的binlog),读写分离
6.写SQL语句
7.索引的数据结构,B+树
8.事物的四个特性,以及各自的特点(原子、隔离)等等,项目怎么解决这些问题