黑马程序员泛型和多线程

来源:互联网 发布:卡盟附带支付源码 编辑:程序博客网 时间:2024/05/22 00:29

----------------------android培训java培训、期待与您交流! ----------------------

泛型(Generic) jdk1.5新特性枚举挺多的练习也多今天好多时间都花在枚举上了

lJDK5以前,对象保存到集合中就会失去其特性,取出时通常要程序员手工进行类型的强制转换,这样不可避免就会引发程序的一些安全性问题。例如:



 ArrayList list = new ArrayList();  

 list.add("abc");  

  Integer num = (Integer) list.get(0);  //运行时会出错,但编码时发现不了  

JDK5中的泛形允许程序员在编写集合代码时,就限制集合的处理类型,从而把原来程序运行时可能发生问题,转变为编译时的问题,以此提高程序的可读性和稳定性(尤其在大型程序中更为突出)

注意:泛型是提供给javac编译器使用的,它用于限定集合的输入类型,让编译器在源代码级别上,即挡住向集合中插入非法数据。但编译器编译完带有泛形的java程序后,生成的class文件中将不再带有泛形信息,以此使程序运行效率不受到影响,这个过程称之为擦除



 ArrayList<Integer> collection1=new ArrayList<Integer>();  

  ArrayList<String> collection2=new ArrayList<String>();  

System.out.println(collection1.getClass()==collection2.getClass());//结果为true所以当编译后所设置指向的类型被去掉了指向同一份字节码  

 

泛形的基本术语,以ArrayList<E>为例:<>念着typeof

ArrayList<E>中的E称为类型参数变量

ArrayList<Integer>中的Integer称为实际类型参数

 

 

 

泛型的使用方法 

使用泛形时的几个常见问题:

使用泛形时,泛形类型须为引用类型,不能是基本数据类型

如果两边都用泛型,则类型必须一致

如果只有一边使用泛型,另外一边不使用泛型,亦可.

 

Java程序中的普通方法、构造方法和静态方法中都可以使用泛型。方法使用泛形前,必须对泛形进行声明,语法:<T>T可以是任意字母,但通常必须要大写。<T>通常需放在方法的返回值声明之前。例如:

public<T,E> void test(T t,E e)

publicstatic <T> void doxx(T t);

 

类名后也可以声明泛型,这样在非静态函数中,就可以直接使用,而不需再次声明.

比如: public class Cat<T>

注意,类名后声明的泛型,在静态函数中是不能直接使用的,仍然需要自己声明,注意T的位置在static.

publicstatic <T> void doxx(T t);

 

如果一个类多处都要用到同一个泛型,这时可以把泛形定义在类上(即类级别的泛型),语法格式如下:



 public class SQlDao<T> {   

 private T field1;   

  public void save(T obj){}   

  public T getId(int id){}   

 }   

  注意,静态方法不能使用类定义的泛形,而应单独定义泛形。  

 

泛型的通配符?使用?通配符主要用于引用对象,使用了?通配符,就只能调对象与类型无关的方法,不能调用对象与类型有关的方法。

泛型的高级应用——有限制的通配符

限定通配符的上边界:



1.  正确:Vector<? extends Number> x = new Vector<Integer>();  

2.  错误:Vector<? extends Number> x = new Vector<String>();  

限定通配符的下边界:



1.  正确:Vector<? super Integer> x = new Vector<Number>();  

2.  错误:Vector<? super Integer> x = new Vector<Byte>();  

参数化类型不考虑类型参数的继承关系

 

错误的:Vector<Object> v=new Vercor<String>

 


 


1.线程就是程序运行中的一条路径,CPU调度和分派的基本单位

2..创建线程的两种方式:

           a.定义一个类继承Thread,重写run()方法,创建该类对象,调用start()方法.

                  程序会开启一条新线程, 在新线程上自动调用run()方法.

           b.定义一个类实现Runnable接口,实现run()方法,创建Thread对象,构造函数中传入Runnable对象,调用start()方法.这种方式的优势在于避免了单继承的局限性。

                  程序会开启一条新线程, 在新线程上自动调用Runnablerun()方法.

代码展示:

class Thread

{

    public static void main(String[] args)

    {

           MyThread mt = new MyThread();

           mt.start();

 

//****************************************

          

           YourThread yt = new YourThread();

           new Thread(yt).start();

    }

}

class MyThread extends Thread

{

    public void run()

    {

           //将需要运行的代码写在这里

    }

}

class yourThread implements Runnable

{

 

    public void run()

    {

           //将需要运行的代码写在这里

    }

}

3.runstart的区别:开启run方法时,只有主函数一个线程在执行。

