java多线程处理与数据集合

时间:2021-12-31 18:31:47
进程:是一个正在执行中的程序
      没一个进程执行都有一个执行顺序,该顺序就是一个执行路径
      或者叫一个控制单元
      进程用于给程序分配内存空间
线程就是:进程中的独立的控制单元,线程控制着进程的执行。
   一个进程中至少有一个线程

main方法所执行的线程称为主线程

创建线程方法2种:
类实现
步骤
1:继承Tread类
2,重写run方法         目的:将自定义代码存储在run方法中让线程运行
3,调用start方法       该方法有两个作用,启动线程,调用run方法 
接口实现
步骤:
1,继承Runable接口
2,重写Runable接口中的run 方法
3,调用new Thread(SubRunable类).start方法开启线程

区别:
1,接口可以对继承,而类只有单继承
2,共享资源(同一个对象)、
3,线程代码存放正在Thread子类run方法中,Runtime接口的run方法中


若在main方法中调用run方法,相当于在主线程中调用了run方法
若调用start方法,则表示另外开启线程执行run方法中代码


为什么覆盖run方法?
Thead用于描述线程,该类就定义了一个运行代码的功能,
该功能存储在run方法中

thread类中的run方法,用于存储线程要运行的代码

线程状态:
start:运行线程
sleep(time):暂停线程,指定time后继续执行
wait():暂停线程,notify()方法唤醒该方法的停止
stop():消亡线程。当run方法结束后也处于消亡状态

线程都有自己的名称通过getName()获取,Thread-0,Thread-1.。。。。
Thread.currentThread()获取当前进程对象
=this.getName();获取线程名称
设置线程名称:setName或者构造函数
线程创建时内存会给特定的线程创建



class thread1  extends Thread
{
   public void run()
   {
     System.out.println();
   }
}
class thread2 extends Thread
{
  public void run()
   {
      System.out.println();
   }
}

class Demo 
{
    public static void main(String args[])
    {
	//创建两个进程
         thread1 t1=new thread1();
         thread2 t2=new thread2();
        //执行两个进程
         t1.start();
         t2.start();   
    }
}
//卖票
class Tickets  extends Thread
{
    public static int ticket=`100;   //共享内存资源,不会重复买多种票
    public void run ()
    {
         while(true)
	 {
 	    if(ticket>0)
	    System.out.println(Tread.currentTread().getName+":"+ticket--);
	    else   break;
	 }
    } 
}
class  SealDemo
{
     public static void main(String args[])
     {
        Tickets t1=new Tickets();
	Tickets t2=new Tickets();
	Tickets t3=new Tickets();
	Tickets t4=new Tickets();
        t1.start();
        t2.start();
        t3.start();
        t4.start();
      }
}

用Runable接口实现
class Tickets  implements Runable
{
     public int ticket=`100;   //共享内存资源,不会重复买多种票
     Object obj=new Object();
     public void run ()
    {
         while(true)
	 {
           synchronized(obj)
	   {	
 	       if(ticket>0)
                  try(Thread.sleep())catch(Exception e){};
	          System.out.println(Tread.currentTread().getName+":"+ticket--);
	       else   break;
	    }
	 }
    } 
}
class  SealDemo
{
     public static void main(String args[])
     {
         Tickets t=new Tickets();
 	 new Thread(t).start();//调用Thead类的构造函数,然后开启
         new Thread(t).start(); 另开启线程
      }
}


多线程安全问题
以上案例中就可能出现线程错误
问题的原因:
   当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完
   另一个线程参与进来执行,导致共享数据的错误

解决办法:
     对多条操作共享数据的语句,只能让一个线程执行完,在执行过程中,
     其他线程不可以参与执行

java对于多线程的安全问题提供了专业的解决方式

同步代码块:


Object obj=new Object();
同步锁----解决代码的安全问题
 synchronized(obj---对象)
{
  需要同步的代码
}

obj相当于锁,持有锁的线程可以再同步中执行。
 没有只有锁的线程即使获取了cpu的执行权,也进不去,因为没有开锁 

同步得前提:
1,必须要有两个以上的线程访问同一个对象的共享属性
2,必须是多个线程使用同一个锁
必须保证同步中只有一个线程在运行


好处:解决多线程的安全问题;
弊端:多个线程每次都要判断锁,所以消耗资源,程序变慢;



同步函数:

找同步成员的方法:
1,明确哪些代码是多线程运行代码;
2,明确共享数据;
3,明确多线程运行代码中哪些语句是操作共享数据的

语法:
public  synchronized void Add()
{

}

多线程中如果重写Runable和Thread中的run方法时使用 同步函数,
那么程序将在一个线称运行完后运行其他线程

同步函数的同步锁是---this,同步函数的锁将函数内容进行枷锁
案例:同步代码块--使用obj锁和同步函数使用的是this

class Tickets  implements Runable
{
   privat int ticket=100;
   object obj =new object();
   boolean flag=true;
   public void run()
   {
        if(flag==ture)
	{
	       while(true)
		{
		  sychronized(obj)
		  {
        	     if(ticket>0)
		     {
			try{Thread.sleep(10);}catch(Exception e){};
			System.out.println(Thread.currentThread().getName()+"..."+ticket--)
		      }
		   }
		}
	}
	else
	{
		while(true)
		{
		    show();//show 方法为同步方法
		}
	}  
     
   }
  public sychronized void show()
  {
             if(ticket>0)
	     {
		try{Thread.sleep(10);}catch(Exception e){};
		System.out.println(Thread.currentThread().getName()+"..."+ticket--)
	      }
   }
    
}
class test
{
 public static void main()
 {
    Tickets  t=new Tickets  ();
     Thread t1=new Thread(t);
     Thread t2=new Thread(t);
     t1.start();
     t2.start();
 }
}


