JAVA基础(二)


55、设计4个线程,其中两个线程每次对j增加1,另外两个线程对j每次减少1。写出程序。
以下程序使用内部类实现线程,对j增减的时候没有考虑顺序问题。
public class ThreadTest1
{
private int j;
public static void main(String args[]){
   ThreadTest1 tt=newThreadTest1();
   Inc inc=tt.new Inc();
   Dec dec=tt.new Dec();
   for(inti=0;i<2;i++){
       Thread t=newThread(inc);
       t.start();
           t=new Thread(dec);
       t.start();
       }
   }
private synchronized void inc(){
   j++;
  System.out.println(Thread.currentThread().getName()+"-inc:"+j);
   }
private synchronized void dec(){
   j--;
  System.out.println(Thread.currentThread().getName()+"-dec:"+j);
   }
class Inc implements Runnable{
   public void run(){
       for(inti=0;i<100;i++){
       inc();
       }
   }
}
class Dec implements Runnable{
   public void run(){
       for(inti=0;i<100;i++){
       dec();
       }
   }
}
}

----------随手再写的一个-------------
class A
{
JManger j =new JManager();
main()
{
   new A().call();
}

void call
{
   for(int i=0;i<2;i++)
   {
        new Thread(
               newRunnable(){ public void run(){while(true){j.accumulate()}}}
        ).start();
        new Thread(newRunnable(){ public void run(){while(true){j.sub()}}}).start();
   }
}
}

class JManager
{
   private j = 0;
 
   public synchronized voidsubtract()
   {
        j--
   }
 
   public synchronized voidaccumulate()
   {
        j++;
   }
 
}

56、子线程循环10次,接着主线程循环100,接着又回到子线程循环10次,接着再回到主线程又循环100,如此循环50次,请写出程序。

最终的程序代码如下:
publicclass 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是java 2时 才提供的,它们是线程不安全的。所以,我们讲课时先讲老的。
(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的,l而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方法怎么做,就看当前这个对象的类中是如何编写这个方法的)
实验代码:
publicclass 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;
    }

}

publicclass 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;

    }
}

publicclass 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 rFileManager("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);
           }
       }
    }

}
7、写一个Singleton出来。
第一种:饱汉模式
public classSingleTon {
    private SingleTon(){
       }

    //实例化放在静态代码块里可提高程序的执行效率,但也可能更占用空间 
    private final static SingleTon instance =new SingleTon();
    public static SingleTon getInstance(){
       return instance;
    }
}

第二种:饥汉模式
public classSingleTon {
    private SingleTon(){}
  
    private static instance = null;//newSingleTon();
  
    public static synchronized SingleTongetInstance(){
       if(instance == null)
           instance = new SingleTon();
       return instance;
    }
}

第三种:用枚举
    public enum SingleTon{
       ONE;
  
    }

第三:更实际的应用(在什么情况用单例)
public classSequenceGenerator{
    //下面是该类自身的业务功能代码
    private int count = 0;

    public synchronized int getSequence(){
       ++count;
    }
  
    //下面是把该类变成单例的代码
    private SequenceGenerator(){}
    private final static instance = newSequenceGenerator();
    public static SingleTon getInstance(){
       return instance;
    } 
  
}

第四:
    public class MemoryDao
    {
    private HashMap map = new HashMap();
  
   publicvoid add(Student stu1){
            map.put(SequenceGenerator.getInstance().getSequence(),stu1);
    }
 
   //把MemoryDao变成单例
  }






Singleton模式主要作用是保证在Java应用程序中,一个类Class只有一个实例存在。
一般Singleton模式通常有几种种形式:
第一种形式: 定义一个类,它的构造函数为private的,它有一个static的private的该类变量,在类初始化时实例话,通过一个public的getInstance方法获取对它的引用,继而调用其中的方法。
public class Singleton {
private Singleton(){}
    //在自己内部定义自己一个实例,是不是很奇怪?
    //注意这是private只供内部调用
    private staticSingleton instance = new Singleton();
    //这里提供了一个供外部访问本class的静态方法,可以直接访问 
    public staticSingleton getInstance() {
    return instance;
    }
   }
   第二种形式:
