您的位置:首页 > 编程语言 > Java开发

JAVA知识点列表

2016-10-13 11:41 218 查看
1、数据类型



int是java提供的8种原始数据类型之一。Java为每个原始类型提供了封装类,Integer是java为int提供的封装类。int的默认值为0,而Integer的默认值为null,
即Integer可以区分出未赋值和值为0的区别,int则无法表达出未赋值的情况,例如,要想表达出没有参加考试和考试成绩为0的区别,则只能使用Integer。
在JSP开发中,Integer的默认为null,所以用el表达式在文本框中显示时,值为空白字符串,而int默认的默认值为0,所以用el表达式在文本框中显示时,
结果为0,所以,int不适合作为web层的表单数据的类型。

Javadoc 详细的说明这个类是用来实现缓存支持,并支持 -128 到 127 之间的自动装箱过程。最大值 127 可以通过 JVM 的启动参数 -XX:AutoBoxCacheMax=size 修改。 缓存通过一个 for 循环实现。从小到大的创建尽可能多的整数并存储在一个名为 cache 的整数数组中。这个缓存会在 Integer 类第一次被使用的时候被初始化出来。以后,就可以使用缓存中包含的实例对象,而不是创建一个新的实例(在自动装箱的情况下)。

实际上在 Java 5 中引入这个特性的时候,范围是固定的 -128 至 +127。后来在 Java 6 中,最大值映射到 java.lang.Integer.IntegerCache.high,可以使用 JVM 的启动参数设置最大值。这使我们可以根据应用程序的实际情况灵活地调整来提高性能。是什么原因选择这个 -128 到 127 这个范围呢?因为这个范围的整数值是使用最广泛的。 在程序中第一次使用 Integer 的时候也需要一定的额外时间来初始化这个缓存。

Java 语言规范中的缓存行为

在 Boxing Conversion 部分的Java语言规范(JLS)规定如下:

如果一个变量 p 的值属于:-128至127之间的整数(§3.10.1),true 和 false的布尔值 (§3.10.3),’u0000′ 至 ‘u007f’ 之间的字符(§3.10.4)中时,将 p 包装成 a 和 b 两个对象时,可以直接使用 a == b 判断 a 和 b 的值是否相等。

其他缓存的对象

这种缓存行为不仅适用于Integer对象。我们针对所有整数类型的类都有类似的缓存机制。

有 ByteCache 用于缓存 Byte 对象

有 ShortCache 用于缓存 Short 对象

有 LongCache 用于缓存 Long 对象

有 CharacterCache 用于缓存 Character 对象

Byte,Short,Long 有固定范围: -128 到 127。对于 Character, 范围是 0 到 127。除了 Integer 可以通过参数改变范围外,其它的都不行。

IntegerCache有一个静态的Integer数组,在类加载时就将-128 到 127 的Integer对象创建了,并保存在cache数组中,一旦程序调用valueOf 方法,如果i的值是在-128 到 127 之间就直接在cache缓存数组中去取Integer对象。
再看其它的包装器:

Boolean:(全部缓存)
Byte:(全部缓存)

Character(<= 127缓存)

Short(-128 — 127缓存)
Long(-128 — 127缓存)

Float(没有缓存)
Doulbe(没有缓存)
Integer i = 100;     
i = null;//will not make any object available for GC at all.  
这里的代码不会有对象符合垃圾回收器的条件,这儿的i虽然被赋予null,但它之前指向的是cache中的Integer对象,而cache没有被赋null,所以Integer(100)这个对象还是存在。

而如果i大于127或小于-128则它所指向的对象将符合垃圾回收的条件:

Integer i = 10000;     
i = null;//will make the newly created Integer object available for GC
java中&、|、^

/ 只有两边都为true结果是true。否则就是false。

       System.out.println(true & true);//true

       System.out.println(true & false);//false

       System.out.println(false & false);//false

       //只要两边都为false结果是false,否则就是true

       System.out.println(true | true);//true

       System.out.println(true | false);//true

       System.out.println(false & false);//false

       //两边结果一样,就为false。两边结果不一样,就为true.

       System.out.println(true ^ true);//false

       System.out.println(true ^ false);//true.

       System.out.println(false ^ false);//false

