zoukankan      html  css  js  c++  java
  • java多线程处理与数据集合

    进程:是一个正在执行中的程序
          没一个进程执行都有一个执行顺序,该顺序就是一个执行路径
          或者叫一个控制单元
          进程用于给程序分配内存空间
    线程就是:进程中的独立的控制单元,线程控制着进程的执行。
       一个进程中至少有一个线程
    
    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.*;
    

      

  • 相关阅读:
    postgresql-磁盘空间不足问题排查
    postgresql-删除重复数据
    postgresql-排序
    磁盘耗时时间
    nginx 报错 The plain HTTP request was sent to HTTPS port
    nodejs使用pkg打包
    npm 设置镜像源
    IDEA通过Ctrl+鼠标滚轮放大/缩小字体
    使 nodejs 代码 在后端运行(nohup)
    加密HSQLDB的.script文件
  • 原文地址:https://www.cnblogs.com/anbylau2130/p/3025347.html
Copyright © 2011-2022 走看看