如果同步函数加上static,那么同步静态方法的锁就不再是this,这时候的锁是 类名.Class
静态进内存时,没有本类对象,但是一定有类对象字节码对象
类名.class,该对象的类型是Class
静态函数中的同步代码块的锁也是类名.class


单类设计模式
class Single
{
   private static final Single s=new Single();
   private Single(){};
   public static Single getInstance()
   {
      return s;
   }
}
class Single
{
   private static Single=null;
   private Single(){};
   public static Single getInstance()
   {
         if(s==null)    //用双重判断减少判断锁的状态,从而增加效率
 	{
             sychronized(Single.class)     //使用同步代码块进行加锁
             {
		if(s==null)
		{
                  s=new Single();
		}
	     }
	}
       return s;
   }
}


死锁:
 同步中嵌套同步,而锁却不同。这时程序会停止

死锁案例:下面案例中会出现死锁
class Test
{
   private boolean flag;
   Test(boolean flag)
   {
      this.flag=flag;
   }
   public void run()
   {
        if(flag)
	{
           synchronized(Mylock.locka)
	   {
   		System.out.println("if locka");
		synchronized(Mylock.lockb)
	        {
   		   System.out.println("if lockb");
	       }
	   }
	}
        else
	{
         
           synchronized(Mylock.lockb)
	   {
   		System.out.println("else lockb");
		synchronized(Mylock.locka)
	        {
   		   System.out.println("else locka");
	       }
	   }
	}
    }
}
class Mylock
{
  static   object lockA=new object();
  static   object lockB=new object();
}

class  DeadLockDemo
{
    public static void main(String args[])
    {
      Test t=
      Thread t1=new Thread(new Test(true));
      Thread t2=new Thread(new Test(false));
    }
}



线程间通信:其实就是多个线程在操作同一个资源,操作的动作不同

class Resourc
{
   string name;
   string sex;
   boolean flag=false;
}
class input implement Runable
{
   private Resource  r;
   input(Resource r)
   {
      this.r=r;
    }
   public void run()
   {
       int x=0;
	
       while(ture)
       {   sychronized(r)//枷锁  该资源是唯一的,所以选择该资源
	  {
             if(flag=true)
               r.wait();
	      if(x==0)  
	      {
                 r.name="张三";
                 r.sex="男";
 	       }
	       else
	       {
                  r.name="李四";
                  r.sex="女";
	        }
               x=(x+1)%2;  //循环输出 张三,李四
              r.flag=true;   
              r.notify();   //唤醒r对象所在的线程
	  }
        }

   }
}

class output implement Runable
{
   private Resource  r;
   input(Resource r)
   {
      this.r=r;
    }
   public void run()
   {
       while(ture)
       {     
	     sychronized(r)//枷锁,该资源是唯一的,所以选择该资源
             if(r.flag)
		r.wait();
             System.out.println(r.name+".."+r.sex);
	     r.flag=false;
             r.notify();
	}
   }
}
class Main
{
   public static void main(String args[])
   {
      Resource r=new Resource();
      input in=new input(r);   
      output out=new output(r);
       in.start();
       out.start();   
      //错误原因:当输入的时候只赋值了姓名,性别还没有赋值就被另一个线程输出
       //解决方法:同步代码块
   }
}


notifyAll()唤醒所有线程
唤醒开发机制:
wait
notify
notifyAll
都使用在同步中,因为要对持有监视器(锁的线程操作)的线程操作。
所以要使用在同步中,因为同步才具有锁

为什么这些操作线程的方法要定义在Object类中呢?
因为这些方法在操作同步中线程时,都必须要表示他们所操作线程只有的锁
只有同一个锁上的被等待线程,可以被同一个锁上notify唤醒。
不可以对不同锁中的线程进行唤醒;

也就是说,等待和唤醒必须是同一个锁;
而锁可以是任意对象,所以可以被任意对象调用的方法定义Object类中

代码优化:用于单生产单消费

class Resourc
{
  private  string name;
  private  string sex;
  private  boolean flag=false;
   void sychronized set(String name,String sex)
   {
     if(flag==false)
         try{this.wait();}catch(Exception e){}
     this.name=name;
     this.sex=sex;
      r.flag=true;   
      r.notify();   //唤醒r对象所在的线程
   }
    void sychronized out()
    {
      if(!flag)
         try{this.wait();}catch(Exception e){}
      System.out.println(this.name+"..."+this.sex);
      r.flag=false;   
      r.notify();   //唤醒r对象所在的线程
    }
}

class input implement Runable
{
   private Resource  r;
   input(Resource r)
   {
      this.r=r;
    }
   public void run()
   {
       int x=0;
	
       while(ture)
       {  
	       if(x==0)  
                    r.set("张三","男");
	       else
		    r.set("李四","女");
               x=(x+1)%2;  //循环输出 张三,李四
       }
   }
}

class output implement Runable
{
   private Resource  r;
   input(Resource r)
   {
      this.r=r;
    }
   public void run()
   {
       while(ture)
       {     
	   r.out();
       }
   }
}
class Main
{
   public static void main(String args[])
   {
      Resource r=new Resource();
      new Thread(new input(r)).start();
      new Thread(new output(r)).start();

   }
}


代码改进:用于多生产,多消费
notify()方法唤醒的是线程池中的第一个线程

class Resourc
{
  private  string name;
  private  string sex;
  private  boolean flag=false;
   void sychronized set(String name,String sex)
   {
     while(flag==false)
         try{this.wait();}catch(Exception e){}
     this.name=name;
     this.sex=sex;
     r.flag=true;   
     r.notifyAll();   //唤醒r对象所在的线程
   }
    void sychronized out()
    {
      while(!flag)
         try{this.wait();}catch(Exception e){}
      System.out.println(this.name+"..."+this.sex);
      r.flag=false;   
      r.notifyAll();   //唤醒r对象所在的线程
    }
}