public class Singleton {
private static Singleton instance = null;
public static synchronized Singleton getInstance() {
//这个方法比上面有所改进,不用每次都进行生成对象,只是第一次  
//使用时生成实例,提高了效率!
if (instance==null)
instance=new Singleton();
               return instance;
   }
}
其他形式:
定义一个类,它的构造函数为private的,所有方法为static的。
一般认为第一种形式要更加安全些
8、递归算法题1
一个整数,大于0,不用循环和本地变量,按照n,2n,4n,8n的顺序递增,当值大于5000时,把值按照指定顺序输出来。
例:n=1237
则输出为:
1237,
2474,
4948,
9896,
9896,
4948,
2474,
1237,
提示:写程序时,先致谢按递增方式的代码,写好递增的以后,再增加考虑递减部分。
    public static void doubleNum(int n)
    {
       System.out.println(n);
       if(n<=5000)
           doubleNum(n*2);
       System.out.println(n);    
    }
Gaibaota(N) = Gaibaota(N-1) + n



9、递归算法题2
第1个人10,第2个比第1个人大2岁,依次递推,请用递归方式计算出第8个人多大?
package cn.itcast;

import java.util.Date;

publicclass A1 {

    public static voidmain(String [] args)
    {
       System.out.println(computeAge(8));
    }
  
    public static int computeAge(intn)
    {
       if(n==1)return 10;
       returncomputeAge(n-1) + 2;
    }
}

    public static voidtoBinary(int n,StringBuffer result)
    {

       if(n/2 != 0)
           toBinary(n/2,result);
       result.append(n%2);    
    }
10、排序都有哪几种方法?请列举。用JAVA实现一个快速排序。
本人只研究过冒泡排序、选择排序和快速排序,下面是快速排序的代码:
public class QuickSort {
/**
* 快速排序
* @param strDate
* @param left
* @param right
*/
public void quickSort(String[] strDate,int left,int right){
String middle,tempDate;
int i,j;
i=left;
j=right;
middle=strDate[(i+j)/2];
do{
while(strDate[i].compareTo(middle)<0&& i<right)
i++; //找出左边比中间值大的数
while(strDate[j].compareTo(middle)>0&& j>left)
j--; //找出右边比中间值小的数
if(i<=j){ //将左边大的数和右边小的数进行替换
tempDate=strDate[i];
strDate[i]=strDate[j];
strDate[j]=tempDate;
i++;
j--;
}
}while(i<=j); //当两者交错时停止

if(i<right){
quickSort(strDate,i,right);//从
}
if(j>left){
quickSort(strDate,left,j);
}
}
/**
  * @param args
  */
public static void main(String[] args){
String[] strVoid=newString[]{"11","66","22","0","55","22","0","32"};
QuickSort sort=new QuickSort();
sort.quickSort(strVoid,0,strVoid.length-1);
for(int i=0;i<strVoid.length;i++){
System.out.println(strVoid[i]+" ");
}
}


}
11、有数组a[n],用java代码将数组元素顺序颠倒
//用下面的也可以
//for(inti=0,int j=a.length-1;i<j;i++,j--)是否等效于for(int i=0;i<a.length/2;i++)呢?

importjava.util.Arrays;

public classSwapDemo{

    public static void main(String[] args){
       int [] a = new int[]{
                     (int)(Math.random() *1000),
                     (int)(Math.random() * 1000),
                     (int)(Math.random() *1000),
                     (int)(Math.random() *1000),                   
                     (int)(Math.random() * 1000)                                                           
       };
     
       System.out.println(a);
       System.out.println(Arrays.toString(a));
       swap(a);
       System.out.println(Arrays.toString(a));     
    }
  
    public static void swap(int a[]){
       int len = a.length;
       for(int i=0;i<len/2;i++){
           int tmp = a[i];
           a[i] = a[len-1-i];
           a[len-1-i] = tmp;
       }
    }
}
12.金额转换,阿拉伯数字的金额转换成中国传统的形式如:(¥1011)->(一千零一拾一元整)输出。
去零的代码:
    returnsb.reverse().toString().replaceAll("零[拾佰仟]","零").replaceAll("零+万","万").replaceAll("零+元","元").replaceAll("零+","零");

public class RenMingBi {

       /**
        * @param args add by zxx ,Nov 29, 2008
        */
       private static finalchar[] data = new char[]{
                     '零','壹','贰','叁','肆','伍','陆','柒','捌','玖'
              };
       private static finalchar[] units = new char[]{
              '元','拾','佰','仟','万','拾','佰','仟','亿'
       };
       public static voidmain(String[] args) {
              // TODOAuto-generated method stub
              System.out.println(
                            convert( 135689123 ));
       }