2、字符串

      2.1、三者在执行速度方面的比较:StringBuilder >  StringBuffer  >  String 

      2.2、String:字符串常量             StringBuffer:字符串变量   线程安全的             StringBuilder:字符串变量  线程非安全的

      2.3、 String s = "abcd"; s = s+1; System.out.print(s);// result : abcd1

                 我们明明就是改变了String型的变量s的,为什么说是没有改变呢? 其实这是一种欺骗,JVM是这样解析这段代码的:首先创建对象s,赋予一个abcd,然后再创建一个新的对象s用来执行第二行代码,也就是说我们之前对象s并没有变化,所以我们说String类型是不可改变的对象了,由于这种机制,每当用String操作字符串时,实际上是在不断的创建新的对象,而原来的对象就会变为垃圾被GC回收掉,可想而知这样执行效率会有多低。
而StringBuffer与StringBuilder就不一样了,他们是字符串变量,是可改变的对象,每当我们用它们对字符串做操作时,实际上是在一个对象上操作的,这样就不会像String一样创建一些新的对象进行操作了,当然速度就快了。

     2.4、 一个特殊的例子:

              
String str = “This is only a” + “ simple” + “ test”;
               StringBuffer builder = new StringBuilder(“This is only a”).append(“ simple”).append(“ test”);

    你会很惊讶的发现,生成str对象的速度简直太快了,而这个时候StringBuffer居然速度上根本一点都不占优势。其实这是JVM的一个把戏,实际上:

    String str = “This is only a” + “ simple” + “test”;

    其实就是:

    String str = “This is only a simple test”;

    所以不需要太多的时间了。但大家这里要注意的是,如果你的字符串是来自另外的String对象的话,速度就没那么快了,譬如:

    String str2 = “This is only a”;

    String str3 = “ simple”;

    String str4 = “ test”;

    String str1 = str2 +str3 + str4;

    这时候JVM会规规矩矩的按照原来的方式去做。

      当我们在字符串缓冲区被多个线程使用是,JVM不能保证StringBuilder的操作是安全的,虽然他的速度最快,但是可以保证StringBuffer是可以正确操作的。当然大多数情况    下就是我们是在单线程下进行的操作,所以大多数情况下是建议用StringBuilder而不用StringBuffer的,就是速度的原因。

     对于三者使用的总结: 1.如果要操作少量的数据用 = String

                        2.单线程操作字符串缓冲区 下操作大量数据 = StringBuilder

                        3.多线程操作字符串缓冲区 下操作大量数据 = StringBuffer



在java中任何一个对象都具备equals和hashcode这两个方法,因为他们是在Object类中定义的。equals方法用来判断两个对象是否相同,如果相同则返回true,否则返回false。

hashcode方法返回一个int数,在Object类中的默认实现是将该对象的内部地址转换成一个整数返回。

关于两个方法的重要规范

规范1、若重写equals方法,有必要重写hashcode方法,确保通过equals方法判断结果为true 的两个对象具备相等的hashcode返回值。说得简单点就是:“”如果两个对象相同“,那么他们的hashcode应该相等”。不过请注意这个只是规范,如果你非要写一个类让equals返回true而hashcode返回两个不相等的值,编译和运行都是不会报错的。不过这样违反了Java规范,程序也就埋下了BUG。

规范2、如果equals返回false,即两个对象不相同,并不要对这两个对象调用hashcode方法得到两个不相同的数。说的简单点就是:"如果两个对象不相同,他们的hashcode可能不相同"。

1、如果两个对象不equals,java运行时环境会认为他们的hashcode一定相等。

2、如果两个对象不equal是,他们的hashcode有可能相等。

3、如果两个对象hashcode相等,他们不一定equals。

4、如果两个对象hashcode不相等,他们不一定equals。

