2011/5/23Java随笔

1.Java IO里主要类的继承关系

java.lang.Object

  java.io.File                                                文件和目录路径名

  java.io.InputStream                                   字节流输入

    java.io.FileInputStream                               把文件作为源进行流式输入的FileInputStream类

    java.io.FilterInputStream

      java.io.BufferedInputStream                        可以对流数据进行缓冲,实现类似“缓输出”的功能

      java.io.DataInputStream

  java.io.OutputStream                                 字节流输出

    java.io.FileOutputStream                             把文件作为源进行流式输入的FileInputStream类

    java.io.FilterOutputStream

      java.io.BufferedOutputStream                      可以对流数据进行缓冲,实现类似“缓输出”的功能

      java.io.DataOutputStream

      java.io.PrintStream                                      能够方便地打印各种数据值表示形式

  java.io.RandomAccessFile                                  随机存取文件,即在文件的任意位置读、数据

  java.io.Reader                                             字符流输入

    java.io.BufferedReader                                 从字符输入流中读取文本,缓冲各个字符

    java.io.InputStreamReader                           根据特定的编码规则从字节流创建相应的字符流

      java.io.FileReader 

  java.io.Writer                                             字符流输出

    java.io.BufferedWriter                                  将文本写入字符输出流,缓冲各个字符

    java.io.OutputStreamWriter                          根据特定的编码规则将字符流写入字节流

      java.io.FileWriter

    java.io.PrintWriter                                       向文本输出流打印对象的格式化表示形式。

2.hashmap中key和value的原理,hashmap的同步问题,如果不同步,会出现什么问题

  HashMap是基于哈希表的Map接口的非同步实现。此实现提供所有可选的映射操作,并允许使用null值和null键。HashMap实际上是一个“链表散列”的数据结构,即数组和链表的结合体HashMap底层就是一个数组结构,数组中的每一项又是一个链表。当新建一个HashMap的时候,就会初始化一个数组。每个Map.Entry是一个Key-Value对,也是数组中的元素,它持有指向下一个元素的引用,这就构成了链表。

 HashMap的存取实现:

   1) 存储:

  当我们往HashMapput元素的时候,先根据keyhashCode重新计算hash值,根据hash值得到这个元素在数组中的位置(即下标),如果数组该位置上已经存放有其他元素了,那么在这个位置上的元素将以链表的形式存放,新加入的放在链头,最先加入的放在链尾。如果数组该位置上没有元素,就直接将该元素放到此数组中的该位置上。

  当系统决定存储HashMap中的key-value对时,完全没有考虑Entry中的value,仅仅只是根据key来计算并决定每个Entry的存储位置。我们完全可以把 Map 集合中的 value 当成 key 的附属,当系统决定了 key 的存储位置之后,value 随之保存在那里即可。

   hash(int h)--计算hash值的方法根据keyhashCode重新计算一次散列。此算法加入了高位计算,防止低位不变,高位变化时,造成的hash冲突。

  2) 读取:

  从HashMapget元素时,首先计算keyhashCode,找到数组中对应位置的某一元素,然后通过keyequals方法在对应位置的链表中找到需要的元素。

 3)Fail-Fast机制:

   我们知道java.util.HashMap不是线程安全的,因此如果在使用迭代器的过程中有其他线程修改了map,那么将抛出ConcurrentModificationException,这就是所谓fail-fast策略。

   这一策略在源码中的实现是通过modCount域,modCount顾名思义就是修改次数,对HashMap内容的修改都将增加这个值,那么在迭代器初始化过程中会将这个值赋给迭代器的expectedModCount在迭代过程中,判断modCountexpectedModCount是否相等,如果不相等就表示已经有其他线程修改了Map: 注意到modCount声明为volatile,保证线程之间修改的可见性。

 

3.在J2ME中,实现多线程的三种方法

一、继承Thread类(java.lang.Thread)

通过编写线程类继承Thread类并重写Thread类中的run()方法实现线程,当线程对象被运行时候将会自动执行run方法中的实体内容,从而开辟一个单独的线程并运行起来。

如:public class ThreadSimple extends Thread{
                  public void run()
                  {
                        //run code entity
                  }
         } 

线程实例使用,直接创建对象并调用start()方法即可运行线程。 new ThreadSimple().start();当执行start方法时候,将会自动运行run方法,但是执行start方法时候只做了一件事,就是将线程转化为可执行状态,然后等待操作系统进行调度并运行,因此无法保证线程能立即启动。在JAVA中,Thread类实现了Runnable接口,因此run方法是通过实现接口Runnable中的抽象方法。

二、直接实现Runnable多线程接口(java.lang.Runnable)

线程接口Runnable中只有一个抽象方法run,通过实现Runnable接口中的方法的类即可创建出有多线程特征的对象,但该对象并无法使其启动线程,需要作为参数并借助Thread的构造方法构造创建对象并调用start方法对线程进行启动。

如:public class RunnablSimple implements Runnable{
               public void run(){
                        //run code entity
               }
      } 

实现类型的对象使用:

RunnableSimple rs = new RunnableSimple(); 
new Thread(rs).start(); 

由此可见,以上两种方法都是通过Thread的start来启动线程的,实际上所有的线程操作都是封装在Thread这个类中,由Thread对象调用各种接口来控制线程。

