56、子线程循环 10 次,接着主线程循环 100,接着又回到子线程循环 10 次,
接着再回到主线程又循环 100,如此循环 50 次,请写出程序。
最终的程序代码如下:
public class ThreadTest {
/**
* @paramargs
*/
public static voidmain(String[] args) {
// TODO Auto-generated method stub
new ThreadTest().init();
}
public void init()
{
final Business business =newBusiness();
new Thread(
new Runnable()
{
public voidrun() {
for(inti=0;i<50;i++)
{
business.SubThread(i);
}
}
}
).start();
for(int i=0;i<50;i++)
{
business.MainThread(i);
}
}
private class Business
{
booleanbShouldSub =true;//这里相当于定义了控制该谁执行的一个信号灯
public synchronized voidMainThread(int i)
{
if(bShouldSub)
try {
this.wait();
} catch(InterruptedException e) {
// TODO Auto-generatedcatch block
e.printStackTrace();
}
for(int j=0;j<5;j++)
{
System.out.println(Thread.currentThread().getName()+ ":i=" + i +",j=" + j);
}
bShouldSub =true;
this.notify();
}
public synchronized voidSubThread(int i)
{
if(!bShouldSub)
try {
this.wait();
} catch (InterruptedExceptione) {
// TODO Auto-generatedcatch block
e.printStackTrace();
}
for(intj=0;j<10;j++)
{
System.out.println(Thread.currentThread().getName()+ ":i=" + i +",j=" + j);
}
bShouldSub =false;
this.notify();
}
}
}
备注:不可能一上来就写出上面的完整代码,最初写出来的代码如下,问题在于两个线程的
代码要参照同一个变量,即这两个线程的代码要共享数据,所以,把这两个线程的执行代码
搬到同一个类中去:
package com.huawei.interview.lym;
publicclass ThreadTest {
private static booleanbShouldMain=false;
public static void main(String[]args) {
// TODO Auto-generated method stub
/*new Thread(){
public void run()
{
for(int i=0;i<50;i++)
{
for(int j=0;j<10;j++)
{
System.out.println("i="+ i + ",j=" + j);
}
}
}
}.start();*/
//final String str = newString("");
new Thread(
new Runnable()
{
public voidrun()
{
for(inti=0;i<50;i++)
{
synchronized(ThreadTest.class) {
if(bShouldMain)
{
try {
ThreadTest.class.wait();}
catch(InterruptedException e) {
e.printStackTrace();
}
}
for(intj=0;j<10;j++)
{
System.out.println(
Thread.currentThread().getName()+
"i="+ i + ",j=" + j);
}
bShouldMain= true;
ThreadTest.class.notify();
}
}
}
}
).start();
for(int i=0;i<50;i++)
{
synchronized (ThreadTest.class){
if(!bShouldMain)
{
try {
ThreadTest.class.wait();}
catch(InterruptedException e) {
e.printStackTrace();
}
}
for(intj=0;j<5;j++)
{
System.out.println(
Thread.currentThread().getName()+
"i=" + i +",j=" + j);
}
bShouldMain =false;
ThreadTest.class.notify();
}
}
}
下面使用 jdk5中的并发库来实现的:
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.Condition;
public class ThreadTest
{
private static Locklock = new ReentrantLock();
private staticCondition subThreadCondition = lock.newCondition();
private staticboolean bBhouldSubThread = false;
public static voidmain(String [] args)
{
ExecutorServicethreadPool = Executors.newFixedThreadPool(3);
threadPool.execute(newRunnable(){
publicvoid run()
{
for(inti=0;i<50;i++)
{
lock.lock();
try
{
if(!bBhouldSubThread)
subThreadCondition.await();
for(intj=0;j<10;j++)
{
System.out.println(Thread.currentThread().getName()+ ",j=" + j);
}
bBhouldSubThread= false;
subThreadCondition.signal();
}catch(Exceptione)
{
}
finally
{
lock.unlock();
}
}
}
});
threadPool.shutdown();
for(inti=0;i<50;i++)
{
lock.lock();
try
{
if(bBhouldSubThread)
subThreadCondition.await();
for(intj=0;j<10;j++)
{
System.out.println(Thread.currentThread().getName()+ ",j=" + j);
}
bBhouldSubThread= true;
subThreadCondition.signal();
}catch(Exceptione)
{
}
finally
{
lock.unlock();
}
}
}
}
57、介绍 Collection 框架的结构
答:随意发挥题,天南海北谁便谈,只要让别觉得你知识渊博,理解透彻即可。
58、Collection 框架中实现比较要实现什么接口
comparable/comparator
59、ArrayList 和 Vector 的区别
答:
这两个类都实现了 List 接口(List 接口继承了 Collection 接口),他们都是有序集合,即存
储在这两个集合中的元素的位置都是有顺序的,相当于一种动态的数组,我们以后可以按位
置索引号取出某个元素,,并且其中的数据是允许重复的,这是 HashSet 之类的集合的最大
不同处,HashSet 之类的集合不可以按索引号去检索其中的元素,也不允许有重复的元素
(本来题目问的与 hashset 没有任何关系,但为了说清楚 ArrayList 与 Vector 的功能,我们
使用对比方式,更有利于说明问题)。
接着才说 ArrayList 与 Vector 的区别,这主要包括两个方面:.
(1)同步性:
Vector 是线程安全的,也就是说是它的方法之间是线程同步的,而 ArrayList 是线程
序不安全的,它的方法之间是线程不同步的。如果只有一个线程会访问到集合,那最好是使
用 ArrayList,因为它不考虑线程安全,效率会高些;如果有多个线程会访问到集合,那最
好是使用 Vector,因为不需要我们自己再去考虑和编写线程安全的代码。
备注:对于 Vector&ArrayList、Hashtable&HashMap,要记住线程安全的问题,记住 Vector
与 Hashtable 是旧的,是 java 一诞生就提供了的,它们是线程安全的,ArrayList 与 HashMap
是 java2时才提供的,它们是线程不安全的。所以,我们讲课时先讲老的。
(2)数据增长:
ArrayList 与 Vector 都有一个初始的容量大小,当存储进它们里面的元素的个数超过
了容量时,就需要增加 ArrayList 与 Vector 的存储空间,每次要增加存储空间时,不是只增
加一个存储单元,而是增加多个存储单元,每次增加的存储单元的个数在内存空间利用与程
序效率之间要取得一定的平衡。Vector 默认增长为原来两倍,而 ArrayList 的增长策略在文
档中没有明确规定(从源代码看到的是增长为原来的1.5倍)。ArrayList 与 Vector 都可以设
置初始的空间大小,Vector 还可以设置增长的空间大小,而 ArrayList 没有提供设置增长空
间的方法。
总结:即 Vector 增长原来的一倍,ArrayList 增加原来的0.5倍。
60、HashMap 和 Hashtable 的区别
(条理上还需要整理,也是先说相同点,再说不同点)
HashMap 是 Hashtable 的轻量级实现(非线程安全的实现),他们都完成了 Map 接口,主
要区别在于 HashMap 允许空(null)键值(key),由于非线程安全,在只有一个线程访问
的情况下,效率要高于 Hashtable。
HashMap 允许将 null 作为一个 entry 的 key 或者 value,而 Hashtable 不允许。
HashMap 把 Hashtable 的 contains 方法去掉了,改成 containsvalue 和 containsKey。因为
contains 方法容易让人引起误解。
Hashtable 继承自 Dictionary 类,而 HashMap 是 Java1.2引进的 Map interface 的一个实现。
最大的不同是,Hashtable 的方法是 Synchronize 的,而 HashMap 不是,在多个线程访问
Hashtable 时,不需要自己为它的方法实现同步,而 HashMap 就必须为之提供外同步。
Hashtable 和 HashMap 采用的 hash/rehash 算法都大概一样,所以性能不会有很大的差异。
就 HashMap 与 HashTable 主要从三方面来说。
一.历史原因:Hashtable 是基于陈旧的 Dictionary 类的,HashMap 是 Java 1.2引进的 Map
接口的一个实现
二.同步性:Hashtable 是线程安全的,也就是说是同步的,而 HashMap 是线程序不安全的,
不是同步的
三.值:只有 HashMap 可以让你将空值作为一个表的条目的 key 或 value
61、List 和 Map 区别?
一个是存储单列数据的集合,另一个是存储键和值这样的双列数据的集合,List 中存储的数
据是有顺序,并且允许重复;Map 中存储的数据是没有顺序的,其键是不能重复的,它的
值是可以有重复的。
62、List, Set, Map 是否继承自 Collection 接口?
List,Set 是,Map 不是
63、List、Map、Set 三个接口,存取元素时,各有什么特点?
这样的题属于随意发挥题:这样的题比较考水平,两个方面的水平:一是要真正明白这些内
容,二是要有较强的总结和表述能力。如果你明白,但表述不清楚,在别人那里则等同于不
明白。
首先,List 与 Set 具有相似性,它们都是单列元素的集合,所以,它们有一个功共同的父接
口,叫 Collection。Set 里面不允许有重复的元素,所谓重复,即不能有两个相等(注意,
不是仅仅是相同)的对象,即假设 Set 集合中有了一个 A 对象,现在我要向 Set 集合再存
入一个 B 对象,但 B 对象与 A 对象 equals 相等,则 B 对象存储不进去,所以,Set 集合的
add 方法有一个 boolean 的返回值,当集合中没有某个元素,此时 add 方法可成功加入该
元素时,则返回 true,当集合含有与某个元素 equals 相等的元素时,此时 add 方法无法加
入该元素,返回结果为 false。Set 取元素时,没法说取第几个,只能以 Iterator 接口取得所
有的元素,再逐一遍历各个元素。
List 表示有先后顺序的集合,注意,不是那种按年龄、按大小、按价格之类的排序。
当我们多次调用 add(Obj e)方法时,每次加入的对象就像火车站买票有排队顺序一样,按先
来后到的顺序排序。有时候,也可以插队,即调用 add(int index,Obj e)方法,就可以指定当
前对象在集合中的存放位置。一个对象可以被反复存储进 List 中,每调用一次 add 方法,
这个对象就被插入进集合中一次,其实,并不是把这个对象本身存储进了集合中,而是在集
合中用一个索引变量指向这个对象,当这个对象被 add 多次时,即相当于集合中有多个索
引指向了这个对象,如图 x 所示。List 除了可以以 Iterator 接口取得所有的元素,再逐一遍
历各个元素之外,还可以调用 get(index i)来明确说明取第几个。
Map 与 List 和 Set 不同,它是双列的集合,其中有 put 方法,定义如下:put(obj
key,objvalue),每次存储时,要存储一对 key/value,不能存储重复的 key,这个重复的规
则也是按 equals 比较相等。取则可以根据 key 获得相应的 value,即 get(Object key)返回
值为 key 所对应的 value。另外,也可以获得所有的 key 的结合,还可以获得所有的 value
的结合,还可以获得 key 和 value 组合成的 Map.Entry 对象的集合。
List 以特定次序来持有元素,可有重复元素。Set 无法拥有重复元素,内部排序。Map 保存
key-value 值,value 可多值。
HashSet 按照 hashcode 值的某种运算方式进行存储,而不是直接按 hashCode 值的大小进
行存储。例如,"abc"---> 78,"def" ---> 62,"xyz" ---> 65在 hashSet 中的存储顺序不是
62,65,78,这些问题感谢以前一个叫崔健的学员提出,最后通过查看源代码给他解释清楚,
看本次培训学员当中有多少能看懂源码。LinkedHashSet 按插入的顺序存储,那被存储对象
的 hashcode 方法还有什么作用呢?学员想想!hashset 集合比较两个对象是否相等,首先看
hashcode 方法是否相等,然后看 equals 方法是否相等。new 两个 Student 插入到 HashSet
中,看 HashSet 的 size,实现 hashcode 和 equals 方法后再看 size。
同一个对象可以在 Vector 中加入多次。往集合里面加元素,相当于集合里用一根绳子连接
到了目标对象。往 HashSet 中却加不了多次的。
64、说出 ArrayList,Vector, LinkedList 的存储性能和特性
ArrayList 和 Vector 都是使用数组方式存储数据,此数组元素数大于实际存储的数据以便增
加和插入元素,它们都允许直接按序号索引元素,但是插入元素要涉及数组元素移动等内存
操作,所以索引数据快而插入数据慢,Vector 由于使用了 synchronized 方法(线程安全),
通常性能上较 ArrayList 差,而 LinkedList 使用双向链表实现存储,按序号索引数据需要进
行前向或后向遍历,但是插入数据时只需要记录本项的前后项即可,所以插入速度较快。
LinkedList 也是线程不安全的,LinkedList 提供了一些方法,使得 LinkedList 可以被当作堆
栈和队列来使用。
65、去掉一个 Vector 集合中重复的元素
Vector newVector = new Vector();
For (int i=0;i<vector.size();i++)
{
Object obj = vector.get(i);
if(!newVector.contains(obj);
newVector.add(obj);
}
还有一种简单的方式,HashSet set = new HashSet(vector);
66、Collection 和 Collections 的区别。
Collection 是集合类的上级接口,继承与他的接口主要有 Set 和 List.
Collections 是针对集合类的一个帮助类,他提供一系列静态方法实现对各种集合的搜索、
排序、线程安全化等操作。
67、Set 里的元素是不能重复的,那么用什么方法来区分重复与否呢?是用==还
是 equals()?它们有何区别?
Set 里的元素是不能重复的,元素重复与否是使用 equals()方法进行判断的。
equals()和==方法决定引用值是否指向同一对象 equals()在类中被覆盖,为的是当两个
分离的对象的内容和类型相配的话,返回真值。
68、你所知道的集合类都有哪些?主要方法?
最常用的集合类是 List 和 Map。 List 的具体实现包括 ArrayList 和 Vector,它们是可变
大小的列表,比较适合构建、存储和操作任何类型对象的元素列表。 List 适用于按数值索
引访问元素的情形。
Map 提供了一个更通用的元素存储方法。 Map 集合类用于存储元素对(称作"键"和"值"),
其中每个键映射到一个值。
ArrayList/VectoràList
àCollection
HashSet/TreeSetàSet
PropetiesàHashTable
àMap
Treemap/HashMap
我记的不是方法名,而是思想,我知道它们都有增删改查的方法,但这些方法的具体名称,
我记得不是很清楚,对于 set,大概的方法是 add,remove, contains;对于 map,大概的方
法就是 put,remove,contains 等,因为,我只要在 eclispe 下按点操作符,很自然的这些方
法就出来了。我记住的一些思想就是 List 类会有 get(int index)这样的方法,因为它可以按
顺序取元素,而 set 类中没有 get(int index)这样的方法。List 和 set 都可以迭代出所有元素,
迭代时先要得到一个 iterator 对象,所以,set 和 list 类都有一个 iterator 方法,用于返回那
个 iterator 对象。map 可以返回三个集合,一个是返回所有的 key 的集合,另外一个返回的
是所有 value 的集合,再一个返回的 key 和 value 组合成的 EntrySet 对象的集合,map 也
有 get 方法,参数是 key,返回值是 key 对应的 value。
69、两个对象值相同(x.equals(y) == true),但却可有不同的 hash code,这句
话对不对?
对。
如果对象要保存在 HashSet 或 HashMap 中,它们的 equals 相等,那么,它们的 hashcode
值就必须相等。
如果不是要保存在HashSet或HashMap,则与hashcode没有什么关系了,这时候hashcode
不等是可以的,例如 arrayList 存储的对象就不用实现 hashcode,当然,我们没有理由不实
现,通常都会去实现的。
70、TreeSet 里面放对象,如果同时放入了父类和子类的实例对象,那比较时使
用的是父类的 compareTo 方法,还是使用的子类的 compareTo 方法,还是抛
异常!
(应该是没有针对问题的确切的答案,当前的 add 方法放入的是哪个对象,就调用哪个对
象的 compareTo 方法,至于这个 compareTo 方法怎么做,就看当前这个对象的类中是如何
编写这个方法的)
实验代码:
public class ParentimplementsComparable {
private int age = 0;
public Parent(int age){
this.age = age;
}
public int compareTo(Object o){
// TODO Auto-generated method stub
System.out.println("method ofparent");
Parent o1 = (Parent)o;
return age>o1.age?1:age<o1.age?-1:0;
}
}
public class Childextends Parent {
public Child(){
super(3);
}
public int compareTo(Object o){
// TODO Auto-generated methodstub
System.out.println("methodof child");
// Child o1 = (Child)o;
return 1;
}
}
public class TreeSetTest {
/**
* @paramargs
*/
public static voidmain(String[] args) {
// TODO Auto-generated method stub
TreeSet set = new TreeSet();
set.add(newParent(3));
set.add(new Child());
set.add(newParent(4));
System.out.println(set.size());
}
} 71、说出一些常用的类,包,接口,请各举 5 个
要让人家感觉你对 java ee 开发很熟,所以,不能仅仅只列 core java 中的那些东西,要多
列你在做 ssh 项目中涉及的那些东西。就写你最近写的那些程序中涉及的那些类。
常用的类:BufferedReader BufferedWriter FileReader FileWirter String Integer
java.util.Date,System,Class,List,HashMap
常用的包:java.lang java.io java.util
java.sql,javax.servlet,org.apache.strtuts.action,org.hibernate
常用的接口:Remote List Map Document
NodeList,Servlet,HttpServletRequest,HttpServletResponse,Transaction(Hibernate)、
Session(Hibernate),HttpSession
72、java 中有几种类型的流?JDK 为每种类型的流提供了一些抽象类以供继承,
请说出他们分别是哪些类?
字节流,字符流。字节流继承于 InputStream OutputStream,字符流继承于
InputStreamReaderOutputStreamWriter。在 java.io 包中还有许多其他的流,主要是为了提
高性能和使用方便。
73、字节流与字符流的区别
要把一片二进制数据数据逐一输出到某个设备中,或者从某个设备中逐一读取一片
二进制数据,不管输入输出设备是什么,我们要用统一的方式来完成这些操作,用一种抽象
的方式进行描述,这个抽象描述方式起名为 IO 流,对应的抽象类为 OutputStream 和
InputStream,不同的实现类就代表不同的输入和输出设备,它们都是针对字节进行操作的。
在应用中,经常要完全是字符的一段文本输出去或读进来,用字节流可以吗?计算
机中的一切最终都是二进制的字节形式存在。对于“中国”这些字符,首先要得到其对应的字
节,然后将字节写入到输出流。读取时,首先读到的是字节,可是我们要把它显示为字符,
我们需要将字节转换成字符。由于这样的需求很广泛,人家专门提供了字符流的包装类。
底层设备永远只接受字节数据,有时候要写字符串到底层设备,需要将字符串转成字节再
进行写入。字符流是字节流的包装,字符流则是直接接受字符串,它内部将串转成字节,
再写入底层设备,这为我们向 IO 设别写入或读取字符串提供了一点点方便。
字符向字节转换时,要注意编码的问题,因为字符串转成字节数组,
其实是转成该字符的某种编码的字节形式,读取也是反之的道理。
讲解字节流与字符流关系的代码案例:
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.InputStreamReader;
import java.io.PrintWriter;
public class IOTest {
public static void main(String[]args) throws Exception {
String str = "中国人";
/*FileOutputStreamfos = newFileOutputStream("1.txt");
fos.write(str.getBytes("UTF-8"));
fos.close();*/
/*FileWriter fw =new FileWriter("1.txt");
fw.write(str);
fw.close();*/
PrintWriter pw =new PrintWriter("1.txt","utf-8");
pw.write(str);
pw.close();
/*FileReader fr =new FileReader("1.txt");
char[] buf = newchar[1024];
int len =fr.read(buf);
String myStr = newString(buf,0,len);
System.out.println(myStr);*/
/*FileInputStreamfr = new FileInputStream("1.txt");
byte[] buf = newbyte[1024];
int len =fr.read(buf);
String myStr = newString(buf,0,len,"UTF-8");
System.out.println(myStr);*/
BufferedReader br =new BufferedReader(
newInputStreamReader(
newFileInputStream("1.txt"),"UTF-8"
)
);
String myStr =br.readLine();
br.close();
System.out.println(myStr);
}
}
74、什么是 java 序列化,如何实现 java 序列化?或者请解释 Serializable 接口
的作用。
我们有时候将一个 java 对象变成字节流的形式传出去或者从一个字节流中恢复成一个 java
对象,例如,要将 java 对象存储到硬盘或者传送给网络上的其他计算机,这个过程我们可
以自己写代码去把一个 java 对象变成某个格式的字节流再传输,但是,jre 本身就提供了这
种支持,我们可以调用 OutputStream 的 writeObject 方法来做,如果要让 java 帮我们做,
要被传输的对象必须实现 serializable 接口,这样,javac 编译时就会进行特殊处理,编译
的类才可以被 writeObject 方法操作,这就是所谓的序列化。需要被序列化的类必须实现
Serializable 接口,该接口是一个 mini 接口,其中没有需要实现的方法,
implementsSerializable 只是为了标注该对象是可被序列化的。
例如,在 web 开发中,如果对象被保存在了 Session 中,tomcat 在重启时要把 Session 对
象序列化到硬盘,这个对象就必须实现 Serializable 接口。如果对象要经过分布式系统进行
网络传输或通过 rmi 等远程调用,这就需要在网络上传输对象,被传输的对象就必须实现
Serializable 接口。
75、描述一下 JVM 加载 class 文件的原理机制?
JVM 中类的装载是由 ClassLoader 和它的子类来实现的,Java ClassLoader 是一个重要的
Java 运行时系统组件。它负责在运行时查找和装入类文件的类。
76、heap 和 stack 有什么区别。
java 的内存分为两类,一类是栈内存,一类是堆内存。栈内存是指程序进入一个方法时,
会为这个方法单独分配一块私属存储空间,用于存储这个方法内部的局部变量,当这个方法
结束时,分配给这个方法的栈会释放,这个栈中的变量也将随之释放。
堆是与栈作用不同的内存,一般用于存放不放在当前方法栈中的那些数据,例如,使用 new
创建的对象都放在堆里,所以,它不会随方法的结束而消失。方法中的局部变量使用 final
修饰后,放在堆中,而不是栈中。
77、GC 是什么?为什么要有 GC?
GC 是垃圾收集的意思(Gabage Collection),内存处理是编程人员容易出现问题的地方,
忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java 提供的 GC 功能可以
自动监测对象是否超过作用域从而达到自动回收内存的目的,Java 语言没有提供释放已分
配内存的显示操作方法。
78、垃圾回收的优点和原理。并考虑 2 种回收机制。
Java 语言中一个显著的特点就是引入了垃圾回收机制,使 c++程序员最头疼的内存管理的
问题迎刃而解,它使得 Java 程序员在编写程序的时候不再需要考虑内存管理。由于有个垃
圾回收机制,Java 中的对象不再有"作用域"的概念,只有对象的引用才有"作用域"。垃圾回
收可以有效的防止内存泄露,有效的使用可以使用的内存。垃圾回收器通常是作为一个单独
的低级别的线程运行,不可预知的情况下对内存堆中已经死亡的或者长时间没有使用的对象
进行清楚和回收,程序员不能实时的调用垃圾回收器对某个对象或所有对象进行垃圾回收。
回收机制有分代复制垃圾回收和标记垃圾回收,增量垃圾回收。
79、垃圾回收器的基本原理是什么?垃圾回收器可以马上回收内存吗?有什么
办法主动通知虚拟机进行垃圾回收?
对于 GC 来说,当程序员创建对象时,GC 就开始监控这个对象的地址、大小以及使用情况。
通常,GC 采用有向图的方式记录和管理堆(heap)中的所有对象。通过这种方式确定哪些对
象是"可达的",哪些对象是"不可达的"。当 GC 确定一些对象为"不可达"时,GC 就有责任回
收这些内存空间。可以。程序员可以手动执行 System.gc(),通知 GC 运行,但是 Java 语
言规范并不保证 GC 一定会执行。
80、什么时候用 assert。
assertion(断言)在软件开发中是一种常用的调试方式,很多开发语言中都支持这种机制。在
实现中,assertion 就是在程序中的一条语句,它对一个 boolean 表达式进行检查,一个正
确程序必须保证这个 boolean 表达式的值为 true;如果该值为 false,说明程序已经处于不
正确的状态下,assert 将给出警告或退出。一般来说,assertion 用于保证程序最基本、关
键的正确性。assertion 检查通常在开发和测试时开启。为了提高性能,在软件发布后,
assertion 检查通常是关闭的。
package com.huawei.interview;
publicclass AssertTest {
/**
* @paramargs
*/
public static voidmain(String[] args) {
// TODO Auto-generated method stub
int i = 0;
for(i=0;i<5;i++)
{
System.out.println(i);
}
//假设程序不小心多了一句--i;
--i;
assert i==5;
}
}
81、java 中会存在内存泄漏吗,请简单描述。
所谓内存泄露就是指一个不再被程序使用的对象或变量一直被占据在内存中。java 中有垃
圾回收机制,它可以保证一对象不再被引用的时候,即对象编程了孤儿的时候,对象将自动
被垃圾回收器从内存中清除掉。由于 Java 使用有向图的方式进行垃圾回收管理,可以消除
引用循环的问题,例如有两个对象,相互引用,只要它们和根进程不可达的,那么 GC 也是
可以回收它们的,例如下面的代码可以看到这种情况的内存回收:
package com.huawei.interview;
import java.io.IOException;
publicclass GarbageTest {
/**
* @paramargs
* @throwsIOException
*/
public static voidmain(String[] args)throws IOException {
// TODO Auto-generated method stub
try {
gcTest();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("hasexited gcTest!");
System.in.read();
System.in.read();
System.out.println("out begingc!");
for(int i=0;i<100;i++)
{
System.gc();
System.in.read();
System.in.read();
}
}
private static voidgcTest()throws IOException {
System.in.read();
System.in.read();
Person p1 = new Person();
System.in.read();
System.in.read();
Person p2 = new Person();
p1.setMate(p2);
p2.setMate(p1);
System.out.println("beforeexit gctest!");
System.in.read();
System.in.read();
System.gc();
System.out.println("exitgctest!");
}
private static classPerson
{
byte[] data =new byte[20000000];
Person mate = null;
public void setMate(Personother)
{
mate = other;
}
}
java 中的内存泄露的情况:长生命周期的对象持有短生命周期对象的引用就很可能发生内
存泄露,尽管短生命周期对象已经不再需要,但是因为长生命周期对象持有它的引用而导致
不能被回收,这就是 java 中内存泄露的发生场景,通俗地说,就是程序员可能创建了一个
对象,以后一直不再使用这个对象,这个对象却一直被引用,即这个对象无用但是却无法被
垃圾回收器回收的,这就是 java 中可能出现内存泄露的情况,例如,缓存系统,我们加载
了一个对象放在缓存中(例如放在一个全局 map 对象中),然后一直不再使用它,这个对象
一直被缓存引用,但却不再被使用。
检查 java 中的内存泄露,一定要让程序将各种分支情况都完整执行到程序结束,然后看某
个对象是否被使用过,如果没有,则才能判定这个对象属于内存泄露。
如果一个外部类的实例对象的方法返回了一个内部类的实例对象,这个内部类对象被长期引
用了,即使那个外部类实例对象不再被使用,但由于内部类持久外部类的实例对象,这个外
部类对象将不会被垃圾回收,这也会造成内存泄露。
下面内容来自于网上(主要特点就是清空堆栈中的某个元素,并不是彻底把它从数组中拿掉,
而是把存储的总数减少,本人写得可以比这个好,在拿掉某个元素时,顺便也让它从数组中
消失,将那个元素所在的位置的值设置为 null 即可):
我实在想不到比那个堆栈更经典的例子了,以致于我还要引用别人的例子,下面的例子不是
我想到的,是书上看到的,当然如果没有在书上看到,可能过一段时间我自己也想的到,可
是那时我说是我自己想到的也没有人相信的。
public class Stack {
private Object[] elements=new Object[10];
private int size = 0;
public void push(Object e){
ensureCapacity();
elements[size++] = e;
}
public Object pop(){
if( size == 0)
throw new EmptyStackException();
return elements[--size];
private void ensureCapacity(){
if(elements.length == size){
Object[] oldElements = elements;
elements = new Object[2 * elements.length+1];
System.arraycopy(oldElements,0, elements, 0, size);
}
}
}
上面的原理应该很简单,假如堆栈加了10个元素,然后全部弹出来,虽然堆栈是空的,
没有我们要的东西,但是这是个对象是无法回收的,这个才符合了内存泄露的两个条件:无
用,无法回收。
但是就是存在这样的东西也不一定会导致什么样的后果,如果这个堆栈用的比较少,也
就浪费了几个 K 内存而已,反正我们的内存都上 G 了,哪里会有什么影响,再说这个东西
很快就会被回收的,有什么关系。下面看两个例子。
例子1
public class Bad{
public static Stack s=Stack();
static{
s.push(new Object());
s.pop(); //这里有一个对象发生内存泄露
s.push(new Object()); //上面的对象可以被回收了,等于是自愈了
}
}
因为是 static,就一直存在到程序退出,但是我们也可以看到它有自愈功能,就是说如
果你的 Stack 最多有100个对象,那么最多也就只有100个对象无法被回收其实这个应该很
容易理解,Stack 内部持有100个引用,最坏的情况就是他们都是无用的,因为我们一旦放
新的进取,以前的引用自然消失!
内存泄露的另外一种情况:当一个对象被存储进 HashSet 集合中以后,就不能修改这个对
象中的那些参与计算哈希值的字段了,否则,对象修改后的哈希值与最初存储进 HashSet
集合中时的哈希值就不同了,在这种情况下,即使在 contains 方法使用该对象的当前引用
作为的参数去 HashSet 集合中检索对象,也将返回找不到对象的结果,这也会导致无法从
HashSet 集合中单独删除当前对象,造成内存泄露。
82、能不能自己写个类,也叫 java.lang.String?
可以,但在应用的时候,需要用自己的类加载器去加载,否则,系统的类加载器永远只是去
加载 jre.jar 包中的那个 java.lang.String。由于在 tomcat 的 web 应用程序中,都是由 webapp
自己的类加载器先自己加载 WEB-INF/classess 目录中的类,然后才委托上级的类加载器加
载,如果我们在 tomcat 的 web 应用程序中写一个 java.lang.String,这时候 Servlet 程序加
载的就是我们自己写的 java.lang.String,但是这么干就会出很多潜在的问题,原来所有用
了 java.lang.String 类的都将出现问题。
虽然 java 提供了 endorsed 技术,可以覆盖 jdk 中的某些类,具体做法是….。但是,能够
被覆盖的类是有限制范围,反正不包括 java.lang 这样的包中的类。
(下面的例如主要是便于大家学习理解只用,不要作为答案的一部分,否则,人家怀疑是题
目泄露了)例如,运行下面的程序:
package java.lang;
publicclass String {
/**
* @paramargs
*/
public static voidmain(String[] args) {
// TODO Auto-generated method stub
System.out.println("string");
}
}
报告的错误如下:
java.lang.NoSuchMethodError:main
Exception inthread "main"
这是因为加载了 jre 自带的 java.lang.String,而该类中没有 main 方法。
83. Java 代码查错
1.
abstract class Name {
private String name;
public abstract boolean isStupidName(String name) {}
}
大侠们,这有何错误?
答案: 错。abstract method 必须以分号结尾,且不带花括号。
2.
public class Something {
void doSomething () {
private String s = "";
int l = s.length();
}
}
有错吗?
答案: 错。局部变量前不能放置任何访问修饰符 (private,public,和 protected)。final 可
以用来修饰局部变量
(final 如同 abstract 和 strictfp,都是非访问修饰符,strictfp 只能修饰 class 和 method 而非
variable)。
3.
abstract class Something {
private abstract String doSomething ();
}
这好像没什么错吧?
答案: 错。abstract 的 methods 不能以 private 修饰。abstract 的 methods 就是让子类
implement(实现)具体细节的,怎么可以用 private 把 abstract
method 封锁起来呢? (同理,abstract method 前不能加 final)。
4.
public class Something {
public int addOne(final int x)
return ++x;
}
}
这个比较明显。
答案: 错。int x 被修饰成 final,意味着 x 不能在 addOne method 中被修改。
5.
public class Something {
public static void main(String[] args) {
Other o = new Other();
new Something().addOne(o);
}
public void addOne(final Other o) {
o.i++;
}
}
class Other {
public int i;
}
和上面的很相似,都是关于 final 的问题,这有错吗?
答案: 正确。在 addOne method 中,参数 o 被修饰成 final。如果在 addOne method 里我
们修改了 o 的 reference
(比如: o = new Other();),那么如同上例这题也是错的。但这里修改的是 o 的 member
vairable
(成员变量),而 o 的 reference 并没有改变。
6.
class Something {
int i;
public void doSomething() {
System.out.println("i = "+ i);
}
}
有什么错呢? 看不出来啊。
答案: 正确。输出的是"i = 0"。int i 属於 instant variable (实例变量,或叫成员变量)。instant
variable 有 default value。int 的 default value 是0。
7.
class Something {
final int i;
public void doSomething() {
System.out.println("i = "+ i);
}
}
和上面一题只有一个地方不同,就是多了一个 final。这难道就错了吗?
答案: 错。final int i 是个 final 的 instant variable (实例变量,或叫成员变量)。final 的 instant
variable 没有 default value,必须在 constructor (构造器)结束之前被赋予一个明确的值。可
以修改为"final int i =0;"。
8.
public class Something {
public static void main(String[] args) {
Something s = new Something();
System.out.println("s.doSomething() returns " + doSomething());
}
public String doSomething() {
return "Do something ...";
}
}
看上去很完美。
答案: 错。看上去在 main 里 call doSomething 没有什么问题,毕竟两个 methods 都在同一
个 class 里。但仔细看,main 是 static 的。static method 不能直接 call non-staticmethods。
可改成"System.out.println("s.doSomething()returns " + s.doSomething());"。同理,static
method 不能访问 non-static instant variable。
9.
此处,Something 类的文件名叫 OtherThing.java
class Something {
private static void main(String[] something_to_do){
System.out.println("Dosomething ...");
}
}
这个好像很明显。
答案: 正确。从来没有人说过 Java 的 Class 名字必须和其文件名相同。但 public class 的
名字必须和文件名相同。
10.
interface A{
int x = 0;
}
class B{
int x =1;
}
class C extends B implements A {
public void pX(){
System.out.println(x);
}
public static void main(String[] args) {
new C().pX();
}
}
答案:错误。在编译时会发生错误(错误描述不同的 JVM 有不同的信息,意思就是未明确的
x 调用,两个 x 都匹配(就象在同时 import java.util 和 java.sql 两个包时直接声明 Date 一
样)。对于父类的变量,可以用 super.x 来明确,而接口的属性默认隐含为 public staticfinal.
所以可以通过 A.x 来明确。
11.
interface Playable {
void play();
}
interface Bounceable {
void play();
}
interface Rollable extends Playable, Bounceable {
Ball ball = new Ball("PingPang");
}
class Ball implements Rollable {
private String name;
public String getName() {
return name;
}
public Ball(String name) {
this.name =name;
}
public void play() {
ball = newBall("Football");
System.out.println(ball.getName());
}
}
这个错误不容易发现。
答案: 错。"interfaceRollable extends Playable, Bounceable"没有问题。interface 可继承多
个 interfaces,所以这里没错。问题出在 interface Rollable 里的"Ball ball =new
Ball("PingPang");"。任何在 interface 里声明的 interface variable (接口变量,也可称成员变
量),默认为 public static final。也就是说"Ball ball = new Ball("PingPang");"实际上是"public
staticfinal Ball ball = new Ball("PingPang");"。在 Ball 类的 Play()方法中,"ball =
newBall("Football");"改变了ball的reference,而这里的ball来自Rollable interface,Rollable
interface 里的 ball 是 public static final 的,final 的 object 是不能被改变 reference 的。因此
编译器将在"ball = newBall("Football");"这里显示有错。
二.算法与编程
1、编写一个程序,将 a.txt 文件中的单词与 b.txt 文件中的单词交替合并到 c.txt
文件中,a.txt 文件中的单词用回车符分隔,b.txt 文件中用回车或空格进行分隔。
答:
packagecn.itcast;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
public class MainClass{
public static voidmain(String[] args) throws Exception{
FileManager a= new FileManager("a.txt",new char[]{'\n'});
FileManager b= new FileManager("b.txt",new char[]{'\n',' '});
FileWriter c= new FileWriter("c.txt");
String aWord= null;
String bWord= null;
while((aWord= a.nextWord()) !=null ){
c.write(aWord+ "\n");
bWord= b.nextWord();
if(bWord!= null)
c.write(bWord+ "\n");
}
while((bWord= b.nextWord()) != null){
c.write(bWord+ "\n");
}
c.close();
}
}
class FileManager{
String[] words =null;
int pos = 0;
publicFileManager(String filename,char[] seperators) throws Exception{
File f = newFile(filename);
FileReaderreader = new FileReader(f);
char[] buf =new char[(int)f.length()];
int len =reader.read(buf);
Stringresults = new String(buf,0,len);
String regex= null;
if(seperators.length>1 ){
regex= "" + seperators[0] + "|" + seperators[1];
}else{
regex= "" + seperators[0];
}
words =results.split(regex);
}
public StringnextWord(){
if(pos ==words.length)
returnnull;
returnwords[pos++];
}
}
2、编写一个程序,将 d:\java 目录下的所有.java 文件复制到 d:\jad 目录下,并
将原来文件的扩展名从.java 改为.jad。
(大家正在做上面这道题,网上迟到的朋友也请做做这道题,找工作必须能编写这些简单问
题的代码!)
答:listFiles 方法接受一个 FileFilter 对象,这个 FileFilter 对象就是过虑的策略对象,不
同的人提供不同的 FileFilter 实现,即提供了不同的过滤策略。
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class Jad2Java {
public static voidmain(String[] args) throws Exception {
File srcDir =new File("java");
if(!(srcDir.exists()&& srcDir.isDirectory()))
thrownew Exception("目录不存在");
File[] files= srcDir.listFiles(
newFilenameFilter(){
publicboolean accept(File dir, String name) {
returnname.endsWith(".java");
}
}
);
System.out.println(files.length);
File destDir= new File("jad");
if(!destDir.exists())destDir.mkdir();
for(File f:files){
FileInputStream fis = new FileInputStream(f);
StringdestFileName = f.getName().replaceAll("\\.java$", ".jad");
FileOutputStreamfos = new FileOutputStream(new
File(destDir,destFileName));
copy(fis,fos);
fis.close();
fos.close();
}
}
private static voidcopy(InputStream ips,OutputStream ops) throws Exception{
int len = 0;
byte[] buf =new byte[1024];
while((len =ips.read(buf)) != -1){
ops.write(buf,0,len);
}
}
}
由本题总结的思想及策略模式的解析:
1.
class jad2java{
1. 得到某个目录下的所有的 java 文件集合
1.1 得到目录 File srcDir = newFile("d:\\java");
1.2 得到目录下的所有 java 文件:File[] files =srcDir.listFiles(new
MyFileFilter());
1.3 只想得到.java 的文件: class MyFileFilterimplememyts FileFilter{
publicboolean accept(File pathname){
returnpathname.getName().endsWith(".java")
}
}
2.将每个文件复制到另外一个目录,并改扩展名
2.1 得到目标目录,如果目标目录不存在,则创建之
2.2 根据源文件名得到目标文件名,注意要用正则表达式,注意.的转义。
2.3 根据表示目录的File和目标文件名的字符串,得到表示目标文件的File。
//要在硬盘中准确地创建出一个文件,需要知道文件名和文件的目
录。
2.4 将源文件的流拷贝成目标文件流,拷贝方法独立成为一个方法,方法的
参数采用抽象流的形式。
//方法接受的参数类型尽量面向父类,越抽象越好,这样适应面更
宽广。
}
分析 listFiles 方法内部的策略模式实现原理
File[] listFiles(FileFilter filter){
File[] files =listFiles();
//ArraylistacceptedFilesList = new ArrayList();
File[] acceptedFiles= new File[files.length];
int pos = 0;
for(File file:files){
booleanaccepted = filter.accept(file);
if(accepted){
//acceptedFilesList.add(file);
acceptedFiles[pos++]= file;
}
}
Arrays.copyOf(acceptedFiles,pos);
//return(File[])accpetedFilesList.toArray();
}
3、编写一个截取字符串的函数,输入为一个字符串和字节数,输出为按字节截
取的字符串,但要保证汉字不被截取半个,如“我 ABC”,4,应该截取“我 AB”,
输入“我 ABC 汉 DEF”,6,应该输出“我 ABC”,而不是“我 ABC+汉的半个”。
答:
首先要了解中文字符有多种编码及各种编码的特征。
假设 n 为要截取的字节数。
public static voidmain(String[] args) throws Exception{
String str ="我 a 爱中华 abc 我爱传智 def';
String str ="我 ABC 汉";
int num =trimGBK(str.getBytes("GBK"),5);
System.out.println(str.substring(0,num));
}
public staticint trimGBK(byte[] buf,int n){
int num = 0;
booleanbChineseFirstHalf = false;
for(inti=0;i<n;i++)
{
if(buf[i]<0&& !bChineseFirstHalf){
bChineseFirstHalf= true;
}else{
num++;
bChineseFirstHalf= false;
}
}
return num;
}
4、有一个字符串,其中包含中文字符、英文字符和数字字符,请统计和打印出
各个字符的个数。
答:哈哈,其实包含中文字符、英文字符、数字字符原来是出题者放的烟雾弹。
String content = “中国 aadf 的111萨 bbb 菲的 zz 萨菲”;
HashMap map = new HashMap();
for(int i=0;i<content.length;i++)
{
char c =content.charAt(i);
Integer num =map.get(c);
if(num == null)
num = 1;
else
num = num +1;
map.put(c,num);
}
for(Map.EntrySet entry : map)
{
system.out.println(entry.getkey()+ “:” + entry.getValue());
}
估计是当初面试的那个学员表述不清楚,问题很可能是:
如果一串字符如"aaaabbc 中国1512"要分别统计英文字符的数量,中文字符的数量,和数字
字符的数量,假设字符中没有中文字符、英文字符、数字字符之外的其他特殊字符。
int engishCount;
int chineseCount;
int digitCount;
for(int i=0;i<str.length;i++)
{
charch = str.charAt(i);
if(ch>=’0’&& ch<=’9’)
{
digitCount++
}
elseif((ch>=’a’&& ch<=’z’) || (ch>=’A’ && ch<=’Z’))
{
engishCount++;
}
else
{
chineseCount++;
}
}
System.out.println(……………);
5、说明生活中遇到的二叉树,用 java 实现二叉树
这是组合设计模式。
我有很多个(假设10万个)数据要保存起来,以后还需要从保存的这些数据中检索是否存在某
个数据,(我想说出二叉树的好处,该怎么说呢?那就是说别人的缺点),假如存在数组中,
那么,碰巧要找的数字位于99999那个地方,那查找的速度将很慢,因为要从第1个依次往
后取,取出来后进行比较。平衡二叉树(构建平衡二叉树需要先排序,我们这里就不作考虑
了)可以很好地解决这个问题,但二叉树的遍历(前序,中序,后序)效率要比数组低很多,
原理如下图:
代码如下:
package com.huawei.interview;
publicclass Node {
public int value;
public Node left;
public Node right;
public void store(intvalue)
{
if(value<this.value)
{
if(left ==null)
{
left = new Node();
left.value=value;
}
else
{
left.store(value);
}
}
else if(value>this.value)
{
if(right ==null)
{
right = new Node();
right.value=value;
}
else
{
right.store(value);
}
}
}
public boolean find(intvalue)
{
System.out.println("happen" +this.value);
if(value ==this.value)
{
return true;
}
else if(value>this.value)
{
if(right ==null)returnfalse;
return right.find(value);
}else
{
if(left ==null)returnfalse;
return left.find(value);
}
}
public void preList()
{
System.out.print(this.value+ ",");
if(left!=null)left.preList();
if(right!=null) right.preList();
}
public void middleList()
{
if(left!=null)left.preList();
System.out.print(this.value+ ",");
if(right!=null)right.preList();
}
public void afterList()
{
if(left!=null)left.preList();
if(right!=null)right.preList();
System.out.print(this.value+ ",");
}
public static voidmain(String [] args)
{
int [] data =new int[20];
for(inti=0;i<data.length;i++)
{
data[i] = (int)(Math.random()*100)+ 1;
System.out.print(data[i] +",");
}
System.out.println();
Node root = new Node();
root.value = data[0];
for(inti=1;i<data.length;i++)
{
root.store(data[i]);
}
root.find(data[19]);
root.preList();
System.out.println();
root.middleList();
System.out.println();
root.afterList();
}
}
-----------------又一次临场写的代码---------------------------
importjava.util.Arrays;
importjava.util.Iterator;
public class Node{
private Node left;
private Node right;
private int value;
//private int num;
public Node(int value){
this.value = value;
}
public void add(int value){
if(value > this.value)
{
if(right != null)
right.add(value);
else
{
Node node = new Node(value);
right = node;
}
}
else{
if(left != null)
left.add(value);
else
{
Node node = new Node(value);
left = node;
}
}
}
public boolean find(int value){
if(value == this.value) return true;
else if(value > this.value){
if(right == null) return false;
else return right.find(value);
}else{
if(left == null) return false;
else return left.find(value);
}
}
public void display(){
System.out.println(value);
if(left != null) left.display();
if(right != null) right.display();
}
/*public Iterator iterator(){
}*/
public static void main(String[] args){
int[] values = new int[8];
for(int i=0;i<8;i++){
int num = (int)(Math.random() * 15);
//System.out.println(num);
//if(Arrays.binarySearch(values,num)<0)
if(!contains(values,num))
values[i] = num;
else
i--;
}
System.out.println(Arrays.toString(values));
Node root = new Node(values[0]);
for(int i=1;i<values.length;i++){
root.add(values[i]);
}
System.out.println(root.find(13));
root.display();
}
public static boolean contains(int [] arr,int value){
int i = 0;
for(;i<arr.length;i++){
if(arr[i] == value) return true;
}
return false;
}
}
6、从类似如下的文本文件中读取出所有的姓名,并打印出重复的姓名和重复的
次数,并按重复次数排序:
1,张三,28
2,李四,35
3,张三,28
4,王五,35
5,张三,28
6,李四,35
7,赵六,28
8,田七,35
程序代码如下(答题要博得用人单位的喜欢,包名用该公司,面试前就提前查好该公司的网
址,如果查不到,现场问也是可以的。还要加上实现思路的注释):
package com.huawei.interview;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeSet;
publicclass GetNameTest {
/**
* @paramargs
*/
public static voidmain(String[] args) {
// TODO Auto-generated method stub
//InputStream ips
=GetNameTest.class.getResourceAsStream("/com/huawei/interview/info.txt");
//用上一行注释的代码和下一行的代码都可以,因为 info.txt 与 GetNameTest 类在
同一包下面,所以,可以用下面的相对路径形式
Map results = new HashMap();
InputStream ips = GetNameTest.class.getResourceAsStream("info.txt");
BufferedReader in = newBufferedReader(new InputStreamReader(ips));
String line = null;
try {
while((line=in.readLine())!=null)
{
dealLine(line,results);
}
sortResults(results);
} catch (IOException e) {
// TODO Auto-generated catchblock
e.printStackTrace();
}
}
static class User
{
public String name;
public Integer value;
public User(String name,Integervalue)
{
this.name = name;
this.value = value;
}
@Override
public booleanequals(Object obj) {
// TODO Auto-generated methodstub
//下面的代码没有执行,说明往 treeset 中增加数据时,不会使用到 equals 方
法。
boolean result =super.equals(obj);
System.out.println(result);
return result;
}
}
private static voidsortResults(Map results) {
// TODO Auto-generated method stub
TreeSet sortedResults =newTreeSet(
new Comparator(){
public intcompare(Object o1, Object o2) {
// TODOAuto-generated method stub
User user1 = (User)o1;
User user2 = (User)o2;
/*如果 compareTo 返回结果0,则认为两个对象相等,新的对象不
会增加到集合中去
* 所以,不能直接用下面的代码,否则,那些个数相同的其他姓名
就打印不出来。
* */
//returnuser1.value-user2.value;
//returnuser1.value<user2.value?-1:user1.value==user2.value?0:1;
if(user1.value<user2.value)
{
return -1;
}else if(user1.value>user2.value)
{
return 1;
}else
{
returnuser1.name.compareTo(user2.name);
}
}
}
);
Iterator iterator =results.keySet().iterator();
while(iterator.hasNext())
{
String name = (String)iterator.next();
Integer value =(Integer)results.get(name);
if(value > 1)
{
sortedResults.add(newUser(name,value));
}
}
printResults(sortedResults);
}
private static voidprintResults(TreeSet sortedResults)
{
Iterator iterator = sortedResults.iterator();
while(iterator.hasNext())
{
User user = (User)iterator.next();
System.out.println(user.name +":" + user.value);
}
}
public static voiddealLine(String line,Map map)
{
if(!"".equals(line.trim()))
{
String [] results =line.split(",");
if(results.length == 3)
{
String name = results[1];
Integer value =(Integer)map.get(name);
if(value ==null)value = 0;
map.put(name,value + 1);
}
}
}
}
注:出自牛客网-程序员笔试面试题库,程序员求职备考网站 http://www.nowcoder.com”,学习分享,侵删!!!