3、集合

      3.1、List接口(public interface List<E> extends Collection<E>,public interface Collection<E> extends Iterable<E>)

                ArrayList:底层数据结构采用的是数组结构,数组长度是可变长度的一半(特点是查询很快但增删较慢线程不同步)

                LinkedList:底层的数据结构是链表结构(特点是查询较慢,增删较快)

                Vector:底层是数组数据结构 线程同步,数组长度是可变的一倍(无论查询还是增删都很慢,被ArrayList替代了)

                List集合特有的迭代器:ListIterator(是Iterator的子接口,public interface ListIterator<E> extends Iterator<E>)

               注意:ArrayList在迭代时,是不可以通过集合对象的方法操作集合中的元素(arrayList.add),因为会发生ConcurrentModificationException异常(并发异常),因为Iterator方法是有限的所以只能对元素进行判断,取出,删除的操作.如果想要其他的操作如添加,修改等,就需要使用其子接口,ListIterator。该接口只能通过List集合的listIterator方法获取.

 public static void main(String[] args) throws ParseException {

     // 创建集合对象

        List list = new ArrayList();

        // 添加元素

        list.add("aa");

        list.add("bb");

        list.add("cc");

        Iterator it = list.iterator();

        while (it.hasNext()) {

        String s = (String) it.next();

        if ("aa".equals(s)) {

          list.add("dd");

         }

       }

       System.out.println("list:" + list);

      }

               Vector:枚举就是Vector特有的取出方式,跟迭代器很像(其实枚举和迭代是一样的) 已经被迭代器取代

               public static void main(String[] args) {

               Vector v = new Vector();

                v.add("java01");

                v.add("java02");

                v.add("java03");

                v.add("java04");

                for(Enumeration en = v.elements();en.hasMoreElements();){

                         System.out.println(en.nextElement());

                }

    }

           

LinkedList:

特有方法:  

addFirst();在头部添加元素      addLast();在尾部添加元素

getFirst(); getLast(); 获取元素但不删除元素。如果集合中没有元素,会出现NoSuchElementException

removeFirst();   removeLast(); 获取元素但是删除元素。如果集合中没有元素,会出现NoSuchElementException

在JDK1.6出现了替代方法

offerFirst(); offerLast();

peekFirst(); peekLast(); 获取元素,但是元素不被删除。如果集合中没有元素,会返回null

pollFirst(); pollLast(); 获取元素,但是元素被删除。如果集合中没有元素,会返回null

public static void main(String[] args) {

         LinkedList link = new LinkedList();

         link.add("java01");

         link.add("java02");

         link.add("java03");

         link.add("java04");

         while(!link.isEmpty()){

            System.out.println((link.removeLast()));

        }

    }

        3.2、Map

HashMap和Hashtable两个类都实现了Map接口,二者保存K-V对(key-value对);HashSet则实现了Set接口,性质类似于集合。

HashMap与HashTable的区别:

第一,继承的父类不同。

Hashtable继承自Dictionary类,而HashMap继承自AbstractMap类。但二者都实现了Map接口。

public class Hashtable<K,V>  

extends Dictionary<K,V>  

implements Map<K,V>, Cloneable, Serializable  

  

public class HashMap<K,V>  

extends AbstractMap<K,V>  

implements Map<K,V>, Cloneable, Serializable 

第二,线程安全性不同。

Hashtable 中的方法是Synchronize的,而HashMap中的方法在缺省情况下是非Synchronize的。在多线程并发的环境下,可以直接使用Hashtable,不需要自己为它的方法实现同步,但使用HashMap时就必须要自己增加同步处理。

第三,是否提供contains方法

HashMap把Hashtable的contains方法去掉了,改成containsValue和containsKey,因为contains方法容易让人引起误解。

Hashtable则保留了contains,containsValue和containsKey三个方法,其中contains和containsValue功能相同。

第四,key和value是否允许null值。

其中key和value都是对象,并且不能包含重复key,但可以包含重复的value。

Hashtable中,key和value都不允许出现null值。

HashMap中,null可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为null。当get()方法返回null值时,可能是 HashMap中没有该键,也可能使该键所对应的值为null。因此,在HashMap中不能由get()方法来判断HashMap中是否存在某个键, 而应该用containsKey()方法来判断。

第五,两个遍历方式的内部实现上不同。

Hashtable、HashMap都使用了 Iterator。而由于历史原因,Hashtable还使用了Enumeration的方式 。

第六,hash值不同。

哈希值的使用不同,HashTable直接使用对象的hashCode。而HashMap重新计算hash值。

第七,内部实现使用的数组初始化和扩容方式不同。

Hashtable和HashMap它们两个内部实现方式的数组的初始大小和扩容的方式。HashTable中hash数组默认大小是11,增加的方式是 old*2+1。

HashMap中hash数组的默认大小是16,而且一定是2的指数。

