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