Set集合的特点和应用
特点:
不可重复、无序
应用:
Set< T > set = new HashSet<>();
结论:
Set集合保证元素的唯一性依赖:equals()和hashCode()两个方法
package cn.itcast.demo8;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class Test {
public static void main(String[] args) {
//1.创建集合对象
Set<Student> set = new HashSet<>();
//2.创建元素对象
Student s1 = new Student("Q",41);
Student s2 = new Student("W",31);
Student s3 = new Student("E",21);
Student s4 = new Student("E",21);
Student s5 = new Student("Q",41);
//3.将集合对象添加到元素对象中
set.add(s1);
set.add(s2);
set.add(s3);
set.add(s4);
set.add(s5);
//4.遍历对象
/*
为什么Set集合没有“去除”?
因为Set集合保证元素的唯一性依赖:equals()和hashCode()两个方法
你没有在Student类中重写这两个方法,默认调用的是Object类中的这两个方法
而Object类中的equals()方法默认比较的是地址值是否相同
解决方案:
在student类中重写equals()和hashCode()方法
*/
System.out.println(set);
System.out.println("-----------------");
//通过迭代器遍历Set集合
System.out.println("通过迭代器遍历Set集合");
//A.通过集合对象获取其对应的迭代器对象
Iterator<Student> it = set.iterator();
//B.判断迭代器中是否有元素
while (it.hasNext()) {
//C.如果有,就获取元素
Student s = it.next();
System.out.println(s);
}
System.out.println("-----------------");
//通过增强for循环遍历Set集合
System.out.println("通过增强for循环遍历Set集合");
for (Student student : set) {
System.out.println(student);
}
}
}
Map集合的特点和应用
特点:
双列集合,元素由键值对(entry)构成;key — value。
key不可以重复,value可以重复
应用:
Map<T1,T2> map = new HashMap<>();
T1:表示键的数据类型;T2:表示值的数据类型
成员方法:
V put (K key ,V value):添加元素(键值对的形式),元素第一次添加,返回null,重复添加,会用新值覆盖旧值,并返回旧值
V get (Object key):根据键获取其对应的值
Set< K > key Set():获取所有键的集合
遍历步骤:
1.获取所有键的集合 keySet()
2.遍历所有的坚,获取到每一个键 迭代器/增强for
3.根据键,获取指定的值 get()
package cn.itcast.demo8;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class Test {
public static void main(String[] args) {
//1.创建集合对象
//键:学生的编号;值:具体的学生对象
Map<Integer,Student> map = new HashMap<>();
//2.创建元素对象
Student s1 = new Student("Q",24);
Student s2 = new Student("W",23);
Student s3 = new Student("Q",24);
//3.将元素对象添加到集合中
/*Student stu1 = map.put(1,s1);
System.out.println("stu1:" + stu1);
Student stu2 = map.put(1,s2);
System.out.println("stu2:" + stu2);*/
map.put(1,s1);
map.put(2,s2);
map.put(3,s3);
Student stu3 = map.get(3);
System.out.println("key:" + 3 + ",value" + stu3);
System.out.println(map);
System.out.println("------------------");
//4.遍历集合
/*Set<Integer> keys = map.keySet();
Iterator<Integer> it = keys.iterator();
while (it.hasNext()){
Integer key = it.next();
Student value = map.get(key);
System.out.println("key:" + key + "...value" + value);
}*/
Set<Integer> keys = map.keySet();
for (Integer key : keys) {
//key就是双列集合中的每一个键
Student v = map.get(key);
System.out.println(v);
}
}
}
package cn.itcast.demo8;
import java.util.Objects;
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age &&
Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
案例:模拟斗地主发牌
package cn.itcast.demo8;
import java.util.*;
/*
案例:模拟斗地主发牌
步骤:1.买牌 /2.洗牌 /3.发牌 /4.看牌
*/
public class SendPokerTest {
public static void main(String[] args) {
//1. 买牌
//1.1 定义一个双列集合,键:表示牌的编号;值:表示具体的牌。规则:编号越小,牌越小
Map<Integer,String> pokers = new HashMap<>();
//1.2 定义一个单列集合,用来存储所有牌的编号
List<Integer> list = new ArrayList<>();
//1.3 具体的买牌动作
int num = 0;
String[] colors = {"♠","♥","♣","♦"};
String[] numbers = {"3","4","5","6","7","8","9","10","J","Q","K","A","2"};
for (String number : numbers) {
for (String color : colors){
String poker = color + number;
pokers.put(num,poker);
list.add(num);
num++;
}
}
pokers.put(num,"小王");
list.add(num++);
pokers.put(num,"大王");
list.add(num++);
System.out.println("所有的牌:" + pokers);
System.out.println("牌的编号:" + list);
System.out.println("---------------------------");
//2.洗牌
Collections.shuffle(list);
System.out.println( "洗好牌后牌的编号为:" + list);
//3. 发牌
//3.1 定义4个集合,分别表示3个玩家,底牌
List<Integer> LiuYiFei = new ArrayList<>();
List<Integer> JungSooJung = new ArrayList<>();
List<Integer> Wo = new ArrayList<>();
List<Integer> DiPai = new ArrayList<>();
//3.2 具体的发牌动作,将索引和3取模,决定发给谁
for (int i = 0; i < list.size(); i++){
Integer pokerNum = list.get(i);
if (i >= list.size() - 3){
DiPai.add(pokerNum);
} else if (i % 3 == 0){
LiuYiFei.add(pokerNum);
} else if (i % 3 == 1){
JungSooJung.add(pokerNum);
} else if (i % 3 == 2){
Wo.add(pokerNum);
}
}
/* //3.3 查看玩家,底牌的编号
System.out.println("LiuYiFei:" + LiuYiFei);
System.out.println("JungSooJung:" + JungSooJung);
System.out.println("Wo:" + Wo);
System.out.println("DiPai:" + DiPai);*/
System.out.println("---------------------------");
//3.3
/*String str = printPoker(LiuYiFei,pokers);
System.out.println("LiuYiFei:" + str);*/
System.out.println("LiuYiFei:" + printPoker(LiuYiFei,pokers));
System.out.println("JungSooJung:" + printPoker(JungSooJung,pokers));
System.out.println("Wo:" + printPoker(Wo,pokers));
System.out.println("DiPai:" + printPoker(DiPai,pokers));
/*
4.定义一个方法,用来看牌
方法名: printPoker
参数列表:List<Integer>,Map<Integer,String>
返回值: String
*/
}
public static String printPoker(List<Integer> nums ,Map<Integer,String> pokers){
//1.对牌的编号进行升序排列
Collections.sort(nums);
//2.遍历牌的编号集合,获取到每一个编号
StringBuilder sb = new StringBuilder();
for (Integer num : nums) {
//3.根据编号去双列集合中查找改编号对应的具体牌
String poker = pokers.get(num);
//4.将获取到的牌进行拼接
sb.append(poker + " ");
}
//5.将最后拼接结果返回即可
String str = sb.toString();
return str.trim();
}
}
异常的分类
顶层父类:
Throwable
异常(Exception):
合理的应用程序可能需要捕获的问题,例:NullPointerException
错误(Error):
合理的应用程序不应该试图捕获的问题,例:StackOverFlowError
异常的处理方式
JVM默认的异常处理方式:
在控制台打印错误信息,并终止程序
开发中异常的处理方式:
try…catch ( finally ): 捕获,自己处理
try{
//尝试执行的代码
}
catch(Exception e){
//出现可能的异常之后的处理代码
}
finally{
//一定会执行的代码,如关闭资源
}
处理完异常之后,程序会继续执行
执行流程:先执行try{}中的内容,看是否有问题(异常);没有的话,直接执行finally语句中的内容,有的话,跳转到catch(){}语句中开始执行,再执行finally{}语句中的内容
package cn.itcast.demo8;
public class Test {
public static void main(String[] args) {
/*int a = 10 / 0;
System.out.println("a:" + a);
System.out.println("TEST");*/
//通过try.catch.finally来处理异常
try{
int a = 10 / 10;
System.out.println("a:" + a);
return;
} catch(Exception e){
System.out.println("被除数不能为0");
return;
} finally { //即使try或者catch中有return,finally里边的代码也会执行
System.out.println("TEST");
}
// System.out.println("TEST");
}
}
throws: 抛出,交给调用者处理
特点:执行结束后,程序不再继续执行
package cn.itcast.demo8;
public class Test {
public static void main(String[] args) throws Exception {
//需求:调用show()
//因为show()方法已经抛出了一个异常,作为调用者(main函数)必须处理这个异常
/*//方案一:接着抛
show();*/
//方案二:采用try.catch处理
try{
show();
}catch (Exception e){
System.out.println("ERROR!");
}
System.out.println("TEST");
}
//定义一个方法
public static void show() throws Exception{
int a = 10 / 0;
System.out.println("a:" + a);
}
}
IO流概述
什么是IO流?
I/O,即输入(Input)输出(Output),IO流指的是数据像连绵的流体一样进行传输。
IO流可以干什么?
再本地磁盘和网络上操作数据
IO流的分类
按数据流向分:输入流 / 输出流
按操作方式分:字节流:InputStream-OutputStream / 字符流:Reader-Writer
IO流体系
1.字符流:按字符读写数据的IO流。Reader:FileReader-BufferedReader;Writer:FileWriter-BufferedWriter
2.字节流:按字节读写数据的IO流。InputStream:FileInputStream-BufferedInputStream;OutputStream:FileOutputStream-BufferedOutputStream
IO流简介:
概述:
I(Input,输入)/ O(Output,输出)流,是Java中用来传输数据的方式。
划分:
按照流向分:
输入流:读数据
输出流:写数据
按照操作分:
字节流:以字节为单位来操作数据
InputStream: 字节输入流的顶层抽象类
FileInputStream: 普通的字节输入流
BufferedInputStream: 高效的字节输入流(也叫:缓冲字节输入流)
OutputStream: 字节输出流的顶层抽象类
FileOutputStream: 普通的字节输出流
BufferedOutputStream: 高效的字节输出流(也叫:缓冲字节输出流)
字符流:以字符为单位来操作数据
Reader: 字符输入流的顶层抽象类
FileReader: 普通的字符输入流
BufferedReader: 高效的字符输入流(也叫:缓冲字符输入流)
Writer: 字节输出流的顶层抽象类
FileWriter: 普通的字符输出流
BufferedWriter: 高效的字符输出流(也叫:缓冲字符输出流)
File类
概念:
文件,文件夹,一个对象代表磁盘上的某个文件或文件夹
构造方法:
File(String pathname)
File(String parent,String child)
File(File parent,String child)
成员方法:
1.创建功能——createNewFile():创建文件;mkdir()和mkdirs():创建目录
2.判断功能——isDirectory():判断File对象是否为目录;isFile():判断File对象是否为文件;exists():判断File对象是否存在。
package cn.itcast.demo8;
import java.io.File;
import java.io.IOException;
public class Test {
public static void main(String[] args) throws IOException {
//需求:将D:\abc\1.txt封装成对象
//法一:根据字符串形式的路径获取FIle对象
// File file1 = new File("D:\\abc\\1.txt");
File file1 = new File("D:/abc/1.txt");
System.out.println(file1);
//法二:根据字符串形式的父目录以及子目录创建File对象
File file2 = new File ("D:/abc/","1.txt");
System.out.println(file2);
//法三:根据父目录对象,以及字符串形式的子目录来获取File对象
File file3 = new File("D:/abc/");
File file4 = new File(file3,"1.txt");
System.out.println(file4);
System.out.println("----------------------");
System.out.println("创建对象");
File file5 = new File("D:/2.txt");
boolean flag1 = file5.createNewFile();
System.out.println(flag1);
File file6 = new File("D:/a");
boolean flag2 = file6.mkdir(); //make directory,创建单级目录
System.out.println(flag2);
File file7 = new File("D:/a/b/c");
// boolean flag3 = file7.mkdir();
boolean flag3 = file7.mkdirs(); //创建多级目录(也可以创建单级目录)
System.out.println(flag3);
System.out.println("----------------------");
System.out.println("创建判断功能");
File file8 = new File("D:/a/b");
/*boolean flag4 = file8.isDirectory();
System.out.println("是否文件夹:" + flag4);*/
System.out.println("是否文件夹:" + file8.isDirectory());
System.out.println("是否是文件: " + file8.isFile());
System.out.println("是否存在: " + file8.exists());
}
}
3.获取功能——getAbsolutePath():获取绝对路径(以盘符开头的路径),如 D:/1.txt;getPath():获取文件的绝对路径 (一般是相对于当前项目路径来讲的),如1.txt;getName():获取文件名;list():获取指定目录下所有文件(夹)名称数组;listFiles():获取指定目录下所有文件(夹)File数组。
package cn.itcast.demo1;
import java.io.File;
public class Test {
public static void main(String[] args) {
File file1 = new File("lib/1.txt");
//获取file1的绝对路径
System.out.println(file1.getAbsolutePath());
//获取file1的相对路径
System.out.println(file1.getPath());
//获取文件名
System.out.println(file1.getName());
System.out.println("---------------------------");
//获取lib文件夹下所有的文件(夹)的:名称数组
File file2 = new File("lib");
String[] names = file2.list();
for (String name : names) {
System.out.println(name);
}
System.out.println("---------------------------");
//获取lib文件夹下所有的文件(夹)的:File对象数组 File[]
File[] files = file2.listFiles();
for (File file : files) {
System.out.println(file);
}
}
}
字符流读数据 - 按单个字符读写
创建字符流读文件对象:
Reader reader = new FileReader(“readme.txt”);
调用方法读取数据:
int data = reader.read();
读取一个字符,返回该字符代表的整数,若到达流的末尾,返回-1
异常处理:
throws IOException
关闭资源:
reader.close();
package cn.itcast.demo1;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
public class ReaderDemo1 {
public static void main(String[] args) throws IOException {
//通过字符流读取数据
//1.创建字符输入流对象
Reader reader = new FileReader("lib/1.txt");
//2.读取数据
/*int ch1 = reader.read();
System.out.println(ch1); //97
int ch2 = reader.read();
System.out.println(ch2); //98
int ch3 = reader.read();
System.out.println(ch3); //99
int ch4 = reader.read();
System.out.println(ch4); //-1*/
/*
优化上述的读法,用循环改进
又因为不知道循环次数,所以用while循环
*/
//定义变量,用来接收读取到的字符
int ch;
/*
(ch = reader.read()) != -1 做的三件事
1.执行(ch = reader.read()),去文件中读取一个字符。
2.执行 ch = reader.read(),将读取到的字符赋值给变量。
3.(ch = reader.read()) != -1,用读取到的字符(内容)与 -1 进行比较
*/
while ((ch = reader.read()) != -1){
System.out.println(ch);
}
//3.释放资源
reader.close();
}
}
字符流读数据 - 一次读取一个字符数组
创建字符流读文件对象:
Reader reader = new FileReader(“readme.txt”);
调用方法读取数据:
char[ ] chs = new char [2048];
int len = r.read.(chs);
读取字符到数组中,返回读取的字符数,若到达流的末尾,返回-1
异常处理:
throws IOException
关闭资源:
reader.close();
package cn.itcast.demo1;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
public class ReaderDemo2 {
public static void main(String[] args) throws IOException {
//需求:通过字符流读取数据,一次读取一个字符数组
//1.创建字符输入流对象
Reader reader = new FileReader("lib/2.txt");
//2.读取数据
/*char[] chs = new char[3];
int len1 = reader.read(chs);
System.out.println(chs); //abc
System.out.println(len1); //3
int len2 = reader.read(chs);
System.out.println(chs); //def
System.out.println(len2); //3
int len3 = reader.read(chs);
System.out.println(chs); //gef
System.out.println(len3); //1
int len4 = reader.read(chs);
System.out.println(chs); //def
System.out.println(len4); //3*/
/*
用while循环优化上述的代码
*/
char[] chs = new char[3];
//定义一个变量,记录读取到的有效字符数
int len;
while ((len = reader.read(chs)) != -1){
//将读取到的内容转换成字符串
/*
chs:表示要操作的数组
0:表示起始索引
len:表示要操作的字符的个数
*/
String s = new String(chs,0,len);
System.out.println(s);
}
//3.释放资源
reader.close();
}
}
字符流写数据 - 按单个字符写入
创建字符流写文件对象:
Writer writer = new FileWriter(“dest.txt”);
调用方法写入数据:
int x = ‘中’;
writer.write(x);
写一个字符
异常处理:
throws IOException
关闭资源:
writer.close();
字符流写数据 - 按单个字符写入
创建字符流写文件对象:
Writer writer = new FileWriter(“dest.txt”);
调用方法写入数据:
char[ ] chs = {‘橙’,‘心’,‘橙’,‘意’};
writer.write(chs);
写一个字符数组
异常处理:
throws IOException
关闭资源:
writer.close();
字符流写数据 - 按字符串写入
创建字符流写文件对象:
Writer writer = new FileWriter(“dest.txt”);
调用方法写入数据:
writer.write(“我爱学习”);
写一个字符串
异常处理:
throws IOException
关闭资源:
writer.close();
package cn.itcast.demo2;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
public class WriterDemo {
public static void main(String[] args) throws IOException {
//通过字符流写数据
//1.创建字符输出流对象
Writer writer = new FileWriter("lib/1.txt");
//2.写数据
/*//一次写一个字符
writer.write('i');*/
/*//一次写一个指定的字符
char[] chs = {'h','e','l','l','o'};
writer.write(chs);
// writer.write(chs,0,2);*/
//一次写一个字符串
writer.write("HelloWorld");
//3.释放资源
writer.close();
}
}
字符流拷贝文件 - 按单个字符读写
创建字符流读文件对象:
Reader reader = new FileReader(“readme.txt”);
调用字符流写文件对象:
Writer writer = new FileWriter(“dest.txt”);
调用方法读取数据:
int data = reader.read();
调用方法写入数据:
writer.write(data);
异常处理:
throws IOException
关闭资源:
reader.close();
write.close();
package cn.itcast.demo3;
import java.io.*;
public class CopyFile1 {
public static void main(String[] args) throws IOException {
//需求:通过字符流拷贝文件,一次读写一个字符
//例如:将1.txt文件中的内容赋值到2.txt文件中
/*
IO流拷贝文件核心六步:
1.创建字符输入流对象,关联数据源文件
2.创建字符输出流对象,关联目的地文件
3.定义变量,记录读取到的内容
4.循环读取,只要条件满足就一直读,并将读取到的内容赋值给变量
5.将读取到的数据写入到目的地文件中
6.释放资源
*/
//1
//Reader reader = new FileReader("lib/1.txt");
FileReader fr = new FileReader("lib/1.txt");
//2
FileWriter fw = new FileWriter("lib/2.txt"); //如果目的地文件不存在,程序会自动创建
//3
int len;
//4
while ((len = fr.read()) != -1){
//5
fw.write(len);
}
//6
fr.close();
fw.close();
}
}
字符流拷贝文件 - 按字符数组读写
创建字符流读文件对象:
Reader reader = new FileReader(“readme.txt”);
调用字符流写文件对象:
Writer writer = new FileWriter(“dest.txt”);
调用方法读取数据:
char[ ] chs = new char[2048];
int len = reader.read(chs);
调用方法写入数据:
writer.write(chs, 0, len);
异常处理:
throws IOException
关闭资源:
reader.close();
writer.close();
package cn.itcast.demo3;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class CopyFile2 {
public static void main(String[] args) throws IOException {
//需求:通过字符流拷贝文件,一次读写一个字符数组
//例如:将1.txt文件中的内容复制到2.txt文件中
/*
IO流拷贝文件核心六步:
1.创建字符输入流对象,关联数据源文件
2.创建字符输出流对象,关联目的地文件
3.定义变量,记录读取到的内容
4.循环读取,只要条件满足就一直读,并将读取到的内容赋值给变量
5.将读取到的数据写入到目的地文件中
6.释放资源
*/
//1
FileReader fr = new FileReader("lib/1.txt");
//2
FileWriter fw = new FileWriter("lib/2.txt");
//3
//定义一个字符数组
char[] chs = new char[1024];
//用来记录读取到的有效字符数
int len;
//4
while ((len = fr.read(chs)) != -1){
//5
fw.write(chs,0,len);
}
fr.close();
fw.close();
}
}
字符缓冲流拷贝文件的标准代码
创建字符流写文件对象:
BufferReader br = new BufferedReader(new FileReader(“readme.txt”));
创建字符流写文件对象:
BufferedWriter bw = new BufferedWriter(new FileWriter(“dest.txt”));
异常处理:
throws IOException
使用while循环读写数据:
int len ;
while((len = br.read()) !+ -1){
bw.write(len);
}
关闭资源:
br.close();
bw.close();
package cn.itcast.demo4;
/*
字符缓冲流用法:
分类:
BufferedReader:字符缓冲输入流(也叫高效字符输入流)
构造方法:
public BufferedReader(Reader reader);
BufferedWriter:字符缓冲输出流(也叫高效字符输出流)
构造方法:
public BufferedWriter(Writer writer);
特点:
字符缓冲流自带有缓冲区,大小为8192个字符,也就是16KB
*/
import java.io.*;
public class CopyFile1 {
public static void main(String[] args) throws IOException {
//需求:通过字符缓冲流,将1.txt文件中的内容拷贝到2.txt文件中
//1.创建字符缓冲输入流对象,关联数据源文件
//1.1 创建普通的字符输入流对象
FileReader fr = new FileReader("lib/1.txt");
//1.2 创建字符流缓冲输入流对象
BufferedReader br = new BufferedReader(fr);
//简化上述的代码
// BufferedReader br2 = new BufferedReader(new FileReader("lib/1.txt"));
//2.创建字符缓冲输出流对象,关联目的地文件
//2.1 创建普通的字符输出流对象
FileWriter fw = new FileWriter("lib/2.txt");
//2.2 创建字符流缓冲输出流对象
BufferedWriter bw = new BufferedWriter(fw);
//3.定义变量,记录读取到的数据
int len;
//4.循环读取,只要条件满足就一直读,并将读取到的内容赋值给变量
while ((len = br.read()) != -1){
//5.将读取到的数据写入到目的地文件中
bw.write(len);
}
//6.释放资源
br.close();
bw.close();
}
}
package cn.itcast.demo4;
import java.io.*;
public class CopyFile2 {
/*
字符缓冲流用法:
分类:
BufferedReader:字符缓冲输入流(也叫高效字符输入流)
成员方法:
public String readLine;
BufferedWriter:字符缓冲输出流(也叫高效字符输出流)
构造方法:
public void newLine(); 根据当前操作系统给出对应的换行符:
windows:\r\n
mac:\r
unix:\n
特点:
字符缓冲流自带有缓冲区,大小为8192个字符,也就是16KB
*/
public static void main(String[] args) throws IOException {
//需求:通过字符缓冲流“一次读写一行”的方式,将1.txt文件中的内容拷贝到2.txt文件中
//1.创建字符流缓冲输入流对象,关联数据源文件
//分开写
/*FileReader fr = new FileReader("lib/1.txt");
BufferedReader br = new BufferedReader(fr);*/
//合并
BufferedReader br = new BufferedReader(new FileReader("lib/1.txt"));
//2.创建字符缓冲流输出流对象,关联目的地文件
BufferedWriter bw = new BufferedWriter(new FileWriter("lib/2.txt"));
//3.定义变量,记录读取到的内容
String str;
//4.循环读取,只要条件满足就一直读,并将读取到的内容赋值给变量
while ((str = br.readLine()) != null){
//5.将读取到的内容写入到目的地文件中
bw.write(str);
//千万注意一个小细节,特别容易忽略——换行
// bw.write("\r\n");
bw.newLine();
}
//6.释放资源
br.close();
bw.close();
}
}
普通字节流 - 一次读写一个字节
创建字节流读文件对象:
InputStream is = new FileInputStream(“Desktop.jpg”);
创建字节流写文件对象:
OutputStreas os = new FileOutputStream(“D:\xxx.jpg”);
异常处理:
throws IOException
使用while循环读写数据:
int b;
while((b = is.read()) != -1){
os.write(b);
}
关闭资源:
is.close();
os.close();
package cn.itcast.demo1;
/*
字节流的用法
File InputStream:普通的字节输入流,用来读取数据的
构造方法:
public FileInputStream(String pathname);
成员方法:
public ine read(); 一次读取一个字节,并返回读取到的内容,读不到返回-1
FileOutputStream:普通的字节输出流,用来写数据的
构造方法:
public FileOutputStream(String pathname);
成员方法:
public void write(int len); 一次写入一个字节
*/
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class CopyFile1 {
public static void main(String[] args) throws IOException {
//需求:通过普通的字节流,一次读写一个字节的方式,将a.jpg复制到b.jpg
//1.创建字节输入流,关联数据源文件
FileInputStream fis = new FileInputStream("lib/a.jpg");
//2.创建字节输出流,关联目的地文件
FileOutputStream fos = new FileOutputStream("lib/b.jpg");
//3.定义变量,用来记录读取到的内容
int len;
//4.循环读取,只要条件满足就一直读,并将读取到的内容赋值给变量
while ((len = fis.read()) != -1){
//5.将读取到的内容写入到目的地文件中
fos.write(len);
}
//6.释放资源
fis.close();
fos.close();
}
}
普通字节流 - 一次读写一个字节数组
创建字节流读文件对象:
InputStream is = new FileInputStream("Desktop.jpg);
创建字节流写文件对象:
OutputStream os = new FileOutputStream(D:\xxx.jpg);
异常处理:
throws IOException
定义字节数组,每次读取2048个字节:
byte [ ] b = new byte[2048];
使用while循环读写数据:
int len;
while((len = is.read(b) != -1){
os.write(b,0,len);
}
关闭资源:
is.close();
os.close();
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class CopyFile2 {
/*
字节流的用法
File InputStream:普通的字节输入流,用来读取数据的
成员方法:
public int read(byte[] bys); 一次读取一个字节数组,将读取到的内容存入到数组中,并返回读取到的有效字节数,读不到返回-1
FileOutputStream:普通的字节输出流,用来写数据的
成员方法:
public void write(byte[] bys,int index,int len); 一次写入一个字节
*/
public static void main(String[] args) throws IOException {
//需求:通过普通的字节流,一次读写一个字节数组的方式,将a.jpg复制到b.jpg
//1.创建字节输入流,关联数据源文件
FileInputStream fis = new FileInputStream("lib/a.jpg");
//2.创建字节输出流,关联目的地文件
FileOutputStream fos = new FileOutputStream("lib/b.jpg");
//3.定义变量,用来记录读取到的内容
byte[] bys = new byte[1024];
//用来记录读取到的有效字节数
int len;
//4.循环读取,只要条件满足就一直读,并将读取到的内容赋值给变量
while ((len = fis.read(bys)) != -1){
//5.将读取到的内容写入到目的地文件中
fos.write(bys,0,len);
}
//6.释放资源
fis.close();
fos.close();
}
}
字节缓冲流拷贝文件的标准代码
创建字节流读文件对象:
BufferedInputStream bis = new BufferedInputStream(
new FileInputStream(“a.jpg”));
创建字节流写文件对象:
BufferedOutStream bos = new
BufferedOutputStream(new FileOutputStream(
“b.jpg”));
异常处理:
throws IOException
使用while循环读取数据:
int len;
while((len = bis.read()) != -1){
bos.write(len);
}
关闭资源:
bis.close();
bos.close();
总结:
拷贝纯文本文件使用字符流,拷贝其他(图片,音频,视频等)使用字节流。
package cn.itcast.demo2;
/*
字节缓冲流的用法
BufferedInputStream:字节缓冲输入流(也叫:高效字节输入流),用来读取数据的
构造方法:
public BufferedInputStream(InputStream is);
成员方法:
public ine read(); 一次读取一个字节,并返回读取到的内容,读不到返回-1
BufferedOutputStream:字节缓冲输出流(也叫:高效字节输出流),用来写数据的
构造方法:
public BufferedOutputStream(String pathname);
成员方法:
public void write(int len); 一次写入一个字节
特点:
字节缓冲流有自己的缓冲区,大小为8192个字节,也就是8KB
*/
import java.io.*;
public class CopyFile1 {
public static void main(String[] args) throws IOException {
//需求:通过字节缓冲流,将a.jpg复制到b.jpg中
//1.创建字节输入流,关联数据源文件
/*//1.1 创建普通的字节输入流
FileInputStream fis = new FileInputStream("lib/a.jpg");
//1.2 创建高效的字节输入流
BufferedInputStream bis = new BufferedInputStream(fis);*/
//合并版
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("lib/a.jpg"));
//2.创建字节输出流,关联目的地文件
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("lib/b.jpg"));
//3.定义变量,用来记录读取到的内容
int len;
//4.循环读取,只要条件满足就一直读,并将读取到的内容赋值给变量
while ((len = bis.read()) != -1){
//5.将读取到的内容写入到目的地文件中
bos.write(len);
}
//6.释放资源
bis.close();
bos.close();
}
}
案例:模拟用户上传头像
package cn.itcast.demo;
import java.io.*;
import java.util.Scanner;
public class UploadFile {
public static void main(String[] args) throws IOException {
//需求:模拟用户上传头像的功能,假设所有的用户头像都应该上传到:项目下的lib文件夹中
//1.定义一个方法用来获取要上传的用户头像的路径。 getPath();
File path = getPath();
System.out.println(path);
//2.定义一个方法用来判断眼上传的用户头像,在lib文件夹中是否存在
boolean flag = isExists(path.getName());
if (flag){
//3.如果存在,提示:该用户头像已经存在,上传失败
System.out.println("该用户头像已经存在,上传失败");
}else{
//4.如果不存在,就上传该用户头像,并提示上传成功
//数据源文件 D:\1.png
//目的地文件 lib/1.png
uploadFile(path);
}
}
public static File getPath(){
//7.因为不知道用户多少次能录入,所以用while(true)改进
while (true){
//1.提示用户录入要上传的用户头像路径,并接收
Scanner sc = new Scanner(System.in);
System.out.println("请录入您要上传的用户头像的路径:");
String path = sc.nextLine();
//2.判断该路径的后缀名是否是:.jpg .png .bmp
//3.如果不是,就提示:您录入的不是图片,请重新录入
if (!path.endsWith(".jpg") && !path.endsWith(".png") && !path.endsWith(".bmp")){
System.out.println("您录入的不是图片,请重新录入");
//细节,千万注意,别忘了写
continue;
}
//4.如果是,判断路径是否存在,并且是否是文件
File file = new File(path);
if (file.exists() && file.isFile()){
//6.如果是,说明就是我们想要的数据(图片,文件),直接返回
return file;
}else{
//5.如果不是,就提示:您录入的路径不合法,请重新录入
System.out.println("您录入的路径不合法,请重新录入");
}
}
}
public static boolean isExists(String path){
//1.将lib文件夹封装成File对象
File file = new File("lib");
//2.获取lib文件夹中所有的文件(夹)的名称数组
String[] names = file.list();
//3.遍历第二步获取到的数组,用获取到的数据依次和path进行比较
for (String name:names){
if (name.equals(path)){
//4.如果一致,说明该用户头像已经存在了,就返回true
return true;
}
}
//5.如果不一致,说明该用户头像不存在,就返回false
return false;
}
public static void uploadFile(File path) throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(path));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("lib/" + path.getName()));
int len;
while((len = bis.read()) != -1){
bos.write(len);
}
bis.close();
bos.close();
System.out.println("上传成功");
}
}
反射基本概念
什么是反射:
在程序运行剁成中分析类的一种能力
作用:
1.分析类:加载并初始化一个类,查看类的所有属性和方法
2.查看并使用对象:查看一个对象的所有属性和方法,使用对象的任意属性和方法
应用场景:
1.构建通用的工具
2.搭建具有高度灵活性和扩展性的系统框架
类加载器(ClassLoader):
负责将类的字节码文件(.class文件)加载到内存中,并生成对应的Class对象
Class对象:
java.lang.Class类的对象,也叫字节码文件对象,每个Class对象对应一个字节码文件
类的加载时机:
1.创建类的实例:Student stu =new Student();
2.访问类的静态成员:Calendar.getInstance();
3.初始化类的子类:class User extends Person{};User user = new User();
4.反射方式创建类的class对象:Class cazz = Class.forName(“类的正名”);
正名:包名 + 类名,例如:cn.itcast.demo1.Student
获取class对象的三种方式:
1.Object类的getClass()方法:Class clazz = 对象名.getClass();
2.类的静态属性:Class clazz = 类名.class;
3.Class类的静态方法:Clas clazz = Class.forName(“类的正名”);
正名:包类路径名,如cn.itcast.bean.Student
package cn.itcast.demo1;
public class ReflectDemo1 {
public static void main(String[] args) throws ClassNotFoundException {
//需求:获取Class对象
//方式一:
Student stu = new Student();
Class clazz = stu.getClass();
//方式二
Class clazz2 = Student.class;
//方式三
Class clazz3 = Class.forName("cn.itcast.demo1.Student");
//思考:如何验证这三个class对象是同一个对象?
System.out.println(clazz == clazz2);
System.out.println(clazz3 == clazz2);
}
}
package cn.itcast.demo1;
public class Student {
}
通过反射的方法获取构造方法并使用
Constructor< T >对象:
构造器对象,属于java.base模块,java.lang.reflect包
通过Class对象获取构造器对象:
1.getConstructor(Class<?>...parameterTypes):返回一个Constructor对象,仅公共构造函数;Class<?>…:可变参数,代表Class类型的数组;?:通配符,代表不确定的任意类型
2.getDeclaredConstructor(Class<?>…parameterTypes):返回一个Constructor对象,可获取私有构造函数
3.getConstructors():返回此类所有(不含私有)构造函数的数组
Constructor的常用方法:
1.String getName():返回构造函数名
2.T newInstance(Object… initargs):使用此构造函数和指定参数创建并初始化对象
package cn.itcast.demo2;
import java.lang.reflect.Constructor;
public class ReflectDemo1 {
public static void main(String[] args) throws Exception {
//需求:通过反射的方式创建:Student类的对象
//1. 获取Student类的字节码文件对象
Class clazz = Class.forName("cn.itcast.demo2.Student");
//2. 根据第一步获取到的字节码文件对象,获取指定的构造器对象
/*//2.1 获取公共的无参构造
Constructor con1 = clazz.getConstructor();
System.out.println(con1);
//2.2 获取公共的带参构造
Constructor con2 = clazz.getConstructor(String.class);
System.out.println(con2);
//2.3 获取私有的有参构造
Constructor con3 = clazz.getDeclaredConstructor(int.class);
System.out.println(con3);
//2.4 获取Student类所有公共的构造函数
System.out.println("----------------------");
Constructor[] con4 = clazz.getConstructors();
// 遍历数组
for (Constructor con : con4) {
System.out.println(con);
}*/
//2.2 获取公共的带参构造
Constructor con2 = clazz.getConstructor(String.class);
System.out.println(con2);
//获取构造器的名字,看看它是哪个类的构造
String name = con2.getName();
System.out.println(name);
//3. 根据构造器对象和参数,创建对应的Student对象
Student stu = (Student) con2.newInstance("ZhangSan");
//4. 打印结果
System.out.println(stu);
}
}
package cn.itcast.demo2;
public class Student {
//公共的无参构造
public Student(){}
//公共的带参构造
public Student(String name){
System.out.println("your name is " + name);
}
//私有的带参构造
private Student(int age){
System.out.println("your age is " + age);
}
}
通过反射的方法获取成员方法并使用
Method对象:
方法对象,属于java.base模块,java.lang.reflect包
通过Class对象获取构造器对象:
1.getMethod(String name,Class<?>…parameterTypes):返回一个method对象,仅公共成员方法;name:方法ming;parameterTypes:方法的参数列表
2.getDeclaredMethod(String,Class<?>…):返回一个Method对象,可获取私有成员方法
3.getMethod():返回此类所有(不含私有)方法的数组
Method的常用方法
1.String getName():返回方法名
2.Object invoke(Object obj,Object…args):在指定对象上调用此方法,参数为args
package cn.itcast.demo3;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class ReflectDemo3 {
public static void main(String[] args) throws Exception {
//需求:通过反射获取Student类中的成员方法并调用
//1. 获取Student类的字节码文件对象
Class clazz = Class.forName("cn.itcast.demo3.Student");
//2. 获取该类的构造器对象,然后创建Student类的对象
Constructor con = clazz.getConstructor();
Student stu = (Student)con.newInstance();
//System.out.println(stu);
//3. 获取该类的成员方法对象,然后调用此方法
//3.1 调用公共的空参方法
Method method1 = clazz.getMethod("show1");
//打印方法对象
System.out.println(method1);
System.out.println("------------------------");
//打印方法名
System.out.println(method1.getName());
System.out.println("------------------------");
//调用此方法
method1.invoke(stu);
System.out.println("------------------------");
//3.2 公共的带参方法
Method method2 = clazz.getMethod("show2", int.class);
method2.invoke(stu,100);
System.out.println("------------------------");
//3.3 私有的带参方法
Method method3 = clazz.getDeclaredMethod("show3", int.class, int.class);
//开启暴力反射
method3.setAccessible(true);
//调用此方法
int sum = (int)method3.invoke(stu,10,20);
System.out.println(sum);
System.out.println("------------------------");
//3.4
Method[] methods = clazz.getMethods();
for (Method method : methods) {
System.out.println(method);
}
}
}
package cn.itcast.demo3;
public class Student {
//公共的空参方法
public void show1(){
System.out.println("EMPTY");
}
//公共的带参方法
public void show2(int a){
System.out.println(a);
}
//私有的带参方法
private int show3(int a ,int b){
System.out.println("PRIVATE");
return a + b;
}
}
案例:通过反射获取方法并使用
package cn.itcast.demo4;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class ReflectDemo1 {
public static void main(String[] args) throws Exception {
//需求:通过反射获取类的setter方法,使用该方法为属性赋值
//1.通过反射获取Student类的字节码文件对象
Class clazz = Class.forName("cn.itcast.demo4.Student");
//2.通过反射获取Student类的构造方法,并创建该类的对象
Constructor con = clazz.getConstructor();
Student stu = (Student)con.newInstance();
//3.获取到指定的setName()方法,给Student对象设置值
Method method1 = clazz.getMethod("setName", String.class);
//调用此方法
method1.invoke(stu,"ZhangWuJi");
//4.打印学生对象
System.out.println(stu);
}
}
package cn.itcast.demo4;
//标准的JavaBean类,学生类
public class Student {
//成员变量
private String name;
//空参构造
public Student() {
}
//带参构造
public Student(String name) {
this.name = name;
}
//get&set
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//toString
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
'}';
}
}
反射方法获取成员变量并使用
Field对象:
域(属性、成员变量)对象,属于java.base模块,java.lang.reflect包
通过Class对象获取属性:
1.getField(String name):返回一个field对象,仅公共属性;name:属性名
2.getDeclaredField(String nam):返回一个field对象,可获取私有属性
3.getDeclaredFields():返回此类所有(含私有)属性的数组
Field的常用方法::
1.void set (Objict obj,Object value):设置obj对象的指定属性值为value
2.void setAccessible(boolean flag):将此属性的可访问性设置为指定布尔值
package cn.itcast.demo5;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
public class ReflectDemo1 {
public static void main(String[] args) throws Exception {
//需求:通过反射获取成员变量并使用
//1.获取Student类的字节码文件对象
Class clazz = Class.forName("cn.itcast.demo5.Student");
//2.通过字节码文件对象获取构造器对象然后创建学生类对象
Constructor con = clazz.getConstructor();
Student stu = (Student)con.newInstance();
// Student stu2 = (Student)clazz.getConstructor().newInstance();
//3.设置学生对象的各个属性值
//3.1 设置姓名
Field field1 = clazz.getField("name");
field1.set(stu,"Q");
//3.2 设置年龄
Field field2 = clazz.getDeclaredField("age");
//开启暴力反射
field2.setAccessible(true);
field2.set(stu,30);
//4.答应学生对象
System.out.println(stu);
}
}
package cn.itcast.demo5;
public class Student {
public String name;
private int age;
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
来源:CSDN
作者:cheng_09
链接:https://blog.csdn.net/cheng_09/article/details/104374080