public static void main(String[] args) {  
  
  
  Map<String, String> map = new HashMap<String, String>();  
  map.put("1", "value1");  
  map.put("2", "value2");  
  map.put("3", "value3");  
    
  //第一种:普遍使用,二次取值  
  System.out.println("通过Map.keySet遍历key和value:");  
  for (String key : map.keySet()) {  
   System.out.println("key= "+ key + " and value= " + map.get(key));  
  }  
    
  //第二种  
  System.out.println("通过Map.entrySet使用iterator遍历key和value:");  
  Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();  
  while (it.hasNext()) {  
   Map.Entry<String, String> entry = it.next();  
   System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());  
  }  
    
  //第三种:推荐,尤其是容量大时  
  System.out.println("通过Map.entrySet遍历key和value");  
  for (Map.Entry<String, String> entry : map.entrySet()) {  
   System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());  
  }  
  
  //第四种  
  System.out.println("通过Map.values()遍历所有的value,但不能遍历key");  
  for (String v : map.values()) {  
   System.out.println("value= " + v);  
  }  
 } 

      3.3、HashSet

对于 HashSet 而言,它是基于 HashMap 实现的,HashSet 底层采用 HashMap 来保存所有元素,因此 HashSet
11f77
的实现比较简单

HashSet 的实现其实非常简单,它只是封装了一个 HashMap 对象来存储所有的集合元素,所有放入 HashSet 中的集合元素实际上由 HashMap 的 key 来保存,而 HashMap 的 value 则存储了一个 PRESENT,它是一个静态的 Object 对象。

HashSet 的绝大部分方法都是通过调用 HashMap 的方法来实现的,因此 HashSet 和 HashMap 两个集合在实现本质上是相同的

      class Name  

{  

    private String first;   

    private String last;   

      

    public Name(String first, String last)   

    {   

        this.first = first;   

        this.last = last;   

    }   

  

    public boolean equals(Object o)   

    {   

        if (this == o)   

        {   

            return true;   

        }   

          

    if (o.getClass() == Name.class)   

        {   

            Name n = (Name)o;   

            return n.first.equals(first)   

                && n.last.equals(last);   

        }   

        return false;   

    }   

}  

  

public class HashSetTest  

{  

    public static void main(String[] args)  

    {   

        Set<Name> s = new HashSet<Name>();  

        s.add(new Name("abc", "123"));  

        System.out.println(  

            s.contains(new Name("abc", "123")));  

    }  

}  

上面程序中向 HashSet 里添加了一个 new Name("abc", "123") 对象之后,立即通过程序判断该 HashSet 是否包含一个 new Name("abc", "123") 对象。粗看上去,很容易以为该程序会输出 true。

实际运行上面程序将看到程序输出 false,这是因为 HashSet 判断两个对象相等的标准除了要求通过 equals() 方法比较返回 true 之外,还要求两个对象的 hashCode() 返回值相等(注意:HashMap就是这样)。而上面程序没有重写 Name 类的 hashCode() 方法,两个 Name 对象的 hashCode() 返回值并不相同,因此 HashSet 会把它们当成 2 个对象处理,因此程序返回 false。

由此可见,当我们试图把某个类的对象当成 HashMap 的 key,或试图将这个类的对象放入 HashSet 中保存时,重写该类的 equals(Object obj) 方法和 hashCode() 方法很重要,而且这两个方法的返回值必须保持一致:当该类的两个的 hashCode() 返回值相同时,它们通过 equals() 方法比较也应该返回 true。通常来说,所有参与计算 hashCode() 返回值的关键属性,都应该用于作为 equals() 比较的标准。

如下程序就正确重写了 Name 类的 hashCode() 和 equals() 方法,程序如下:

class Name   

{   

    private String first;  

    private String last;  

    public Name(String first, String last)  

    {   

        this.first = first;   

        this.last = last;   

    }   

    // 根据 first 判断两个 Name 是否相等  

    public boolean equals(Object o)   

    {   

        if (this == o)   

        {   

            return true;   

        }   

        if (o.getClass() == Name.class)   

        {   

            Name n = (Name)o;   

            return n.first.equals(first);   

        }   

        return false;   

    }   

       

    // 根据 first 计算 Name 对象的 hashCode() 返回值  

    public int hashCode()   

    {   

        return first.hashCode();   

    }  

  

    public String toString()   

    {   

        return "Name[first=" + first + ", last=" + last + "]";   

    }   

 }   

   

 public class HashSetTest2   

 {   

    public static void main(String[] args)   

    {   

        HashSet<Name> set = new HashSet<Name>();   

        set.add(new Name("abc" , "123"));   

        set.add(new Name("abc" , "456"));   

        System.out.println(set);   

    }   

}  

