自己4月份面试的一些总结
最近面试的一些公司的面试题进行一个汇总,也是对自己的一个总结,也是希望对后来人有所帮助。
问题:
-
快速排序(笔试)
-
Ajax原理
-
SpringMVC和Struts你认为有什么区别
-
单例模式(笔试)
PS:这个最好写线程安全的 -
多线程编程 两个线程 一个往数组写数据 一个将写入的数据读出来,写入数据库
-
Spring AOP IOC底层实现原理
-
Mybaits与Hibernate的区别,为什么使用Mybaits
-
Hibernate乐观锁与悲观锁
-
分布式Session保持机制的设计方案
-
线程池的作用 它与创建线程有什么区别
-
JVM的内存区域
-
Java是否可以直接操作内存
-
Struts工作原理
-
Oracle/MySQL分表
-
什么是Oracle的表水位线
-
讲一讲TCP协议,三次握手与四次挥手
-
Spring Bean加载机制
-
Java GC机制
-
说一说Collection
-
线程的几种状态
-
String 的 replace与replaceAll
-
Linux常用的指令
-
HashTable和HashMap实现机制,有什么区别
-
synchronized和volatile有什么区别
-
volatile为什么可以做到线程之间的数据共享
-
JDBC是如何连接数据库的
-
JDBC的preparedstatement与statement有什么区别
-
介绍一下JMM模型
-
栈区与堆区有什么区别
-
内存溢出有哪些种?如何解决?
-
新生代的垃圾回收如何控制?如何配置JVM的参数?
-
Tomcat与WebLogic有什么区别?
-
for each与for i循环有什么区别
-
Oracle常用的优化方式
-
RabbitMQ的机制
-
RabbitMQ是如何进行通信的,为什么要使用MQ?
-
Oracle SQL分页写法
-
多线程有哪些实现的方式?
-
线程池有哪些种?实现方式是什么?
-
Java NIO是什么?
-
线程池调优
-
HTTP长连接和短连接
-
乐观锁和悲观锁
-
加密算法有哪些
-
HashMap底层实现
-
数据库调优
暂时先整理这些,以后随时进行补充。
下面是一些简单题的代码:
- public class sort {
- /**
- * @param args
- */
- public static void main(String[] args) {
- int[] data = {8,4,9,2,1,6,3,7,5};
- for (int i = 0; i < data.length; i++) {
- System.out.print(data[i]+" ");
- }
- System.out.println();
- sort s = new sort();
- //s.sort4(data,0,data.length-1);
- s.sort5(data,0,data.length-1);
- for (int i = 0; i < data.length; i++) {
- System.out.print(data[i]+" ");
- }
- }
- /*
- * 冒泡排序:
- 依次比较相邻的两个元素,通过一次比较把未排序序列中最大(或最小)的元素放置在未排序序列的末尾
- */
- public void sort1(int[] data){
- for (int i = 0; i < data.length -1; i++) {
- for (int j = 0; j < data.length - i - 1; j++) {
- if (data[j] > data[j + 1]) { //把大的往后排
- int temp = data[j];
- data[j] = data[j + 1];
- data[j + 1] = temp;
- }
- }
- }
- }
- /*
- * 选择排序:
- 每一次从待排序的数据元素中选出最小(或最大)的一个元素,顺序放在已排好序的数列的最后,直到全部待排序的数据元素排完。
- */
- public void sort2(int data[]) {
- int minVal;
- int minIndex;
- for (int i = 0; i < data.length - 1; i++) {
- minVal = data[i];
- minIndex = i;
- //选择最小的元素以及最小的下标
- for (int j = i + 1; j < data.length; j++) {
- if (data[j] < minVal) {
- minVal = data[j];
- minIndex = j;
- }
- }
- //找到的那个最小元素
- if (minVal != data[i] && minIndex != i) {
- data[minIndex] = data[i];
- data[i] = minVal;
- }
- }
- }
- /*
- * 插入排序:
- 将数列分为有序和无序两个部分,每次处理就是将无序数列的第一个元素与有序数列的元素从后往前逐个进行比较,找出插入位置,将该元素插入到有序数列的合适位置中。
- */
- public void sort3(int data[]) {
- for (int i = 1; i < data.length; i++) {
- for (int j = i; j > 0; j--) {
- if (data[j] < data[j - 1]) {
- int temp = data[j];
- data[j] = data[j - 1];
- data[j - 1] = temp;
- }
- }
- }
- }
- /*
- * 归并排序:
- 将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。排序过程如下:
- (1)申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
- (2)设定两个指针,最初位置分别为两个已经排序序列的起始位置
- (3)比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
- (4)重复步骤3直到某一指针达到序列尾
- (5)将另一序列剩下的所有元素直接复制到合并序列尾
- */
- public void sort4(int data[], int start, int end) {
- if (start < end) {
- int mid = (start + end) / 2;
- sort4(data, start, mid);
- sort4(data, mid + 1, end);
- merge(data, start, mid, end);
- }
- }
- public static void merge(int data[], int start, int mid, int end) {
- int temp[] = new int[end - start + 1];
- int i = start;
- int j = mid + 1;
- int k = 0;
- while (i <= mid && j <= end) {
- if (data[i] < data[j]) {
- temp[k++] = data[i++];
- } else {
- temp[k++] = data[j++];
- }
- }
- while (i <= mid) {
- temp[k++] = data[i++];
- }
- while (j <= end) {
- temp[k++] = data[j++];
- }
- for (k = 0, i = start; k < temp.length; k++, i++) {
- data[i] = temp[k];
- }
- }
- /*
- * 快速排序:
- 通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都小,
- 然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
- */
- public void sort5(int data[], int start, int end) {
- if (end - start <= 0) {
- return;
- }
- int last = start;
- for (int i = start + 1; i <= end; i++) {
- if (data[i] < data[start]) {
- int temp = data[++last];
- data[last] = data[i];
- data[i] = temp;
- }
- }
- int temp = data[last];
- data[last] = data[start];
- data[start] = temp;
- sort5(data, start, last - 1);
- sort5(data, last + 1, end);
- }
- }
-
public class SortDemo {/*** @param args*/public static void main(String[] args) {// TODO Auto-generated method stub//demo2();int[] arr = {1,9,344,12,7,8,3,4,65,22};quicksort(arr, 0, arr.length-1);for(int i:arr){System.out.print(i+" ");}}//选择排序public static void demo(){int[] arr = {78,9,2,22,445,90,-9,55};int temp;for(int i=0;i<arr.length;i++){for(int j=i+1;j<arr.length;j++){if(arr[i]>arr[j]){temp=arr[i];arr[i]=arr[j];arr[j]=temp;}}}for(int a:arr){System.out.print(a+" ");}}//冒泡排序public static void demo2(){int[] arr = {78,9,2,22,445,90,-9,55};int temp;for(int i=1;i<arr.length;i++){for(int j=0;j<arr.length-i;j++){if(arr[j]>arr[j+1]){temp = arr[j];arr[j]=arr[j+1];arr[j+1]=temp;}}}for(int a=0;a<arr.length;a++){System.out.print(arr[a]+" ");}}//插入排序public static void demo3(){int [] arr= {99,25,3,899,22,-1};int temp,i,j;for(i=1;i<arr.length;i++){temp= arr[i];for(j=i;j>0&&arr[j-1]>temp;j--){arr[j]=arr[j-1];}arr[j]=temp;}for(int a:arr){System.out.print(a+" ");}}//快速排序startpublic static int parttion(int []arr,int lo,int hi){int key = arr[lo]; //选取基准点while(lo<hi){//从后半部分向前扫描while(arr[hi]>=key&&hi>lo){hi--;}arr[lo]=arr[hi];//从前半部分向后扫描while(arr[lo]<=key&&hi>lo){lo++;}arr[hi]=arr[lo];}arr[hi]= key; //最后把基准存入return hi;}public static void quicksort(int []arr,int lo,int hi){if(lo>=hi){return;}//进行第一轮排序获取分割点int index = parttion(arr, lo, hi);//排序前半部分quicksort(arr,lo,index -1);//排序后半部分quicksort(arr,index+1,hi);}//快速排序end}
-
二、多线程相关
-
package hanwl.demo;/*** A线程打印10次A,B线程打印10次B,C线程打印10次C,要求线程同时运行,交替打印10次ABC*/public class MyThreadPrinter implements Runnable {private String name;private Object prev;private Object self;public MyThreadPrinter(String name, Object prev, Object self) {//super();this.name = name;this.prev = prev;this.self = self;}@Overridepublic void run() {// TODO Auto-generated method stubint count = 10;while(count>0){synchronized(prev){synchronized(self){System.out.print(name);count--;self.notify();}try {prev.wait();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}public static void main(String[] args) throws Exception {Object a = new Object();Object b = new Object();Object c = new Object();MyThreadPrinter pa = new MyThreadPrinter("A", c, a);MyThreadPrinter pb = new MyThreadPrinter("B", a, b);MyThreadPrinter pc = new MyThreadPrinter("C", b, c);new Thread(pa).start();Thread.sleep(100); //确保按顺序A、B、C执行new Thread(pb).start();Thread.sleep(100);new Thread(pc).start();Thread.sleep(100);}}
-
package hanwl.demo;/***死锁例子*/public class DeadLock {public static String obj1 = "obj1";public static String obj2 = "obj2";public static void main(String[] args){Thread a = new Thread(new Lock1());Thread b = new Thread(new Lock2());a.start();b.start();}}class Lock1 implements Runnable{@Overridepublic void run(){try{System.out.println("Lock1 running");while(true){synchronized(DeadLock.obj1){System.out.println("Lock1 lock obj1");Thread.sleep(3000);//获取obj1后先等一会儿,让Lock2有足够的时间锁住obj2synchronized(DeadLock.obj2){System.out.println("Lock1 lock obj2");}}}}catch(Exception e){e.printStackTrace();}}}class Lock2 implements Runnable{@Overridepublic void run(){try{System.out.println("Lock2 running");while(true){synchronized(DeadLock.obj2){System.out.println("Lock2 lock obj2");Thread.sleep(3000);synchronized(DeadLock.obj1){System.out.println("Lock2 lock obj1");}}}}catch(Exception e){e.printStackTrace();}}}
-
三、IO相关
-
package hanwl.demo;import java.io.BufferedReader;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileReader;import java.io.IOException;import java.io.InputStream;public class SelectDemo {/*** @param args*/public static void main(String[] args) {// TODO Auto-generated method stub//demo();test2();}//给定一个txt文件,如何得到某字符串出现的次数public static void demo(){try {File file = new File("E://demo.txt");InputStream is = new FileInputStream(file);byte b[] = new byte[1024];int a = is.read(b);String str[] = new String(b,0,a).split("");int count = 0;for(int i = 0;i<str.length;i++){if("x".equals(str[i])){count++;}}System.out.println(count);}catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}public static void test(){try {FileReader ins = new FileReader("e:\\demo.txt");char [] buf = new char[6];int num = 0;while((num = ins.read(buf))!=-1){System.out.print(new String(buf,0,num));}ins.close();} catch (IOException e) {// TODO 自动生成 catch 块e.printStackTrace();}}//读取磁盘文件到控制台public static void test2(){try {FileReader ins = new FileReader("e:\\demo.txt");BufferedReader br = new BufferedReader(ins);char [] buf = new char[6];int num = 0;while((num = br.read(buf))!=-1){System.out.print(new String(buf,0,num));}br.close();ins.close();} catch (IOException e) {// TODO 自动生成 catch 块e.printStackTrace();}}}
-
四、单例模式
-
package hanwl.singleton;//单例模式//用“双重检查加锁”,在getInstance()中减少使用同步public class Singleton3 {private volatile static Singleton3 instance;private Singleton3(){}public static Singleton3 getInstance(){if(instance==null){synchronized (Singleton3.class) {if(instance==null){instance =new Singleton3();}}}return instance;}}
-
package hanwl.singleton;/*** 单例模式* 懒汉式* 线程安全给get方法增加*/public class Singleton2 {private static Singleton2 instance;private Singleton2(){}public static synchronized Singleton2 getInstance(){if(instance==null){instance = new Singleton2();}return instance;}}
-
package hanwl.singleton;/*** 单例模式* 饿汉式*/public class Singleton {private static final Singleton instance = new Singleton();private Singleton(){}public static Singleton getInstance() {return instance;}}package hanwl.singleton;public class MyThread extends Thread {@Overridepublic void run() {// TODO Auto-generated method stubSystem.out.println(Singleton.getInstance().hashCode());}/*** @param args*/public static void main(String[] args) {// TODO Auto-generated method stubMyThread[] mts = new MyThread[10];for(int i=0;i<mts.length;i++){mts[i]=new MyThread();}for (int j = 0; j < mts.length; j++) {mts[j].start();}}}
-
五、一些面试题
-
package hanwl.demo;public class ArrayDemo {/*** 有两个有序数组a[]和b[],将它们合并成数组c[],需要c[]也是有序数组,考虑时间复杂度* @param args*/public static void main(String[] args) {// TODO Auto-generated method stubsortArray();}public static void sortArray(){int [] a = {1,5,22,44,98};int [] b = {2,4,18,33,50,90,109,180,222};//定义一个新数组,长度为两个数组长度之和int [] c = new int[a.length+b.length];//i:a数组下标 j:b数组下标 k:新数组下标int i=0,j=0,k=0;//按位循环比较两个数组,较小元素的放入新数组,下标加一(注意,较大元素对应的下标不加一),直到某一个下标等于数组长度时退出循环while(i<a.length&&j<b.length){if(a[i]<=b[j]){c[k++]=a[i++];}else{c[k++]=b[j++];}}/* 后面连个while循环是用来保证两个数组比较完之后剩下的一个数组里的元素能顺利传入 ** 此时较短数组已经全部放入新数组,较长数组还有部分剩余,最后将剩下的部分元素放入新数组,大功告成*/while(i<a.length){c[k++]=a[i++];}while(j<b.length){c[k++]=b[j++];}for(int x=0;x<c.length;x++){System.out.print(c[x]+",");}}}
-
package hanwl.string;public class StringDemo {/*** 字符串反转* @param args*/public static void main(String[] args) {//String str = "aaabbbcccddd";//reversell(str);reverseDemo();//demo();}public static String reversell(String str){return new StringBuffer(str).reverse().toString();}public static void reverseDemo(){String str = "aaabbbcccddd";StringBuffer sb = new StringBuffer();for(int i=str.length()-1;i>=0;i--){char ch = str.charAt(i);sb.append(ch);}System.out.println(sb.toString());}public static void demo(){int count = 0;int num = 0;for(int i=0;i<=100;i++){num = num+i;count = count++;}System.out.println(num*count);}}
-
package hanwl.demo;import java.io.File;public class ListFileDemo {/*** 递归列出某个路径下的所有文件名,包括子目录* @param args*/public static void main(String[] args) {// TODO Auto-generated method stubFile file = new File("e:\\资料文件");listFile2(file);}public static void listFile(File file){File [] subFile = file.listFiles();for(File f:subFile){if(f.isDirectory()){listFile(f);}else{System.out.println(f);}//System.out.println(f.getName());}}public static void listFile2(File file){File [] subFile = file.listFiles();for(int i=0;i<subFile.length;i++){if(subFile[i].isDirectory()){listFile2(subFile[i]);}else{System.out.println(subFile[i].getAbsolutePath());}}}}
-
import java.io.File;/*** 递归列出某个路径下的所有文件名,包括子目录,带级别* @author loong**/public class ListFileDemo3 {public static void main(String[] args){File dir = new File("e:\\KanKan");showDir(dir,0);//System.out.println(dir.delete());}public static String getLevel(int level){StringBuilder sb = new StringBuilder();sb.append("|--");for(int x=0; x<level; x++){//sb.append("|--");sb.insert(0,"| ");}return sb.toString();}public static void showDir(File dir,int level){System.out.println(getLevel(level)+dir.getName());level++;File[] files = dir.listFiles();for(int x=0; x<files.length; x++){if(files[x].isDirectory())showDir(files[x],level);elseSystem.out.println(getLevel(level)+files[x]);}}
-
六、JDBC例子
-
package hanwl.jdbc;import java.sql.Connection;import java.sql.DriverManager;import java.sql.ResultSet;import java.sql.SQLException;import java.sql.Statement;public class JdbcDemo {/*** @param args*/public static void main(String[] args) {// TODO Auto-generated method stubtry {//加载数据库驱动String driver = "com.mysql.jdbc.Driver";Class.forName(driver);String url = "jdbc:mysql://localhost:3306/spring?useUnicode=true&characterEncoding=UTF8";String username = "root";String password = "root";//获取数据库连接(就是用Java连接数据库)对象Connection conn = DriverManager.getConnection(url, username, password);//操作数据库//1.创建Statement对象,用于操作数据库//2.利用Statement对象的相关方法,操作数据库//3.如果执行查询语句,需创建ResultSet对象,此对象为查询结果集Statement stmt = conn.createStatement();//查询部门信息包括部门的平均工资String sql = "select dept.did id,dname name,avg(emp.salary) pjgz from emp,dept where emp.did = dept.did group by dept.did,dname;";//查询部门平均工资小于3500的部门信息String sql2 ="select b.* ,avg(a.salary) from emp a,dept b where a.did=b.did and b.did in (select did from emp group by did having avg(salary)<3500) group by b.did;";//查询工资低于部门平均工资的员工信息String sql3 ="select a.ename, a.salary from emp a where salary<(select avg(salary)from emp where a.did=did group by did);";ResultSet rs = stmt.executeQuery(sql);while(rs.next()){System.out.print(rs.getInt("id")+" ");System.out.print(rs.getString("name")+" ");System.out.println(rs.getString("pjgz"));}if(rs!=null){rs.close();}if(stmt!=null){stmt.close();}if(conn!=null){conn.close();}} catch (ClassNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}
-
/*** 一个整形数组,数组里有正数也有负数。 数组中连续的一个或多个整数组成一个子数组,* 每个子数组都有一个和,求所有子数组的和的最大值,要求时间复杂度为O(n)* @author*/public class Test {public static void main(String[] args) {int[] a = { 1, -2, 3, 10, -4, 7, 2, -5 };int max = MaxSum(a);System.out.println(max);}/*** * @param a 源数组 * @return 返回子数组和的最大值 */public static int MaxSum(int[] a) {int sum = 0;int max = 0;for (int i = 0; i < a.length; i++) {sum = sum + a[a.length - i - 1];if (a[a.length - i - 1] >= 0) {if (max < sum) {max = sum;}}if (sum < 0) {sum = 0;}}return max;}}
-
/*二分查找法。*/public static int halfSearch(int[] arr,int key){int max,min,mid;min = 0;max = arr.length-1;mid = (max+min)/2;while(arr[mid]!=key){if(key>arr[mid])min = mid + 1;else if(key<arr[mid])max = mid - 1;if(max<min)return -1;mid = (max+min)/2;}return mid;
-
/** 练习:* "fdgavcbsacdfs" 获取该字符串中,每一个字母出现的次数。* 要求打印结果是:a(2)b(1)...;* 思路:* 对于结果的分析发现,字母和次数之间存在着映射的关系。而且这种关系很多。* 很多就需要存储,能存储映射关系的容器有数组和Map集合。* 关系一方式有序编号吗?没有!* 那就是使用Map集合。 又发现可以保证唯一性的一方具备着顺序如 a b c ...* 所以可以使用TreeMap集合。** 这个集合最终应该存储的是字母和次数的对应关系。** 1,因为操作的是字符串中的字母,所以先将字符串变成字符数组。* 2,遍历字符数组,用每一个字母作为键去查Map集合这个表。* 如果该字母键不存在,就将该字母作为键 1作为值存储到map集合中。* 如果该字母键存在,就将该字母键对应值取出并+1,在将该字母和+1后的值存储到map集合中,* 键相同值会覆盖。这样就记录住了该字母的次数.* 3,遍历结束,map集合就记录所有字母的出现的次数。oy.***/public class MapTest {/*** @param args*/public static void main(String[] args) {String str = "fdg+avAdc bs5dDa9c-dfs";String s = getCharCount(str);System.out.println(s);}public static String getCharCount(String str) {//将字符串变成字符数组char[] chs = str.toCharArray();//定义map集合表。Map<Character,Integer> map = new TreeMap<Character,Integer>();for (int i = 0; i < chs.length; i++) {if(!(chs[i]>='a' && chs[i]<='z' || chs[i]>='A' && chs[i]<='Z'))// if(!(Character.toLowerCase(chs[i])>='a' && Character.toLowerCase(chs[i])<='z'))continue;//将数组中的字母作为键去查map表。Integer value = map.get(chs[i]);int count = 1;//判断值是否为null.if(value!=null){count = value+1;}// count++;map.put(chs[i], count);/*if(value==null){map.put(chs[i], 1);}else{map.put(chs[i], value+1);}*/}return mapToString(map);}private static String mapToString(Map<Character, Integer> map) {StringBuilder sb = new StringBuilder();Iterator<Character> it = map.keySet().iterator();while(it.hasNext()){Character key = it.next();Integer value = map.get(key);sb.append(key+"("+value+")");}return sb.toString();}}
-
遍历map的4种方式的比较
public static void main(String[] args) {
Map<String, String> map = new HashMap<String, String>();
map.put("1", "value1");
map.put("2", "value2");
map.put("3", "value3");
//第一种:普遍使用,二次取值
System.out.println("通过Map.keySet遍历key和value:");
for (String key : map.keySet()) {
System.out.println("key= "+ key + " and value= " + map.get(key));
}
//第二种
System.out.println("通过Map.entrySet使用iterator遍历key和value:");
Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, String> entry = it.next();
System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
}
//第三种:推荐,尤其是容量大时
System.out.println("通过Map.entrySet遍历key和value");
for (Map.Entry<String, String> entry : map.entrySet()) {
System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
}//第四种
System.out.println("通过Map.values()遍历所有的value,但不能遍历key");
for (String v : map.values()) {
System.out.println("value= " + v);
}
}