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