上面程序中提供了一个 Name 类,该 Name 类重写了 equals() 和 toString() 两个方法,这两个方法都是根据 Name 类的 first 实例变量来判断的,当两个 Name 对象的 first 实例变量相等时,这两个 Name 对象的 hashCode() 返回值也相同,通过 equals() 比较也会返回 true。

程序主方法先将第一个 Name 对象添加到 HashSet 中,该 Name 对象的 first 实例变量值为"abc",接着程序再次试图将一个 first 为"abc"的 Name 对象添加到 HashSet 中,很明显,此时没法将新的 Name 对象添加到该 HashSet 中,因为此处试图添加的 Name 对象的 first 也是" abc",HashSet 会判断此处新增的 Name 对象与原有的 Name 对象相同,因此无法添加进入,程序在①号代码处输出 set 集合时将看到该集合里只包含一个 Name
对象,就是第一个、last 为"123"的 Name 对象。

4、IO



     4.1、File       

                  public static void file(){

        File f = new File("F:\\io\\createfile.txt");

//      f.createNewFile();

//      f.mkdirs();

//      f.delete();

      System.out.println("该分区大小:" + f.getTotalSpace()/(1024*1024*1024) + "G");

      System.out.println(f.getParent());

      System.out.println(f.getAbsolutePath());

    }

  4.2、输入流InputStream(记得close)

       /*************************************1************************************/


        int count = 0;

        InputStream inputStream = new FileInputStream(new File("F:\\io\\2.txt"));

        int i =0;

        while((i = inputStream.read()) != -1){

            count++;

            System.out.println((char)i + "");

        }

        System.out.println(count);//14操作14次

        /**********************************2放入缓冲区***************************************/

         InputStream inputStream = new FileInputStream(new File("F:\\io\\2.txt"));

        byte[] b = new byte[5];

        int i =0;

        String s = "";

        while((i=inputStream.read(b)) != -1){

            String str = new String(b);

            s += str;

            System.out.println(str);

        }

        System.out.println(s);

    4.3、OutputStream输出流(记得close)

        InputStream inputStream = new FileInputStream("F:/io/1.jpg");

        OutputStream outputStream = new FileOutputStream("F:/io2/11.jpg");

        byte[] buffer = new byte[512];

        int numberRead = 0;

        while((numberRead = inputStream.read(buffer)) != -1){

            System.out.println(numberRead);//读取的字节长度

            outputStream.write(buffer, 0, numberRead);

        }

   4.4、字符流FileReader

       

        char[] buffer = new char[5];

        int numberRead = 0;

        FileReader fileReader = new FileReader("F:/io/2.txt"); //读取字符文件的流

        FileWriter fileWriter = new FileWriter("F:/io2/2.txt");

        while((numberRead = fileReader.read(buffer)) != -1){

            System.out.println(new String(buffer, 0, numberRead));

            fileWriter.write(buffer, 0, numberRead);

        }

        fileReader.close();

        fileWriter.close();
  4.5、字节流(字节流,一般用于处理二进制数据,包括图片,视频,音频等)

        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("F:/io/2.txt"));

        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("F:/io2/2.txt"));

        byte[] buffer = new byte[5];

        int len = 0;

        while((len = bis.read(buffer)) != -1){

            System.out.println(new String(buffer));

            bos.write(buffer, 0, len);

        }

        bis.close();

        bos.close();

  4.6、字符流

        BufferedReader br =new BufferedReader(new InputStreamReader(new FileInputStream("F:/io/2.txt")));

        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("F:/io2/2.txt")));

        String line = "";

        String str = "";

        while((line = br.readLine()) != null){

            str += line;

            bw.write(line);

        }

        bw.flush();

        br.close();

        bw.close();

        System.out.println(str);

   4.7、设计模式

   

Java的IO中主要用了适配器模式与装饰模式。

