java面试题总结
来源:互联网 发布:网络黄金egd裴蕾抓了吗 编辑:程序博客网 时间:2024/05/19 00:10
集合
1、获取字符串中每一个字母出现的次数。比如给定字符串”abcdabdeeadb”,输出结果:”a(3)b(3)c(1)d(3)e(2)”
法一:定义26个统计变量。遍历字符串,得到每一个字符进行判断,对应的统计变量++即可,输出拼接输出结果。但是很明显,造成浪费。
法二:
1、定义一个Map集合。
2、把字符串转换为字符数组。
3、遍历字符数组,得到每一个字符。
4、把这个字符到Map集合中查找看有没有这个字符存在,如果不存在,就把该字符作为键,1作为值存储;如果存在,就把值++,然后重
新存储该键和值。
5、定义一个字符串缓冲区
6、遍历TreeMap集合,获取每一个键值对元素拼接
7、把字符串缓冲区转换为字符串输出。
选择使用Map集合的哪一个类型呢?
可以发现输出是按照字母顺序排列的,所以我选择使用TreeMap,这样键会自动排序。
为什么要要用StringBuilder呢?
因为String对象是不可改变的。每次使用 System.String类中的方法之一时,都要在内存中创建一个新的字符串对象,这就需要为该新对象分配新的空间。在需要对字符串执行重复修改的情况下,与创建新的 String对象相关的系统开销可能会非常昂贵。如果要修改字符串而不创建新的对象,可以使用System.Text.StringBuilder类。例如,当在一个循环中将许多字符串连接在一起时,使用 StringBuilder类可以提升性能。
public class TestDemo { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out.println("请输入一个字符串:"); String str = scanner.nextLine(); //把字符串转换为字符数组 char[] charStr = str.toCharArray(); TreeMap<Character, Integer> tm = new TreeMap<Character, Integer>(); for(char ch:charStr){ //获取这个字符对应的值。通过返回值看这个字符是否存在 Integer i = tm.get(ch); //如果不存在,存入集合,值设为1 if(i == null){ tm.put(ch, 1); }else{ //如果存在,把这个键对应的值加1再存入集合中。 i++; tm.put(ch, i); } } //定义字符串缓冲区变量 StringBuilder sb = new StringBuilder(); //按照输出格式进行拼接 Set<Character> keySet = tm.keySet(); for(Character key:keySet){ Integer value = tm.get(key); sb.append(key).append("(").append(value).append(")"); } //把字符串缓冲区转换为字符串输出 String result = sb.toString(); System.out.println(result); }}
输出:
请输入一个字符串:asbdakshdkgasa(3)b(1)d(2)g(1)h(1)k(2)s(3)
2、HashMap和Hashtable的区别是什么?
Hashtable:线程安全,效率低。不允许null键和null值。
HashMap:线程不安全,效率高。允许null键和null值。
public class HashtableDemo { public static void main(String[] args) { HashMap<String, String> hm = new HashMap<String, String>(); hm.put("lili", "21"); hm.put("xiong", "22"); hm.put(null, null); hm.put("caicai", "13"); System.out.println(hm); System.out.println("------"); Hashtable<String, String> ht = new Hashtable<String, String>(); ht.put("lili", "21"); ht.put("xiong", "22"); //ht.put(null, null); //编译虽然不报错,但是运行就报错 ht.put("caicai", "13"); System.out.println(ht); }}
输出:
{null=null, lili=21, xiong=22, caicai=13}------{xiong=22, lili=21, caicai=13}
3、List,Set,Map等接口是否都继承自Map接口?
List、Set不是继承自Map接口,他们继承自Collection接口
Map接口本身就是一个顶层接口
4、Collection和Collections的区别是什么?
Collection:是单列集合的顶层接口。有子接口List和Set。
Collections:是针对集合操作的工具类。有对集合进行排序和二分查找的方法。
5、Map集合的四种遍历方式是哪四种?
可以去看我的这篇文章:http://blog.csdn.net/qq_36748278/article/details/77921523
6、TreeSet保证元素的唯一性和有序性的原理是什么?
可以去看我的这篇文章:http://blog.csdn.net/qq_36748278/article/details/77915801
7、HashSet保证元素的唯一性的原理是什么?
可以去看我的这篇文章:http://blog.csdn.net/qq_36748278/article/details/77842660
8、如何给ArrayList对象里面添加字符串?
可以去看我的这篇文章:http://blog.csdn.net/qq_36748278/article/details/76736235
实参与形参
java的基本数据类型是传值调用,对象引用类型是传引用。
当传值调用时,改变的是形参的值,并没有改变实参的值,实参的值可以传递给形参,但是,这个传递是单向的,形参不能传递回实参。因此在函数调用过程中,形参的值发生改变,而实参中的值不会变化。
当引用调用时,如果参数是对象,无论对对象做了何种操作,都不会改变实参对象的引用,但是如果改变了对象的内容,就会改变实参对象的内容。
代码1:
public static void testStringBuffer(StringBuffer sb){ sb.append("java"); } public static void main(String[] args) { StringBuffer sb = new StringBuffer("my "); testStringBuffer(sb); System.out.println("sb=" + sb.toString()); }
输出:sb=my java
对于这段代码,我们可以知道sb是个实参,它是通过new一个对象生成的,是一个对象引用,它指向的对象引用是”my “,因此它传递给testStringBuffer()方法中的参数也是一个引用,所以在方法内部对sb指向的引用中的数据进行的操作会反应在sb对象引用上,所以输出的是”sb=my java”
代码2:
public static String anaString(String str){ str = str + "_APPEND"; return str; } public static void main(String[] args) { String s = "TEST"; anaString(s); System.out.println("result = " + s); s = anaString(s); System.out.println("result_1 = " + s); }
输出:
result = TESTresult_1 = TEST_APPEND
我们可以知道String是引用类型对象,参数传递的应该是地址值,调用了 testStr() 方法后,虽然在这个方法内部进行了值的拼接,但是由于 s 对象指向的引用没有变,所以 s 还是TEST,但是函数返回的就是进行拼接操作后的结果。
代码3:
public static void main(String [] args){ int a = 1; int b = 2; change(a,b); System.out.println("a :" + a + ", b: "+b );}public static void change(int a ,int b){ int temp = 0; temp = a; a = b; b = temp;}
输出:a :1, b: 2
这种情况是参数是基本类型的数据,由于传值是单向的,实参的值可以传递给形参,但是形参的值不能传递回实参。所以实参的值还是不会改变。
代码4:
public static void main(String [] args){ ArrayList<String> list2 = new ArrayList<String>(); list2.add("AAAAA"); list2.add("BBBBB"); list2.add("CCCCC"); newList(list2); System.out.println("sizeC=:"+list2.size());}public static void newList(ArrayList<String> list){ list=new ArrayList<String>(); list.add("DDDDD"); System.out.println("sizeB=:"+list.size()); }
输出:
sizeB=:1sizeC=:3
因为这个虽然传递了一个引用数据类型的实参,但是在方法中重新new了一个新的对象,新的对象的值只添加了1个,所以sizeB输出的是1,但是对于实参list2来说,它指向的引用是没变的,它还是有3个值的,所以他的大小还是3。
也就是说改变了形参对象的引用,但是它的实参引用还是没有改变。
代码5:
public static void main(String [] args){ int [] a = new int[10]; int [] b = new int[10]; a[0] = 1; b[0] = 2; change(a,b); System.out.println("a: " + a[0] + ",b: " + b[0] );}public static void change(int[] a ,int[] b){ int temp = 0; temp = a[0]; a[0] = b[0]; b[0] = temp;}
输出:
a: 2,b: 1
接口
Java接口的修饰符可以为()
A private B protected C final D abstract
答案:CD
解析:
(1)接口用于描述系统对外提供的所有服务,因此接口中的成员常量和方法都必须是公开(public)类型的,确保外部使用者能访问它们;
(2)接口仅仅描述系统能做什么,但不指明如何去做,所以接口中的方法都是抽象(abstract)方法;
(3)接口不涉及和任何具体实例相关的细节,因此接口没有构造方法,不能被实例化,没有实例变量,只有静态(static)变量;
(4)接口的中的变量是所有实现类共有的,既然共有,肯定是不变的东西,因为变化的东西也不能够算共有。所以变量是不可变(final)类型,也就是常量了。
接口的方法默认是public abstract;
所以接口的属性默认是public static final 常量,且必须赋初值。
JSP和Servlet
jsp的四大作用域是哪四个?
1、page:当前页面有效
2、request:请求中有效
3、session:在整个会话中有效
4、application:整个应用程序有效
从小到大:page < request < session < application
内部类
1、内部类
题目:要求在A、B、C位置填空分别输出30,20,10
class Outer{ public int num = 10; class Inner{ public int num = 20; public void show(){ int num = 30; System.out.println(A); System.out.println(B); System.out.println(C); } }}public class Test { public static void main(String[] args) { Outer.Inner oi = new Outer().new Inner(); oi.show(); }}
答案:
System.out.println(num);//30System.out.println(this.num);//20System.out.println(new Outer().num);//10System.out.println(Outer.this.num);//10
分析:
1、声明的oi是一个Inner类的对象,也就是说this指代的是Inner类。所以要输出20,也就是Inner类的成员变量,可以通过this.num来获得
2、内部类和外部类没有继承关系。
3、可以通过外部类名限定this对象。
2、局部内部类访问局部变量的注意事项?
局部内部类访问局部变量必须用final修饰。
因为局部变量会随着方法的调用完毕而消失,但是这个时候,局部对象并没有立马从堆内存中消失,但还要使用那个变量。为了让数据还能继续被使用,就用fianl修饰。加了final修饰后,这个变量就变成了常量。既然是常量,你消失了,虽然变量名字不见了,但我在内存中存储的还是那个数据,还是有数据在使用。
final存储在堆内存中,堆内存的内容不会立即消失,只有垃圾回收机制回收的时候才会消失。
package org.danni.Demo2;class Outer{ private int num = 10; //局部内部类访问局部变量必须用final修饰 public void method(){ final int num2 = 20; class Inner{ public void show(){ System.out.println(num); System.out.println(num2); } } //被垃圾回收机制回收的时候对象才消失。所以还会要用到num2变量。 //要还能够使用,使用final类型,存储在堆内存中,只有垃圾回收机制回首才消失。这样就可以了。 Inner i = new Inner(); i.show(); }}public class Test { public static void main(String[] args) { Outer o = new Outer(); o.method(); //10 20 }}
3、匿名内部类
补齐代码,要求在控制台输出:”你很漂亮”
interface Inter{ void show();}class Outer{}public class Test { public static void main(String[] args) { Outer.method().show(); }}
分析:
1、Outer.method()可以看出method()是Outer类的一个静态方法
2、Outer.method().show()可以看出method()方法有返回值,且返回的是一个对象。
3、由于接口Inter中有一个show方法,所以可以想得到method方法的返回值的类型是一个接口(本质是返回接口的子类实现对象),然后子类对象在调用它的show方法。
class Outer { public static Inter method() { return new Inter() { @Override public void show() { System.out.println("你很漂亮"); } }; }}
基础
1、如果一个类没有构造方法,有哪些情况?
1、成员都是静态的,可以通过类直接调用。比如Math、Arrays、Collections
2、单例设计模式(Runtime)
3、类中有静态方法返回该类的对象。(InetAddress)
public static InetAddress getByName(String host),通过该类调用这个静态方法就会返回这个类的一个对象
2、写出下列程序输出的结果。
public class IntegerDemo { public static void main(String[] args) { Integer i1 = new Integer(127); Integer i2 = new Integer(127); System.out.println(i1 == i2); //false System.out.println(i1.equals(i2)); //true System.out.println("--------"); Integer i3 = new Integer(128); Integer i4 = new Integer(128); System.out.println(i3 == i4); //false System.out.println(i3.equals(i4)); //true System.out.println("--------"); Integer i5 = 128; Integer i6 = 128; System.out.println(i5 == i6); //false System.out.println(i5.equals(i6)); //true System.out.println("--------"); Integer i7 = 127; Integer i8 = 127; System.out.println(i7 == i8); //true System.out.println(i7.equals(i8)); //true }}
Integer i7 = 127;把一个int类型的变量赋值给一个Integer引用类型的变量,在jdk5之后叫做自动装箱,这个编译器会帮我们完成,通过查看它的编译后的文件我们可以知道他其实经过了这样的操作:Integer i7 = Integer.valueOf(127);
下面我们查看valueOf方法的源码:我们可以发现针对在low=-128和high=127之间的数据创建了一个数据缓冲池。如果数据是该范围内的,就直接返回一个缓冲池中的值,否则就要重新new一个Integer对象。
因此代码中的i5,i6值为128超过了最大值127,因此通过new重新创建了一个空间,因此==操作返回的是false。
而i7,i8值为127,在范围内,就直接在缓冲池中取数据,并没有重新创建对象。所以==返回的是true
public static Integer valueOf(int i) { assert IntegerCache.high >= 127; if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i);}private static class IntegerCache { static final int low = -128; static final int high; static final Integer cache[]; static { // high value may be configured by property int h = 127; String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); if (integerCacheHighPropValue != null) { int i = parseInt(integerCacheHighPropValue); i = Math.max(i, 127); // Maximum array size is Integer.MAX_VALUE h = Math.min(i, Integer.MAX_VALUE - (-low) -1); } high = h; cache = new Integer[(high - low) + 1]; int j = low; for(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++); } private IntegerCache() {}}
3、变量的值只有在运行的时候才能确定,而常量的值在编译期间就可以确定。
byte b1 = 3;byte b2 = 4;byte b;//b = b1 + b2; //编译错误b = 3 + 4; //常量,先计算,看计算结果是否在byte的范围内,如果存在,就不会报错
1、因为变量相加首先看类型问题,常量相加首先看结果看计算结果是否在赋值的数据类型范围内,如果是则正确,不是则报错。
2、因为b1和b2都是byte类型,他们在运行的时候才能计算它的结果,他们相加之后是int类型,而int类型不能转换为为byte类型(大可以转小,小不可以转大,int是da,byte是小),因此把一个int类型的值赋值给byte类型会报错
3、而3+4,都是常量,在编译的时候就计算好了,计算结果在byte范围内,就可以
4、throw和throws的区别是什么?
throws:
用在方法声明后面,跟的是异常类名
可以跟多个异常类名,用逗号隔开
表示抛出异常,由该方法的调用者来处理
throws表示出现异常的一种可能性,并不一定会发生这些异常
throw
用在方法体内,跟的是异常对象名
只能抛出一个异常对象名
表示抛出异常,由方法体内的语句处理
throw则是抛出了异常,执行throw则一定抛出了某种异常
5、final,finally和finalize的区别是什么?
final:可以修饰类、成员变量、成员方法
修饰类:类不能被继承
修饰变量:变量是常量
修饰方法:方法不能被重写
finally:是异常处理的一部分,用于释放资源。一般来说finally控制的代码肯定会执行,特殊情况:在执行到finally之前JVM退出了finally控制的代码就不会执行
finalize:是Object类的一个方法,用于垃圾回收。
6、如果catch里面有return语句,请问finally的代码还会执行吗?如果会,请问是在return前还是return后。?
会。在return前面执行。但是准确的说,是在return中间执行。
通过调试,我们可以发现程序是这么执行的:
public class FinallyDemo { public static void main(String[] args) { System.out.println(getInt()); //1 //9(控制台输出30) } public static int getInt(){ int a = 10; //2 try{ System.out.println(a / 0); //3(异常了,直接去执行catch) a = 20; }catch(ArithmeticException e){ //4 a = 30; //5 return a; //6 //8 //程序在执行到这一步的时候,这里不是return a而是return 30,这个返回路径就形成了。但是发现后面有finally,继续执行finally的内容,然后回到以前的返回路径,继续走return 30 }finally{ a = 40; //7(执行完之后,继续回到之前的返回路径) } return a; }}
但是如果也在finally之后加个return呢?这个时候输出的就是40了。
public class FinallyDemo { public static void main(String[] args) { System.out.println(getInt()); //1 //9(控制台输出40) } public static int getInt(){ int a = 10; //2 try{ System.out.println(a / 0); //3(异常了,直接去执行catch) a = 20; }catch(ArithmeticException e){ //4 a = 30; //5 return a; //6 }finally{ a = 40; //7 return a; //8 } }}
线程
1、同步有几种方式,分别是什么?
两种。同步代码块和同步方法。
2、sleep()和wait()方法的区别是什么?
1、sleep()方法必须指定时间。
wait()方法可以不指定时间,也可以指定时间。
2、sleep()不释放锁
wait()释放锁
3、为什么wait()、nitify()、notifyAll()等方法都定义在Object类中?
因为这些方法的对象的调用是依赖于锁对象的。而同步代码块的多对象是任意锁。而Object代码是任意的对象。所以,定义在Object里面。
4、线程的生命周期图
http://blog.csdn.net/qq_36748278/article/details/78144988
- java面试题总结
- java面试题总结
- java面试题总结
- java面试题总结
- java面试题总结
- java面试题总结
- java面试题总结
- Java面试题总结
- java总结面试题
- 总结java面试题
- java面试题总结
- java面试题总结
- java 面试题总结
- java 面试题总结
- java面试题总结
- Java面试题总结
- java面试题总结
- java面试题总结
- 学习笔记—诊断机器学习模型
- Java电话本管理系统(数组版)
- java多线程Runnable入门实例
- json 解析报错
- 将三个数有序输出
- java面试题总结
- 实现单层json按照key字母顺序排序
- Java学习总结之数组
- MyEclipse自动补全设置
- centos系统安装tar/rpm文件
- dokuwiki升级步骤
- hdfs shell 命令
- leetcode 102. Binary Tree Level Order Traversal
- 上下文切换-FreeRTOS是如何工作的