       public static Stringconvert(int money)
       {
              StringBuffersbf = new StringBuffer();
              int unit = 0;
              while(money!=0)
              {
                     sbf.insert(0,units[unit++]);
                     intnumber = money%10;
                     sbf.insert(0,data[number]);
                     money/= 10;
              }

              returnsbf.toString();
       }
}
三. html&JavaScript&ajax部分
1. 判断第二个日期比第一个日期大
       如何用脚本判断用户输入的的字符串是下面的时间格式 2004-11-21 必须要保证用户的输入是此格式,并且是时间,比如说月份不大于12等等,另外我需要用户输入两个,并且后一个要比前一个晚,只允许用JAVASCRIPT,请详细帮助作答,,
//这里可用正则表达式判断提前判断一下格式,然后按下提取各时间字段内容
<script type="text/javascript">
   window.onload =function()
   {
        //这么写是为了实现js代码与html代码的分离,当我修改js时,不能影响html代码。
        document.getElementById("frm1").οnsubmit=
               function(){
                      vard1 = this.d1.value;
                      vard2 = this.d2.value;
                      if(!verifyDate(d1)) {alert("第一个日期格式不对");return false;}
                      if(!verifyDate(d2)) {alert("第二个日期格式不对");return false;}
                      if(!compareDate(d1,d2)){alert("第二个日期比第一日期小");return false;}                
               };
        }
      
        functioncompareDate(d1,d2)
        {
               var arrayD1= d1.split("-");
               var date1 =new Date(arrayD1[0],arrayD1[1],arrayD1[2]);
               var arrayD2= d2.split("-");
               var date2 =new Date(arrayD2[0],arrayD2[1],arrayD2[2]);
               if(date1> date2) return false;            
               return true;
        }
      
        functionverifyDate(d)
        {
               vardatePattern = /^\d{4}-(0?[1-9]|1[0-2])-(0?[1-9]|[1-2]\d|3[0-1])$/;
               returndatePattern.test(d);
        }
</script>

<form id="frm1" action="xxx.html">
<input type="text" name="d1" />
<input type="text" name="d2" />
<input type="submit"/>
</form>
2. 用table显示n条记录,每3行换一次颜色,即1,2,3用红色字体,4,5,6用绿色字体,7,8,9用红颜色字体。
<body>
<table id="tbl">
   <tr><td>1</td></tr>
   <tr><td>2</td></tr>
   <tr><td>3</td></tr>
   <tr><td>4</td></tr>
   <tr><td>5</td></tr>
   <tr><td>6</td></tr>
   <tr><td>7</td></tr>
   <tr><td>8</td></tr>
   <tr><td>9</td></tr>
   <tr><td>10</td></tr>
</table>
</body>
<script type="text/javascript">
   window.οnlοad=function()
        {
               var tbl =document.getElementById("tbl");
               rows =tbl.getElementsByTagName("tr");
               for(i=0;i<rows.length;i++)
               {
                      var j= parseInt(i/3);
                      if(j%2==0)rows[i].style.backgroundColor="#f00";
                      else  rows[i].style.backgroundColor="#0f0";
               }
        }
</script>
3、HTML的 form提交之前如何验证数值文本框的内容全部为数字?否则的话提示用户并终止提交?
<form οnsubmit=’return chkForm(this)’>
<input type="text" name="d1"/>
<input type="submit"/>
</form>
<script type=”text/javascript” />  
function chkForm(this)
       {
              var value = thist.d1.value;
              var len =value.length;
              for(vari=0;i<len;i++)
              {
                     if(value.charAt(i)>"9"|| value.charAt(i)<"0")
                     {
                            alert("含有非数字字符");
                            returnfalse;
                     }
              }
              return true;
       }
</script>

4、请写出用于校验HTML文本框中输入的内容全部为数字的javascript代码
<input type="text" id="d1" οnblur=" chkNumber(this)"/>
<script type=”text/javascript” />  
function chkNumber(eleText)

       {
              var value =eleText.value;
              var len =value.length;
              for(vari=0;i<len;i++)
              {
                     if(value.charAt(i)>"9"|| value.charAt(i)<"0")
                     {
                            alert("含有非数字字符");
                            eleText.focus();
                            break;
                     }
              }
       }
</script>
除了写完代码,还应该在网页上写出实验步骤和在代码中加入实现思路,让面试官一看就明白你的意图和检查你的结果。

5、说说你用过那些ajax技术和框架,说说它们的区别

四. Java web部分
1、Tomcat的优化经验
答:去掉对web.xml的监视,把jsp提前编辑成Servlet。
有富余物理内存的情况,加大tomcat使用的jvm的内存