4.同步:A:代码中,线程的安全隐患是如何造成的:但多条语句对同一资源进行操作,而这些语句没多线程分开执行,就容易造成线程安全问题。因此,要保证在同一时刻,只有一个线程来执行这些操作资源的代码,可通过同步代码块完成,其实就是锁原理。B:同步的弊端在于降低了程序的效率,因为判断锁是对资源的一种消耗。C:同步的前提:必须是2个或2个以上线程;保证多个线程使用同一个锁。

D:同步的2种实现方式:同步代码块,同步函数(使用的锁是this

 

补充:静态同步函数使用的锁是该方法所属类的字节码文件对象。因为static是随着类的加载而加载的,此时还没有建立该类的对象,只有类被加载进了内存,这时只有所属类的字节码文件对象。

5. 用同步优化个健全单例设计模式中的懒汉式。

A:直接用同步函数优化:解决安全问题,但效率超低。

class Single

{

       private static Single s = null;

       private Single(){}

       public static synchronized  Single getInstance()

       {           

              if(s == null)                 

                     s = new Single();          

              return s;

       }

}

B:双重判断加同步代码块解决安全问题,提高效率。

 

class Single

{

    private static Single s = null;

    private Single(){}

    public static  Single getInstance()

    {

           if(s==null)

           {

                  synchronized(Single.class)

                  {

                         if(s == null)                 

                                s = new Single();

                  }

           }

           return s;

    }

}

 

顺便复习一下饿汉式:

class Single

{

       private static final Single s = new Single();

       private Single(){}

       public static Single getInstance()

       {                  

              return s;

       }

}

6.同步中的死锁现象:通常发生在同步嵌套的嵌套.

                     class Demo implements Runnable

{

       private boolean flag;

       Demo(boolean flag)

       {

              this.flag = flag ;

       }

       public void run()

       {

              if(flag)

              {

 

 

                     synchronized(MyLock.lock1)

                     {

                            System.out.println(Thread.currentThread().getName()+"...if....lock1");

                            synchronized(MyLock.lock2)

                            {

                                   System.out.println(Thread.currentThread().getName()+"... if...lock2");                                

                            }

                     }

              }

              else

              {

                     synchronized(MyLock.lock2)

                     {

                            System.out.println(Thread.currentThread().getName()+"..else....lock2"); 

                            synchronized(MyLock.lock1)

                            {

                                   System.out.println(Thread.currentThread().getName()+"..else...lock1");  

                            }

                     }

              }

       }

}

 

class MyLock

{

       static MyLock lock1 = new MyLock();

       static MyLock lock2 = new MyLock();

}

 

 

 

class  DeadLock

{

       public static void main(String[] args)

       {

              Demo d1 = new Demo(true);

              Demo d2 = new Demo(false);

              Thread t1 = new Thread(d1);

              Thread t2 = new Thread(d2);

              t1.start();

              t2.start();

 

       }

}

7.同一资源被不同线程操作,而且这些线程动作不一致时,就叫做线程通讯.

8.wait(),notify,notifyAll()用来操作线程却定义在了object类中是因为:这些方法存在在同步中,使用它们必须标识所属的同步锁,而锁可以是任意对象,任意对象调用的方法一定定义在object类中。

9.wait():释放资源释放锁,sleep();释放资源不释放锁。

10.停止线程:停止线程的两种方式:

A.定义标记,让run方法结束。

       run方法中一般都定义循环。只要控制住循环条件即可。

       但是这种方式有局限性,如果线程进入到冻结状态,是不会读取标记的。那么线程是不会停止的。

B.中断线程。其实就是清除线程的冻结状态,让线程恢复到可运行状态,这样就可以让线程去读取标记,并结束线程。

 

停止线程原理:就是让run方法结束。

代码演示:

class StopThread implements Runnable

{

       private boolean flag = true;

       public synchronized void run()

       {

              while(flag)

              {

                     try

                     {

                            wait();

                     }

                     catch (InterruptedException e)

                     {

                            System.out.println(Thread.currentThread().getName()+"...exception....");

                            flag = false;

                     }

                     System.out.println(Thread.currentThread().getName()+"....");

              }

       }

       public void change()

       {

              flag = false;

       }

 

}

 

class  ThreadDemo13

{

       public static void main(String[] args)

       {

              StopThread st = new StopThread();

              Thread t1 = new Thread(st);

              Thread t2 = new Thread(st);

 

              t1.start();

              t2.start();

 

              int num = 0;

 

              while(true)

              {

                     if(num++==50)

                     {

                            //st.change();

                            t1.interrupt();

                            t2.interrupt();

                            break;

                     }

                     System.out.println(Thread.currentThread().getName()+"...."+num);

              }

       }

}



---------------------- android培训java培训、期待与您交流! ----------------------