七、集合
简介
JAVA中的集合是一个名词,数据的一种容器,用于容纳数据。
JAVA集合框架中就包含了对不确定个数的数据处理的集合类。
#总结:对不确定的有关系的数据进行相同的逻辑处理的场合,使用集合是一个不错的选择
根据数据的不同设立不同集合规则,JAVA集合分为两大体系:
- 单一数据体系:Collection接口定义了相关的规则
- 成对出现的数据体系:Collection接口定义了相关的规则(两个数据有关系,可以通过第一个数据关联到第二个数据)//也称之为键值对数据
常用接口和类
Collection接口:
常用的子接口:
List:按照插入保存数据,数据是可重复的
- 具体实现类:ArrayList,LinkedList
Set:集,无序保存,数据不能重复
- 具体实现类:HashSet
Queue:队列
- 具体实现类:ArrayBlockingQueue
Map接口:
具体实现类:HashMap,Hashtable
ArrayList
List:列表,清单
按照数据插入顺序进行存储
Array:数组,阵列
基本操作
ArrayList list = new ArrayList();
1.不需要传递构造参数,直接new就可以,底层数组为空数组。(用到时候再放)
2.构造参数需要传递一个int类型的值,用于设定底层数组的长度。(马上放数据)
3.构造参数需要传递一个Collection集合类型的值,用于将其他集合中的数据放置在当前集合中。(Collection c)
增加数据
List.add(“示例”);或者整型数字也可以
ArrayList list = new ArrayList(3);
假如已经加了三条数据,再来一条依然能放进去,假如是数组的话就会报错了。当放第四条数据的时候,ArrayList中会产生新的更大的数组(扩容),然后来引用第四条数据,旧的已经不再使用。
访问集合中数据
- 获取条数:list.size()
- 获取指定位置数据:list.get(0)获取索引0的
- 遍历集合数据:for(int i=0;i<list.size();i++) { sout(list.get(i)); }
- 如果循环遍历集合数据时,不关心数据的位置,那么可以采用特殊的for循环:for(Object obj:list) { sout{obj}; }格式:for(循环对象:集合)
修改数据
list.set(0,修改的新数据)//修改索引为0的数据
删除数据
list.remove(0)删除索引为0的数据
Object obj=list.remove(0),输出obj就是删除的值
常用方法
- add(0,“zhangsan”)方法可以传递2个参数的,第一个参数表示索引,第二个表示数据。假如说原来的位置0已经有东西了,那么就从该位置开始替换为新数据,旧数据集体后移。
- addAll()示例:
ArrayList list = new ArrayList();
ArrayList list222 = new ArrayList();
list.add("zhangsan");
list.add("zhangsan2");
list222.addAll(list);
直接把list的数据都放到list222中了。
- clear()数据全部清空
- isEmpty()判断集合数据是否为空。
- removeAll()删除指定集合中数据,用法跟addAll()一样,A.removeAll(B)就相当于把A中B的元素清除
- contains()判断是否包含
- indexOf(数据)判断该数据在集合的第一个位置,如果没有返回-1
- lastIndexOf(数据)判断该数据在集合的最后一个位置
- xxx.toArray()集合变数组
- xxx.clone()复制创建一个新的集合,后加.var克隆一个新的对象(通用类型)
LinkedList
链表
基本操作
获取数据
list.get(0)//获取索引0的
list.getFirst()//获取第一个
list.getLast()//获取最后一个
增加数据
list.add(“zhangsan”)
list.addFirst(“zhangsan”)
list.add(1,“zhangsan”)在原先索引1的位置插入
LinkedList list=new LinkedList<>();
list.add("zhangsan");
System.out.println(list);
System.out.println(list.getFirst());
System.out.println(list.getLast());
list.add("zhangsan1");
System.out.println(list);
list.addFirst("zhangsan2");
System.out.println(list);
运行结果:
[zhangsan]
zhangsan
zhangsan
[zhangsan, zhangsan1]
[zhangsan2, zhangsan, zhangsan1]
遍历数据
- 获取条数:list.size()
- 获取指定位置数据:list.get(0)获取索引0的
- 遍历集合数据:for(int i=0;i<list.size();i++) { sout(list.get(i)); }
- 如果循环遍历集合数据时,不关心数据的位置,那么可以采用特殊的for循环:for(Object obj:list) { sout{obj}; }格式:for(循环对象:集合)
修改数据
list.set(0,修改的新数据)//修改索引为0的数据
删除数据
list.remove(0)删除索引为0的数据
list.remove()删除第一个
list.removeAll()与上面ArrayList中用法一样
list.removeFirst()删除第一个
list.removeLast()删除最后一个
Object obj=list.remove(0),输出obj就是删除的值
常用方法
- clear()数据全部清空
- isEmpty()判断集合数据是否为空。
- removeAll()删除指定集合中数据,用法跟addAll()一样,A.removeAll(B)就相当于把A中B的元素清除
- contains()判断是否包含
- indexOf(数据)判断该数据在集合的第一个位置,如果没有返回-1
- lastIndexOf(数据)判断该数据在集合的最后一个位置
- xxx.toArray()集合变数组
- xxx.clone()复制创建一个新的集合,后加.var克隆一个新的对象(通用类型)
- list.push(“aaa”)//添加数据,数据直接添加到第一个
- list.pop()//删除第一个数据
泛型
介绍
泛型语法:ArrayList<P> list=new ArrayList<P>();
表示存放到集合的是P类型的,添加的类型不满足要求,就会报错。
import java.util.ArrayList;
public class Chap {
public static void main(String[] args) {
ArrayList list=new ArrayList();
P p=new P();
U u=new U();
list.add(p);
list.add(u);
Object o = list.get(0);
o.s();//运行会报错,多态限制使用场景
}
}
class P{
public void s(){}
}
class U{}
集合仅是一个容器,没有约束存储数据类型,获取对象时就返回了一个通用类型Object。这样对象o由于多态的限制无法使用P中的方法,因此可以进行强制类型转换来使用(P m=§o)
假如引入泛型,就不用这么麻烦,直接声明集合中只能存放这个类型的对象,取出时就可直接使用这个类型的方法。
基本使用
泛型的声明:interface接口<T>和class类<k,v>
比较器
list.sort(传入一个比较器的对象);
HashSet
放数据可以重复,但是存储不会重复。
HashSet set=new HashSet();
set.remove(“wangwu”)
set.add(“zhangsan”)
无法查询(只能遍历得到)
无法修改(只能先删除后添加)
常用方法
与之前的一样
Queue
ArrayBlockingQueue queue=new ArrayBlockingQueue(3);
queue.add(“zhangsan”)
queue.add(“zhangsan1”)
queue.add(“zhangsan2”)
queue.add(“zhangsan3”)//que已满报错
que.put(“zhangsan”);
que.put(“zhangsan”);
que.put(“zhangsan”);
que.put(“zhangsan”);//阻塞,代码没继续进行
queue.offer(“zhangsan”)//返回bool类型数据
queue.offer(“zhangsan”)
queue.offer(“zhangsan”)
queue.offer(“zhangsan”)//已经满了返回false
queue.pull()//取出第一个
queue.pull()
queue.pull()
queue.pull()//取不出来只能取出[ ]
queue.take()//取出第一个
queue.take()
queue.take()
queue.take()//代码不会继续运行,阻塞
HashMap
映射
HashMap map=new HashMap();//可放参数表示大小
map.put(“a”,“1”)
map.put(“b”,“2”)
map.put(“c”,“3”)
数据存储无序,数据存储无重复
K值相同后来的会把旧的覆盖掉
put也可以修改数据,返回的就是修改的值
查询:
map.get(“a”);
消除数据:
remove(“b”)
常用方法
底层:单项链表+数组
添加数据:
map.put(“d”,“3”);
Object o=map.put(“d”,“4”);
System.out.println(o);//结果是3,修改返回的是旧的值
map.putIfAbsent(“b”,“2”)
map.putIfAbsent(“b”,“3”)//b已经有数据,就不放入了
修改数据:
map.replace(“b”,“3”).//修改为3
当b没有时,就不会添加数据
清空:
map.clear();
判断:
map.containsKey(“b”)判断是否有b
map.containsValue(“1”)判断是否有1这个值
Collection c=map.values()取出所有值
map.entrySet();得到键值对
map.remove(“b”)//删除
map.remove(“b”,“1”)//也能删除
map.remove(“b”,“10086”)//这个特定键值对的不存在,所以不会删除
循环遍历一旦启动,中间无法删除数据,但可以修改数据,尽量使用迭代器。
keySet()返回 hashMap 中所有 key 组成的集合视图。
Hashtable
Hashtable t=new Hashtable()
put
get
remove都有
与HashMap的不同
- HashMap的pv值都可以是null,数据定位采用Hash算法,Hashtable用的Hashcode
- HM性能较高,HT性能较低
- 底层结构容量不同,HM(16)HT(11)
- 继承父类不同
迭代器
iterator
迭代器接口定义了几个方法,最常用的是以下三个:
-
next() - 返回迭代器的下一个元素,并将迭代器的指针移到下一个位置。
-
hasNext() - 用于判断集合中是否还有下一个元素可以访问。
-
remove() - 从集合中删除迭代器最后访问的元素(可选操作)。
// 获取迭代器
ArrayList<String> sites = new ArrayList<String>();
Iterator<String> it = sites.iterator();
hasNext()判断是否有下一条数据
// 输出集合中的所有元素
while(it.hasNext()) {
System.out.println(it.next());
remove只能对当前数据删除,不能对其他数据删除
工具类
package Chap06;
import java.util.Arrays;
import java.util.List;
public class TOOL {
public static void main(String[] args) {
int[]i={1,2,3,4,5,6,7,8,9,10};
int[]i2={1,2,3,4,5,6,7,8,9,10};
System.out.println(Arrays.toString(i));
System.out.println(i);
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
System.out.println(list);
Arrays.sort(i);
System.out.println(Arrays.binarySearch(i, 9));//返回值是排序后的数组中,9所在的位置,从0开始
System.out.println(i);
System.out.println(Arrays.equals(i, i2));//位置相同的地方都相等返回true,假如乱序不同返回false
System.out.println(Arrays.equals(i,0,5,i2,0,5));//0,5表示从第0位开始,到第5位结束,所以是前6位,从第0位开始,到第5位结束,所以是前6位
}
}
八、IO
文件流
package CHAP08;
import java.io.*;
public class ioo {
public static void main(String[] args) {
String filepath="E:\\Coding\\Java-Project\\untitled1\\data\\nfiee.txt";
File file=new File(filepath);
System.out.println(file);//打印出路径
//文件对象的操作
System.out.println(file.isFile());//判断当前文件对象是否为文件,假如把路径改到文件夹,就是false
file.isDirectory();//判断是否为文件夹
file.exists();//判断文件对象是否存在关联
//file.mkdirs();//创建多级文件目录
try {
file.createNewFile(); // 保留原行,但添加异常处理
} catch (IOException e) {
e.printStackTrace();
}//创建新文件
}
}
文件复制
package CHAP08;
import java.io.*;
public class M08 {
public static void main(String[] args) {
File file=new File("E:\\Coding\\Java-Project\\untitled1\\data\\nfiee.txt");
File file2=new File("E:\\Coding\\Java-Project\\untitled1\\data\\nfiee.txt.copy");//自动生成文件
FileInputStream fis=null;//为什么要设置为NULL?避免编译错误:如果变量未被初始化(即使声明时未赋值),在 try 块外直接使用会导致编译错误(可能未初始化)。
FileOutputStream fos=null;
try{ //文件输入流,管道对象
fis=new FileInputStream(file);
fos = new FileOutputStream(file2);
//打开阀门,流转数据(输入)
int data = fis.read();
//输出
fos.write(data);
data = fis.read();
fos.write(data);
data = fis.read();
fos.write(data);
data = fis.read();
fos.write(data);
//如果文件数据读取完毕,在读取读取结果为-1
while(data!=-1){//为了避免上述重复,可以直接循环
fos.write(data);
data = fis.read();
}
}
catch(IOException e){
e.printStackTrace();
}finally{
if(fis!=null){try{fis.close();}
catch(IOException e){e.printStackTrace();
}
}
if (fos!=null){
try{
fos.close();
}
catch(IOException e){
e.printStackTrace();
}
}
}
}
}
如果不想要每次复制都只能复制过去一个字符的话,可以采用缓冲流Buffer
字符串
可将字符串转换为字节数组,然后将数组中的每一个字节写到文件中
package Chap06;
import java.io.*;
public class M08 {
public static void main(String[] args) {
File file=new File("E:\\Coding\\Java-Project\\untitled1\\data\\nfiee.txt");
File file2=new File("E:\\Coding\\Java-Project\\untitled1\\data\\nfiee.txt.copy");//自动生成文件
//FileInputStream fis=null;//为什么要设置为NULL?避免编译错误:如果变量未被初始化(即使声明时未赋值),在 try 块外直接使用会导致编译错误(可能未初始化)。
//FileOutputStream fos=null;
BufferedReader fis=null;
PrintWriter fos=null;
try{ //文件输入流,管道对象
fis=new BufferedReader(new FileReader(file));
fos = new PrintWriter(file2);
//打开阀门,流转数据(输入)
// int data = fis.read();
//输出
// fos.write(data);
// data = fis.read();
// fos.write(data);
// data = fis.read();
// fos.write(data);
// data = fis.read();
// fos.write(data);
String data=null;
//如果文件数据读取完毕,在读取读取结果为-1
while((data= fis.readLine()) != null){//为了避免上述重复,可以直接循环
//fos.write(data);
//data = fis.read();
fos.println(data);
}
//刷写数据
fos.flush();//把缓冲区的数据强制全部输出
}
catch(IOException e){
e.printStackTrace();
}finally{
if(fis!=null){try{fis.close();}
catch(IOException e){e.printStackTrace();
}
}
if (fos!=null){
fos.close();
}
}
}
}
这样会直接输出字符串而不是ASCII码
序列化(把对象变成字节)
反序列化:字节变为对象
package Chap04;
import java.io.*;
public class M08 {
//构建了一个分层管道系统,允许将Java对象通过以下流程写入文件: 对象 → 智能处理站(序列化为字节流) → 物理管道 → 文件
public static void main(String[] args) {
File file=new File("E:\\Coding\\Java-Project\\untitled1\\data\\nfie.txt");
//对象输出流
ObjectOutputStream fis=null;
FileOutputStream fos=null;
try{ //文件输入流,管道对象
fos=new FileOutputStream(file);
fis = new ObjectOutputStream(fos);//顺序不可变,ObjectOutputStream装饰类必须依附于一个OutputStream
User user=new User();
fis.writeObject(user);
fis.flush();
}
catch(IOException e){
e.printStackTrace();
}finally{
if(fis!=null){try{fis.close();}
catch(IOException e){e.printStackTrace();
}
}
}
}
}
class User implements Serializable{
}
反序列化就是改成ObjectInputStream,FileInputStream即可
然后Object o=fis.readObject();即可
九、线程
进程
定义:自己写的程序就是一个进程,它的名字就是执行的类的名字。
线程
定义:java程序运行时候默认就会产生一个进程,这个进程会有一个主线程,代码都在主线程中执行。
创建线程
package Chap04;
public class TT {
public static void main(String[] args) {
myThread t=new myThread();
t.start();
System.out.println("MyThread"+Thread.currentThread().getName());
}
}
class myThread extends Thread{
//重写运行指令 ctrl+o
@Override
public void run() {
System.out.println("MyThread"+Thread.currentThread().getName());
}
}
运行结果是:
main
MyThread
两条县城互不干扰,没有必然先后关系,但是新的线程要准备,因此启动时候会慢于main线程
生命周期
线程的生命周期主要包括以下几个状态:
NEW: 线程新建状态
RUNNABLE: 就绪状态 (可运行状态)
RUNNING: 运行状态 (等待状态)
BLOCKED: 堵塞状态
TERMINTED: 终止状态
runnable可以转换为除了首尾的其他状态
线程执行方式
串行执行,并发执行
- 先来看并发执行:如下列代码,除了main线程,其他两个线程启动顺序不一定,谁先抢到CPU执行权就算谁的
package Chap04;
public class TT {
public static void main(String[] args) {
myThread t1=new myThread();
myThread2 t2=new myThread2();
t1.start();
t2.start();
System.out.println("main执行完毕");
}
}
class myThread extends Thread{
//重写运行指令
@Override
public void run() {
System.out.println("MyThread"+Thread.currentThread().getName());
}
}
class myThread2 extends Thread{
//重写运行指令
@Override
public void run() {
System.out.println("MyThread2"+Thread.currentThread().getName());
}
}
- 串行
package Chap04;
public class TT {
public static void main(String[] args) throws InterruptedException {
myThread t1=new myThread();
myThread2 t2=new myThread2();
t1.start();
t1.join();//相当于阻塞,等待t1执行完毕才会执行下一线程
t2.start();
t2.join();
System.out.println("main执行完毕");
}
}
class myThread extends Thread{
//重写运行指令
@Override
public void run() {
System.out.println("MyThread"+Thread.currentThread().getName());
}
}
class myThread2 extends Thread{
//重写运行指令
@Override
public void run() {
System.out.println("MyThread2"+Thread.currentThread().getName());
}
}
线程休眠
package Chap04;
public class TTTT {
public static void main(String[] args) throws InterruptedException {
Thread.sleep(1000);//休眠一秒钟
System.out.println("Hello");
while(true){
Thread.sleep(1000);//休眠一秒钟
System.out.println("Hello");//每一秒钟打印一个
}
}
}
工作
package Chap04;
public class RRRR {
public static void main(String[] args) {
Thread3 t3 = new Thread3();
t3.start();
Thread4 t4 = new Thread4();
t4.start();
System.out.println("main执行完毕");
}
}
class Thread3 extends Thread {
public void run() {
System.out.println("Thread3: " );
}
}
class Thread4 extends Thread {
public void run() {
System.out.println("Thread4: " );
}
}
结果:
Thread3:
main执行完毕
Thread4:
主线程在启动子线程后会继续执行后续代码(System.out.println(“main执行完毕”)),而子线程的执行由JVM调度器决定。由于线程调度的不确定性,t3的run()方法可能在主线程打印"main执行完毕"前被调度执行
线程池
同步
关键字synchronized,可修饰方法和代码块
方法:public synchronized void test
代码块:synchronized(用于同步的对象){处理逻辑 }
package Chap04;
public class Tongbu {
public static void main(String[] args) {
NUMBER number=new NUMBER();
KeHu kehu=new KeHu(number);
kehu.start();
Bank bank=new Bank(number);
bank.start();
}
}
class NUMBER{}
class KeHu extends Thread{
private NUMBER number;
public KeHu(NUMBER number){
this.number=number;
}
public void run(){
synchronized (number){
System.out.println("银行没开门我先等一会");
try {
number.wait(20000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("银行开门了,我可以办业务了");
}}
}
class Bank extends Thread{
private NUMBER number;
public Bank(NUMBER number){
this.number=number;
}
public void run() {
synchronized (number) {
System.out.println("银行开门了");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
number.notify();
}
}
}
wait和sleep
wait:等待(成员方法) sleep:休眠(静态方法)
使用方法:
wait:只能使用在同步代码中。
sleep:可以在任意地方使用。
阻塞时间:
w:超时时间
s:休眠时间(不会发生错误)
同步处理:
w:如果执行,那么其他线程有机会执行当前同步操作
s:如果执行,那么其他线程没有机会执行当前同步操作
十、反射
java中的类主要分为三种:
核心类库中的(String,Object):加载类时,采用操作系统平台语言实现
JVM软件平台开发商
自己写的类
类加载器也有三种:
BootClassLoader:启动类加载器
PlatformClassLoader:平台类加载器
AppClassLoader:应用类加载器
加载顺序:
核心类库>平台类库>自己类
857

被折叠的 条评论
为什么被折叠?