2、HTTP请求的GET与POST方式的区别
答:servlet有良好的生存期的定义,包括加载和实例化、初始化、处理请求以及服务结束。这个生存期由javax.servlet.Servlet接口的init,service和destroy方法表达。
3、解释一下什么是servlet;
答:servlet有良好的生存期的定义,包括加载和实例化、初始化、处理请求以及服务结束。这个生存期由javax.servlet.Servlet接口的init,service和destroy方法表达。
4、说一说Servlet的生命周期?
答:servlet有良好的生存期的定义,包括加载和实例化、初始化、处理请求以及服务结束。这个生存期由javax.servlet.Servlet接口的init,service和destroy方法表达。

Servlet被服务器实例化后,容器运行其init方法,请求到达时运行其service方法,service方法自动派遣运行与请求对应的doXXX方法(doGet,doPost)等,当服务器决定将实例销毁的时候调用其destroy方法。
web容器加载servlet,生命周期开始。通过调用servlet的init()方法进行servlet的初始化。通过调用service()方法实现,根据请求的不同调用不同的do***()方法。结束服务,web容器调用servlet的destroy()方法。

5、Servlet的基本架构
public class ServletName extends HttpServlet {
public void doPost(HttpServletRequest request,HttpServletResponse response) throws
ServletException, IOException {
}
public void doGet(HttpServletRequest request,HttpServletResponse response) throws
ServletException, IOException {
}
}
6、SERVLET API中forward()与redirect()的区别?
答:前者仅是容器中控制权的转向,在客户端浏览器地址栏中不会显示出转向后的地址;后者则是完全的跳转,浏览器将会得到跳转的地址,并重新发送请求链接。这样,从浏览器的地址栏中可以看到跳转后的链接地址。所以,前者更加高效,在前者可以满足需要时,尽量使用forward()方法,并且,这样也有助于隐藏实际的链接。在有些情况下,比如,需要跳转到一个其它服务器上的资源,则必须使用
sendRedirect()方法。

7、什么情况下调用doGet()和doPost()?
Jsp页面中的FORM标签里的method属性为get时调用doGet(),为post时调用doPost()。

8、Request对象的主要方法:
setAttribute(String name,Object):设置名字为name的request的参数值
getAttribute(String name):返回由name指定的属性值
getAttributeNames():返回request对象所有属性的名字集合,结果是一个枚举的实例
getCookies():返回客户端的所有Cookie对象,结果是一个Cookie数组
getCharacterEncoding():返回请求中的字符编码方式
getContentLength():返回请求的Body的长度
getHeader(String name):获得HTTP协议定义的文件头信息
getHeaders(String name):返回指定名字的request Header的所有值,结果是一个枚举的实例
getHeaderNames():返回所以request Header的名字,结果是一个枚举的实例
getInputStream():返回请求的输入流,用于获得请求中的数据
getMethod():获得客户端向服务器端传送数据的方法
getParameter(String name):获得客户端传送给服务器端的有name指定的参数值
getParameterNames():获得客户端传送给服务器端的所有参数的名字,结果是一个枚举的实例
getParametervalues(String name):获得有name指定的参数的所有值
getProtocol():获取客户端向服务器端传送数据所依据的协议名称
getQueryString():获得查询字符串
getRequestURI():获取发出请求字符串的客户端地址
getRemoteAddr():获取客户端的IP地址
getRemoteHost():获取客户端的名字
getSession([Boolean create]):返回和请求相关Session
getServerName():获取服务器的名字
getServletPath():获取客户端所请求的脚本文件的路径
getServerPort():获取服务器的端口号
removeAttribute(String name):删除请求中的一个属性



9、forward和redirect的区别
forward是服务器请求资源,服务器直接访问目标地址的URL,把那个URL的响应内容读取过来,然后把这些内容再发给浏览器,浏览器根本不知道服务器发送的内容是从哪儿来的,所以它的地址栏中还是原来的地址。
   redirect就是服务端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址,一般来说浏览器会用刚才请求的所有参数重新请求,所以session,request参数都可以获取。
10、request.getAttribute()和 request.getParameter()有何区别?
11. jsp有哪些内置对象?作用分别是什么?分别有什么方法?
答:JSP共有以下9个内置的对象:
request 用户端请求,此请求会包含来自GET/POST请求的参数
response 网页传回用户端的回应
pageContext 网页的属性是在这里管理
session 与请求有关的会话期
application servlet 正在执行的内容
out 用来传送回应的输出
config  servlet的构架部件
page JSP网页本身
exception 针对错误网页,未捕捉的例外

request表示HttpServletRequest对象。它包含了有关浏览器请求的信息,并且提供了几个用于获取cookie, header,和session数据的有用的方法。
   response表示HttpServletResponse对象,并提供了几个用于设置送回浏览器的响应的方法(如cookies,头信息等)
   out对象是javax.jsp.JspWriter的一个实例,并提供了几个方法使你能用于向浏览器回送输出结果。
   pageContext表示一个javax.servlet.jsp.PageContext对象。它是用于方便存取各种范围的名字空间、servlet相关的对象的API,并且包装了通用的servlet相关功能的方法。
   session表示一个请求的javax.servlet.http.HttpSession对象。Session可以存贮用户的状态信息
   applicaton 表示一个javax.servle.ServletContext对象。这有助于查找有关servlet引擎和servlet环境的信息
   config表示一个javax.servlet.ServletConfig对象。该对象用于存取servlet实例的初始化参数。
   page表示从该页面产生的一个servlet实例

12. jsp有哪些动作?作用分别是什么?
(这个问题似乎不重要,不明白为何有此题)
答:JSP共有以下6种基本动作
jsp:include:在页面被请求的时候引入一个文件。
jsp:useBean:寻找或者实例化一个JavaBean。
jsp:setProperty:设置JavaBean的属性。
jsp:getProperty:输出某个JavaBean的属性。
jsp:forward:把请求转到一个新的页面。
jsp:plugin:根据浏览器类型为Java插件生成OBJECT或EMBED标记
13、JSP的常用指令
isErrorPage(是否能使用Exception对象),isELIgnored(是否忽略表达式)

14. JSP中动态INCLUDE与静态INCLUDE的区别?
答:动态INCLUDE用jsp:include动作实现
<jsp:include page=included.jsp flush=true />它总是会检查所含文件中的变化,适合用于包含动态页面,并且可以带参数 静态INCLUDE用include伪码实现,定不会检查所含文件的变化,适用于包含静态页面 <%@include file=included.htm %>

15、两种跳转方式分别是什么?有什么区别?
(下面的回答严重错误,应该是想问forward和sendRedirect的区别,毕竟出题的人不是专业搞文字艺术的人,可能表达能力并不见得很强,用词不一定精准,加之其自身的技术面也可能存在一些问题,不一定真正将他的意思表达清楚了,严格意思上来讲,一些题目可能根本就无人能答,所以,答题时要掌握主动,只要把自己知道的表达清楚就够了,而不要去推敲原始题目的具体含义是什么,不要一味想着是在答题)
答:有两种,分别为:
<jsp:include page=included.jsp flush=true>
<jsp:forward page= nextpage.jsp/>
前者页面不会转向include所指的页面,只是显示该页的结果,主页面还是原来的页面。执行完后还会回来,相当于函数调用。并且可以带参数.后者完全转向新页面,不会再回来。相当于go to 语句。

16、页面间对象传递的方法
request,session,application,cookie等
17、JSP和Servlet有哪些相同点和不同点,他们之间的联系是什么?
JSP是Servlet技术的扩展,本质上是Servlet的简易方式,更强调应用的外表表达。JSP编译后是"类servlet"。Servlet和JSP最主要的不同点在于,Servlet的应用逻辑是在Java文件中,并且完全从表示层中的HTML里分离开来。而JSP的情况是Java和HTML可以组合成一个扩展名为.jsp的文件。JSP侧重于视图,Servlet主要用于控制逻辑。

18、MVC的各个部分都有那些技术来实现?如何实现?
答:MVC是Model-View-Controller的简写。Model代表的是应用的业务逻辑(通过JavaBean,EJB组件实现),View是应用的表示面(由JSP页面产生),Controller是提供应用的处理过程控制(一般是一个Servlet),通过这种设计模型把应用逻辑,处理过程和显示逻辑分成不同的组件实现。这些组件可以进行交互和重用。

19、我们在web应用开发过程中经常遇到输出某种编码的字符,如iso8859-1等,如何输出一个某种编码的字符串?
Public String translate(String str) {
   String tempStr ="";
   try {
     tempStr = newString(str.getBytes("ISO-8859-1"), "GBK");
     tempStr =tempStr.trim();
   }
   catch (Exception e) {
    System.err.println(e.getMessage());
   }
   return tempStr;
}
20. 现在输入n个数字,以逗号,分开;然后可选择升或者降序排序;按提交键就在另一页面显示按什么排序,结果为,提供reset



转载于:https://my.oschina.net/wdkxyd/blog/160470

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值