另外一种情况:

   关键字Synchronized 用于保护共享数据,当然前提是要分清哪些数据是共享数据。每个对象都有一个锁标志,当一个线程访问该对象时,被Synchronized修饰的数据将被“上锁”,阻止其他线程访问。当前线程访问完这部分数据后释放锁标志,其他线程就可以访问了。 

  public RunnableTest implements Runnable{

  public synchronized void run(){

    int i ;

  }

  public static void main(String[] args){

    Runnable r1 = new RunnableTest();

    Runnable r2 = new RunnableTest();

    Thread t1 = new Thread(r1);

    Thread t2 = new Thread(r2);

    t1.start;

    t2.start;

  }

}

这时候变量i并不是共享数据,因为t1和t2是两个对象(r1,r2)的不同线程,如果想让i为共享数据,需改为:

Thread t1 = new Thread(r1); Thread t2 = new Thread(r1);

t1.start;t2.start;

J2ME中线程(Thread)中主要方法:

 void setPriority(int newPriority),设置线程优先级,在操作系统中线程的调度是不确定性的,可以通过该方法设置相应线程的优先级别。

   static void sleep(long millis) ,用于让线程在指定时间millis毫秒内休眠,并不释放对象锁

 static void yield(),暂停当前正在执行的线程对象,并执行其他同优先级别的线程。

void start(),使现在进入可执行状态。 

void run() ,线程执行主体。 

void join(),等待调用该方法的线程执行完毕后再往下继续执行。 

wait()和notify()、notifyAll() 这三个方法用于协调多个线程对共享数据的存取,
所以必须在Synchronized语句块内使用这三个方法。
怎样在当前线程还没退出Synchronized数据块时让其他线程也有机会访问共享数据呢?
此时就用这三个方法来灵活控制。 
wait()方法使当前线程暂停执行并释放对象锁标志,让其他线程可以进入Synchronized数据块,
当前线程被放入对象等待池中。
当调用 notify()方法后,唤醒在此对象监视器上等待的单个线程,
将从对象的等待池中移走一个任意的线程并放到锁标志等待池中,
只有锁标志等待池中的线程能够获取锁标志;如果锁标志等待池中没有线程,则notify()不起作用。
 notifyAll()则从对象等待池中移走所有等待那个对象的线程并放到锁标志等待池中。
  注意 这三个方法都是java.lang.Ojbect的方法!

三、使用任务组合实现多线程

在J2ME中,同样具有JAVA中的任务处理组合类,他们分别为Timer和TimerTask,可以使用他们实现多线程,简单说就是定时实现任务。

Timer是JAVA中的一个定时器,可以实现在某一时间做某件事或者在某一时间段做某些事,分别通过方法schedule(TimerTask tt,long millis)和schedule(TimerTask tt,long start,long off)。

TimerTask是一个任务类,通过继承该类并覆盖方法run即可创建一个任务。

如:public class TimerTaskS extends TimerTask{
         public void run(){
                   //run code entity
         }
      } 

任务调用:

Timer timer = new Timer(); 

//3秒钟后执行任务 

timer.schedule(new TimerTaskS(),3000); 

//3秒钟后执行任务并且之后每5秒钟执行一次 

timer.schedule(new TimerTaskS(),3000,5000); 


有此可见在使用计时任务可以达到实现线程的效果,分别执行不同的并发操作,通过Timer类对象来操作TimerTask对象,通过schedule方法来计时执行任务,在结束任务的时候,通常使用cancel()来实现。


4.ArrayList和LinkedList的区别

ArrayList的内部实现是基于内部数组Object[],所以从概念上讲,它更像数组,但LinkedList的内部实现是基于一组连接的记录,所以,它更像一个链表结构,所以,它们在性能上有很大的差别。

ArrayList的前面或中间插入数据时,必须将其后的所有数据相应的后移,这样必然要花费较多时间,所以,当你的操作是在一列数据的后面添加数据而不是在前面或中间,并且需要随机地访问其中的元素时,使用ArrayList会提供比较好的性能;

而访问链表中的某个元素时,就必须从链表的一端开始沿着连接方向一个一个元素地去查找,直到找到所需的元素为止,所以,当你的操作是在一列数据的前面或中间添加或删除数据,并且按照顺序访问其中的元素时,就应该使用LinkedList了。

如果在编程中,两种情形交替出现,这时,可以考虑使用List这样的通用接口,而不用关心具体的实现,在具体的情形下,它的性能由具体的实现来保证。

 

5.URL和URI的区别

url:同一资源定位符   uri:同一资源标志符 
url定位客户端连接到服务器所需要的信息,如   
http://www.csdn.nethttp://tcc.com:8080/servlet/logon?name=zhangsan&addr=tttt   
完整构成   
<protocol>://<servername>[:port]/<url-path>[?query-string]   
uri是url组成的一部分,没有域名和查询字符串
即域名之后查询字符串之前所有的信息,用于制定资源。   
例如:

url--->http://java.sun.com/products/servlet/index.html?id=09

uri--->/products/servlet/index.html  

 

6.Java的回收机制

http://developer.51cto.com/art/200912/173251.htm

posted @ 2011-05-23 21:30  跳刀的兔子  阅读(256)  评论(0编辑  收藏  举报