class input implement Runable
{
   private Resource  r;
   input(Resource r)
   {
      this.r=r;
    }
   public void run()
   {
       int x=0;
	
       while(ture)
       {  
	       if(x==0)  
                    r.set("张三","男");
	       else
		    r.set("李四","女");
               x=(x+1)%2;  //循环输出 张三,李四
       }
   }
}

class output implement Runable
{
   private Resource  r;
   input(Resource r)
   {
      this.r=r;
    }
   public void run()
   {
       while(ture)
       {     
	   r.out();
       }
   }
}
class Main
{
   public static void main(String args[])
   {
      Resource r=new Resource();
      new Thread(new input(r)).start();
      new Thread(new input(r)).start();
      new Thread(new output(r)).start();
      new Thread(new output(r)).start();

   }
}

JDK1.5中提供了多线程升级解决方案,
、将同步Synchronized替换成现实lock操作
将object中的wait,notify,notifyall,替换成Condition对象,
该对象可以Lock锁,进行获取
在该实例中,实现了本方只唤醒对方操作

一个lock对应多个Condition



class Resourc
{
    private  string name;
    private  string sex;
    private  boolean flag=false;


    private  Lock lock=new ReentrantLock();
    private  Condition condition_com=lock.newCondation();
    private  Condition condition_pro=lock.newCondation();

   void set(String name,String sex)throws InterruptionException
   {
     try{
     lock.lock();
  	    while(flag==false)
  	       conditon_pro.await();
  	    this.name=name;
 	    this.sex=sex;
 	    r.flag=true; 
    }
    catch(InterruptionException e)  
    {
     lock.unlock();
    }
     conditon_con.signal();   //唤醒r对象所在的线程
     
   }
    void out()
    {
      lock.lock();
     	     while(!flag)
         	 condition_con.await();
      	     System.out.println(this.name+"..."+this.sex);
      	     r.flag=false; 
      lock.unlock();  
      conditon_pro.signal();    //唤醒r对象所在的线程
    }
}

stop方法已经过时:
如果停止线程:只有一种,run方法结束
开启多线程运行,运行代码通常是循环结构
只要控制住循环,就能让run方法结束,也就是线程结束

当线程处于冻结状态;
就不会读取到标记,那么线程就不会结束

当没有指定的方式让冻结的线程恢复到运行状态时,这时需要对冻结状态进行清除,
强制让线程恢复到运行状态中来,这样就可以操作标记让线程结束



使用Thread类的setDaemon(true)将线程标记为守护线程
当主线程结束之后,守护线程也将终止

join方法,表示加入到正在执行的线程中,
正在执行的线程等到调用join的线程运行完后开始继续运行

join特点,当a线程执行到了b线程的join()方法时,a线程就会等待b线程执行完,a才会执行
join可以临时加入线程执行
当b线程处于冻结状态时,使用interrupt()方法中断该线程返回到a线程中

Thread.tostring()重写了object的tostring()方法,
打印:线程名,优先级,线程组
线程组:谁开启了该线程,该线程就处于哪个组   ThreadGroup可以定义线程组
优先级:抢资源的频率,谁的优先级高,被执行的频率会多一点  
        setPriority ()设置线程的优先级,默认的所有线程的优先级为5,
        最大为10  10:MAX_PRIORITY   5:           1:MIN_PRIORITY
yield() 暂停正在执行的线程对象,执行其他线程、


什么时候用多线程

线程与线程之间无太大关联,且都为循环体,为了提高运行效率,可以开多个线程进行数据的执行


class Thread
{
        private static void main(String args[])			
        {
           new Thread()
	   {
                public void run()
		{
			for(int i=0;i<1000;i++)
			{
				System.out.println(Thread.currentThread().getName());
			}
		}
	   }.start();
           Runnable r=new Runnable()
	   {
		public void run()
		{
			for(int i=0;i<10000;i++)
			{
				System.out.println(Thread.currentThread().getName());
			}
		}
	   };
	   new Thread(r).start();

    
	}
}



class StopThread implement Runable
{
     private boolean flag=ture;
    public void run()
    {
        while(flag)
       System.out.println(Thread.currentThread().getName()+".....run");
    }

    public void changeFlag()
    {
       flag=false
    }
}

class DEMO
{
   private static void main(String args[])
   {
      StopThread st=new StopTread();
      new Thread(st.start());
\     new Thread(st.start());
      int num=0;
      while(true)
	{
           if(num++==60)
             {
                  break;
		  st.changeFlag();
	     }
          
	
             System.out.println(Thread.currentThread().getName()+"....."+num);
      }
      
   }
}


String 类
string s1="abc";
string s2=new String("abc");
string s3="abc"
区别:s1创建一个对象,s2创建两个对象;

s1==s2 为false,判断的是对象;
s1.equies(s2) 为true,判断两个字符串是否相同
s1==s3 为ture,为了节约内存,s1和s3指向同一个对象

int length(); 获取长度
char charAt(int index)获取指定位置的字符
int indexof(int ch) 返回ch在字符串中第一次出现的位置
int indexOf(int ch,int fromindex);获取指定字符在指定位置index开始的位置,出现的位置

boolean  isEmpty()   判断长度是否为0
boolean  contains(str)
boolean  startsWith(str)
boolean   endWith(str)
boolean   equals(str)  判断内容是否相同复写了object类的equals方法
boolean equalsIgnoreCase(str)  忽略大小写判断是否相同
if(str.indexof(str)!=-1)   if(str.containt(str))


构造函数:string(char[])将字符转换为字符串
          string (char[] ,offset,count)将字符串一部分转换为字符串
          string  copyValueOf(char[],int offset ,int count)将字符串一部分转换为字符串
          
	  char[] toCharArray();将字符串变成字符数组
	  string valueOf(int)    将整形转换为string
          string valueOf(double)  将double转换为string
          string replace(oldchar,newchar)替换指定字符串
          string[] split(regex)字符串切割
          string subString(begin)
	  string subString(begin,end)  获取子字符串
 	  字符串大小写转换,toLowerCase(),toUpperCase()
          去除空格:trim()
	  对两个字符串自然顺序比较:compareTo(string)


