目录
四、转换流简化写法FileReader、FileWriter
五、 BufferedReader/BufferedWriter
4、将文本文件中的内容读取到属性列表中Properties 加载
1)现在有一个ArrayList,里面有一些元素,如何给ArrayList添加String类型的元素?
2)现在有一个学生类以及工人类,两类都有一个love方法,ReflectTest2在测试类中进行测试
设计模式
一、要素
名字 必须有一个简单,有意义的名字
问题 描述在何时使用模式
解决方案 描述设计的组成部分以及如何解决问题
效果 描述模式的效果以及优缺点
二、分类
创建型模式:简单工厂模式,工厂方法模式,抽象工厂模式,建造者模式,原型模式,单例模式。(6个)
结构型模式:外观模式、适配器模式、代理模式、装饰模式、桥接模式、组合模式、享元模式。(7个)\
行为型模式:模版方法模式、观察者模式、状态模式、职责链模式、命令模式、访问者模式、策略模式、备忘录模式、迭代器模式、解释器模式。(10个)
三、简单工厂模式
简单工厂模式概述
又叫静态工厂方法模式,它定义一个具体的工厂类负责创建一些类的实例
优点
客户端不需要在负责对象的创建,从而明确了各个类的职责
缺点
这个静态工厂类负责所有对象的创建,如果有新的对象增加,或者某些对象的创建方式不同,就需要不断的修改工厂
类,不利于后期的维护
四、工厂方法模式
工厂方法模式概述
工厂方法模式中抽象工厂类负责定义创建对象的接口,具体对象的创建工作由继承抽象工厂的具体类实现。
优点
客户端不需要在负责对象的创建,从而明确了各个类的职责,如果有新的对象增加,只需要增加一个具体的类和具体的 工厂类即可,不影响已有的代码,后期维护容易,增强了系统的扩展性
缺点
需要额外的编写代码,增加了工作量
五、单例设计模式
单例设计模式概述
单例模式就是要确保类在内存中只有一个对象,该实例必须自动创建,并且对外提供。
优点
在系统内存中只存在一个对象,因此可以节约系统资源,对于一些需要频繁创建和销毁的对象单例模式无疑可以提高系 统的性能。
缺点
没有抽象层,因此扩展很难。
职责过重,在一定程序上违背了单一职责
1、如何保证类在内存中只有一个对象呢?
A:把构造方法私有
B:在成员位置自己创建一个对象
C:通过一个公共的方法提供访问
2、单例模式的思想是什么?请写一个代码体现。
开发:饿汉式(是不会出问题的单例模式)
面试:懒汉式(可能会出问题的单例模式)
A:懒加载(延迟加载)
B:线程安全问题
a:是否多线程环境 是
b:是否有共享数据 是
c:是否有多条语句操作共享数据 是
public class Teacher { private Teacher() { } private static Teacher t = null; public synchronized static Teacher getTeacher() { // t1,t2,t3 if (t == null) { //t1,t2,t3 t = new Teacher(); } return t; } } public class TeacherDemo { public static void main(String[] args) { Teacher t1 = Teacher.getTeacher(); Teacher t2 = Teacher.getTeacher(); System.out.println(t1 == t2); System.out.println(t1); System.out.println(t2); } }
1、饿汉式
1)构造方法私有:保证外界不能直接创建当前类对象
2)在当前类的成员位置:创建当前类实例
3)提供一个静态的功能,返回值就是当前类本身(需要当前类的实例)
public class Student {
//成员变量
// public static Student s = new Student() ; //当前类实例
private static Student s = new Student() ; //当前类实例 (静态实例变量)
private Student(){}
//静态功能
//返回是当前类本身
public static Student getStudentInstance(){
return s;
}
}
2、懒汉式
1)构造方法私有化
2)在当前成员变量的位置声明变量:数据类型就是当前类 (私有的,静态的)
3)提供静态功能,返回值还是当前类本身,
判断如果当前没有给当前类型变量为null,直接new 当期类的实例
如果不为null,就返回当前类的变量!
public class Worker {
//成员变量位置声明变量w
private static Worker w;//默认值null
//构造方法私有化
private Worker() {} //外界不能直接new 对象
//改进:同步代码块---->静态的同步方法
public synchronized static Worker getWorkerIntance(){ //锁对象:Worker.class
// synchronized (w){
//w1
//先判断w变量为null
if(w == null){ //当为null
w = new Worker() ; //如果当前w变量为null,创建一个新的对象,返回
return w;
}
return w ;
}
}
六、Runtime类的exec的和运行环境相连接的功能
Runtime:当前获取的当前本地运行环境的实例
public int availableProcessors():获取本地计算机的处理器的数量
public Process exec(String command):开启某个软件的进程(参数为字符串命令)
File
一、构造方法
file:文件和目录(文件夹)路径名的抽象表示
File(String pathname) :参数就是指定的路径/如果没有指定路径(默认是在当前项目下),通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例
File(File parent, String child) :从父抽象路径名和子路径名字符串创建新的 File实例。参数1:父目录地址 参数2:具体的子文件地址
二、成员方法
public boolean createNewFile() throws IOException 表示创建文件 :如果不存在,则创建
public boolean mkdir():创建文件夹,如果不存在,则创建;否则就返回false
public boolean mkdirs() :创建多个文件,如果父目录不存在,则创建
public boolean delete() :删除文件者文件夹(如果删除文件夹,文件夹必须为空目录)
public boolean renameTo(File dest) :重命名
三、判断功能
public boolean canRead()是否可读
public boolean canWrite()是否可写
public boolean exists():是否存在
public boolean isFile():是否是文件
public boolean isDirectory():是否是文件夹
public boolean isHidden():是否隐藏
四、 高级获取功能
public long length()
public String getName():获取抽象路径名所表示的文件或者目录的名称
public File[] listFiles():获取某个目录下的所有的文件以及文件夹的File数组
public String[] list():获取某个抽象路径名所表示的文件以及目录的字符串数组
五、另一个重载功能
public File[] listFiles(FilenameFilter filter)
String[] list(FilenameFilter filter)
boolean accept(File dir,String name):测试指定文件是否包含在文件列表中, 返回如果true,将文件添加到文件列表中
//描述下D盘
File srcFile = new File("D://") ;
//获取当前D盘下的所有文件以及文件夹File数组,并进行文件名过滤
//public File[] listFiles(FilenameFilter filter)
File[] files = srcFile.listFiles(new FilenameFilter() {//接口的匿名内部类
@Override
public boolean accept(File dir, String name) {
//返回true:表示将指定文件添加列表文件中
//描述文件所表示抽象路径File
File file = new File(dir, name);
//两个条件:file是文件并且file的文件名称以".jpg结尾"
return file.isFile() && file.getName().endsWith(".jpg");
}
});
if(files!=null){
for(File f :files){
System.out.println(f.getName());
}
}
递归
一、方法递归
方法调用方法本身的一种现象,并非是方法嵌套方法
二、前提条件
1)必须有一个成员方法
2)必须有方法递归的出口条件(结束条件),如果没有出口条件,就是死递归...
3)还存在一定的规律
三、伪代码
public void show(int n){ //50 调用
if(n<0){
System.out.println(n) ;
}
n -- ;//49
show(n) ;
}
四、求5的阶乘!
public class DiGuiDemo {
public static void main(String[] args) {
System.out.println("5的阶乘是:"+jieCheng(5));
}
//递归:需要考虑(一定要有规律)
private static int jieCheng(int i) {
if(i==1){
return 1 ;
}else{
return i * jieCheng(i-1) ;
}
}
}
五、删除文件
需求:使用递归方式去删除D盘某个demo文件夹中有很多个目录, 每个目录中可能还有目录,删除这些所有目录中的带.java文件的文件!
public class DiGuiTest {
public static void main(String[] args) {
//描述D盘的demo文件夹
File srcFloder = new File("d://demo") ;
//调用递归删除的方法
deleteFloder(srcFloder) ;
}
public static void deleteFloder(File srcFloder) {
//获取srcFloder下的所有的文件以及文件的File数组
File[] fileArray = srcFloder.listFiles();
if(fileArray!=null){
for(File file:fileArray){
//获取到每一个file对象
//如果file是文件夹,继续回到deleteFloder(srcFloder) ; 删除文件夹
if(file.isDirectory()){
deleteFloder(file) ;
}else{
//判断是文件,必须以.java结尾 文件
if(file.getName().endsWith(".java")){
//删除的同时----获取名称
System.out.println(file.getName()+"------------"+file.delete());
}
}
}
//删除文件夹
System.out.println(srcFloder.getName()+"----"+srcFloder.delete());
}
}
}
IO流
IO流的分类
按流的方向
输入流:读入数据
输出流:写出数据
按类型
字节流
字节输入流:InputStream:表示输入字节流的所有类的超类(父类)
字节输出流:OutputStream:表示字节输出流的所有类的超类
字符流
字符输入流:Reader表示输入字符流的抽象类
字符输出流:Writer表示输出字符流的抽象类
一、字节流
字节输出流
1、字节输出流 OutputStream的抽象类
子类进行实例化FileOutputStream:将指定的内容写到文件中
2、实现步骤
1)创建文件输出流对象 :FileOutputStream(String name) :推荐:可以指定参数地址
FileOutputStream(File file)
2)写数据
public void write(int b) throws IOException 写一个字节
public void write(byte[] bytes) throws IOException 写一个字节数组
public void write(byte[] bytes,int off,int len) throws IOException:写一部分字节数组
3)关闭资源
3、字节输出流
private static void method2() {
FileOutputStream fos = null ;
//alt+ctrl+t--->
try {
fos = new FileOutputStream("fos2.txt") ;
//写数据
fos.write("hello,我来了".getBytes());
} catch (IOException e) {
e.printStackTrace();
}finally {
//释放资源
if(fos!=null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
字节输入流
1、字节输入流 InputStream
子类:FileInputStream
2、实现步骤
需要读取当前项目下的fis.txt文件
1)创建文件字节输入流对象,指向 fis.txt
public FileInputStream(String name) throws FileNotFoundException
2)读内容
read(byte[] bytes):一次读取一个字节数组
read():一次读取一个字节
3)释放资源
3、 一次读取一个字节
public class FileInputStreamDemo {
public static void main(String[] args) {
//创建一个字节输入流对象
FileInputStream fis = null ;
try {
fis = new FileInputStream("DiGuiTest.java") ;
//读取内容
//使用循环优化: 结束条件:获取的字节数为-1
//当前不知道循环多少次:while循环
int by = 0 ; //字节数为0
while((by=fis.read())!=-1) {
System.out.print((char)by);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
//释放资源
if(fis!=null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
4、一次读取一个字节数组
public class FileInputStreamDemo2 {
public static void main(String[] args) {
//创建字节输入流对象
FileInputStream fis = null ;
try {
fis = new FileInputStream("fis2.txt") ;
//创建一个数组:长度:1024或者1024的整数倍
byte[] buffer = new byte[1024] ; //长度虽然1024个长度
int len = 0 ;
while((len=fis.read(buffer))!=-1){
//每次获取的从0开始获取实际字节长度
System.out.println(new String(buffer,0,len)) ;
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
读写复制操作
字节流一次读写复制一个字节
private static void method(String srcFile, String destFile) {
FileInputStream fis = null ;
FileOutputStream fos = null ;
try {
// 封装源文件:FileInputStraem(String pathname)
//字节输入流
fis = new FileInputStream(srcFile) ;
//字节输出流
// 封装目的地文件:FileOutputStream(String pathname)
fos = new FileOutputStream(destFile) ;
//读写复制操作
//一次读取一个字节
int by = 0 ;
while((by=fis.read())!=-1){
//没有读完,继续复制 :写一个字节
fos.write(by);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
fos.close();
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
字节流一次读写复制一个字节数组
private static void method2(String srcFile, String destFile) {
FileInputStream fis = null ;
FileOutputStream fos = null ;
try {
// 封装源文件:FileInputStraem(String pathname)
//字节输入流
fis = new FileInputStream(srcFile) ;
//字节输出流
// 封装目的地文件:FileOutputStream(String pathname)
fos = new FileOutputStream(destFile) ;
//读写复制操作
//一次读取一个字节数组
byte[] bytes = new byte[1024] ;
int len = 0 ;
while((len=fis.read(bytes))!=-1){
//赋值
//fos流对象中写
//带上len的使用
fos.write(bytes,0,len);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
fos.close();
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
二、字节缓冲流:缓冲区类(高效类)
特点:
缓冲流的特点:提供缓冲区大写:1024的8倍 还是通过底层流提高读速度(FileInputStream)
字节缓冲输出流
BufferedOutputStream(OutputStream out) 这个:默认缓冲区大小 足够大了 8kb
字节缓冲输入流
BufferedInputStream(InputStream in) :默认缓冲区大写 (足够大了)
读写复制操作
1、字节缓冲流一次读取一个字符
private static void copyMp4_3(String srcFile, String destFile) {
BufferedInputStream bis = null ;
BufferedOutputStream bos = null ;
try {
bis = new BufferedInputStream(new FileInputStream(srcFile)) ;
bos = new BufferedOutputStream(new FileOutputStream(destFile)) ;
//读写操作
int by = 0 ;
while((by=bis.read())!=-1){
bos.write(by);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
bos.close();
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
2、字节缓冲流一次读取一个字符数组
private static void copyMp4_4(String srcFile, String destFile) {
BufferedInputStream bis = null ;
BufferedOutputStream bos = null ;
try {
bis = new BufferedInputStream(new FileInputStream(srcFile)) ;
bos = new BufferedOutputStream(new FileOutputStream(destFile)) ;
//读写操作
byte[] bytes = new byte[1024] ;
int len = 0 ;
while((len=bis.read(bytes))!=-1){
bos.write(bytes,0,len);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
bos.close();
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
三、转换流
字符转换输出流:OutputStreamWriter
提供子类:字符转换输出流: 字节输出流通向字符输出流的桥梁!
OutputStreamWriter 字符转换输出流
public OutputStreamWriter(OutputStream out) 使用平台默认编码集写入数据
public OutputStreamWriter(OutputStream out,String charsetName) 使用指定的字符集进行编码 写入数据
1、写入数据
write(String str)
write(int ch):写入字符: 字符--->对应的ASCII码表
write(char[] ch)
write(char[] ch,int off,int len)
write(String str,int off,int len)
//创建字符缓冲输出流对象
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("osw.txt")) ;
osw.write("hello,字符流我来了");
osw.write(97);
char[] chs = {'A','B','C','D','E'} ;
osw.write(chs);
osw.write(chs,2,2);
//使用flush():刷新字符输出流
osw.flush();
//关闭资源,释放相关的资源
osw.close(); //关闭之前,flush
字符转换输入流 :InputStreamReader
InputStreamReader 字符转换输入流
public InputStreamReader(InputStream in) 使用平台默认解码集进行读
public InputStreamReader(InputStream in,String charsetName) 使用指定的解码集进行读
字符转换流一次读取一个字符、一次读取一个字符数组
//创建字符转换输入流对象
InputStreamReader isr = new InputStreamReader(new FileInputStream("osw.txt")) ;
//读一个字符
int ch = 0;
while ((ch = isr.read()) != -1) {
System.out.print((char) ch);
}
// 释放资源
isr.close();
//读一个字符数组
char[] chs = new char[1024] ;
//实际字符数
int len = 0 ;
while((len=isr.read(chs))!=-1){
//打印控制台上:每次获取的实际长度
System.out.println(new String(chs,0,len));
}
//释放资源
isr.close();
四、转换流简化写法FileReader、FileWriter
读取数据:FileReader(File file)
FileReader(String pathname)写数据 :
FileWriter(File file)
FileWriter(String filename)
转换流简化写法一次读取一个字符、一次读取一个字符数组
//1)封装源文件:
FileReader fileReader = new FileReader("ReaderDemo.java") ;
//2)封装目文件
FileWriter fileWriter = new FileWriter("D://Demo.java") ;
//一次读取一个字符
int by = 0 ; //实际字符数
while((by=fileReader.read())!=-1){
fileWriter.write(by) ;
fileWriter.flush() ;
}
//一次读取一个字符数组
char[] charArray = new char[1024] ;
int len = 0 ;
while((len=fileReader.read(charArray))!=-1){
//写入实际字符数
fileWriter.write(charArray,0,len);
fileWriter.flush();
}
//关闭
fileWriter.close();
fileReader.close();
五、 BufferedReader/BufferedWriter
BufferedReader ---- 键盘录入数据
BufferedReader(Reader in)创建使用默认大小的输入缓冲区的缓冲字符输入流
BufferedReader(Reader in, int size) :指定缓冲区大小
特有功能:public String readLine() :一次读取一行内容
BufferedWriter --字符缓冲输出流
BufferedWriter(Writer out) :创建默认的缓冲区大小:
默认大小:defaultcharbuffersize:8192(默认值足够大)
BufferedWriter(Writer out, int sz) :指定的大小
public void newLine() throws IOException:写入行的分隔符号
BufferedReaer/BufferedWrite
一次读取一个字符
一次读取一个字符数组
特有功能:
利用BufferedReader的readLine()读取一行
利用BufferedWriter写一行,然后换行
读写复制操作
public class CopyFile {
public static void main(String[] args) {
BufferedReader br = null ;
BufferedWriter bw = null ;
try {
//封装源文件:前项目下的 ReaderDemo.java
br = new BufferedReader(new FileReader("ReaderDemo.java")) ;
bw = new BufferedWriter(new FileWriter("copy.java")) ;
//使用特有功能读取一行内容
String line = null ;
while((line=br.readLine())!=null){
//读取一行,bw写一行并换行,然后刷新
bw.write(line);
bw.newLine();
bw.flush();;
}
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
bw.close();
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
六、字节流的逻辑串联!
1、字节流的逻辑串联
SequenceInputStream:
可以将两个或者是两个以上的文件进行读的操作 ,只能操作源文件
2、构造方法
public SequenceInputStream(InputStream s1,InputStream s2)
参数1和参数2:分别要读取的字节输入流对象
3、合并复制文件
(1)将当前项目下的BufferedWriterDemo.java+copy.java文件---->复制到当前项目下b.java文件
//创建两个字节输入流对象
InputStream is = new FileInputStream("BufferedWriterDemo.java") ;
InputStream is2 = new FileInputStream("copy.java") ;
//public SequenceInputStream(InputStream s1,InputStream s2)
//创建字节合并流
SequenceInputStream sis = new SequenceInputStream(is,is2) ;
//封装目的地文件:
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("b.java")) ;
//一次读取一个字节数组
byte[] bytes = new byte[1024] ;
int len = 0 ;
while((len = sis.read(bytes))!=-1){
bos.write(bytes,0,len);
}
//释放资源
bos.close();
sis.close();
(2)将两个以上的文件进行读取
public SequenceInputStream(Enumeration<? extends InputStream> e) :
Vector<InputStream> -- 创建集合
add(添加多个字节输入流对象) -- 添加对象
//public SequenceInputStream(Enumeration<? extends InputStream> e)
//需要三个字节输入流对象
InputStream is1 = new FileInputStream("BufferedWriterDemo.java") ;
InputStream is2 = new FileInputStream("ReaderDemo.java") ;
InputStream is3 = new FileInputStream("CopyMp4.java") ;
//创建一个Vector集合
Vector<InputStream> vector = new Vector<>() ;
//添加流对象
vector.add(is1) ;
vector.add(is2) ;
vector.add(is3) ;
//public Enumeration<E> elements() ---- >类似于Collection的Iterator迭代器
Enumeration<InputStream> enumeration = vector.elements();
//创建合并流对象 封装源文件
SequenceInputStream sis = new SequenceInputStream(enumeration);
//创建字节缓冲输出流对象
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("d://hello.java")) ;
//一次读取一个字节
int by = 0 ;
while((by=sis.read())!=-1){
bos.write(by);
bos.flush();
}
bos.close();
sis.close();
七、序列化与反序列化
1、序列化--ObjectOutputStream
将某个实体对象写入到流对象中---->将一个对象变成 流数据
构造方法
protected ObjectOutputStream()
protected ObjectOutputStream(OutputStream out) :将某个对象通过底层的基本字节输出进行写的动作
public final void writeObject(Object obj) throws IOException
2、反序列化 --ObjectInputStream
将流数据----还原成 "对象"
3、构造方法
public ObjectInputStream(InputStream in)
public final Object readObject() throws IOException, ClassNotFoundException
public class ObjectStreamDemo {
public static void main(String[] args) throws IOException, ClassNotFoundException {
myWrite() ;//写
myRead() ;//读
}
//反序列化
private static void myRead() throws IOException, ClassNotFoundException {
//创建反序列化流对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("oos.txt")) ;
//读
//public final Object readObject()
Object object = ois.readObject();
//关闭流
ois.close();
System.out.println(object);//toString()
}
//序列化
//将Person p = new Person("高圆圆",42) ;---->变成流对象 进行传输
private static void myWrite() throws IOException {
//创建Person对象
Person p = new Person("高圆圆",42) ;
//protected ObjectOutputStream(OutputStream out):创建一个序列化流对象
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("oos.txt")) ;
//将p对象写入到oos流对象中
//public final void writeObject(Object obj)throws IOException
oos.writeObject(p);
//释放资源
oos.close();
}
}
4、一个实体类
1)当前类必须为具体类 class 类名{}
2)必须存在私有字段(私有成员变量)
3)必须提供公共的setXXX()/getXXX()
4)如果当前类需要在网络中进行传输(分布式系统中)必须implements Serializable
5、产生一个固定的序列化版本Id
file--->setting---->editor---->Inspections----->java---->序列化serializion issue
--->serializable class 打上对钩即可!//产生一个固定的序列化版本Id
private static final long serialVersionUID = 8988325735017562383L; //常量值
八、持久的 --Properties
1、格式
Properties extends Hashtable<K,V> ,它没有泛型,Key和Value都是String
2、属性
表示一组持久的属性。 Properties可以保存到流中或从流中加载。
属性列表中的每个键及其对应的值都是一个字符串。
3、特点
1)可以使用Map的功能
put(K ,V)
遍历:
keySet()通用2)有自己特有功能添加元素和遍历
public Object setProperty(String key,String value):给属性列表中添加属性描述(key和value)
public Set<String> stringPropertyNames():获取属性列表中的所有的键
public String getProperty(String key):在属性列表中通过键获取值
//Properties() :空参构造
Properties properties = new Properties() ;
//创建一个空的属性列表
Properties prop = new Properties() ;
prop.setProperty("张三","30") ;
prop.setProperty("李四","40") ;
prop.setProperty("王五","35") ;
prop.setProperty("赵六","45") ;
//遍历:
Set<String> set = prop.stringPropertyNames();//获取所有键
for(String key:set){
String value = prop.getProperty(key);
System.out.println(key+"---"+value);
4、将文本文件中的内容读取到属性列表中Properties 加载
将字节输入流或者字符输入中所在的文件中的内容加载属性列表中
void load(Reader reader)
void load(InputSteram in)将Properties里面存储的内容----->保存到某个目录的xxx配置文件中 保存
public void store(Writer writer,String comments)
public void store(OutputStream out,String comments)
将属性列表中的内容保存到指定字节输出流/字符输出流所指向那个文件中
将一个文本文件中属性,加载到属性集合列表(Properties)中,并将这些数据 ---->保存到另一个文件中
public class PropertiesDemo2 {
public static void main(String[] args) throws IOException {
// myLoad() ;
myStore() ;
}
//将属性集合类中的内容 ---保存到指定文件中
private static void myStore() throws IOException {
Properties prop = new Properties() ;
//添加key-value
prop.setProperty("张三丰","56") ;
prop.setProperty("吴奇隆","60") ;
prop.setProperty("成龙","65") ;
prop.setProperty("刘德华","70") ;
//public void store(Writer writer,String comments):
//参数2:给当前属性列表中加入一个描述
//保存指定的文件中
prop.store(new FileWriter("user.txt"),"name's list'");
System.out.println("保存完毕");
}
//加载:需要将names.txt文件加载到属性列表中,然后遍历
private static void myLoad() throws IOException {
//创建一个空的属性列表
Properties prop = new Properties() ;
System.out.println(prop);
//void load(Reader reader)
// Reader r = new FileReader("names.txt") ;//names.txt是在当前项目下路径下
// prop.load(r) ;
//读取src路径下的names.properties (类路径)
//使用步骤
//1)获取当前类所在的字节码文件对象
Class clazz = PropertiesDemo2.class ;
//2)获取当前类所在的类加载器Class:public ClassLoader getClassLoader()
ClassLoader classLoader = clazz.getClassLoader();
//3)在类加载器中:获取当前资源文件(配置文件names.proprites)所在的输入流对象
//public InputStream getResourceAsStream(String name) {
InputStream inputStream = classLoader.getResourceAsStream("names.properties");
//将inputStream加载到属性集合类中
// void load(InputSteram in)
prop.load(inputStream);
System.out.println(prop);
Set<String> keySet = prop.stringPropertyNames();
for(String key:keySet){
String value = prop.getProperty(key);
System.out.println(key+"---"+value);
}
}
}
网络编程
1、网络编程三要素
ip:IP地址
port:端口号
协议:
udp协议
1)不需要建立连接通道
2)属于一种不可靠连接
3)发送文件大小限制的
4)执行效率高 (不同步的)
TCP/Ip协议
1)建立连接通道
2)属于安全连接(可靠连接)
3)发送文件(使用基本字节流),相对udp协议来说没有限制
4)执行效率低(同步的)
2、特点
发送端/客户端
接收端/服务器端 这两端必须存在Socket对象
3、InetAddress:互联网ip地址
获取InetAddress:ip地址对象
public static InetAddress getByName(String host):参数:主机名称(计算机电脑名称)
public String getHostAddress():获取ip地址字符串形式
如何获取自己电脑上的ip地址
public class NetDemo {
public static void main(String[] args) throws UnknownHostException {
//如何获取自己电脑上的ip地址----》String形式!
InetAddress inetAddress = InetAddress.getByName("DESKTOP-4KUN8QI");//主机名
String ip = inetAddress.getHostAddress();
System.out.println(ip);
}
4、UDP
upd发送端
1)创建Socket对象
2)发送内容 :内容数据一种数据报文(报包)DatagramPacket
3)释放资源
public class UdpSend {
public static void main(String[] args) throws IOException {
//1)创建Socket对象
//DatagramSocket:发送和接收数据报数据包的套接字。
//public DatagramSocket() throws SocketException
DatagramSocket ds = new DatagramSocket() ;
//2)创建一个数据报包对象DatagramPacket
//DatagramPacket(byte[] buf, int length, InetAddress address, int port)
//参数1:当前数据的字节数组
//参数2:当前数据的长度
//参数3:InetAddress:ip地址对象
//参数4:绑定的端口号
byte[] bytes = "hello,马三奇".getBytes() ;
int length = bytes.length ;
//public static InetAddress getByName(String host)
InetAddress inetAddress = InetAddress.getByName("10.12.156.107");
int port = 12306 ;
DatagramPacket dp = new DatagramPacket(bytes,length,inetAddress,port) ;
//3)发送数据报包
//public void send(DatagramPacket p)
ds.send(dp);
//4)释放资源
ds.close();
}
}
upd接收端
1)创建Socket对象
2)创建一个接收容器:数据报包:DatagramPacket
3)接收
4)解析容器的的实际数据大小
5)展示发送端发送的数据
public class UdpReceive {
public static void main(String[] args) throws IOException {
//)创建Socket对象
//public DatagramSocket(int port)
DatagramSocket ds = new DatagramSocket(12306) ;
//2)创建一个接收容器:数据报包:DatagramPacket 实际数据没有这么大
//public DatagramPacket(byte[] buf, int length)
//自定义字节缓冲区
byte[] bytes = new byte[1024] ;
int lentgth = bytes.length ;
DatagramPacket dp = new DatagramPacket(bytes,lentgth);
//3)public void receive(DatagramPacket p)
ds.receive(dp);
//4)解析实际数据
//byte[] getData() 获取实际字节数
//返回数据缓冲区。
//int getLength() 获取实际长度
byte[] bytes2 = dp.getData();
int length2 = dp.getLength();
String receiverStr = new String(bytes2,0,length2) ;
//获取ip地址
//InetAddress getAddress()
//InetAddress
//public String getHostAddress():
String ip = dp.getAddress().getHostAddress();
//展示数据
System.out.println("data from "+ip+" ,content is :"+receiverStr);
}
}
5、TCP
TCP客户端写数据
1)创建TCP客户端的Socket对象
2)写数据
3)释放资源
public class ScoketDemo {
public static void main(String[] args) throws IOException {
//1)创建TCP客户端的Socket对象
// public Socket(String host, int port)throws UnknownHostException, IOException
//参数1:主机名称/或者ip地址字符串形式
//参数2:指定的端口(0-65535(不包含0-1024))
Socket s = new Socket("192.168.0.7",8888) ;
//2)写数据
//public OutputStream getOutputStream()throws IOException
OutputStream out = s.getOutputStream();//获取通道内的输出流对象
out.write("hello,TCP".getBytes());
//读取服务器端反馈的数据
//3)释放资源
s.close();
}
}
TCP服务器端的实现步骤:
1)创建服务器端的Socket对象
public ServerSocket(int port)throws IOException
2)监听客户端连接
public Socket accept()throws IOException 返回值就是当前监听到的客户端的Socket对象
3)获取通道内的输入流
public InputStream getInputStream() throws IOException
4)读取数据:一次读取一个字节数组
5)展示数据 而且获取ip地址
ublic InetAddress getInetAddress()
public class ServerDemo {
public static void main(String[] args) throws IOException {
// 1)创建服务器端的Socket对象
//public ServerSocket(int port)throws IOException
ServerSocket ss = new ServerSocket(8888) ;
System.out.println("服务器正在等待连接...");
//2)监听客户端连接
// public Socket accept()throws IOException 返回值就是当前监听到的客户端的Socket对象
Socket socket = ss.accept(); //阻塞式方法
//3)取通道内的输入流
//public InputStream getInputStream() throws IOException
InputStream inputStream = socket.getInputStream();
//4)读取数据:一次读取一个字节数组
byte[] bytes = new byte[1024] ;
int len = inputStream.read(bytes);
//获取内容
String clientStr = new String(bytes,0,len) ;
//再去反馈数据
//5)获取ip
String ip = socket.getInetAddress().getHostAddress();
//展示数据
System.out.println("data from "+ip+" content is--->"+clientStr);
//关闭
ss.close();
}
}
6、反馈操作
目的
客户端的一个文本文件,服务器端进行复制到指定的某个文件中 ,复制完毕了,服务器端需要给客户端反馈!(反馈的消息,客户端能不能获取到)
出现的问题
加入反馈操作:出现客户端和服务器端互相等待的情况--->但是文件已经复制完毕!
针对服务器端:不知道客户端是否还需要从通道内的输出流对象中写入数据(此时文件读写复制结束条件:只是null),文件读完毕的条件是null,但是TCP通过流的方式 要进行结束; 服务器端不知道客户端是否还需要写入数据,客户端等待着服务器反馈的数据!
解决方案
1)自定义结束条件
在客户端读完文件中,通知一下服务器端
写入一行内容("886/over"),服务器端只要读取到886或者over
2)可以使用客户端Socket的一个方法 标记(通知服务器端,客户端已经没有数据输出了)
public void shutdownOutput()throws IOException
反射
1、什么是反射?
能够获取当前某个类的字节码文件对象Class,那么就可以获取当前类的构造器并且创建当前类实例,还可以获取当前类的成员变量并去赋值,或者获取当前类的成员方法并去调用!
2、如何获取一个类的字节码文件对象?
1、 Object类的getClass()获取 获取当前某个类的实例(正在运行的类)
Person p = new Person() ;
Class c1 = p.getClass();
2、 任意Java类型的class属性
Class c3 = Person.class ;3、 Class类的静态功能 public static Class<?> forName(String className)
Class c4 = Class.forName("com.qf.reflect_03.Person");
3、使用反射访问
创建Person类
public class Person {
//成员变量
private String name ;//姓名 私有
public int age ; //年龄 默认
String address ; //地址 默认修饰符
//无参构造方法:公共的
public Person(){}
//提供带两个参数的构造方法,默认修饰符
Person(String name,int age){
this.name = name ;
this.age = age ;
}
//提供三个参数的构造方法,私有的
private Person(String name,int age,String addrss){
this.name = name ;
this.age = age ;
this.address = addrss ;
}
//提供一些成员方法(非静态)
public void show(){
System.out.println("show Person");
}
private String functioin(String str){
return str ;
}
void method(String message,int num){
System.out.println(message+num);
}
public int method2(){
return 100 ;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", address='" + address + '\'' +
'}';
}
}
4、访问
访问成员方法
一、 Class类
public Constructor<?>[] getConstructors():获取当前字节码文件对象中(正在运行的这个类)里面所有的公共的构造方法所在的对象
public Constructor<?>[] getDeclaredConstructors():获取所有的构造器对象Constructor,返回构造器对象数组 包含私有化构造/默认的
二、 获取所有的成员方法:公共的(包含他父类的所有的公共的方法)
public Method[] getMethods()
public 方法[] getDeclaredMethods():通过此表示类对象,包括公共,保护,默认(包)访问和私有方法,但不包括继承的方法。
public class ReflectDemo {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException {
//Person p = new Person();
//Class clazz = p.getClass();
Class clazz = Person.class;
// Class clazz = Class.forName("反射.ReflectDemo");
//方式1:直接获取当前类的实例
// private String name;
// public int age;
// String diqu;
Object obj = clazz.newInstance();
Field nameField = clazz.getDeclaredField("name");
nameField.setAccessible(true);
nameField.set(obj,"李娜");
// System.out.println(obj);
Field ageFiled = clazz.getField("age");
ageFiled.set(obj,24);
//System.out.println(obj);
Field diquField = clazz.getDeclaredField("diqu");
diquField.setAccessible(true);
diquField.set(obj,"临汾");
System.out.println(obj);
// public void show()
Method showMethod = clazz.getDeclaredMethod("show");
showMethod.invoke(obj);
//private String functioin(String str)
Method functioin = clazz.getDeclaredMethod("functioin", String.class);
//取消Java语言访问检查:私有方法
functioin.setAccessible(true);
Object o = functioin.invoke(obj, "该上课了");
System.out.println(o);
//void method(String message,int num)
Method method1 = clazz.getDeclaredMethod("method", String.class, int.class);
// method1.setAccessible(true);
method1.invoke(obj,"上数学",30);
//public int method2()
Method method3 = clazz.getDeclaredMethod("method2");
Object invoke = method3.invoke(obj);
System.out.println(invoke);
//获取某一个构造器对象Constructor
//public Constructor<T> getConstructor(Class<?>... parameterTypes) :// ... :jdk5以后 可变参数 (参数数量未知)
//获取指定的公共的单个的构造器对象 参数:需要书写的是当前参数类型的字节码文件对象
Constructor constructor = clazz.getConstructor();//java.lang.String
//通过构造器对象创建当前类的实例
//public T newInstance(Object... initargs): 参数为最终赋值的实际参数 (可变参数:实际参数未知)
Object obj1 = constructor.newInstance();
System.out.println(obj1); //p
//获取构造器对象
//public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
Constructor con = clazz.getDeclaredConstructor(String.class,int.class,String.class) ;
//取消Java语言访问检查
con.setAccessible(true);
//通过构造器对象创建当前类实例
Object obj2 = con.newInstance("高圆圆", 20, "西安市");
System.out.println(obj2);//Person{name='高圆圆', age=20, address='西安市'}
}
}
5、反射的应用
1)现在有一个ArrayList<Integer>,里面有一些元素,如何给ArrayList添加String类型的元素?
public class ReflectTest {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
//有一个ArrayList集合对象
ArrayList<Integer> arrayList = new ArrayList<>();
arrayList.add(100);
System.out.println(arrayList);
//1)获取当前集合实例所在的字节码文件对象
//通过Object的getClass()获取当前实例所在的类的字节码对象
Class<? extends ArrayList> aClass = arrayList.getClass();
//System.out.println(clazz);//class java.util.ArrayList
//System.out.println(obj);
//获取当前类中 add方法所在的Method
//public boolean add(E e) ://参数就是任意Java类型 (Element)
Method add = aClass.getMethod("add", Object.class);
add.invoke(arrayList, 20);
System.out.println(arrayList);
}
}
2)现在有一个学生类以及工人类,两类都有一个love方法,ReflectTest2在测试类中进行测试
Java设计原则:
开闭原则:对修改关闭,对扩展开放 (在现有代码进程上,想办法进行扩展...)如果提供配置文件,以后只需要修改配置文件中内容,而不更改当前的代码!
如果能将配置文件,如果能加载属性集合列表中
className=com.qf.reflect_06.Worker
methodName=love就可以通过key--->value
com.qf.reflect_06.Worker:创建当前类的字节码文件对象
学生类:Student
public class Student {
public void love(){
System.out.println("爱学习,爱Java,爱高圆圆...");
}
}
工人类:Worker
public class Worker {
public void love(){
System.out.println("爱生活,爱drink...,爱足球");
}
}
测试:ReflectTest2
public class ReflectTest2 {
public static void main(String[] args) throws Exception {
//优化:提供src(类路径下提供配置文件)myClass.properties
//1)读取src下面的myClass.properties
//获取资源文件所在的输入流对象
InputStream inputStream = ReflectTest2.class
.getClassLoader().
getResourceAsStream("myClass.properties");
//创建属性集合列表:空的
Properties prop = new Properties() ;
//将指定的配置文件所在的输入流加载属性列表中
prop.load(inputStream);
System.out.println(prop);
//可以通过可以key获取value
String className = prop.getProperty("className") ; //当前类的全限定名称
String methodName = prop.getProperty("methodName") ;
//通过反射创建当前类的字节码文件对象
Class clazz = Class.forName(className) ;
//创建当前类的实例 (解耦)
Object obj = clazz.newInstance() ;
//通过clazz字节码文件对象获取当前成员方法所在的Method类对象
Method method = clazz.getMethod(methodName) ;
method.invoke(obj) ;
}
}
// myClass.properties
lassName=com.qf.reflect_06.Worker
methodName=love
MySQL
一、入门
1、mysql库的管理
1、查看所有数据库
show databases;
2、 创建数据库
create database 库名;
3、查看数据库,创建数据语句
show create database 库名;
4、删除数据库
drop database 库名;
2、表的管理
1、查看所有的表
show tables;
2、创建表
create table 表名( -- 内容
id INT,
NAME VARCHAR(20),
age INT,
gender VARCHAR(20),
math INT,
english INT,
chinese INT
);
3、 查看表sql格式
show create table 表名 ;
4、查看表格格式
desc 表名 ;
5、删除表
drop table 表名 ;
6、管理数据-增删改
插入数据
-- insert into 表名 values (值);
INSERT INTO stydent92class VALUES (1,'王彦登',24,'男',98,56,85);
修改数据
-- update 表名 set 列明=值 where 条件;
UPDATE stydent92class SET math = 145 WHERE id = 1 ;
删除数据
-- delete from 表名 where 条件; 带条件删除数据
-- delete from 表名 ;删除全表数据,表的结构还存在
-- truncate table 表名;-- 删除所有数据,再创建一张一模一样的表
删除全表的语法 delete from 表名 truncate table 表名; 两个区别 1)delete from 表名:只是删除全表数据;表的结构还存在, 如果表中 存在主键并且自增长约束,那么不会受影响,下一次在插入数据 继续在之前的基础上继续自增长! 2)truncate table 表名 ; 将表中数据删除的同时删除了表,然后在创建一张一模一样空表, 肯定影响自增长主键的值,再次插入数据,自增长从1开始... 等价于 drop table my_use; 创建一个当前一模一样的表结构
7、查询数据
-- DQL带条件查询
-- where条件查询
-- 可以基本运算符:比较运算符(<,>,<=,>=,!=)/逻辑运算符(|| && /and /or)/赋值运算符 =
-- where后面多个or in(集合数据) 在两个值之间 between 值1 and 值2
-- mysql 判断某个字段为null , is null /is not null
-- 模糊查询 like
-- 聚合函数 count(列名)/max(列名)/min(列名)/sum(列名)/avg(列名)
-- 排序查询 order by
-- 分组查询 group by
-- 筛选查询 having
-- 分页查询 limit
(1)查询所有列
-- select * from 表名 ;
-- 查询年龄在20岁和30岁之间的学生信息(1)
SELECT * FROM stydent92class WHERE age > 20 AND age < 30 ;
-- 在两个值之间 between 值1 and 值2(2)
SELECT * FROM stydent92class WHERE age BETWEEN 20 AND 30 ;
-- 查询年龄是18或者20的学生的编号(|| 或者 or)(1)
SELECT * FROM stydent92class WHERE age = 18 || age = 20 ;
-- 查询年龄是18或者20的学生的编号 :IN (2)
SELECT * FROM stydent92class WHERE age IN (18,20);
-- 查询语文成绩为null的学号编号 : is null
SELECT * FROM stydent92class WHERE chinese IS NULL;
-- 查询语文成绩不为null的学号编号: is not null
SELECT * FROM stydent92class WHERE chinese IS NOT NULL;
(2)as 可以省略 -- 查询时指定别名
SELECT
id AS 92班,
SUM(IFNULL(chinese,0)) AS 语文总分,
AVG(math) AS 数学平均分,
MAX(english) AS 英语最高分,
MIN(english) AS 英语最低分
FROM
stydent92class;
(3)distinct -- 去除重复数据
(4)查询年龄大于 20 的总数 : <> !=
SELECT * FROM stydent92class WHERE age <> 20 ;
(5)模糊查询 like
-- 模糊查询mysql服务中带字符集相关的变量 show variables like '%character%' ;
-- 模糊查询 like
-- select 字段列表 from 表名 where 字段名称 like '%字符%' ;
% :包含的指定的字符 使用'%字符值%' 模糊查询包含指定字符的信息
_ :代表单个字符(一个_下划线代表一个字符)
两个相结合使用: '_%字符值%_' 三个字符:中间字符包含指定的值进行模糊查询-- 查询第二个字符包含化的学生信息
SELECT * FROM student WHERE NAME LIKE '_%化%' ;
(6) 聚合函数查询--单行单列的数据
-- count(列名) :总记录数
-- max(列名): 最大值
-- min(列名字段):最小值
-- sum(字段名称):求和
-- avg(列名):平均分
-- select 聚合函数(列名) from 表名;
-- ifnull
-- 查询英语成绩的最高成绩
SELECT MAX(IFNULL(english,0)) 英语最高分 FROM student ;
(8) 排序查询
order by 字段名称 asc/desc (升序/降序)
-- select 字段列表 from 表名 order by 字段名 排序规则; -- 单个字段进排序
SELECT
*
FROM
student
ORDER BY
math DESC,
english ASC ;
(9)分组查询
-- group by :group by 后面不能使用聚合函数
-- 现在需要按照性别分组-----分组之后查询出总人数,数学的平均分
-- 数学成绩不大于70分的人不参与分组;
SELECT
sex '性别', -- 查询分组字段
COUNT(id) '总人数',
AVG(math) '数学平均成绩'
FROM
student
WHERE
math > 70 -- 条件:数学成绩大于70分人参与分组
GROUP BY
sex ; -- 性别分组
(10)筛选
-- having
-- having 必须置于group by 之后,where 置于 group by 之前
-- group by不能聚合函数,但是having后面可以聚合函数
SELECT
sex 性别, -- 查询分组字段
COUNT(id) 总人数,
AVG(math) 数学平均成绩
FROM
student
WHERE
math > 70 -- 条件:数学成绩大于70分人参与分组
GROUP BY
sex -- 性别分组
HAVING
总人数 > 2 ;
(11)分页查询
-- limit
-- select 字段列表 from 表名 limit 起始行数,每页显示多少条;
-- 每页显示3条记录
-- 查询第一页的数据
-- limit 起始行数=(当前页码数-1)*每页显示的条数,每页显示条数;
SELECT * FROM student LIMIT 0,3 ;
-- 查询第二页的数据
SELECT * FROM student LIMIT 3 ,3 ;
-- 查询第三页数据
SELECT * FROM student LIMIT 6,3 ;
-- 第四页数据
SELECT * FROM student LIMIT 9,3 ;
8、数据库约束
(1)默认约束 default
default 默认约束 防止出现非法数据null(没有插入造成null值)
-- 添加约束
ALTER TABLE test MODIFY gender VARCHAR(2) DEFAULT '女' ;
-- 通过sql语句修改表的类型,删除默认约束
ALTER TABLE test MODIFY gender VARCHAR(2) ;
(2)非空约束 not null
DROP TABLE test ;
CREATE TABLE test(
id INT ,
NAME VARCHAR(10) NOT NULL -- 非空约束
);
INSERT INTO test VALUES(1,NULL) ; -- 直接插入null值
-- insert into test (id) values(1) ; 没有给姓名赋值
INSERT INTO test VALUES(1,'') ; -- 存在值,只是空字符 和null不一样
-- 删除非空约束
ALTER TABLE test MODIFY NAME VARCHAR(10) ;
UPDATE test SET NAME = '高圆圆' WHERE id = 1 ;
INSERT INTO test VALUES(2,NULL) ; -- Column 'NAME' cannot be null
-- 修改表,加入非空约束
ALTER TABLE test MODIFY NAME VARCHAR(10) NOT NULL ;
DELETE FROM test WHERE id = 2 ;
(3) 唯一约束 nuique
DROP TABLE test;
CREATE TABLE test(
id INT ,
NAME VARCHAR(10),
phone VARCHAR(11) UNIQUE -- 唯一约束 :可以有null值,不能重复
) ;
INSERT INTO test VALUES(1,'张三','13666668888') ;
INSERT INTO test VALUES(2,'李四','13666668889') ;
-- 通过语句删除唯一约束
-- 删除唯一约束的sql alter table test drop index 字段名称;
ALTER TABLE test DROP INDEX phone ;
INSERT INTO test VALUES(4,'赵六','13666668878') ;
DELETE FROM test WHERE id = 4 ;
-- 添加唯一约束
ALTER TABLE test MODIFY phone VARCHAR(11) UNIQUE ; -- unique
(4)主键约束 primary key
-- 主键约束 (非空+唯一特点) primary key
-- 都会给当前非业务字段去设置主键(xxid)
DROP TABLE test ;
CREATE TABLE test(
id INT PRIMARY KEY , -- 非业务字段
NAME VARCHAR(10),
gender VARCHAR(2)
) ;
INSERT INTO test VALUES(1,'洪学佳','男'),(2,'马三奇','男') ;