基础知识:
1.二叉树的先,中,后序遍历(递归的过程):
前序遍历:根节点->左子树->右子树
中序遍历:左子树->根节点->右子树
后序遍历:左子树->右子树->根节点
2.string和stringbuffer:
String和StringBuffer,它们可以储存和操作字符串,即包含多个字符的字符数据。这个String类提供了数值不可改变的字符串。而这个StringBuffer类提供的字符串进行修改。当你知道字符数据要改变的时候你就可以使用StringBuffer。典型地,你可以使用StringBuffers来动态构造字符数据。另外,String实现了equals方法,new String(“abc”).equals(new String(“abc”)的结果为true,而StringBuffer没有实现equals方法,所以,new StringBuffer(“abc”).equals(new StringBuffer(“abc”)的结果为false。
3.java主流的开源框架
SSH和SSM框架,
其中spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。
IOC:spring中创建被调用者的工作不再由调用者来完成,这叫控制反转,由spring完成,并注入调用者,叫依赖注入。
AOP:面向切面编程。
spring相当于一个工厂类,在其配置文件中通过<bean>元素,配置用于创建实例对象的类和属性。
SpringMVC分离了控制器、模型对象、分派器以及处理程序对象的角色,这种分离让它们更容易进行定制。
springmvc的工作流程:
1.用户发送请求至前端控制器dispatcherservlet
2.前端控制器收到请求调用HandlerMapper处理器映射器。
3.处理器映射器根据请求的url找到对应的处理器,生成处理器对象和处理器拦截器返回给前端控制器。
4.前端控制器通过HandlerAdapter处理器适配器调用处理器
5.执行处理器,返回modelandview;
6.处理器适配器将modelandview对象返回给前端控制器。
7.前端控制器将modelandview发送个视图解析器ViewResolver。
8.试图解析器返回具体的view给前端控制器。
9.前端控制器对view进行视图渲染。
10.前端控制器对用户做出响应。
MyBatis是一个支持普通SQL查询,存储过程和高级映射的优秀持久层框架。
MyBatis的工作原理:MyBatis根据xml配置文件创建sqlsessionfactory,sqlsessionfactory再根据配置创建出一个session,session包含执行sql所需要的所有方法,可以通过session直接运行映射的sql语句,完成对数据库的增删改查和事务的提交,用完后关闭session。
4.Java中的cloneable和Serializable接口:
clone三部曲。
1 声明实现Cloneable接口。
2 调用super.clone拿到一个对象,如果父类的clone实现没有问题的话,在该对象的内存存储中,所有父类定义的field都已经clone好了,该类中的primitive和不可变类型引用也克隆好了,可变类型引用都是浅copy。
3 把浅copy的引用指向原型对象新的克隆体。
为什么?:
1 效率和简单性,简单的copy一个对象在堆上的的内存比遍历一个对象网然后内存深copy明显效率高并且简单。
2 不给别的类强加意义。如果A实现了Cloneable,同时有一个引用指向B,如果直接复制内存进行深copy的话,意味着B在意义上也是支持Clone的,但是这个是在使用B的A中做的,B甚至都不知道。破坏了B原有的接口。
3 有可能破坏语义。如果A实现了Cloneable,同时有一个引用指向B,该B实现为单例模式,如果直接复制内存进行深copy的话,破坏了B的单例模式。
4 方便且更灵活,如果A引用一个不可变对象,则内存deep copy是一种浪费。Shadow copy给了程序员更好的灵活性。
使用Serializable同样可以做到对象的clone。但是:
Cloneable本身就是为clone设计的,虽然有一些缺点,但是如果它可以clone的话无疑用它来做clone比较合适。如果不行的话用原型构造函数,或者静态copy方法也可以。
Serializable制作clone的话,添加了太多其它的东西,增加了复杂性。
5.Tranient关键字
在对象序列化的时候,有些变量不需要序列化,比如密码等,可以使用transient关键字来解决这个问题,transient修饰的变量不会被序列化。
6.如何决定选用HashMap还是TreeMap?
对于在Map中插入、删除和定位元素这类操作,HashMap是最好的选择。然而,假如你需要对一个有序的key集合进行遍历,TreeMap是更好的选择。基于你的collection的大小,也许向HashMap中添加元素会更快,将map换为TreeMap进行有序key的遍历。7.Java中实例化对象的5种方式:
1、用new语句创建对象,这是最常见的创建对象的方法。
2、通过工厂方法返回对象,如:String str = String.valueOf(23);
3、运用反射手段,调用java.lang.Class或者java.lang.reflect.Constructor类的newInstance()实例方法。如:Object obj = Class.forName("java.lang.Object").newInstance();
4、调用对象的clone()方法。
5、通过I/O流(包括反序列化),如运用反序列化手段,调用java.io.ObjectInputStream对象的 readObject()方法。
8.排序方法:
选择排序:
/**
数组的最小值
*/
int SelectMinKey(int a[], int n, int i){
Int k=i;
for(int j=0;j<n;j++){
if(a[j]>a[k]){
j=k;
}
}
return k;
}
void selectSort(int a[], int n){
int key, tmp;
for(int i = 0; i< n; ++i) {
key = SelectMinKey(a, n,i); //选择最小的元素
if(key != i){
tmp = a[i];
a[i] = a[key];
a[key] = tmp; //最小元素与第i位置元素互换
}
print(a, n , i);
}
}
9.内部类:
使用内部类最吸引人的原因是:每个内部类都能独立地继承一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。
可以这样说,接口只是解决了部分问题,而内部类使得多重继承的解决方案变得更加完整。
1、内部类可以用多个实例,每个实例都有自己的状态信息,并且与其他外围对象的信息相互独立。
2、在单个外围类中,可以让多个内部类以不同的方式实现同一个接口,或者继承同一个类。
3、创建内部类对象的时刻并不依赖于外围类对象的创建。
4、内部类并没有令人迷惑的“is-a”关系,他就是一个独立的实体。
5、内部类提供了更好的封装,除了该外围类,其他类都不能访问。
OuterClass.InnerClass innerClass = outerClass.new InnerClass();
内部类是个编译时的概念,一旦编译成功后,它就与外围类属于两个完全不同的类(当然他们之间还是有联系的)。对于一个名为OuterClass的外围类和一个名为InnerClass的内部类,在编译成功后,会出现这样两个class文件:OuterClass.class和OuterClass$InnerClass.class。
在Java中内部类主要分为成员内部类、局部内部类、匿名内部类、静态内部类。
在成员内部类中要注意两点,
第一:成员内部类中不能存在任何static的变量和方法;
第二:成员内部类是依附于外围类的,所以只有先创建了外围类才能够创建内部类。
有这样一种内部类,它是嵌套在方法和作用域内的;局部内部类和成员内部类一样被编译,只是它的作用域发生了改变。
1、 匿名内部类是没有访问修饰符的。
2、 new 匿名内部类,这个类首先是要存在的。如果我们将那个InnerClass接口注释掉,就会出现编译出错。
3、 注意getInnerClass()方法的形参,第一个形参是用final修饰的,而第二个却没有。同时我们也发现第二个形参在匿名内部类中没有使用过,所以当所在方法的形参需要被匿名内部类使用,那么这个形参就必须为final。
4、 匿名内部类是没有构造方法的。因为它连名字都没有何来构造方法。
使用static修饰的内部类我们称之为静态内部类,不过我们更喜欢称之为嵌套内部类。静态内部类与非静态内部类之间存在一个最大的区别,我们知道非静态内部类在编译完成之后会隐含地保存着一个引用,该引用是指向创建它的外围内,但是静态内部类却没有。没有这个引用就意味着:
1、 它的创建是不需要依赖于外围类的。
2、 它不能使用任何外围类的非static成员变量和方法。
10.单例模式创建的3种方式:
1.饿汉式:
public class Singleton{
Private Singleton(){
System.out.println(“”);
}
Private static Singleton instance=new Singleton();
Public static Singleton getInstance(){
Return instance;
}
}
Singleton实例在什么时候创建是不受控制的。对于静态成员instance,它会在类第一次初始化的时候被创建。这个时刻并不一定是getInstance()方法第一次被调用的时候。任何对Singleton方法或者字段的引用,都会导致类初始化,并创建instance实例,但是类初始化只有一次,因此instance实例永远只会被创建一次
2.懒汉式:
Public class Singleton{
Private Singleton(){
Syso(“”);
}
Private static Singleton instance=null;
Public static synchronized Singleton getInstance(){
If(instance==null){
Instance=new Singleton();
}
Return instance;
}
}
优点:精确控制instance的创建时间,它只会在in-stance被第一次使用时,创建对象,这种实现的好处是,充分利用了延迟加载,只在真正需要时创建对象
缺点:并发环境下加锁,竞争激烈的场合对性能可能产生一定的影响。
3.使用内部类:
Public class StaticSingleton(){
Private StaticSingleton(){
Syso(“”);
}
Private static class StaticSingleton{
Private static StaticSingleton instance=new StaticSingleton();
}
Public static StaticSingleton getInstance(){
Return Singleton.insatnce;
}
}
优点:
同时拥有前两种方式的优点
1.首先getInstance()方法中没有锁,这使得在高并发环境下性能优越
2.只有在getInstance()方法被第一次调用时,StaticSingleton的实例才会被创建(这种方法巧妙地使用了内部类和类的初始化方式)
3.内部类Singleton被申明为private,这使得我们不可能在外部访问并初始化它。而我们只可能在getInstance()内部对Singleton类进行初始化,利用虚拟机的类初始化机制创建单例。
11.两个变量交换值的三种方法:
1.利用第三个变量实现交换:
Int a=100; int b=200;
Int c=0;
c=a;
a=b;
b=c;
2.利用加减法实现两个变量值交换:
a=a+b;
b=a-b;
a=a-b;
3.利用位的异或实现两个变量的值交换:
a=a^b;
b=a^b;
a=a^b;
12.java中的反射机制:
反射机制获取值的3种方式:(获取User类型)
1.Class c1=Class.forName(“User”);
//java中每个类型都有class属性
2.Class c2=User.class;
//java中任何一个java对象都有getClass方法
3.User user=new User();
Class c3=user.getClass();
13.java性能优化:
使用StringBuilder:避免使用+运算符,使用append
避免使用正则表达式
避免使用for(),iterator()方法:使用他们时会额外在堆上为每个循环创建一个对象。
使用原始类型和栈:避免使用包装类,给gc带来了很大的压力
避免递归
使用entrySet()
14.java中创建线程主要有3种方式:
继承Thread类创建线程类
实现Runnable接口创建线程类
通过Callable和Future创建线程
15.java中的并发和并行:
并发和并行的区别就是一个处理器同时处理多个任务和多个处理器或者是多核的处理器同时处理多个不同的任务。
16.java中同步方法和同步块:
同步块是更好的选择,因为它不会锁住整个对象(当然你也可以让它锁住整个对象)。
同步方法会锁住整个对象,哪怕这个类中有多个不相关联的同步块,这通常会导致他们停止执行并需要等待获得这个对象上的锁。
17.java中的堆和栈:
对象的生存空间 堆和方法调用及变量的生存空间 栈。
18.servlet:
客户端请求该 Servlet;
加载 Servlet类到内存;
实例化并调用init()方法初始化该Servlet;
service()(根据请求方法不同调用doGet()或者 doPost(),此外还有doHead()、doPut()、doTrace()、doDelete()、doOptions()、destroy())。
加载和实例化 Servlet。这项操作一般是动态执行的。然而,Server通常会提供一个管理的选项,用于在 Server启动时强制装载和初始化特定的 Servlet。
19.对Spring的理解。
1.Spring实现了工厂模式的工厂类(在这里有必要解释清楚什么是工厂模式),这个类名为BeanFactory(实际上是一个接口),在程序中通常BeanFactory的子类ApplicationContext。Spring相当于一个大的工厂类,在其配置文件中通过<bean>元素配置用于创建实例对象的类名和实例对象的属性。
2. Spring提供了对IOC良好支持,IOC是一种编程思想,是一种架构艺术,利用这种思想可以很好地实现模块之间的解耦。IOC也称为DI(Depency Injection),什么叫依赖注入呢?
譬如,Class Programmer
{
Computer computer = null;
public void code()
{
//Computer computer = new IBMComputer();
//Computer computer = beanfacotry.getComputer();
computer.write();
}
public void setComputer(Computer computer)
{
this.computer = computer;
}
}
另外两种方式都由依赖,第一个直接依赖于目标类,第二个把依赖转移到工厂上,第三个彻底与目标和工厂解耦了。在spring的配置文件中配置片段如下:
<bean id=”computer” class=”cn.itcast.interview.Computer”>
</bean>
<bean id=”programmer” class=”cn.itcast.interview.Programmer”>
<property name=”computer” ref=”computer”></property>
</bean>
3. Spring提供了对AOP技术的良好封装, AOP称为面向切面编程,就是系统中有很多各不相干的类的方法,在这些众多方法中要加入某种系统功能的代码,例如,加入日志,加入权限判断,加入异常处理,这种应用称为AOP。实现AOP功能采用的是代理技术,客户端程序不再调用目标,而调用代理类,代理类与目标类对外具有相同的方法声明,有两种方式可以实现相同的方法声明,一是实现相同的接口,二是作为目标的子类在,JDK中采用Proxy类产生动态代理的方式为某个接口生成实现类,如果要为某个类生成子类,则可以用CGLI B。在生成的代理类的方法中加入系统功能和调用目标类的相应方法,系统功能的代理以Advice对象进行提供,显然要创建出代理对象,至少需要目标类和Advice类。spring提供了这种支持,只需要在spring配置文件中配置这两个元素即可实现代理和aop功能,例如,
<bean id=”proxy” type=”org.spring.framework.aop.ProxyBeanFactory”>
<property name=”target” ref=””></property>
<property name=”advisor” ref=””></property>
</bean>