1.IO中用到的适配器模式(适配器模式具体就不在这里写,小编的伙伴前面的博客有介绍http://blog.csdn.net/lzgs_4/article/details/45157473

        在IO中,如将字符串数据转变成字节数据保存到文件中,将字节数据转变成流数据等都用到了适配器模式,下面以InputStreamReader和OutputStreamWriter类为例介绍适配器模式。

        InputStreamReader和OutputStreamWriter类分别继承了Reader和Writer接口,但要创建它们必须在构造函数中传入一个InputStream和OutputStream的实例,InputStreamReader和OutputStreamWriter的作用也就是将InputStream和OutputStream适配到Reader和Writer。InputStreamReader的类结构图如下:



       InputStreamReader实现了Reader接口,并且持有了InputStream的引用,这是通过StreamDecoder类间接持有的,因为byte到char要经过编码。

       这里,适配器就是InputStreamReader类,而源角色就是InputStream代表的实例对象,目标接口就是Reader类,OutputStreamWriter类也是类似的方式。

       在IO中类似的还有,如StringReader将一个String类适配到Reader接口,ByteArrayInputStream适配器将byte数组适配到InputStream流处理接口。

 

    2.IO中用到的装饰模式

        装饰模式就是对一个类进行装饰,增强其方法行为,在装饰模式中,作为原来的这个类使用者还不应该感受到装饰前与装饰后有什么不同,否则就破坏了原有类的结构了,所以装饰器模式要做到对被装饰类的使用者透明,这是对装饰器模式的一个要求。

        装饰器模式的结构如下:



(这里没具体讲解装饰器模式,不清楚的可以查询相关资料)

 

        在IO中有许多不同的功能组合情况,这些不同的功能组合都是使用装饰器模式实现的,下面以FilterInputStream为例介绍装饰器模式的使用。

        FilterInputStream的类结构图:



从上图可以看出,InputStream类就是以抽象组件存在的,而FileInputStream就是具体组件,它实现了抽象组件的所有接口,FilterInputStream类就是装饰角色,它实现了InputStream类的所有接口,并持有InputStream的对象实例的引用,BufferedInputStream是具体的装饰器实现者,这个装饰器类的作用就是使得InputStream读取的数据保存在内存中,而提高读取的性能。类似的还有LineNumberInputStream类,它的作用是提高按行读取数据的功能。

 

    最后对比下适配器模式与装饰器模式:

    这两种设计模式看起来都是起到包装一个类或对象的作用,但是使用它们的目的却不尽相同。适配器模式主要在于将一个接口转变成另一个接口,它的目的是通过改变接口来达到重复使用的目的;而装饰器模式不是要改变被装饰对象的接口,而是保持原有的接口,但是增强原有对象的功能,或改变原有对象的方法而提高性能

File file = new File("e:" + SEPARATOR + "io" + SEPARATOR + "test.txt");
//BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
// 备注上面这个初始化过程就是多次使用包装来完成的,不推荐这么写,会让新手看不懂。

//1、获得子节输入流
FileInputStream fileInputStream=new FileInputStream(file);
//2、构造转换流(是继承Reader的)
InputStreamReader inputStreamReader=new InputStreamReader(fileInputStream);
//3、 构造缓冲字符流
BufferedReader bufferedReader=new BufferedReader(inputStreamReader);

//备注1、2两步骤体现出了适配器模式
//2步骤体现了InputStreamReader类具有将子节输入流转换为字符输入流的功能
//2、3两步骤体现了装饰模式(wrapper包装模式)


最后对比下适配器模式与装饰器模式:

    这两种设计模式看起来都是起到包装一个类或对象的作用,但是使用它们的目的却不尽相同。适配器模式主要在于将一个接口转变成另一个接口,它的目的是通过改变接口来达到重复使用的目的;而装饰器模式不是要改变被装饰对象的接口,而是保持原有的接口,但是增强原有对象的功能,或改变原有对象的方法而提高性能

5、多线程

      5.1、进程与线程的区别

               进程:每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,一个进程包含n个线程。

               线程:同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程切换开销小。

             线程和进程一样分为五个阶段:创建、就绪、运行、阻塞、终止。多线程是指操作系统能同时运行多个任务(程序),多线程是指在同一个程序中有多个顺序流在执行。

    5.2、实现Runnable接口比继承Thread类所具有的优势:

              1):适合多个相同的程序代码的线程去处理同一个资源

              2):可以避免java中的单继承的限制

              3):增加程序的健壮性,代码可以被多个线程共享,代码和数据独立

            
1、新建状态(New):新创建了一个线程对象。
2、就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权。
3、运行状态(Running):就绪状态的线程获取了CPU,执行程序代码。
4、阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种:
(一)、等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中。
(二)、同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。
(三)、其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
5、死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

6、Socket通讯
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: