下面是java的一些面试点,主要是基础知识。java
检查式异常:咱们常常遇到的IO异常及sql异常就属于检查式异常。对于这种异常,java编译器要求咱们必须对出现的这些异常进行catch 因此 面对这种异常无论咱们是否愿意,只能本身去写一堆catch来捕捉这些异常。程序员
运行时异常:咱们能够不处理。当出现这样的异常时,老是由虚拟机接管。好比:咱们历来没有人去处理过NullPointerException异常,它就是运行时异常,而且这种异常仍是最多见的异常之一。面试
RuntimeExecption在java.lang包下,ajax
ClassCastException(类转换异常)算法
IndexOutOfBoundsException(数组越界)spring
NullPointerException(空指针)sql
ArrayStoreException(数据存储异常,操做数组时类型不一致)数据库
还有IO操做的BufferOverflowException异常编程
能够,可是一个文件中只能有一个public类,而且此public类必须与文件名相同。
抽象
抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面。
继承数组
类的重用。一个新类能够从现有的类中派生,这个过程称为类继承。派生类能够从它的基类那里继承方法和实例变量,而且类能够修改或增长新的方法使之更适合特殊的须要,提升代码的重用行。
封装
封装是把数据和过程(对数据的操做)包围起来,隐藏内部的实现细节,对数据的访问只能经过已定义的方法 。
多态
多态性是指容许不一样类的对象对同一消息做出响应。
AOP能够对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度下降,提升程序的可重用性,同时提升了开发的效率。
AOP、OOP在字面上虽然很是相似,但倒是面向不一样领域的两种设计思想。
OOP(面向对象编程)针对业务处理过程的实体及其属性和行为进行抽象封装,以得到更加清晰高效的逻辑单元划分。
而AOP则是针对业务处理过程当中的切面进行提取,它所面对的是处理过程当中的某个步骤或阶段,以得到逻辑过程当中各部分之间低耦合性的隔离效果。这两种设计思想在目标上有着本质的差别。
上面的陈述可能过于理论化,举个简单的例子,对于“雇员”这样一个业务实体进行封装,天然是OOP/OOD的任务,咱们能够为其创建一个“Employee”类,并将“雇员”相关的属性和行为封装其中。而用AOP设计思想对“雇员”进行封装将无从谈起。
一样,对于“权限检查”这一动做片段进行划分,则是AOP的目标领域。而经过OOD/OOP对一个动做进行封装,则有点不三不四。
换而言之,OOD/OOP面向名词领域,AOP面向动词领域。
IoC就是Inversion of Control,控制反转。在Java开发中,IoC意味着将你设计好的类交给系统去控制,而不是在你的类内部控制。这称为控制反转。
将对象的建立和获取提取到外部。由外部容器提供须要的组件。
AOP 关注与主要的东西,也能够说让你只关注与业务,其余的东西就让AOP帮你完成。好比事务管理、持久化、资源池、系通通一的认证、权限管理等。容许经过分离应用的业务逻辑与系统级服务进行内聚性的开发。
设要排序的数组是A[0]……A[N-1],首先任意选取一个数据(一般选用数组的第一个数)做为关键数据,而后将全部比它小的数都放到它前面,全部比它大的数都放到它后面,这个过程称为一趟快速排序。值得注意的是,快速排序不是一种稳定的排序算法,也就是说,多个相同的值的相对位置也许会在算法结束时产生变更。
一趟快速排序的算法是:
1)设置两个变量i、j,排序开始的时候:i=0,j=N-1;
2)以第一个数组元素做为关键数据,赋值给key,即key=A[0];
3)从j开始向前搜索,即由后开始向前搜索(j--),找到第一个小于key的值A[j],将A[j]和A[i]互换;
4)从i开始向后搜索,即由前开始向后搜索(i++),找到第一个大于key的A[i],将A[i]和A[j]互换;
5)重复第三、4步,直到i=j; (3,4步中,没找到符合条件的值,即3中A[j]不小于key,4中A[i]不大于key的时候改变j、i的值,使得j=j-1,i=i+1,直至找到为止。找到符合条件的值,进行交换的时候i, j指针位置不变。另外,i==j这一过程必定正好是i+或j-完成 的时候,此时令循环结束)。
假设用户输入了以下数组:
下标 |
0 |
1 |
2 |
3 |
4 |
5 |
数据 |
6 |
2 |
7 |
3 |
8 |
9 |
建立变量i=0(指向第一个数据), j=5(指向最后一个数据), k=6(赋值为第一个数据的值)。
咱们要把全部比k小的数移动到k的左面,因此咱们能够开始寻找比6小的数,从j开始,从右往左找,不断递减变量j的值,咱们找到第一个下标3的数据比6小,因而把数据3移到下标0的位置,把下标0的数据6移到下标3,完成第一次比较:
下标 |
0 |
1 |
2 |
3 |
4 |
5 |
数据 |
3 |
2 |
7 |
6 |
8 |
9 |
i=0 j=3 k=6
接着,开始第二次比较,此次要变成找比k大的了,并且要从前日后找了。递加变量i,发现下标2的数据是第一个比k大的,因而用下标2的数据7和j指向的下标3的数据的6作交换,数据状态变成下表:
下标 |
0 |
1 |
2 |
3 |
4 |
5 |
数据 |
3 |
2 |
6 |
7 |
8 |
9 |
i=2 j=3 k=6
称上面两次比较为一个循环。
接着,再递减变量j,不断重复进行上面的循环比较。
在本例中,咱们进行一次循环,就发现i和j“碰头”了:他们都指向了下标2。因而,第一遍比较结束。获得结果以下,凡是k(=6)左边的数都比它小,凡是k右边的数都比它大:
下标 |
0 |
1 |
2 |
3 |
4 |
5 |
数据 |
3 |
2 |
6 |
7 |
8 |
9 |
若是i和j没有碰头的话,就递加i找大的,尚未,就再递减j找小的,如此反复,不断循环。注意判断和寻找是同时进行的。
而后,对k两边的数据,再分组分别进行上述的过程,直到不能再分组为止。
注意:第一遍快速排序不会直接获得最终结果,只会把比k大和比k小的数分到k的两边。为了获得最后结果,须要再次对下标2两边的数组分别执行此步骤,而后再分解数组,直到数组不能再分解为止(只有一个数据),才能获得正确结果。
代码:
public class QuickSort { private static int par(int[]arr,int left,int right){ int key=arr[left]; while(left < right){ //从最右边开始找比key小的数 while(left<right && arr[right]>=key) right--; //把找到的数移到左边 arr[left]=arr[right]; //从最左边开始找比key大的数 while(left<right && arr[left]<=key) left++; //把找到的数移到右边 arr[right]=arr[left]; } //最后,left等于right,将key至于中间,这样,key以前的数,比key小,key以后的数,比key大 arr[left]=key; return left; } private static void quickSort(int[]arr,int left,int right) { if(arr==null || arr.length==0 || left>=right){ return ; } int pos=par(arr,left,right); quickSort(arr,left,pos-1); quickSort(arr,left+1,right); } public static void main(String[]args) { int[] arr={22,11,23,32,45,32,21,33,67,12}; quickSort(arr,0,arr.length-1); for(int k:arr) System.out.print(k+" "); } }
创建在归并操做上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个很是典型的应用。将已有序的子序列合并,获得彻底有序的序列;即先使每一个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
归 并过程为:比较a[i]和a[j]的大小,若a[i]≤a[j],则将第一个有序表中的元素a[i]复制到r[k]中,并令i和k分别加上1;不然将第二 个有序表中的元素a[j]复制到r[k]中,并令j和k分别加上1,如此循环下去,直到其中一个有序表取完,而后再将另外一个有序表中剩余的元素复制到r中 从下标k到下标t的单元。归并排序的算法咱们一般用递归实现,先把待排序区间[s,t]以中点二分,接着把左边子区间排序,再把右边子区间排序,最后把左 区间和右区间用一次归并操做合并成有序的区间[s,t]。
归并操做
归并操做(merge),也叫归并算法,指的是将两个顺序序列合并成一个顺序序列的方法。
如 设有数列{6,202,100,301,38,8,1}
初始状态:6,202,100,301,38,8,1
第一次归并后:{6,202},{100,301},{8,38},{1},比较次数:3;
第二次归并后:{6,100,202,301},{1,8,38},比较次数:4;
第三次归并后:{1,6,8,38,100,202,301},比较次数:4;
总的比较次数为:3+4+4=11,;
逆序数为14;
算法描述
归并操做的工做原理以下:
第一步:申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
第二步:设定两个指针,最初位置分别为两个已经排序序列的起始位置
第三步:比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
重复步骤3直到某一指针超出序列尾
将另外一序列剩下的全部元素直接复制到合并序列尾
代码:
public class MergeSort { public static void mergeSort(int[] arr) { if(arr==null || arr.length<=1){ return; } mSort(arr, 0, arr.length-1); } public static void mSort(int[] arr, int left, int right) { if(left >= right) return ; int mid = (left + right) / 2; mSort(arr, left, mid); //递归排序左边 mSort(arr, mid+1, right); //递归排序右边 merge(arr, left, mid, right); //合并 } /** * 合并两个有序数组 * @param arr 待合并数组 * @param left 左指针 * @param mid 中间指针 * @param right 右指针 */ public static void merge(int[] arr, int left, int mid, int right) { //[left, mid] [mid+1, right] int[] temp = new int[right - left + 1]; //中间数组 int i = left; int j = mid + 1; int k = 0; while(i <= mid && j <= right) { if(arr[i] <= arr[j]) { temp[k++] = arr[i++]; } else { temp[k++] = arr[j++]; } } while(i <= mid) { temp[k++] = arr[i++]; } while(j <= right) { temp[k++] = arr[j++]; } for(int p=0; p<temp.length; p++) { arr[left + p] = temp[p]; } } public static void main(String[] args) { int[] arr={1,98,33,31,35,2,55,78,44,3}; mergeSort(arr); for(int k:arr) System.out.print(k+" "); } }
所谓洗牌算法,就是给你一个1到n的序列,让你随机打乱,保证每一个数出如今任意一个位置的几率相同,也就是说在n!个的排列中,每个排列出现的几率相同。
咱们考虑,当一个数被选以后,咱们是没有必要在下一次随机的时候再考虑它的,所以,咱们每次只从可选的数的集合中进行随机,也就不用考虑是否会碰到已经选过的数了,这样子直接将算法的复杂度降了一个数量级。
咱们考虑,当一个数被选以后,咱们是没有必要在下一次随机的时候再考虑它的,所以,咱们每次只从可选的数的集合中进行随机,也就不用考虑是否会碰到已经选过的数了,这样子直接将算法的复杂度降了一个数量级。
void MySwap(int &x, int &y) { int temp = x; x = y; y = temp; } void Shuffle(int n) { for(int i=n-1; i>=1; i--) { MySwap(num[i], num[rand()%(i+1)]); } }
把对象转换为字节序列的过程—序列化。
把字节序列恢复为对象的过程—反序列化。
对象的序列化主要有两种用途:
1) 把对象的字节序列永久地保存到硬盘上,一般存放在一个文件中;
2) 在网络上传送对象的字节序列。
JDK类库中的序列化API
java.io.ObjectOutputStream表明对象输出流,它的writeObject(Object obj)方法可对参数指定的obj对象进行序列化,把获得的字节序列写到一个目标输出流中。
java.io.ObjectInputStream表明对象输入流,它的readObject()方法从一个源输入流中读取字节序列,再把它们反序列化为一个对象,并将其返回。
只有实现了Serializable和Externalizable接口的类的对象才能被序列化。Externalizable接口继承自 Serializable接口,实现Externalizable接口的类彻底由自身来控制序列化的行为,而仅实现Serializable接口的类能够 采用默认的序列化方式 。
对象序列化包括以下步骤:
1) 建立一个对象输出流,它能够包装一个其余类型的目标输出流,如文件输出流;
2) 经过对象输出流的writeObject()方法写对象。
对象反序列化的步骤以下:
1) 建立一个对象输入流,它能够包装一个其余类型的源输入流,如文件输入流;
2) 经过对象输入流的readObject()方法读取对象。
StringBuffer对象的内容能够修改;而String对象一旦产生后就不能够被修改,从新赋值后生成的新对象。
硬件环境不一样:
C/S 通常创建在专用的网络上, 小范围里的网络环境, 局域网之间再经过专门服务器提供链接和数据交换服务. B/S 创建在广域网之上的, 没必要是专门的网络硬件环境,例与电话上网, 租用设备. 信息本身管理. 有比C/S更强的适应范围, 通常只要有操做系统和浏览器就行
对安全要求不一样 :
C/S 通常面向相对固定的用户群, 对信息安全的控制能力很强. 通常高度机密的信息系统采用C/S 结构适宜. 能够经过B/S发布部分可公开信息.
B/S 创建在广域网之上, 对安全的控制能力相对弱, 面向是不可知的用户群.
对程序架构不一样:
C/S 程序能够更加注重流程, 能够对权限多层次校验, 对系统运行速度能够较少考虑.
B/S 对安全以及访问速度的多重的考虑, 创建在须要更加优化的基础之上. 比C/S有更高的要求 B/S结构的程序架构是发展的趋势, 从MS的.Net系列的BizTalk 2000 Exchange 2000等, 全面支持网络的构件搭建的系统. SUN 和IBM推的JavaBean 构件技术等,使 B/S更加成熟.
软件重用不一样:
C/S 程序能够不可避免的总体性考虑, 构件的重用性不如在B/S要求下的构件的重用性好.
B/S 对的多重结构,要求构件相对独立的功能. 可以相对较好的重用.就入买来的餐桌能够再利用,而不是作在墙上的石头桌子
系统维护不一样 :
系统维护是软件生存周期中,开销大, -------重要
C/S 程序因为总体性, 必须总体考察, 处理出现的问题以及系统升级. 升级难. 多是再作一个全新的系统
B/S 构件组成,方面构件个别的更换,实现系统的无缝升级. 系统维护开销减到最小.用户从网上本身下载安装就能够实现升级.
处理问题不一样:
C/S 程序能够处理用户面固定, 而且在相同区域, 安全要求高需求, 与操做系统相关. 应该都是相同的系统
B/S 创建在广域网上, 面向不一样的用户群, 分散地域, 这是C/S没法做到的. 与操做系统平台关系最小.
用户接口不一样
C/S 可能是创建的Window平台上,表现方法有限,对程序员广泛要求较高
B/S 创建在浏览器上, 有更加丰富和生动的表现方式与用户交流. 而且大部分难度减低,减低开发成本.
不能够,private咳哟用来修饰类变量。方法内的变量做用域是从这个变量声明直到方法体结束,若是再使用private修饰的话二者就会冲突,因此不能在方法体内声明一个变量为private,并且在方法里 声明变量为private也没什么意义,方法内声明的变量的做用域原本就在方法体内,天然也不会被其它方法所访问。
能够进入其余非synchronized的方法,synchronized的方法不能够的!
Java中的每一个对象都有一个锁(lock)或者叫作监视器(monitor),当访问某个对象的synchronized方法时,表示的将该对象上锁,此时其余任何线程都没法再去访问该synchronized方法了,直到以前的那个线程执行方法完毕后(或者是抛出了异常),才将该对象的锁释放掉,其余线程才有可能再去访问该synchronized方法。
若是一个对象有多个synchronized方法,某一时刻某个线程已经进入到了某个synchronized方法,那么在该方法没有执行完毕前,其余线程是没法访问该对象的任何synchronized方法的。
13.对象的上转型,子类重写了基类的方法A,那么上转型对象操做的这个方法A,是基类的方法A?仍是子类的方法A?
对象的上转型,操做的是子类的方法A。上转型对象只能操做基类的变量,子类继承的方法和子类重写的方法,不能使用子类新增的变量和方法。
能够。for( boolean1; boolean2&&条件表达式;boolean3)是正确的。
byte、short、char、int、enum
在jdk1.5上,Byte、Short、Character、Integer也支持。
1 读取并解析配置文件
Configuration conf = new Configuration().configure();
2 读取并解析映射信息,建立SessionFactory
SessionFactory sf = conf.buildSessionFactoty();
3 打开Session
Session session = sf.openSession;//sf.getCurrentSession();
4 开始一个事务(增删改操做必须,查询操做可选)
Transaction tx = session.beginTransaction();
5 数据库操做
session.sava();
6 提交事务(回滚事务)
tx.commit();(tx.rollback();)
7 关闭session
session.close();
一:static声明的内部类
假设定义了一个类Outer,在Outer里定义了一个内部类Inner。
class Outer{ // 定义外部类 private static String info = "hello world" ; // 定义外部类的私有属性 static class Inner{ // 使用static定义内部类为外部类 public void print(){ // 定义内部类的方法 System.out.println(info) ; // 直接访问外部类的私有属性 } }; public void fun(){ // 定义外部类的方法 new Inner().print() ; // 经过内部类的实例化对象调用方法 } }
那么编译后会生成Outer.class和Outer$Inner.class。
经过Outer.Inner in=new Outer.Inner(); 访问内部类。
二:不使用statc声明一个内部类
class Outer{ // 定义外部类 private static String info = "hello world" ; // 定义外部类的私有属性 class Inner{ // 使用static定义内部类为外部类 public void print(){ // 定义内部类的方法 System.out.println(info) ; // 直接访问外部类的私有属性 } }; public void fun(){ // 定义外部类的方法 new Inner().print() ; // 经过内部类的实例化对象调用方法 } }
经过 Outer o=new Outer(); Outer.Inner in=o.new Inner();访问内部类。
注意点:内部类不能含有static变量和方法,由于成员内部类的建立依赖于外部类对象。只有建立了外部类对象,才能建立内部类对象。
Inverse是hibernate双向关系中的基本概念。inverse的真正做用就是指定由哪一方来维护之间的关联关系。当一方中指定了“inverse=true”,那么那一方就有责任负责之间的关联关系。
在set节点里设置。
①浏览器和服务器会对用get方式提交的数据进行限制,服务器会对用post方式提交的数据进行限制。
②post的请求数据放置在http请求包中。
③get的参数个数理论上没有限制,可是浏览器和服务器会对用get方式提交的数据进行限制。
另外,get方式的提交的url采用ASCII编码。
1. public static void main(String args[]){ {
String a;
System.out.println("a="+a);
}
2. public class InnerClassDemo03{
static String a;
public static void main(String args[]){
System.out.println("a="+a);
}
}
结果:第一个编译会有问题,第二个运行输出a=null。
分析:第一个很好理解,使用前没进行初始化,因此报错。第二个的a实际上是成员变量,编译器有个默认初始化,初始化为null,因此有运行结果。
java集合(能够存储和操做数目不固定的一组数据,只能存放引用类型的数据,不能存放基本类型的数据,位于java.util包中)主要分为三种类型,set、list、map。
List:可自动扩展的数组。
Set:没有重复的数组。
部署java应用:Tomcat、Resin、Jboss、Weblogic
和ajax有关的框架:JQuery、DWR、Dojo、ExtJs、Mootools
System.gc()方法强制垃圾回收
① abstract class 在 Java 语言中表示的是一种继承关系,一个类只能使用一次继承关系。可是,一个类却能够实现多个interface,实现多重继承。接口还有标识(里面没有任何方法,如Remote接口)和数据共享(里面的变量全是常量)的做用。abstract class和interface所反映出的设计理念不一样。其实abstract class表示的是"is-a"关系,interface表示的是"has-a"关系
② 接口是公开的,里面不能有私有的方法或变量,是用于让别人使用的,而抽象类是能够有私有方法或私有变量的。
③ 在abstract class 中能够有abstract的成员方法,也能够有非abstarct的成员方法,而在interface中全部的成员方法默认都是public abstract 类型的
④ 接口中定义的变量默认是public static final 型,且必须给其初值,因此实现类中不能从新定义,也不能改变其值。抽象类中的变量默认是 friendly 型,其值能够在子类中从新定义,也能够在子类中从新赋值。
⑤ 实现接口的必定要实现接口里定义的全部方法,而实现抽象类能够有选择地重写须要用到的方法,通常的应用里,最顶级的是接口,而后是抽象类实现接口,最后才到具体类实现。抽象类中能够有非抽象方法。接口中则不能有实现方法。
1)一旦变量被transient修饰,变量将再也不是对象持久化的一部分,该变量内容在序列化后没法得到访问。
2)transient关键字只能修饰变量,而不能修饰方法和类。注意,本地变量是不能被transient关键字修饰的。变量若是是用户自定义类变量,则该类须要实现Serializable接口。
3)被transient关键字修饰的变量再也不能被序列化,一个静态变量无论是否被transient修饰,均不能被序列化。
对象的初始化顺序:(1)类加载以后,按从上到下(从父类到子类)执行被static修饰的语句;(2)当static语句执行完以后,再执行main方法;(3)若是有语句new了自身的对象,将从上到下执行构造代码块、构造器(二者能够说绑定在一块儿)。
在Java中,子类的构造过程当中必须调用其父类的构造函数,是由于有继承关系存在时,子类要把父类的内容继承下来。但若是父类有多个构造函数时,该如何选择调用呢?第 一个规则:子类的构造过程当中,必须调用其父类的构造方法。一个类,若是咱们不写构造方法,那么编译器会帮咱们加上一个默认的构造方法(就是没有参数的构造 方法),可是若是你本身写了构造方法,那么编译器就不会给你添加了,因此有时候当你new一个子类对象的时候,确定调用了子类的构造方法,可是若是在子类构造方法中咱们并无显示的调用基类的构造方法,如:super(); 这样就会调用父类没有参数的构造方法。
第二个规则:若是子类的构造方法中既没有显示的调用基类构造方法,而基类中又没有无参的构造方法,则编译出错,因此,一般咱们须要显示的:super(参数列表),来调用父类有参数的构造函数,此时无参的构造函数就不会被调用。
总之,一句话:子类没有显示调用父类构造函数,无论子类构造函数是否带参数都默认调用父类无参的构造函数,若父类没有则编译出错。