string s="hello java"
string s1=s.replace('a','n')
s:hello java
s1:hello jnvn
string 为final,所以不能被赋值



stringBuffer 
是字符串缓冲区,
一个容器,可以操作多种数据类型,长度可变,
数组长度是固定的,但是只能存储一种类型
append(str)增加
insert(int index,string str)  在指定位置增加字符串
delete(int start,int end)    删除字符串 包含start,不包含end  
				sb.delete(0,sb.length())删除缓冲区
deleteCharAt(index)产出指定位置的字符

stringbuffer replace(start,end,str)
void   setCharAt()

API学习方法:先看累说明,思考类的功能,
             推测应有方法,推测方法的参数和返回值,查找对应方法

StringBuilder
StringBuilder是线程不同步,StringBuffer是线程同步的

若单线程时使用StringBuilder,多线程使用StringBuffer

多线程操作StringBuffer时只能有一个人来操作该对象,里面枷锁
而StringBuilder没有线程


线程安全的:表示多线程操作时同步

JDK升级3个因素:
1提高效率
2,简化书写
3,提高安全性


基本数据类型对象包装类

byte  Byte
short short
int   Integer
long Long
boolean Boolean
float Float
double Double
char  Charactor

最常见作用:
就是用于基本数据类型和字符串类型之间做转换,
基本数据类型转为字符转:
1,基本数据类型+"" 
2,基本数据类型.toString(基本数据类型值)Integer.toString(34);
字符串转成基本数据类型
1,基本数据类型包装类.parseXXX(String);    Integer.parseInt("123")



10进制转其他进制
   toBinaryString();
   toHexString();
   toOctalString();
其他进制转成10进制:
   Integer.parseInt("数值",进制);Integer.parseInt("110",2);

装箱:值类型 转换为引用类型
拆箱:引用类型转换为值类型
引用类型比值类型 多了一个null值,抛出 空异常


Integer m=128;
Integer n=128
m==n   false
Integer a=127;
Integer b=127;
a==b   true;

因为a和b指向了同一个内存地址,当int型数值在byte范围0-127内时,将不开辟内存空间
                             如果超出了空间,则开辟内存空间


Integer x=Integer("123");
Integer y=Integer(123);
x==y   false  比较的是对象
x.equals(y)  true   比较的是数值

数据结构: Api学习,从顶层查看接口的共性方法

集合类:用于存储对象

数组固定长度,集合可变长度
数组存储的对象为同一种对象类型,集合可以存储不同类型的对象


Collection ---接口   获取长度  size(),add(),remove(),clear(),contains(),isEmpty();retainAll--交集 ,iterator();
 |--List   ---接口     ---元素是有序的,元素可以重复,该集合体系有索引
                        特有方法:add(idex,element),addAll(index,Collection),
                                  remove(index),set(index),set(index,element),get(index)
                                  subList(form,to),listIterator();
        默认长度为10;                            
    |--ArrayList     --类   底层的结构是数组结构 (每个元素都有角标) 特点:查询速度很快,插入删除慢(角标需要后移)1.2JDK线程不同步
    |--LinkedList    --类   底层使用的是链表数据结构 (每个元素记录前后关系)特点:插入删除速度快,查询速度慢
    |--Vector        --类   底层是数组数据结构 (被ArrayList替代)  1.0的jdk,特点:同线程同步ArrayList线程不同步
 vector 和ArrayList 却别:vector中有枚举取出,ArrayList没有
|--Set    ---接口    ---元素是无序的,元素不可以重复
    |--HashSet      --类    底层数据结构是hash表,线程时非同步的,保证元素唯一性的原理是判断元素的hashCode是否相同,如果相同,还会继续判断元素的equals方法是否为真
    |--TreeSet      --类    底层数据结构为二叉树,可以对set集合中的元素进行排序,保证元素唯一性的依据是compareTo方法return 0
                            返回值为1,表示大于,返回值=0表示相同(不在存储),返回值-1表示小
                            当compare恒等于一时,按存入顺序迭代输出
			    
			   TreeSet排序的第一种方式:让元素本身具备比较性;
			   匀速需要实现Comparable接口实现ComparTo方法
			   这种方式也成为元素的自然顺序,或者叫做默认顺序
 			   treeset第二种排序方式:当元素自身不具备比较性时,或者具备的比较性不是所需要的
                           需要让集合自身具有比较性,在集合初始化时就有了比较方式。
			   使用构造函数
			   当两种排序都存在时,以比较器为主,

			   比较器:定义一个类,实现Comparator接口,覆盖compare方法
			   TreeSet  ts=new TreeSet(new MyComparator());


