一些java名词和技术,与java面经的知识有很多重叠,资料全部来自网上搜集,如有错误请见谅。
servlet
Servlet(Server Applet),全称Java Servlet,未有中文译文。 是用Java编写的服务器端程序。 其主要功能在于交互式地浏览和修改数据,生成动态Web内容。
MySQL
SSM
SSM SPRING+SPING MVC + MYBATIS
Spring
Spring的一个核心功能是IOC,就是将Bean初始化加载到容器中,Bean是如何加载到容器的,可以使用Spring注解方式或者Spring XML配置方式。
Spring注解方式减少了配置文件内容,更加便于管理,并且使用注解可以大大提高了开发效率!
下面安装分类讲解Spring中常用的一些注解。
AOP 即 Aspect Oriented Program 面向切面编程 。首先,在面向切面编程的思想里面,把功能分为核心业务功能,和周边功能。
所谓的核心业务,比如登陆,增加数据,删除数据都叫核心业务
所谓的周边功能,比如性能统计,日志,事务管理等等
周边功能在Spring的面向切面编程AOP思想里,即被定义为切面
在面向切面编程AOP的思想里面,核心业务功能和切面功能分别独立进行开发
然后把切面功能和核心业务功能 “编织” 在一起,这就叫AOP
- 功能分两大类,辅助功能和核心业务功能
- 辅助功能和核心业务功能彼此独立进行开发
- 比如登陆功能,即便是没有性能统计和日志输出,也可以正常运行
- 如果有需要,就把”日志输出” 功能和 “登陆” 功能 编织在一起,这样登陆的时候,就可以看到日志输出了
- 辅助功能,又叫做切面,这种能够选择性的,低耦合的把切面和核心业务功能结合在一起的编程思想,就叫做切面编程
JDBC
Java数据库连接,(Java Database Connectivity,简称JDBC)是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口,提供了诸如查询和更新数据库中数据的方法。
抽象类与接口
比如:抽象类有没有构造函数。答案:有,接口没有构造函数
先说区别:
接口可以多实现,一个类实现多个接口,抽象类只能单继承,即一个类只能继承一个抽象类。
抽象类可以有非抽象的方法和构造方法,变量等,但是接口只能用抽象方法和静态常量。
抽象类和子类具有父子关系,即子类可以拥有父类的属性。接口被实现之后,由于接口中变量都是静态常量,因此不存在继承关系。
相同点:就是二者均不能被实例化,new只能是通过实现类或者子类实现。
总结一下,图标链接:http://www.importnew.com/12399.html
参数 | 抽象类 | 接口 |
---|---|---|
默认的方法实现 | 它可以有默认的方法实现 | 接口完全是抽象的。它根本不存在方法的实现 |
实现 | 子类使用extends关键字来继承抽象类。如果子类不是抽象类的话,它需要提供抽象类中所有声明的方法的实现。 | 子类使用关键字implements来实现接口。它需要提供接口中所有声明的方法的实现 |
构造器 | 抽象类可以有构造器 | 接口不能有构造器 |
与正常Java类的区别 | 除了你不能实例化抽象类之外,它和普通Java类没有任何区别 | 接口是完全不同的类型 |
访问修饰符 | 抽象方法可以有public、protected和default这些修饰符 | 接口方法默认修饰符是public。你不可以使用其它修饰符。 |
main方法 | 抽象方法可以有main方法并且我们可以运行它 | 接口没有main方法,因此我们不能运行它。 |
多继承 | 抽象方法可以继承一个类和实现多个接口 | 接口只可以继承一个或多个其它接口 |
速度 | 它比接口速度要快 | 接口是稍微有点慢的,因为它需要时间去寻找在类中实现的方法。 |
添加新方法 | 如果你往抽象类中添加新的方法,你可以给它提供默认的实现。因此你不需要改变你现在的代码。 | 如果你往接口中添加方法,那么你必须改变实现该接口的类。 |
描述一下二者设计的目的以及二者使用条件:
抽象类就是抽象了子类的共有的特性,但是不给具体实现,比如水果之于苹果,苹果就继承水果的特性。当然还有苹果之于红苹果 ,苹果也可以是抽象类。
接口更像是一种模板和协议,一旦实现了这个接口,就要严格实现接口提供的所有方法,必须按照接口给的逻辑去设计某个类。
显然如果希望保留一部分共同的方法,就使用抽象类,这样所有子类都可以使用该方法,不用再写一遍。如果实现多继承,那就没办法了,抽象类只能继承一个,那就使用接口,这样类就可以同时具有多个接口的规则,但是方法要全部实现一遍。
从结果来看抽象类的子类都是相似的类,他们有共同的属性和方法,但是实现接口的多个类他们之间区别却可以很大,但是他们均有共同的行为,即均要实现接口提供的方法,比如飞机和鸟实现了接口Fly,于是他们的类中就要按照Fly的逻辑提供相应的方法。可以总结为抽象类是对类抽象,接口是对行为抽象。
在自己设计抽象类或者接口的时候,显然抽象类要自下而上,必须知道所有子类的细节,才能提炼他们的共性,不然抽象类的设计就有缺陷(共性不够全或者层次不合理)。而接口则不同,设计的时候完全仅仅从自身出发,考虑自身的特性,而不用在乎什么类实现该接口,只需要设计自己框架内的规则。所有的类均遵守该规则即可。比如设计Fly接口的时候只需要提供飞行的基本逻辑方法,飞行高度,速度等等。而不必考虑什么类(鸟,飞机,火箭。。)实现Fly接口。
以上分析借鉴http://blog.csdn.net/chenssy/article/details/12858267,感谢作者
多线程
封装、多态与继承
内部类
内部类直白就是在类的内部再定义一个类。目的是更好的实现继承关系,更好的实现多重继承。
说明:一个类已经实现了一个接口,而内部类则可以实现另一个接口,相互之间不受影响。
分为 成员内部类 局部内部类 匿名内部类 静态内部类
好处:
1.每个内部类都能独立的继承一个接口的实现,所以无论外部类是否已经继承了某个(接口的)实现,对于内部类都没有影响。内部类使得多继承的解决方案变得完整,
2.方便将存在一定逻辑关系的类组织在一起,又可以对外界隐藏。
3.方便编写事件驱动程序
4.方便编写线程代码
SpringMvc
异常
java能处理的异常均来自于一个共同的祖先Throwable。有两个重要的子类,Error和Exception。二者各自均有大量的子类。
Error一般指程序无法处理的错误,是运行中比较严重的错误,大多数与代码与操作无关,比如JVM运行时出现问题等。这些情况一般JVM会选择线程终止。
Exception指程序本身可以处理的异常。RuntimeException及其子类就是JVM常用操作引发的错误。比如数组越界等。
运行异常java编译器不回去检查他,编译可以通过。而RuntimeExceprion之外的Exception理论上不处理程序就不可能编译通过。
异常的捕捉和抛出:
总体来说,Java规定:对于可查异常必须捕捉、或者声明抛出。允许忽略不可查的RuntimeException和Error。
在Java中提供了一些异常用来描述经常发生的错误,对于这些异常,有的需要程序员进行捕获处理或声明抛出,有的是由Java虚拟机自动进行捕获处理。Java中常见的异常类:
1. runtimeException子类:
1、 java.lang.ArrayIndexOutOfBoundsException
数组索引越界异常。当对数组的索引值为负数或大于等于数组大小时抛出。
2、java.lang.ArithmeticException
算术条件异常。譬如:整数除零等。
3、java.lang.NullPointerException
空指针异常。当应用试图在要求使用对象的地方使用了null时,抛出该异常。譬如:调用null对象的实例方法、访问null对象的属性、计算null对象的长度、使用throw语句抛出null等等
4、java.lang.ClassNotFoundException
找不到类异常。当应用试图根据字符串形式的类名构造类,而在遍历CLASSPAH之后找不到对应名称的class文件时,抛出该异常。
5、java.lang.NegativeArraySizeException 数组长度为负异常
6、java.lang.ArrayStoreException 数组中包含不兼容的值抛出的异常
7、java.lang.SecurityException 安全性异常
8、java.lang.IllegalArgumentException 非法参数异常
2.IOException
IOException:操作输入流和输出流时可能出现的异常。
EOFException 文件已结束异常
FileNotFoundException 文件未找到异常
3. 其他
ClassCastException 类型转换异常类
ArrayStoreException 数组中包含不兼容的值抛出的异常
SQLException 操作数据库异常类
NoSuchFieldException 字段未找到异常
NoSuchMethodException 方法未找到抛出的异常
NumberFormatException 字符串转换为数字抛出的异常
StringIndexOutOfBoundsException 字符串索引超出范围抛出的异常
IllegalAccessException 不允许访问某类异常
InstantiationException 当应用程序试图使用Class类中的newInstance()方法创建一个类的实例,而指定的类对象无法被实例化时,抛出该异常
异常的抛出和异常的捕获
如果一个方法可能可能出现异常(比如内部调用其他方法而出现的异常)如果不能在内部进行捕获并处理,就要抛出,而抛出的方法必须在方法命名的时候就要声明。
比如
1 | methodname throws Exception1,Exception2,..,ExceptionN |
一旦方法声明中抛出异常,则方法内部不需要处理这些异常,这些异常会自动被抛向调用该方法的方法,并且由它来处理。
try catch final
使用try 和大括号包含一段代码,目的是监控代码中是否抛出了异常。
一旦抛出异常,就有catch中的代码接管,不会执行try剩余的代码。
最后无论有没有异常,try执行结束或者catch执行结束均要执行final。
1、不管有木有出现异常,finally块中代码都会执行;
2、当try和catch中有return时,finally仍然会执行;
3、finally是在return后面的表达式运算后执行的(此时并没有返回运算后的值,而是先把要返回的值保存起来,管finally中的代码怎么样,返回的值都不会改变,任然是之前保存的值),所以函数返回值是在finally执行前确定的;
4、finally中最好不要包含return,否则程序会提前退出,返回值不是try或catch中保存的返回值。
传值还是传引用
答: java里面只有传值,没有传引用。我的理解,任何一个代码块跳转的时候(就是函数调用,还包括上面的调用final里面的代码)传递的都是值,而不是指向对象的指针(引用)。
区别在于,你传一个基本类型的变量a=1,那么就是复制1这个值传过去。当你在代码块内部写 x=a之类的操作就是将新的x变量指向栈内存的1的地址。因此怎么写都不会改变原来a指向1的事实,结果输出a还是1。
1 | int a = 1; |
return 返回的顺序
先说结论
return返回之前,执行final语句。
1 | public class Test { |
上面的代码,首先执行try,再执行 return内部的语句i+1,但是执行i+1就是i变成2的之后,要返回2之前,要先执行final代码,因此屏幕上会先输出final block再输出return value of getValue():2 但是为什么是2 ,就要提到上面讲的传值的问题。在final代码块中得到的数仅仅是2这个值,而i++就是新的i指向了3这个值。而try代码块中的i指向2并没有发生变化。(基本类型不存在修改内存中的值,因为存在栈内存中,改变了就是重新指向新的栈内存)。因此返回输出的是2.
扩展:错误和异常的区别(Error vs Exception)
1) java.lang.Error: Throwable的子类,用于标记严重错误。合理的应用程序不应该去try/catch这种错误。绝大多数的错误都是非正常的,就根本不该出现的。
java.lang.Exception: Throwable的子类,用于指示一种合理的程序想去catch的条件。即它仅仅是一种程序运行条件,而非严重错误,并且鼓励用户程序去catch它。
2) Error和RuntimeException 及其子类都是未检查的异常(unchecked exceptions),而所有其他的Exception类都是检查了的异常(checked exceptions).
checked exceptions: 通常是从一个可以恢复的程序中抛出来的,并且最好能够从这种异常中使用程序恢复。比如FileNotFoundException, ParseException等。检查了的异常发生在编译阶段,必须要使用try…catch(或者throws)否则编译不通过。
unchecked exceptions: 通常是如果一切正常的话本不该发生的异常,但是的确发生了。发生在运行期,具有不确定性,主要是由于程序的逻辑问题所引起的。比如ArrayIndexOutOfBoundException, ClassCastException等。从语言本身的角度讲,程序不该去catch这类异常,虽然能够从诸如RuntimeException这样的异常中catch并恢复,但是并不鼓励终端程序员这么做,因为完全没要必要。因为这类错误本身就是bug,应该被修复,出现此类错误时程序就应该立即停止执行。 因此,面对Errors和unchecked exceptions应该让程序自动终止执行,程序员不该做诸如try/catch这样的事情,而是应该查明原因,修改代码逻辑。
RuntimeException:RuntimeException体系包括错误的类型转换、数组越界访问和试图访问空指针等等。
处理RuntimeException的原则是:如果出现 RuntimeException,那么一定是程序员的错误。例如,可以通过检查数组下标和数组边界来避免数组越界访问异常。其他(IOException等等)checked异常一般是外部错误,例如试图从文件尾后读取数据等,这并不是程序本身的错误,而是在应用环境中出现的外部错误。
多线程
线程的创建
1、通过某个类继承Thread类,并且重写run()方法来实现(不推荐)
2、通过某个类实现Runnable接口,并且重写run()方法 来实现
不推荐使用第一种的原因:Java是单继承的,如果某个类extends了Thread类,将不能再继承别的类,影响了代码的延展性。
俩种方法的区别:启动方法不同。
方法1:直接 线程名.start();即可启动线程。
方法2:先new一个对象,如:Test t=new Test(); //此时线程并没有被创建。
然后建立线程对象,并且将t放入其中, Thread td1=new Thread(t);
最后通过td1.start()来启动线程。
“方法2的启动方式其实就是将实现了Runnable接口的类的对象转换成标准的Thread类对象,然后再.start()来启动”
为什么要覆盖run方法呢?
Thread类用于描述线程,该类就定义了一个功能,用于存储线程要运行的代码。该存储功能就是run方法。也就是说Thread类中的run方法,用于存储线程要运行的代码。
thread.join()
该方法是等待某个线程结束之后,才会执行之后的代码。
见 https://blog.csdn.net/dabing69221/article/details/17472901
Start和Run方法
start是启动一个线程,但是不立刻运行它,该线程处于就绪状态,会正常运行start后面的代码,顺序不定
然而run是立刻运行该线程,在运行run下面的代码,就是顺序执行,和普通方法调用 没有区别。
sleep()和wait()的区别
sleep是Thread类的方法,wait是Object类中定义的方法
sleep()睡眠时,保持对象锁,仍然占有该锁;而wait()睡眠时,释放对象锁。
wait()使用notify或者notifyAlll或者指定睡眠时间来唤醒当前等待池中的线程。
sleep()方法可以在任何地方使用;wait()方法则只能在同步方法或同步块中使用
Java内存模型 JMM
Synchronized (同步)关键字 :
同步 可以是同步代码块,也可以同步一个函数。
synchronized(this){}指的是这段代码使用对象。
synchronized(Object){}指的就是Object这个对象。其实两者可以是一样的
上面两种情况就是要是想运行{}内部的代码,必须获得this:调用这段代码的对象的锁,或者Object这个对象的锁。
如果synchronized后面修饰的是方法或者静态变量。对于修饰静态变量就是对于这整个类的所有实例都要申请同一把锁来使用这个静态变量。而修饰方法则是对每个类实例的方法,都有一把锁,要使用这个实例的方法,就要先申请锁才能调用这个方法。
Volatile 关键字
原子性 可见性 有序性
原子性就是操作不可分,要么全部执行,要么全部不执行。
i++就是一个可分的操作, 赋值操作就是一个不可分的操作
可见性就是一个线程对数据的改变可以立刻看得见。
java中每个线程都有自己的线程栈,每次操作数据的时候,先把数据拷贝一份到自己的线程栈,然后再进行操作,最后将修改后的数据写回内存。
volatile关键字就是保证数据的可见性的。
有序性指程序执行的顺序就是按照写代码的顺序执行,单线程改变顺序一般不会有不良后果,因为要保证程序的正确性。而多线程下,程序正确也可能会出错,因为两个线程的顺序可能不一致。
volatile就是保证了可见性和一定程度的有序性,不能保证原子性。