Iterator 迭代器接口  hasNext() 判断是否有迭代的对象,  next()取出迭代对象
ArrayList al=new ArrayList();
al.add("h1");
al.add("h2");
Iterator it=al.iterator();
while(it.hasNext())
{
   System.out.println(it.next();
}

for(Iterator it=al.iterator();it.hasNext();)
{
   System.out.println(it.Next());
}

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

ListIterator li=al.listIterator();
while(li.hasNext())
{
  Object obj=li.next();
  if(obj.equals("java"))
   {
    li.set("java1");
    li.remove();
    li.add(java);
    }
}
while(li.hasPrevious())
{
  Object obj=li.next();
  if(obj.equals("java"))
   {
    li.set("java1");
    li.remove();
    li.add(java);
    }
}


枚举和迭代时一样的,枚举的名称以及方法的名称过长,被迭代器取代
import java.util.*;
class Vector 
{
   Vector v=new Vector();
   v.add("123");

   Enumeration en=v.elements();
   while(en.hasMoreElement())
   {
      en.nextElement();
   }

}
LinkList 特有方法:
addFirst();addLast()
getFirst();getLast()  只取
removeFirst();removeLast();即取又删


若LinkList中没有元素,会抛出NosuchElement异常,
在Jdk1.6出现了替代方法:
offerFirst();offerLast();
peekFirst();peekLast();
获取元素,但元素不被删除,如果集合中没有元素,会返回Null
pollFirst(),pollLast();
获取元素,但是元素被删除,如果集合中没有元素,会返回Null

class LinkListDemo
{
  public static void main(String args[])
  {
    LinkList link=new LinkList();
    while(link.isEmpty())
    {
       link.removeFirst();
    }
  }
}

LinkListTest
使用LinkList模拟堆栈,或者队列的数据结构
堆栈:先进后出  杯子
队列:先进先出  水管

class duilie
{
 private LinkedList link
  dulie()
  {
   link=new LinkedList();
  }
  public void add(object obj)
  {
    link.addFirst();  
  }  
  public object get()
  {
    link.removeLast();
  }
  public boolean isNull()
  {
    return link.isEmpty();
  }
}

class duizhan
{
 private LinkedList link
  dulie()
  {
   link=new LinkedList();
  }
  public void add(object obj)
  {
    link.addFirst();  
  }  
  public object get()
  {
    link.removeFirst();
  }
  public boolean isNull()
  {
    return link.isEmpty();
  }
}

duilie d=new duilie();
duilie.add("h1")
duilie.add("h2")
duilie.add("h3")
while(!d.isNull())
{
   d.get();
}

去除ArrayList中同名元素
在迭代时,循环中,next调用一次就要hasnext判断一次
class GetNewArrayList
{
    public static ArrayList singleElement(ArrayList al)
    {
       ArrayList newal=new ArrayList()
       Iterator it=al.iterator()
       while(it.hasNext())
       {
         object obj=it.next();
          if(!newal.contains(obj))
           {
               newal.add(obj)   
	   }
       }
      return newal;
   }
}
存人对象,同姓名,同年龄,视为一个人,为重复对象

class person
{
   String name;
   int age;
   person(string name ,int age)
   {
      this.name=name;
      this.age=age;
    }
   public boolean equals(object obj)
   {
     if(obj instanceof person)
     {
        return false;
     }
      person p=(person)obj;
      return this.name.equals(p.name)&&this.age==p.age;
   }
}

List集合判断元素是否相同(remove,contains()方法),依据的是元素的equals方法
HashSet对于判断判断,删除HashSet集合,依据的是元素的hashCode()方法



hashSet:是如何保证元素唯一性
hashCode和equals来完成,
如果元素的HashCode值相同,才会判断equals、是否为true。(true代表相同元素,所以不会存储,否则存储)
如果元素的hashcode值不同,不会调用equals

如果将对象存进HashSet,一般会复写equals和hasCode方法



class hashSetDemo
{
   public static void main(String args[])
   {
	 HashSet h=new HashSet();
	h.add("java1");  //add返回boolean型数据,表示该数据是否存入HashSet中
	h.add("java2");
	h.add("java3");
	h.add("java4");
        Iterator it=h.iterator();
        while(it.hasNext())
        {
		System.out.println(it.next());
	}
   } 
}
class hashSetTest
{
   public static void main(String args[])
   {
	HashSet hs=new HashSet();
        hs.add(new person("a1",18));
        hs.add(new person("a2",19));
        hs.add(new person("a3",20));
        hs.add(new person("a4",21));
        Iterator it=hs.iterator();
        while(it.hasNext())
	{
	    person p=(person)it.next();
	    System.out.println(p.name+"::"+p.age);
	}
   } 
}

class person
{
   String name;
   int age;
   person(string name ,int age)
   {
      this.name=name;
      this.age=age;
    }
    public int  hashCode()
    {
     return name.hashCode()+age;
    }
   public boolean equals(object obj)
   {
     if(obj instanceof person)
     {
        return false;
     }
      person p=(person)obj;
      return this.name.equals(p.name)&&this.age==p.age;
   }
  
}


TreeSet:可以进行排序
对象如果要存入TreeSet中去,必须具备可比性,继承Comparable接口实现compareTo方法
当主要条件相同时,要判断次要条件是否相同
class TreeSetTest
{
   public static void main(String args[])
   {
	TreeSet ts=new TreeSet();
        ts.add("abc");
        ts.add("bcd");
        ts.add("efd");
        ts.add("fed");
        Iterator it=ts.iterator();
        while(it.hasNext())
	{
	    System.out.println(it.next());
	}
   } 
}


class person  implement Compareable 人本身不具备可比性,所以会出现异常,要继承此接口
{
   String name;
   int age;
   person(string name ,int age)
   {
      this.name=name;
      this.age=age;
    } 
    public int compareto(Object obj)
    {
	if(! obj instanceof person)
        {
	      throw new Exception();
	} 
	 person p=(person)obj;
         if(this.age>p.age)
	     return 1;
         if(this.age==p.age)
	     return  this.name.compareto(p.name);
   	 return -1;
    }
}
class TreeSetTest
{
   public static void main(String args[])
   {
	TreeSet ts=new TreeSet();
        ts.add(new person("a1",11));
        ts.add(new person("a2",12));
        ts.add(new person("a3",13));
        ts.add(new person("a4",14));
        Iterator it=ts.iterator();
        while(it.hasNext())
	{
	    person p=(person)it.next()
	    System.out.println(p.name+""+p.age);
	}
   } 
}

classTreeSetDemo2    --当元素本身不具备比较性,
或者具备的比较性不是需要的,这时需要让容器本身具备可比性
定义一个比较器,将比较器对象做为参数传递给TreeSet集合的构造函数
class TreeSetTest
{
   public static void main(String args[])
   {
	TreeSet ts=new TreeSet(new Mycompare());  //使用排序器进行排序,(比较器排序优先)
        ts.add(new person("a1",11));
        ts.add(new person("a2",12));
        ts.add(new person("a3",13));
        ts.add(new person("a4",14));
        Iterator it=ts.iterator();
        while(it.hasNext())
	{
	    person p=(person)it.next()
	    System.out.println(p.name+""+p.age);
	}
   }
}
class Mycompare implement Comparator
{
   public int compare(object o1,object o2)
   {
	 person p1=(person)o1;
	 person p2=(person)o2;
         int num=p.name.compare(p2.name);
         if(num==0)
	 {
		//return p1.age=p2.age;
               return   new Integer(p1.age).compareTo(new Integer(p2.age));
 	 }
         return num;
   }
}

匿名内部类的实现
class TreeSetTest
{
   public static void main(String args[])
   {
	TreeSet ts=new TreeSet(new Comparator()
	{
             public int compare(object o1,object o2)
             {
		 person p1=(person)o1;
		 person p2=(person)o2;
        	 int num=p.name.compare(p2.name);
        	 if(num==0)
		 {
			//return p1.age=p2.age;
             	     return   new Integer(p1.age).compareTo(new Integer(p2.age));
 	 	  }
      	  	 return num;
              }
	);  //使用排序器进行排序,(比较器排序优先)
        ts.add(new person("a1",11));
        ts.add(new person("a2",12));
        ts.add(new person("a3",13));
        ts.add(new person("a4",14));
        Iterator it=ts.iterator();
        while(it.hasNext())
	{
	    person p=(person)it.next()
	    System.out.println(p.name+""+p.age);
	}
   }
}


泛型:JDK1.5版本以后出现新特性,用于解决安全问题,是一个安全机制
好处:
1,将运行时期出现的问题classCastexception,转移到编译时期;
方便程序员及时修改bug
2,避免了强制转换的麻烦
3,提高了类型存储的安全性

泛型格式:
通过<>来定义要操作的引用类型的数据类型
其实<>就是用来接收类型的
当使用集合时,将集合中要存储的数据类型做为参数传递到<>中即可
什么时候使用泛型,通常在集合框架中很常见,只要见到<>就要定义泛型
class GenericDemo
{
   public static void main(String args[])
   {
	TreeSet<String> ts=new TreeSet<String>(new StringlengthComparator());
        ts.add("abcd");
        ts.add("abcd");
        ts.add("abcd");
	Iterator<String> it=ts.iterator();
        while(ts.hasNext())
	{
	    String s=ts.next();
	    System.out.println(s);
	}
    }
}


class StringlengthComparator implement Comparator<String>
{
        public int compare(String o1,String o2)
	{
		int num= new integer(o1.length()).compareTo(o2.length());
	    	if(num==0)
		{
		    return o1.compare(o2);
		}
		return num;
	}	
}


泛型的应用:
什么时候定义泛型类:当类中要操作的引用数据类型不确定的时候
早起定义object来完成扩展,现在定义泛型来完成扩展

泛型类定义的泛型,在整个类中有效,如果被方法是用,
那么泛型类的对象明确要操作的具体类型后,所有要操作的类型就已经固定了,
为了不同方法可以操作不同类型,而且类型还不确定。
那么可以将泛型定义在方法上

class worker
{
}
class student
{
}
class teacher
{
}

class Tool<T>   //泛型类
{
   private T type;
   public void setObject(T type)
   {
	this.type=type;
   }
   public T getObject(T type)
   {
     return this.type;
    }
}
class GenericApp
{
	public static void main(String args[])
	{
		Tool<worker> t=new Tool<worker>();
                t.setObject(new worker());
                t.getObject();
		
	}
}

泛型方法
public <T> void show(T t)
{
  System.out.print(t);
}

特殊之处:静态方法不可以访问类上定义的泛型,如果静态方法操作的引用数据类型不确定
可以将泛型定义在方法上

class GenericClass<T>
{
  public static void show(T t)  //传入的t的类型应类的类型一致
  {
     System.out.println(t);
  }
  public static <M> void print(M m)	//而静态泛型方法不能与类上定义的类型一致,静态方法只能使用静态成员
  {
     System.out.println(m);
  }
}

泛型接口:
interface Inter<T>
{
  void show(T t);
}

class InterClass implements Inter<String>
{
    public <String> void show(String t)
    {
	System.out.println(t);
    }
}
class InterClass<T> implements Inter<T>
{
     public <T> void show(T t)
    {
	System.out.println(t);
    }
}

泛型应用
?占位符:泛型的限定
? extends E;可以接收E类型或者E的子类型 上限定
? super E;可以接收E类型或者E的父类型   下限定
class App
{
	public static void main(String args[])
	{
		ArrayList<String> a1=new ArrayList<String>();
		ArrayList<Integer> a2=new ArrayList<Integer>();
                Print(a1);
		Print(a2);
		
	}
	public <T> void Print(ArrayList<T> a)  //传入T类型时可以进行接收,然后操作(T为具体类型)
	{	//遍历两个方法
	      	Interator<T> it=a.interator();
 		while(it.hasNext())
		{
		    System.out.println(it.next());
		}
	}
	public  void Print(ArrayList<?> a)  //传入?时无法接收并操作该类型,(?为未知类型,占位符)
	{	//遍历两个方法
	      	Interator<?> it=a.interator();
 		while(it.hasNext())
		{
		    System.out.println(it.next());
		}
	}
	public  void Print(ArrayList<?extends Person> a)  //类型限定符,只能传入Person及其子类
	{	//遍历两个方法
	      	Interator<? extends Person> it=a.interator();
 		while(it.hasNext())
		{
		    System.out.println(it.next());
		}
	}


}

class Person
{
   String name ;
   int  age;
     Person(String name,int age)
    {
       this.name=name;
       this.age=age;
    }
}

class Student  extends  Person
{
   Student(String name,int age)
   {
      super(name,age);
    }
   
}
class Worker   extends  Person
{
    Worker(String name,int age)
    {
       super(name,age);
    }
}
public Demo
{
    public static void main(String args[])
    {
          //将student类和woker类存入TreeSet
           TreeSet  ts1=new  TreeSet(new comp<Student>()); //在使用比较器的时候使用到了泛型计较器,以Person为比较器的类型,然后传入子类进行比较
           ts1.add(new Student("a1",19));
	   ts1.add(new Student("a2",20));
           ts1.add(new Student("a3",21));
           
	   Interator<Student> it=ts1.interator();
   	   while(it.hasNext())
	   {
		System.out.println(it.next());
	   }  

           TreeSet  ts2=new  TreeSet(new comp<Worker>());     //在使用比较器的时候使用到了泛型计较器,以Person为比较器的类型,然后传入子类进行比较
           ts2.add(new Worker("a1",19));
	   ts2.add(new Worker("a2",20));
           ts2.add(new Worker("a3",21));
           Interator<Student> it=ts2.interator();
   	   while(it.hasNext())
	   {
		System.out.println(it.next());
	   }  
    }
}
class comp implements Comparator<Person>
{
        public int compareTo(Person p1,Person p2)
	{
	    int num= p1.name.compareTo(p2.name) ;
  	    if(num==0)
	    {
		return p1.age.compareTo(p2.age);
	    }
	    return  num;
 	}
}



传智播客毕向东Java基础视频教程-day16-01-集合(Map概述)
Map:该集合存储键值对,一对一的对应关系,而且保证建的唯一性
clear();
boolean containKey(object key)
boolean  containValue(Object value)
isEmpty()
put(K key,V value)
putAll(Map())
get(Object key)
size();
value();
entrySet();
keySet();


Map
   |--Hashtable  底层是hash表数据结构,不能存入null建null值的情况,该集合是线程同步的
   |--Hashmap    底层是hash表数据结构,允许使用null建null值的情况,该集合是线程不同步的
   |--TreeMap    底层是二叉树结构,线程不同步,可以用于给map集合的健排序


和set很像:set底层使用的是Map集合


class MapDemo
{
	public static void main(String args[])
	{
		Map<String,String> map=new HashMap<String,String>();
		map.put("zhangsan","001");
		map.put("Lisi","002");
		map.put("Wangwu","003")
;
                if(map.containKey("zhangsan"))
                    System.out.println(map.remove("zhangsan"));
		if(map.get("Lisi")!=null)//可以通过get方法的返回值来判断一个键是否存在
		       System.out.println(map.remove(“Lisi"));
	}
}


put会返回这个键原来的值,并覆盖该值
增加元素,如果出现增加时相同的健,那么后增加的值会覆盖原有键对应的值,并put方法会返回被覆盖的值

map集合的两种取出方式:
1,keySet()将map中所有的键存入到Set集合,因为Set集合具备迭代器,所以可以通过迭代方式取出所有的键,并通过get方法取出所有的值
              先获取map集合的所有键的set集合,keySet();
	      有了set集合就可以取出键值了

 		map集合的取出原理:将map集合转成set集合,在通过迭代器取出
2,Set<Map.Entry<k,v>> entrySet()   将map集合中的映射关系存入到了set中,
					这个关系的类型为Map.Entry对象,该方法的getKey(),getValue();

 					那么关系对象Map.Entry获取到后,就可以通过getKey(),getValue()获取键值

Map.Entry:其实Entry也是一个借口,它是Map接口中的一个内部接口
interface Map
{
   public static interface Entry  //接口在成员位置才能使用static 修饰符
   {
	public  abstract Object  getKey();
	public  abstract Object  getValue();
   }
}

class HashMap implements Map   
{
   class hash implemetns Map.Entry
   {
        public  abstract Object  getKey();
	public  abstract Object  getValue();
   }
}

class MapDemo
{
	public static void main(String args[])
	{
		Map<String,String> map=new HashMap<String,String>();
		map.put("zhangsan","001");
		map.put("Lisi","002");
		map.put("Wangwu","003")

		//两种取出方法
;               Set<String> keySet=map.keySet();
		Interator<String> it=keyset.iterator();
   		while(it.hasNext())
		{
		      Syste.out.println(map.get(it.next()));
		}
		

		Set<Map.Entry<String,String>> entrySet=map.entrySet();
		Iterator<Map.Entry<String,String>> it=map.entrySet();
		while(it.hasNext())
		{
  		 Map.Entry<String,String>  me =	it.next();
		 String key=me.getKey();
		 String value=me.getValue();

		}
            
	}
}
什么时候使用map集合:
当数据之间存在映射关系时,可以使用map集合



class APPDemo
{
   public static void main(String args[])
   {
	String str="abcdeabcdefgaaaabbc";
        char[] ch=str.toCharArray();
        TreeMap<Charactor,Integer> tm=new TreeMap<Charactor,Integer>();
	for(int i=0;i<ch.length;i++)
	{
		Integer value=tm.get(ch[i]);  //获取ch[i]对应的值,如果不存在返回null
                if(value==null)
		{
 			tm.put(ch[i],1);      //将ch[i]对应的值,存入到treeMap中,如果该值存在,则覆盖原有数据
		}
		else
		{
			value+=1;
			tm.put(ch[i],value);
		}
	}
 	StringBuilder sb=new StringBuilder();
	Set<Map.Entry<Charactor,Interger>> entrySet=tm.entrySet();
	Iterator<Map.Entry<Charactor,Interger>> it=entrySet.iterator();
	while(it.hasNext())
	{
		Map.Entry<Charactor,Integer> me=it.next();
		Charactor ch=me.getKey();
		Integer value=me.getValue();
		sb.append(ch+"("+value+")");
	}
	System.out.println(sb);
   }
}

map扩展:
map集合被使用是因为具备映射关系;
map嵌套
1对多映射
class Demo
{
    public static void main(String args[])
    {
	HashMap<String,String> renliziyuan=new HashMap<String,String>();
	bumen.put("01","a");
	bumen.put("02","b");
	HashMap<String,String> it=new HashMap<String,String>();
	bumen.put("01","c");
	bumen.put("02","d");
	HashMap<String,HashMap<String,String>> Main=HashMap<String,HashMap<String,String>>();
	Main.put("renliziyuan",renliziyuan);
	Main.put("it",it);
	//取数据
	Iterator<String> it=Main.keySet().iterator();
        while(it.hasNext())
	{
		String name=it.next();
		HashMap<String,String> part =Main.get(name);
		System.out.println(name);
		GetPartInfo( part);
	}
        
    }


       public void GetPartInfo(HashMap<String,String> part)
	{
		Iterator<String> it=part.keySet().iterator();
		while(it.hasNext())
		{
			String id=it.next();
			String name=part.get(id);
			System.out.println(id+":"+name);
		}
	       
	}
}
Collections: 工具类,静态类,用于对集合进行操作
Collections.sort(List)   自然排序
Collections.sort(List l,Comparator c)按照比较器排序
Collections.binarySearch(List)   返回角标,如果为负,表示角标不存在,返回-号,加上插入点-1
Collections.fill(List l,String str)  将集合中的元素全部替换为str
Collections.replaceAll(List l,String Old,String new) 将制定集合中的Old值全部替换成new
Collections.reverse(List l)   反转集合
Collections.swap(List l,int a,int b )  交换List中角标为a和b的位置
Collections.shuffle(List);     随机置换List
Arrays   用于操作数据的工具类,静态类
Arrays.equals(Object a1,object a2)  比较数组中元素是否相同
Arrays.toString(arr);    
Arrays.asList(arr);                将数组编程list集合,可以使用集合的思想和方法来操作数组中的元素
                                     将数组编程集合,不可以使用集合的增删方法,因为数组的长度是固定的
                                      如果增删,那么发生unsupporteException异常
                                     如果数组中的元素都是对象,变成集合时,数组中的元素就直接转换为集合中的元素
					如果数组中的元素都是基本数据类型。,那么会将该数组作为集合中的元素存在
Collection接口中的toArray()方法:指定类型的数组要定义长度,当指定类型的数组的长度小于了集合的size,那么该方法内部会创建一个新的数组,长度为集合的size,
                                                            当指定的数组类型的长度,大于了集合的size就不会新创建数组,而是使用传递进来的数组
                                                            所以创建一个刚刚好的数组最优
 								toArray(new String[0]);

集合变数组的原因:为了限定对元素的操作,不需要对元素进行增删

foreach迭代
ArrayList<String> a=new ArrayList<String>();
a1.add("123")
a1.add("123")
a1.add("123")
for(String s:a)   //只能对集合中元素进行取出,不能修改
{
  System.out.println(s);
}



格式:
for(数据类型 变量名:被遍历的集合(Collection)或者数组)
{
}
对集合进行遍历的时候,只能获取元素,但是不能对集合进行操作
迭代器,除了遍历,还可以进行remove集合中元素的操作
如果用ListIterator,还可以再遍历过程中进行增删改查操作

传统的for循环高级for区别:高级for有一个局限性,必须有被遍历的目标,(如打印指定次数的一条语句)
建议在遍历数组的时候使用传统for循环,因为传统for循环可以定义角标
	HashMap<Integer,String> hm=new HashMap<Integer,String>();
        hm.put(1,"a");
 	hm.put(2,"b");
	hm.put(3,"c");
        Set<Integer>  keySet=hm.keySet();
	 for(Integer i:keySet)
	{
	    System.out.println(i+":"+hm.get(i))
	}
 	
	Set<Map.Entry<Integer,String>> entrySet=hm.entrySet();
	for(Map.Entry<Integer,String> me: hm.entrySet())
	{
    	    System.out.println(me.getKey()+":"+me.getValue())
	}
JDK1.5出现新特性
可变参数:上一种参数的简写形式
public static void show(String str,int... arr)
方法的可变参数,可变参数一定定义在参数最后面


静态导入:
import static  java.util.Arrays.*;将类中所有“静态成员”导入到该类中
当类名重名时,需要制定具体的包名,
当方法重名时,需要指定具体的对象或者类





创建图形化界面:
1,创建Frame窗体
2,对Frame进行设计,大小,位置,布局
3,定义组建
4,将组建通过窗体的add方法增加到窗体中
5,将窗体现实,通过setVisible(true)


事件监听机制特点:
1,事件源
2,事件
3,监听器
4,事件处理

事件源:就是awt或者swing包中的那些图形界面组建

事件:每一个事件源都有自己特有的对应事件和共性事件

监听器:将可以出发某一个事件的动作(不止一个)都已经封装到了监听器中


以上三者在java中都已经定义好了,直接获取其对象用就可以了

程序员要做的就是:事件处理


class AwtDemo
{
	public static void main(String args[])
	{
	        Frame f=new Frame("Java Awt");
		f.setSize(500,400);
		f.setLocation(300,200);
		f.setLayout(new FlowLayout());
		
		Button btn=new Butten("btn按钮");
		f.add(btn);
		//f.addWindowLisener(new MyWin());



		f.addWindowLisener(new MyWin(){  //匿名内部类来实现事件
		public windowClosing(WindowEvent e)
		{
      			 System.exit(0);
		}
		});

		f.setVisible(true);
	}
}
因为WindowLisener的子类:windowAdapter已经实现了WindowListener接口
并覆盖了其中的所有方法,那么我们只要继承自windowAdapter覆盖我们需要的方法即可;

class MyWin extends WindowAdapter
{
	public windowClosing(WindowEvent e)
	{
               System.exit(0);
	}
}
需要导入以下两个包
java.awt.*;
java.awt.event.*;