文章目录

    • 20.设计原则
      • 1.工厂模式
      • 2.单例模式
        • 1)饿汉式
        • 2)懒汉式
      • 3.Runtime类
      • 4.代理模式
        • 1)静态代理
        • 2)动态代理
        • 动态代理模板
    • 21.递归
    • 22.IO流
      • 1.File
      • 2.IO流的分类
      • 3.字节流
        • 1)OutputStream
        • 2)InputStream
      • 4.缓冲字节流
        • 1)BufferedInputStream
        • 2)BufferedInputStream
      • 复制对比
      • 5.字符流
        • 1)Writer--OutputStreamWriter
        • 2)Reader--InputStreamReader
        • 3)便捷类
      • 6.字符缓冲流
        • 1)BufferedReader
        • 2)BufferedWriter
        • 3)Copy
      • 7.SequenceInputStream
        • 1)合并两个文件
        • 2)合并两个以上文件
      • 8.序列化
      • 9.Properties
        • 文件操作
    • 23.网络编程
      • 1.udp通信
      • 2.TCP通信
        • 一个有回复的TCP通信
        • 可以连续发送的TCP通信
        • 发送文本文件并有反馈
        • 客户端的图片文件
    • 24.反射
      • 1.字节码文件
      • 2.创建对象
      • 3.成员变量
      • 4.成员方法
      • 5.应用
    • 25.数据库
      • DDL语句:数据库定义语句
      • 1.库的增删查改
        • 1.查询当前mysql下所有的数据库
        • 2.创建数据库
        • 3.查看创建数据库的默认的字符集(了解)
        • 4.修改数据库的字符集(了解)
        • 5.删除库
        • 6.模糊查询mysql服务中所有的带character字符集的全局变量
      • 2.表的增删改查
        • 1.创建表
        • 2.查询当前数据库中有哪些表
        • 3.查询当前表的结构
        • 修改表
        • 4.给student表添加一列
        • 5.修改表中的字段类型
        • 6.修改表中的字段名称
        • 7.删除某一列字段
        • 8.修改表的表名
        • 9.复制一张表结构和以前表的结果一样
        • 10.删除表
        • 11.插入语句
        • 12.最基本的查询:查全表数据
        • 13.修改表的数据
        • 14.删除表中数据
      • 3.查询表的数据
      • 1.where条件查询
        • 查询null
        • 字段去重 distinct
      • 2.模糊查询
      • 3.聚合函数查询
      • 4.order by
      • 5.group by
      • 6.HAVING
        • having 与 where 的区别
      • 7.分页查询limit
    • 4.数据库约束
      • 1)默认约束
      • 2)非空约束
      • 3)唯一约束
      • 4)主键约束

20.设计原则

设计原则:开闭原则:对现有代码修改关闭,对扩展代码开放举例:项目开发完毕,进行更新,不能够修改现有代码,在现有代码的基础上提供扩展!接口分离原则一个接口中定义一个功能,接口和接口之间独立的,不能相互影响实际开发中:某个接口中,可能将相关的功能都定义在这一个接口中按模块划分:用户模块        UserDao  接口login()/register()/logout()/checkUserName()商品模块ProductDao 接口Product findById(Integer id) ;List<Product> findAll() ;void update(Product product);订单模块OrderDao 接口List<Order> findPage(int pageSize,int currentPage);里氏替换原则:任何父类出现的地方都可以子类替代!class Father{public void show(){// ...Class<Son> clazz  = Son.class ;//反射方式---->字节码文件对象就调用method----->将所有的成员方法---->Method}}class Son extends Father{public void method(){}}23种设计模式都需要遵循 原则"低耦合,高内聚"设计模式是一种思想,前人总结出来,不是技术!创建型:对象的创建 (使用最多)结构型:整个结构的组成代理模式静态代理代理角色真实角色行为型:具备功能性的
创建型设计模式:简单工厂:----称为 静态工厂方法模式优点:利用多态创建子类对象,能够灵活去创建对象(提供的静态功能)弊端:代码量大,一旦有新的类型增加,工厂类的静态功能就需要改动...

1.工厂模式

工厂方法模式:1)抽象类:Animal 动物类 (基类)  2)提供一些子类,完成方法重写:eat(){} sleep(){}    3)提供一个接口 :        Factory             public Animal createAnimal() ;      DogFactory /CatFactory具体的子实现类实现对象的创建 优点:具体的动物创建,交给类工厂类来实现 (面向接口编程),便于功能维护(代码维护)弊端:代码量非常大   如果有新的类中增加,那么还必须提供对应具体的工厂类创建当前类实例!
//抽象的动物类
public abstract class Animal { public abstract  void eat() ;  public abstract  void sleep() ;
}
public class Cat extends Animal { @Override  public void eat() {  System.out.println("猫吃鱼");  }  @Override  public void sleep() {   System.out.println("猫趴着睡觉..."); }
}public class Dog extends Animal { @Override   public void eat() {   System.out.println("狗吃骨头...");  }  @Override   public void sleep() {    System.out.println("狗躺着睡觉...");  }
}
//工厂接口
//    具体的对象的创建工作----交给工厂接口(抽象类)的子实现类完成!
public interface Factory {public Animal createAnimal() ;}
// 猫的工厂类
public class CatFactory  implements  Factory{ @Override    public Animal createAnimal() {   return new Cat();    }
}
//具体的工厂类 创建狗这个类型的实例
public class DogFactory  implements Factory{  @Override   public Animal createAnimal() {//接口多态中---->抽象类多态   return new Dog();    }
}public class FactoryPattern {  public static void main(String[] args) {  //没有工厂方法之前:     //使用抽象类多态    Animal a = new Dog() ;     a.eat();     a.sleep();    System.out.println("-------------------------------");  a = new Cat() ;       a.eat();    a.sleep();  //使用工厂方式模式来操作 System.out.println("-------------------------------------");   Factory factory = new DogFactory() ;   Animal animal = factory.createAnimal();     animal.eat();      animal.sleep();    System.out.println("---------------------------------------");   factory = new CatFactory() ;  Animal a2 = factory.createAnimal();      a2.eat();  a2.sleep(); }
}

2.单例模式

单例模式:  始终在内存中创建一个实例分为两种    饿汉式:永远不会出现的单例模式(最简单的一种单例)  懒汉式:可能出现问题的一种单例模式
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;}
}
//测试类
public class Single_Pattern_01 {public static void main(String[] args) {// Student s1 = new Student() ;//Student s2 = new Student() ;// System.out.println(s1==s2);// System.out.println(s1.getClass()==s2.getClass());//class  com.qf.single_pattern.Student//调用公共方法Student s1 = Student.getStudentInstance();Student s2 = Student.getStudentInstance();Student s3 = Student.getStudentInstance();Student s4 = Student.getStudentInstance();System.out.println(s1==s2);System.out.println(s1==s3);System.out.println(s1==s4);// Student.s = null ; // 赋值null,堆内存不开辟空间(外界可以更改当前类地址值)//当前这个成员变量的实例s应该被私有修饰(保证安全性)}
}
2)懒汉式
懒汉式:可能出现问题的一种单例模式  1)构造方法私有化  2)在当前成员变量的位置声明变量:数据类型就是当期类 (私有的,静态的)3)提供静态功能,返回值还是当前类本身,      判断如果当前没有给当前类型变量为null,直接new 当期类的实例      如果不为null,就返回当前类的变量!                延迟加载或者懒加载----出现安全问题 面试中,问的最多就是懒汉式----->如何解决线程安全问题: 想到同步方法解决
public class Worker {//成员变量位置声明变量wprivate static Worker w;//默认值null//构造方法私有化private Worker() {} //外界不能直接new 对象//提供静态功能,返回值是当前类本身//w1,w2,w3 互相抢占getWorkerIntance的内容---会造成安全问题/*public static Worker getWorkerIntance(){//w1//先判断w变量为nullif(w == null){ //当为nullw = new Worker() ; //如果当前w变量为null,创建一个新的对象,返回return w;}return w ;}*///改进:同步代码块---->静态的同步方法public synchronized static Worker getWorkerIntance(){ //锁对象:Worker.class// synchronized (w){//w1//先判断w变量为nullif(w == null){ //当为nullw = new Worker() ; //如果当前w变量为null,创建一个新的对象,返回return w;}return w ;//}}
}
public class Single_pattern_02 {public static void main(String[] args) {//使用Worker第一次调用getInstance方法Worker w1 = Worker.getWorkerIntance();   //第一个用户操作这个方法----属于一个线程//第二次Worker w2 = Worker.getWorkerIntance();      //第二个用户操作---->属于一个线程System.out.println(w1==w2);Worker w3 = Worker.getWorkerIntance();        //第三个用户操作--->属于一个线程System.out.println(w1==w3);}
}

3.Runtime类

Runtime:当前获取的当前本地运行环境的实例public int availableProcessors():获取本地计算机的处理器的数量public Process exec(String command):开启某个软件的进程(参数为字符串命令)exec("shutdown -s"):立即关机exec("shutdown -s -t 300"):延时关机 exec("shutdown -a"):取消关机
public class RuntimeDemo {public static void main(String[] args) throws IOException {//获取当前类的实例:Runtime  利用单例模式Runtime runtime = Runtime.getRuntime();System.out.println(runtime.availableProcessors());Process notepad = runtime.exec("notepad");System.out.println(runtime.exec("QQ"));//利用关机//exec("shutdown -s"):立即关机//exec("shutdown -s -t 300"):延时关机//exec("shutdown -a"):取消关机System.out.println(runtime.exec("shutdown -s -t 300"));System.out.println(runtime.exec("shutdown -a"));}
}
public class DiGuiDemo {/* public DiGuiDemo(){//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) ;}}
}
/*
Runtime类的原码
*
* public class Runtime {  单例模式之饿汉式(类一加载就在当前内存中创建一个实例)//静态实例变量private static Runtime currentRuntime = new Runtime();//公共的静态功能:返回值就是当类本身
public static Runtime getRuntime() {return currentRuntime;
}Don't let anyone else instantiate this class  构造方法私有:外界不能直接访问private Runtime() {}
* */
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());}}
}

4.代理模式

1)静态代理
第二种实现方式:静态代理特点:真实角色和代理角色必须实现同一个接口真实角色:专注于自己的功能代理角色:完成对真实角色功能的"增强"
/*
结婚:结婚这个这个情况真实角色:You  你自己代理角色:WeddingCompany 婚庆公司
*///定义一个接口的接口
interface  Mary{void mary() ;//结婚
}//自己:真实角色
class You implements  Mary{@Overridepublic void mary() {System.out.println("结婚了,很开心...");}
}
//代理角色:婚庆公司 在你结婚之前,它可以给你布置婚礼线程, 结婚之后,开开心心吃席
class WeddingCompany implements Mary{//将真实角色作为参数传递private You you ;public WeddingCompany(You you){this.you = you ;}@Overridepublic void mary() {System.out.println("给你布置婚礼现场...");you.mary();  //只要专注于自己的事情!System.out.println("婚礼线程布置完毕,吃席...");}
}public class ThreadDemo {public static void main(String[] args) {//接口多态//Mary mary = new You() ;You mary = new You() ;mary.mary();System.out.println("----------------------");//静态代理:通过婚庆公司帮助自己You来完成结婚//真实角色You you2  = new You() ;     // MyRunnableWeddingCompany wc = new WeddingCompany(you2) ;// Thread类对象wc.mary();}
}
2)动态代理
动态代理jdk动态代理cglib动态代理-----导入cglib第三方jar包
1.动态代理核心思想:再程序执行过程中通过一些特殊的方式产生代理
2.代理角色和真实角色代理角色完成真实角色的一些额外功能,真实角色专注于完成自己的事情!
3.jdk动态代理:前提必须有一个接口    比如 :UserDaojdk提供的java.lang.reflect.Proxy:提供了创建动态代理类和实例的静态方法public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) throws IllegalArgumentException参数1:当前针对该接口的类加载器参数2:代理类实现的接口列表的字节码文件对象参数3:基于代理的处理程序  接口自定义一类来实现 代理角色的产生 (InvocationHandler:基于代理的处理接口)public Object invoke(Object proxy, Method method, Object[] args) throws Throwableproxy  代理实例method  调用基于接口的代理方法     method底层调用方法 invoke(当前类的实例,实际参数 args)args   当前传递的实际参数返回代理角色throws Throwable  代理过程中可能产生代理异常
目前接口:UserDao接口 -------> 产生代理角色完成 "权限校验"  "日志记录
/* 针对用户数据库访问接口层*/
public interface UserDao {/*** 添加用户*/void add() ;/*** 修改用户*/void update() ;/*** 删除用户的功能*/void delete() ;/*** 查询用户*/void findAll() ;
}/*针对用户的数据库访问接口实现层*/
public class UserDaoImpl implements UserDao {@Overridepublic void add() {System.out.println("添加用户");}@Overridepublic void update() {System.out.println("修改用户");}@Overridepublic void delete() {System.out.println("删除用户");}@Overridepublic void findAll() {System.out.println("查询所有用户");}
}/* 自定义一类来实现 代理角色的产生 (InvocationHandler:基于代理的处理接口)*/
public class MyInvocationHandler  implements InvocationHandler {//成员变量位置定义Object类型:对任意Java类型产生代理角色 (当前某个具体的实例)private Object target ;public MyInvocationHandler(Object target){this.target = target ;}/*** @param proxy  代理实例* @param method  调用基于接口的代理方法* @param args   当前传递的实际参数* @return   返回代理角色* @throws Throwable  代理过程中可能产生代理异常*///method底层调用方法 invoke(当前类的实例,实际参数 args)@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("权限校验");Object returnObj = method.invoke(target, args);System.out.println("日志记录");return returnObj; //代理角色对象}
}public class UserTest {public static void main(String[] args) {//直接:通过接口多态:创建接口对象UserDao ud = new UserDaoImpl() ;  //ud产生代理ud.add();ud.delete();ud.update();ud.findAll();//需求: 不仅实现自己的主要功能:add,update,delete,findAll() ...//而且还需要在每一个功能使用之前,先进行权限校验,然后使用功能,需要产生日志记录System.out.println("-------------------------------------");//通过jdk动态代理反射来完成代理角色的产生//Class --->public Class<?>[] getInterfaces()//创建基于代理处理接口的子实现类对象MyInvocationHandler invocationHandler = new MyInvocationHandler(ud) ;UserDao proxyClass = (UserDao) Proxy.newProxyInstance(UserDao.class.getClassLoader(),new Class[]{UserDao.class}, invocationHandler);proxyClass.add();proxyClass.delete();proxyClass.update();proxyClass.findAll();}
}
动态代理模板
/*模板类:可套用
*/public class MyInvocationHandler implements InvocationHandler {//被代理的接口private Object target ;public MyInvocationHandler(Object target) {this.target = target ;}//生成得到代理类public Object getProxy(){return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this) ;}//处理代理实例,并返回结果:public Object invoke(Object proxy,Method method,Object[] args) throws Throwable {//得到方法名  可省略System.out.println("方法:" + method.getName()) ;Object result = method.invoke(target, args) ;return result;}
}
//模板工具类举例
/* 针对用户数据库访问接口层*/
public interface UserDao {/*** 添加用户*/void add() ;/*** 修改用户*/void update() ;/*** 删除用户的功能*/void delete() ;/*** 查询用户*/void findAll() ;
}/*针对用户的数据库访问接口实现层*/
public class UserDaoImpl implements UserDao {@Overridepublic void add() {System.out.println("添加用户");}@Overridepublic void update() {System.out.println("修改用户");}@Overridepublic void delete() {System.out.println("删除用户");}@Overridepublic void findAll() {System.out.println("查询所有用户");}
}//模板工具类    可套用
public class MyInvocationHandler implements InvocationHandler {//被代理的接口private Object target ;public MyInvocationHandler(Object target) {this.target = target ;}//生成得到代理类public Object getProxy(){return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this) ;}//处理代理实例,并返回结果:public Object invoke(Object proxy,Method method,Object[] args) throws Throwable {//得到方法名  可省略System.out.println("方法:" + method.getName()) ;Object result = method.invoke(target, args) ;return result;}
}//测试类
public class Test {public static void main(String[] args) {//真实角色UserDaoImpl useDan = new UserDaoImpl();//代理角色,不存在  设置要代理的对象MyInvocationHandler mih = new MyInvocationHandler(useDan);//动态生成代理UserDao proxy = (UserDao) mih.getProxy();proxy.add();proxy.delete();proxy.findAll();proxy.update();}
}

21.递归

1.方法递归:方法调用方法本身的一种现象,并非是方法嵌套方法前提条件1)必须有一个成员方法2)必须有方法递归的出口条件(结束条件),如果没有出口条件,就是死递归...3)还存在一定的规律注意事项:构造方法不存在递归
伪代码:public void show(int n){ //50   调用if(n<0){System.out.println(n) ;}n -- ;//49show(n) ;}Math.max(Math.max(10,30),50) ;  //×  嵌套
需求:使用递归方式去删除D盘某个demo文件夹中有很多个目录,每个目录中可能还有目录,删除这些所有目录中的带.java文件的文件!分析:1)描述下D盘下demo文件夹  File srcFile = new File("d://demo")2)调用递归删除方法//递归删除多级目录中的java文件public void  deleteSrcFile(File srcFile){//获取srcFile的所有的文件夹以及文件的File数组//非空判断//判断如果是文件夹回到2)继续调用递归删除则,是文件判断是否以.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());}}
}
 有一对兔子,从出生后第三个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问第二十个月的兔子对数为多少?(递归方式实现:找规律)不死神兔月数          兔子对数第一个月          1第二个月          1第三个月          2第四个月          3第五个月          5第六个月          8第七个月          13...规律1)第一个和第二个月:兔子对数都是12) 从第三个月开始:兔子对数等于两个月兔子对数之后a,b分别相邻两个月兔子的对数第一个月:  1       a第二个月: 1        b第三个月: 2        a第四个月:  3       b第五个月:  5       a第六个月:  8       b方式1)可以使用数组完成方式2)递归思想完成递归:1)定义一个方法2)得有结束条件(出口条件)3)必须有规律定义变量n:来表示月份数(1,2,3...20)public static int getRabit(int n){if(n==1 ||n==2){return 1 ;} else{//n=3//getRabit(1) +getRabit(2)return getRabit(n-2)+getRabit(n-1) ;}}
public class Test4 {public static void main(String[] args) {//创建数组,动态初始化//使用x角标:表示月份int[] arr = new int[20] ;//初始化 第一个月arr[0] ,arr[1]  = 1arr[0] = 1 ;arr[1] = 1 ;//从arr[2] 开始= arr[0]+arr[1]//arr[3] = arr[2] + arr[1]//遍历arr数组 :角标从2开始:第三个月for(int x = 2 ; x < arr.length ;x ++){arr[x] = arr[x-2] + arr[x-1] ;}System.out.println("第二十月兔子的对数是:"+arr[19]); //6765对象System.out.println("-----------------------------------------------");//递归:方法本身调用方法的中调用System.out.println("第二十个月兔子的对数是:"+getRabit(20));}//n表示月份数public static int getRabit(int n){ //20//出口条件if(n==1||n==2){ //第一个月和第二个月兔子对数1return 1 ;}else{//从第三个月开始:兔子对数等于两个月兔子对数之后return getRabit(n-2)+getRabit(n-1) ;}}
}

22.IO流

1.File

File 文件和目录(文件夹)路径名的抽象表示。
1.构造方法1)File(String pathname)  :参数就是指定的路径/如果没有指定路径(默认是在当前项目下)通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例2)File(File parent, String child)从父抽象路径名和子路径名字符串创建新的 File实例。3)File(String parent, String child):参数1:父目录地址    参数2:具体的子文件地址
2.成员方法:创建/删除/重名1)public boolean createNewFile() throws IOException :表示创建文件 :如果不存在,则创建2)public boolean mkdir():创建文件夹,如果不存在,则创建;否则就返回false3)public boolean mkdirs():创建多个文件,如果父目录不存在,则创建4)public boolean delete():删除文件或者文件夹(如果删除文件夹,文件夹必须为空目录)5)public boolean renameTo(File dest):重命名参数传递的修改的File对象
public class FileDemo {public static void main(String[] args) throws IOException {//表示:E盘下的demo文件夹中的a.txt文件//File(String pathname) 方式1 (推荐)// File file = new File("e://demo//a.txt") ;只是表示这个路径,如果创建a.txt文件,系统找不到指定路径//File(File parent, String child) 方式2/*  File file2 = new File("E://demo") ;File file3 = new File(file2,"a.txt") ;//File(String parent, String child):方式3File file4 = new File("E://demo","a.txt") ;*/File file = new File("D:\\EE_2106\\day25\\code\\a.txt"); //绝对路径File file2 = new File("aaa.txt");//没有带路径,就默认在当前项目下(相对路径)File file3 = new File("D:\\EE_2106\\day25\\code\\demo") ;File file4 = new File("aaa\\bbb\\ccc\\ddd") ;// public boolean createNewFile()System.out.println(file.createNewFile());System.out.println(file2.createNewFile());System.out.println(file3.mkdir());System.out.println(file4.mkdirs());System.out.println(file3.delete());System.out.println(file.delete());System.out.println("------------------------");//D:\EE_2106\day25\code路径下logo.jpg :描述下这个地址File// File srcFile  = new File("D:\\EE_2106\\day25\\code\\logo.jpg") ;File srcFile = new File("D:\\EE_2106\\day25\\code\\mv.jpg") ;File destFile = new File("高圆圆.jpg") ;//当前项目路径下了//public boolean renameTo(File dest)System.out.println(srcFile.renameTo(destFile)) ;}
}
3.判断功能     1)public boolean canRead()是否可读   2)public boolean canWrite()是否可写  3)public boolean exists():是否存在   4)public boolean isFile():是否是文件    5)public boolean isDirectory():是否是文件夹 6)public boolean isHidden():是否隐藏
4.高级获取功能: 1)public long length()  2)public String getName():获取抽象路径 名所表示的文件或者目录的名称 3)public File[] listFiles():获取某个目录下的所有的文件以及文件夹的File数组   4)public String[] list():获取某个抽象路径名所表示的文件以及目录的字符串数组
public class FileDemo2 {public static void main(String[] args) {//创建File对象,描述当前项目下的aaa.txt文件File file = new File("aaa.txt") ;System.out.println(file.canRead());        System.out.println(file.canWrite());System.out.println(file.exists()); System.out.println(file.isDirectory());//false     System.out.println(file.isFile());  System.out.println(file.isHidden());   System.out.println(file.length());   System.out.println(file.getName());    System.out.println("------------------------");      /*需求:获取       D盘下的所有的文件夹以及文件的名称....*/     // public File[] listFiles():获取某个目录下的所有的文件以及文件夹的File数组   //描述D盘   File file2 = new File("d://") ;     File[] fileArray = file2.listFiles();     //防止空指针异常    if(fileArray!=null){      for(File f :fileArray){         System.out.println(f.getName());     }    }     System.out.println("----------------------------------");   //public String[] list():获取某个抽象路径名所表示的文件以及目录的字符串数组    String[] strArray = file2.list();   if(strArray!=null){      for(String s:strArray){       System.out.println(s);     }     }   }
}
需求2:获取D盘下所有的以.jpg结尾的文件分析:1)描述下D盘2)  public File[] listFiles():获取D盘下的所有的文件以及文件夹的File数组2.1)对获取到的数组进行非判断如果不为null,再去判断2.2)判断File是一个文件2.3)判断:文件必须以.jpg结尾String类 endsWith(".jpg")
提供了另一个重载功能:public File[] listFiles(FilenameFilter filter)String[] list(FilenameFilter filter)参数为:文件名称过滤器FilenameFilter:接口成员方法:boolean accept(File dir,String name):测试指定文件是否包含在文件列表中返回如果true,将文件添加到文件列表中1) 描述下D盘2) public File[] listFiles(FilenameFilter filenamefilter):获取D盘下的File数组的时候,就已经指定文件进行过滤...
public class FileTest {public static void main(String[] args) {//方法一//1)描述D盘File file = new File("D://") ;//2)获取盘符下的所有的文件以及文件夹的File数组File[] fileArray = file.listFiles();//这一步并没有直接获取到要的.jpg文件//后面一些判断if(fileArray!=null){for(File f:fileArray){//判断f是文件if(f.isFile()){//是文件//判断它的名称是否以.jpg结尾if(f.getName().endsWith(".jpg")){System.out.println(f.getName());}}}}System.out.println("-------------------------------------------------------");//方法二//描述下D盘File srcFile = new File("D://") ;//获取当前D盘下的所有文件以及文件夹File数组,并进行文件名过滤//public File[] listFiles(FilenameFilter filter)File[] files = srcFile.listFiles(new FilenameFilter() {//接口的匿名内部类@Overridepublic boolean accept(File dir, String name) {//返回true:表示将指定文件添加列表文件中//描述文件所表示抽象路径FileFile 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());}}}
}

2.IO流的分类

 IO流的分类:按流的方向:输入和输出流按类型分:字节和字符流:字节先出现,后面在有字符流再次流的方向划分字节输入流:InputStream:表示输入字节流的所有类的超类(父类)字节输出流:OutputStream:表示字节输出流的所有类的超类字符输入流:Reader表示输入字符流的抽象类字符输出流:Writer表示输出字符流的抽象类字节/字符流都很多子类XXXInputStreamXXXOutputStreamXXXReaderXXXWriter

3.字节流

1)OutputStream
字节输出流:OutputStream抽象类    子类进行实例化FileOutputStream:将指定的内容写到文件中   实现步骤:         1)创建文件输出流对象 :FileOutputStream(String name) :推荐:可以指定参数地址                                                            FileOutputStream(File file)              写入文件末尾处构造函数:public FileOutputStream(File file,boolean append)throws FileNotFoundException            创建一个向指定 File 对象表示的文件中写入数据的文件输出流。如果第二个参数为 true,则将字节写入文件末尾处,而不是写入文件开始处。                  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)关闭资源
public class FileOutputStreamDemo {public static void main(String[] args) throws IOException {//创建文件输出流对象//指向某个盘符下的文件中(或者当前项目下)FileOutputStream fos = new FileOutputStream("my.txt") ;//文件需要被创建当前项目下//2)写数据/* fos.write(97);fos.write(98);fos.write(99);*///写一个字节数组/*  byte[] bytes = {97,98,99,100,101,102} ;// fos.write(bytes);fos.write(bytes,2,2);*/for(int x = 0 ; x < 10 ; x ++){fos.write(("hello world").getBytes());//windows操作系统  "\r\n"代表换换行fos.write("\r\n".getBytes());}//3)关闭资源fos.close(); //释放fos流对象所指向的my.txt的系统资源}
}
public class FileOutputStreamDemo2 {public static void main(String[] args) {// method1() ;method2() ;//}//标准方式:try...catch...finally//统一处理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();}}}}//分别try...catch...(不用,这种方式阅读性很差)private static void method1() {//在当前项目下输出fos.txt//创建字节输出流对象FileOutputStream fos = null ;try {fos = new FileOutputStream("fos.txt") ;} catch (FileNotFoundException e) {e.printStackTrace();}//写数据try {fos.write("hello,IO".getBytes()) ;} catch (IOException e) {e.printStackTrace();}//关闭资源try {fos.close();} catch (IOException e) {e.printStackTrace();}}
}
2)InputStream
字节输入流:InputStream 子类:FileInputStream实现步骤:   需要读取当前项目下的fis.txt文件      1)创建文件字节输入流对象,指向 fis.txt                     public FileInputStream(String name) throws FileNotFoundException       2)读内容           public int read(byte[] bytes) throws IOException一次读取一个字节数组  ,返回值值的是每次读取的实际字节数              read():一次读取一个字节    3)释放资源        读取文件的时候,一次读取一个字节,存在中文乱码, 在最终输出的结果 (char)by   (场景:将某一个文件内容打印在控制台上了)  注意:          "abc" 英文 读一个字节  a--->97   b --98          针对中文字符: 现在idea环境: 编码格式:utf-8格式: 一个中文对应三个字节 ,和前面的英文拼接出现问题,只要中文都会乱码    才出现了字符流(加入编码和解码的格式)
public class FileInputStreamDemo {  public static void main(String[] args) {   //创建一个字节输入流对象      FileInputStream fis = null ;   try {       // fis  = new FileInputStream("fis.txt") ;   fis  = new FileInputStream("DiGuiTest.java") ; //读取当前项目下的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();        }        }     }   }}
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)) ;//应该描述:每一次从0这个位置读取实际长度     }  } catch (IOException e) {   e.printStackTrace();    }finally {          try {             fis.close();     } catch (IOException e) {       e.printStackTrace();       }     } }
}
读写复制操作:一次读取一个字节的方式     一次读取一个字节数组需求:      将当前项目下的DiGuiTest.java 的内容 复制到D盘下的Copy.java文件中分析:      源文件:  当前项目下 "DiGuiTest.java"      封装源文件:FileInputStraem(String pathname)                一次读取一个字节      目的地文件:  D://Copy.java      封装目的地文件:FileOutputStream(String pathname)                一次写一个字节
public class CopyFileDemo {public static void main(String[] args) {long start = System.currentTimeMillis() ;//时间毫秒值// method("DiGuiTest.java","D://Copy.java") ;method2("DiGuiTest.java","D://Copy.java") ;long end  = System.currentTimeMillis() ;System.out.println("共耗时:"+(end-start)+"毫秒");}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();}}}/*** 一次读取一个字节:读写复制* @param srcFile  源文件* @param destFile 目的地文件*/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();}}}

4.缓冲字节流

1)BufferedInputStream
字节缓冲输入流构造方法   BufferedInputStream(InputStream in) :默认缓冲区大写 (足够大了)    提供一个指定的缓冲区大小                            BufferedInputStream(InputStream in, int size)
public class BufferedInputStreamDemo {public static void main(String[] args) throws IOException {//创建一个字节缓冲输入流对象BufferedInputStream bis = new BufferedInputStream(new FileInputStream("bos.txt")) ;/***  class BufferedInputStream{**      private static int DEFAULT_BUFFER_SIZE = 8192; //8kb**  public BufferedInputStream(InputStream in) {*         this(in, DEFAULT_BUFFER_SIZE);*     }**     public BufferedInputStream(InputStream in, int size) {*         super(in);*         if (size <= 0) {*             throw new IllegalArgumentException("Buffer size <= 0");*         }*         buf = new byte[size];  //底层还是一个字节数组*     }*     }*///读内容//一次读取一个字节/*  int by = 0 ;while((by=bis.read())!=-1){//打印控制台上System.out.print((char)by);}*///一次读取一个字节数组byte[] bytes = new byte[1024] ;int len = 0  ;while((len=bis.read(bytes))!=-1){System.out.println(new String(bytes,0,len));}}
}
2)BufferedInputStream
缓冲流的特点:提供缓冲区大写:1024的8倍   还是通过底层流提高读速度(FileInputStream)构造方法:BufferedInputStream   BufferedOutputStream(OutputStream out)   推荐使用这个:默认缓冲区大小 足够大了  8kb  创建一个新的缓冲输出流,以将数据写入指定的底层输出流。  BufferedOutputStream(OutputStream out, int size)
public class BufferedOutputStreamDemo {public static void main(String[] args) throws IOException {//BufferedOutputStream(OutputStream out)  //参数父类:抽象类//创建字节缓冲输出流BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("bos.txt")) ;/*** 源码:* public BufferedOutputStream(OutputStream out) {*         this(out, 8192);*     }*  public BufferedOutputStream(OutputStream out, int size){*super(out);*if (size <= 0) {*throw new IllegalArgumentException("Buffer size <= 0");*}*buf = new byte[size]; //创建了字节数组  byte[] buf = new  byte[8192]*}*///写数据//写一个字节数组bos.write("hello.bufferedOutputStream".getBytes());//释放资源bos.close();}
}

复制对比

读取D://a.mp4将这个文件内容复制到 当前项目下的copy.mp4中基本的字节流一次读取一字节共耗时89021毫秒基本的字节流一次读取一字节数组共耗时116毫秒字节缓冲流一次读取一个字节共耗时348毫秒字节缓冲流一次读取一个字节数组共耗时47毫秒
public class CopyMp4 {public static void main(String[] args) {//起始时间long start = System.currentTimeMillis() ;//  copyMp4("D://a.mp4","copy.mp4") ;//copyMp4_2("D://a.mp4","copy.mp4") ;//copyMp4_3("D://a.mp4","copy.mp4") ;copyMp4_4("D://a.mp4","copy.mp4") ;//结束时间long end = System.currentTimeMillis() ;System.out.println("共耗时"+(end-start)+"毫秒");}//缓冲流一次读取一个字节数组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();}}}//缓冲流一次读取一个字节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();}}}//基本的字节流一次读取一个字节数组public static void copyMp4_2(String srcFile,String destFile){//封装源文件和目的地文件FileInputStream fis = null ;FileOutputStream fos = null ;try {fis = new FileInputStream(srcFile) ;fos = new FileOutputStream(destFile) ;//读写复制byte[] bytes = new byte[1024] ;int len = 0 ;//实际字节数while((len=fis.read(bytes))!=-1){fos.write(bytes,0,len);//强制输出流将缓冲的这字节数写出来fos.flush();}} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}finally {try {fos.close();fis.close();} catch (IOException e) {e.printStackTrace();}}}//基本的字节流一次读取一个字节public static void copyMp4(String srcFile, String destFile) {//封装源文件和目的地文件FileInputStream fis = null ;FileOutputStream fos = null ;try {fis = new FileInputStream(srcFile) ;fos = new FileOutputStream(destFile) ;//读写复制int by = 0 ;while((by=fis.read())!=-1){fos.write(by);}} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}finally {try {fos.close();fis.close();} catch (IOException e) {e.printStackTrace();}}}
}

5.字符流

1)Writer–OutputStreamWriter
Writer:抽象类   (字符流的出现是在字节流的后面,可以解决中文乱码问题)
提供子类:字符转换输出流: 字节输出流通向字符输出流的桥梁!
构造方法   OutputStreamWriter(OutputStream out) :使用平台默认编码集写入数据  OutputStreamWriter(OutputStream out, String charsetName) :使用指定的字符集进行编码 写入数据   write                 write(String str)        write(int ch):写入字符: 字符--->对应的ASCII码表    write(char[] ch)     write(char[] ch,int off,int len)     write(String str,int off,int len)
public class WriterDemo {  public static void main(String[] args) throws Exception {   //创建字符缓冲输出流对象    OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("osw.txt")) ;//使用平台的默认编码集(utf-8)     //写入数据    /**     * write(String str)    * write(int ch):写入字符: 字符--->对应的ASCII码表    * write(char[] ch)   * write(char[] ch,int off,int len)  * write(String str,int off,int len)    */    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    //osw.write(98);  }
}
2)Reader–InputStreamReader
Reader:抽象类    具体的子类:字符转换输入流 InputStreamReader构造方法    InputStreamReader(InputStream in) :使用平台默认解码集进行读    InputStreamReader(InputStream in,String charset) :使用指定的解码集进行读
public class ReaderDemo {  public static void main(String[] args) throws Exception {   //创建字符转换输入流对象    //InputStreamReader(InputStream in,String charset) :使用指定的解码集进行读      // InputStreamReader isr = new InputStreamReader(new FileInputStream("osw.txt"),"UTF-8") ;      //InputStreamReader(InputStream in)   InputStreamReader isr = new InputStreamReader(new FileInputStream("osw.txt"));//平台默认的解码集进行读取       //读一个字符数组    char[] chs = new char[1024] ; //实际字符数  int len = 0 ;      while((len=isr.read(chs))!=-1){   //打印控制台上:每次获取的实际长度       System.out.println(new String(chs,0,len));     }    //释放资源       isr.close();}
}
3)便捷类
Reader/Writer子类:转换流     InputStreamReader(InputStream in)    OutputStreamWriter(OutputStream out)
他们不能直接去操作文件,jdk提供了这两种类型的便捷类,可以直接操作文件
FileReader(File file)      FileReader(String pathname)    FileWriter(File file)     FileWriter(String filename)   public FileWriter(File file,boolean append)throws IOException     根据给定的 File 对象构造一个 FileWriter 对象。如果第二个参数为 true,则将字节写入文件末尾处,而不是写入文件开始处。          这两个类:使用的平台的默认编码和解码 (utf-8)
需求:    当前项目下的ReaderDemo.java  复制到 D://Demo.java    针对文本文件:优先采用字符流

6.字符缓冲流

1)BufferedReader
字符缓冲输入流:     BufferedReader  ---- 键盘录入数据      Scanner(InputSteram in)  String nextLine()  BufferedReader(Reader in)
Reader        InputStreamReader(InputStream in):转换流          如果直接进行读的操作(直接操作文件)FileReader(String pathName)创建使用默认大小的输入缓冲区的缓冲字符输入流。BufferedReader(Reader in, int size)  :指定缓冲区大小特有功能: public String readLine() :一次读取一行内容
public class BufferedReaderDemo { public static void main(String[] args) throws IOException {  //创建字符缓冲输入流对象  :使用键盘录入数据!(流的方式)//        InputStreamReader(InputStream in):     //InputStream in = System.in ;//标准输入流//        BufferedReader(Reader in)      //Reader reader = new InputStreamReader(in) ;      //BufferedReader br = new BufferedReader(reader) ;    //一步走     /* BufferedReader br = new BufferedReader(new InputStreamReader(System.in)) ;    System.out.println("请您输入一个字符串数据:");//        public String readLine()    String line = br.readLine();//阻塞式方法     System.out.println("您输入的数据是:"+line);         System.out.println("------------------------------------------");*/    //使用BufferedReader读取bw.txt的文件内容   //readLine:读取一行内容    BufferedReader br2 = new BufferedReader(new FileReader("bw.txt")) ;      //定义变量     String line2 = null ;      while((line2=br2.readLine())!=null){         System.out.println(line2);    }   }
}
2)BufferedWriter
BufferedWriter:字符缓冲输出流
BufferedWriter(Writer out) :创建默认的缓冲区大小:  默认大小:defaultcharbuffersize:8192(默认值足够大)    BufferedWriter(Writer out, int sz)  :指定的大小      public void newLine() throws IOException:写入行的分隔符号特有功能:  利用BufferedReader的readLine()读取一行     利用BufferedWriter写一行,然后换行 public void newLine() throws IOException:
public class BufferedWriterDemo {  public static void main(String[] args) throws IOException {  //输出bw.txt文件,并给里面写内容,而且去实现换行效果   write("\r\n")----现在可以使用newLine    //创建字符缓冲输出流对象   //BufferedWriter(Writer out) :     BufferedWriter bw = new BufferedWriter(new FileWriter("bw.txt"));      //写入数据   //写字符串/写字符       bw.write("hello");   //public void newLine()     bw.newLine();   bw.write("world");     bw.newLine();    bw.write("javaEE");   bw.newLine();    //刷新流       bw.flush();    //释放资源     bw.close();  }
}
3)Copy
BufferedReaer/BufferedWriter  :读写复制操作          一次读取一个字符      一次读取一个字符数组特有功能:      利用BufferedReader的readLine()读取一行     利用BufferedWriter写一行,然后换行 将当前项目下的
ReaderDemo.java 复制到当前项目下:copy.java  一个文本文件读写复制:   阻塞流 (传统的IO流)         当一个线程如果操作的是读的动作,  read(byte[] byte/char[] ..)/readLine():都属于阻塞式方法    另一个线程如果操作的是写的动作,读的线程如果开始读,这边写的线程才能开始进行写的复制操作!             基本的字节流:一次读取一个字节/一次读取一个字节数组             字节缓冲流:一次读取一个字节/一次读取一个字节数组    字符转换流:InputStreamReader(InputStream in)            OutputStreamWriter(OutputStream out)         一次读取一个字符/一次读取一个字符数组     转换流的便捷类           FileReader(String name)     FileWriter(String writer)           一次读取一个字符/一次读取一个字符数组
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();        }      }   }
}

7.SequenceInputStream

SequenceInputStream:       字节流的逻辑串联!
可以将两个或者是两个以上的文件进行读的操作 ,只能操作源文件构造方法       public SequenceInputStream(InputStream s1,InputStream s2)    参数1和参数2:分别要读取的字节输入流对象
1)合并两个文件
现在:合并流
当前项目a.java+b.java---->当前项目下的c.java文件中
将当前项目下的BufferedWriterDemo.java+copy.java文件---->复制到当前项目下b.java文件中
public class CopyMulFile {    public static void main(String[] args) throws Exception {        //创建两个字节输入流对象        InputStream is = new FileInputStream("BufferedWriterDemo.java") ;        InputStream is2 = new FileInputStream("copy.java") ;        //public SequenceInputStream(InputStream s1,InputStream s2)        //创建字节合并流        SequenceInputStream sis = new SequenceInputStream(is,is2) ; //SequenceInputStream extends InputStream        //封装目的地文件:        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(添加多个字节输入流对象)
需求:
BufferedWriterDemo.java
ReaderDemo.java
CopyMp4.java
复制到D://hello.java文件中
public class CopyFileDemo2
{    public static void main(String[] args) throws Exception {        //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();    }
}

8.序列化

序列化:ObjectOutputStream
将某个实体对象写入到流对象中---->将一个对象变成 流数据      构造方法           protected ObjectOutputStream()           protected ObjectOutputStream(OutputStream out) :将某个对象通过底层的基本字节输出进行写的动作      public final void writeObject(Object obj) throws IOException
需求:将Person p = new Person("高圆圆",42) ;---->变成流对象 进行传输反序列化:ObjectInputStream     将流数据----还原成 "对象"
构造方法           public ObjectInputStream(InputStream in)      public final Object readObject() throws IOException, ClassNotFoundException
   NotSerializableException:未实现序列化接口的异常           一个类在进行序列化的时候,(将类的对象写入序列化流中),标记接口Serializable 它有个特点                        为当前这个Person进行编码(为类以及类的成员----->序列化化版本ID(签名):SerialversonUID) java.io.InvalidClassException: com.qf.serailizable_05.Person; local class incompatible:             stream classdesc serialVersionUID = 2588921225545403990,               local class serialVersionUID = -862808041229244683          在进行序列化的时候:当前的    serialVersionUID:序列化版本id号 (假设100):  内存中生成一个id值         在进行反序列化的时候:将流--->对象  :         Person类的字段信息更改了(类的签名信息就会被更改),那么直接进行反序列化产生serialVersionUID=(假设200)         序列化版本id保证,               在idea中生成一个固定的序列版本id号 (一般都针对实体类)          一个实体类:               1)当前类必须为具体类 class 类名{}               2)必须存在私有字段(私有成员变量)               3)必须提供公共的setXXX()/getXXX()               4)如果当前类需要在网络中进行传输(分布式系统中)必须implements Serializable   idea- file--->setting---->editor---->Inspections----->java---->序列化serializion issue                                    --->serializable class  打上对钩即可!
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()        //java.io.StreamCorruptedException: invalid stream header: EFBFBDEF        //当从对象流读取的控制信息违反内部一致性检查时抛出。    }    //序列化    //将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();    }
}public class Person implements Serializable {    //产生一个固定的序列化版本Id    private static final long serialVersionUID = 8988325735017562383L; //常量值    String name ; //姓名    private transient int age  ; //年龄  //transient :想让某个字段不参与序列化:这个字段(成员变量就使用transient)   public Person(){}    public Person(String name, int age) {        this.name = name;        this.age = age;    }    @Override   public String toString() {        return "Person{" +                "name='" + name + '\'' +                ", age=" + age +                '}';    }
}

对多个对象进行操作

class Person0 implements Serializable{    private static final long serialVersionUID = 9166507990237193254L;    private String name ;    private int age ;    public Person0() {    }    public Person0(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 "Person0{" +                "name='" + name + '\'' +                ", age=" + age +                '}';    }
}
public class Test {    public static void main(String[] args) throws IOException, ClassNotFoundException {//        write();        read();    }    public static void read() throws IOException, ClassNotFoundException {        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("Object.txt"));        Object obj =null;        while((obj=ois.readObject())!=null) {            System.out.println(obj);        }        ois.close();    }        private static void write() throws IOException {        //创建序列化流对象        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("Object.txt"));        //创建对象       Person0 p1 = new Person0("Mike",22);        Person0 p2 = new Person0("Like",44);        //存入        oos.writeObject(p1);        oos.writeObject(p2);        oos.writeObject(null);//加入null 用来判断是否到末尾,如果不加会报错EOFException        oos.close();    }
}

9.Properties

Properties extends Hashtable<K,V> ,它没有泛型,Key和Value都是String表示一组持久的属性。 Properties可以保存到流中或从流中加载。属性列表中的每个键及其对应的值都是一个字符串。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):在属性列表中通过键获取值
public class PropertiesDemo {public static void main(String[] args) {//Properties() :空参构造Properties properties = new Properties() ;//利用Map集合的功能去添加元素properties.put("高圆圆","赵又廷") ;properties.put("文章","姚笛") ;properties.put("文章","马伊琍") ;properties.put("王宝强","马蓉") ;//遍历Set<Object> keySet = properties.keySet();for(Object key :keySet){//通过key获取valueObject value = properties.get(key);System.out.println(key+"---"+value);}System.out.println("---------------------------------------");/*** 推荐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);}}
}
文件操作
Propeties:键和值都是字符串类型:可能需要在src(类所在的路径:类路径)作为一个配置文件xxx.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)将属性列表中的内容保存到指定字节输出流/字符输出流所指向那个文件中
需求:有一个文本文件username.txtkey1=value1key2=value2.......将文本文件中的内容读取到属性列表中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)将属性列表中的内容保存到指定字节输出流/字符输出流所指向那个文件中
public class PropertiesDemo2 {public static void main(String[] args) throws IOException {//        myLoad() ;myStore() ;}//将属性集合类中的内容 ---保存到指定文件中private static void myStore() throws IOException {Properties prop = new Properties() ;//添加key-valueprop.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);}}
}

xxx.txt操作

/* 有一个文本文件user.txt,如果里面键是lisi,* 然后将他的年龄改为45,然后重新写入到user.txt文件中**        user.txt*       zhangsan=30*       lisi=40*       wangwu=50*/
public class Test3 {public static void main(String[] args) throws IOException {//创建一个属性集合列表:PropertiesProperties prop = new Properties() ;//空的,需要将user.txt内容加载到属性列表中Reader r  = new FileReader("user.txt") ;prop.load(r);//System.out.println(prop);//遍历属性集合列表,获取每一个元素Set<String> keySet = prop.stringPropertyNames();for (String key : keySet) {//获取每一个元素 :键//判断如果"lisi"和key一致,那么改变它的值if("lisi".equals(key)){//通过属性列表设置prop.setProperty(key,"45") ;}}//将修改后的内容,重写在保存到user.txt文件中Writer w = new FileWriter("user.txt") ;prop.store(w,"name's lis"); //参数2:对属性列表的信息面搜}
}

23.网络编程

网络编程------>Socket编程特点:发送端/客户端接收端/服务器端  这两端必须存在Socket对象
网络编程的三要素:举例:我要找到高圆圆 说一句话1)ip:知道高圆圆的ip地址2)port     0-65535  (0-1024属于保留端口)知道高圆圆的端口号3)规定一种协议协议:udp协议1)不需要建立连接通道2)属于一种不可靠连接4)执行效率高 (不同步的)TCP/Ip协议1)建立连接通道2)属于安全连接(可靠连接)3)发送文件(使用基本字节流),相对udp协议来说没有限制4)执行效率低(同步的)
InetAddress:互联网ip地址获取InetAddress:ip地址对象public static InetAddress getByName(String host):参数:主机名称(计算机电脑名称)public String getHostAddress():获取ip地址字符串形式
public class NetDemo {public static void main(String[] args) throws UnknownHostException {//如何获取自己电脑上的ip地址----》String形式!//10.12.156.107InetAddress inetAddress = InetAddress.getByName("DESKTOP-Q62EUJH");String ip = inetAddress.getHostAddress();System.out.println(ip);//10.12.156.107}
}

1.udp通信

/*  Udp编程的发送端:*  1)创建Socket对象*  2)发送内容  :内容数据一种数据报文(报包)DatagramPacket*  3)释放资源*/
public class UdpSend {public static void main(String[] args) throws IOException {//1)创建Socket对象//DatagramSocket:发送和接收数据报数据包的套接字。//public DatagramSocket() throws SocketExceptionDatagramSocket 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();}
}/* Udp接收端* 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);}
}
发送端不断键盘录入数据,接收端不断接收数据,然后展示内容
接收端端不断的接收数据接收端一般不关闭接收端只能开启一次,多次就出现 BindException:绑定一次Address already in use: Cannot bind:端口号被占用!
public class UdpSend {public static void main(String[] args) {DatagramSocket ds = null ;try {//创建发送端的Socketds = new DatagramSocket() ;//键盘录入数据//IO流的方式BufferedReader br = new BufferedReader(new InputStreamReader(System.in)) ;//使用readLine()读取一行内容String line = null ;while((line=br.readLine())!=null){    //readLine():阻塞式方法//自定义结束条件if("886".equals(line)){break ;}//创建数据报包DatagramPacket dp = new DatagramPacket(line.getBytes(),line.getBytes().length,InetAddress.getByName("10.12.156.107"),6666);//发送数据报包ds.send(dp);}} catch (SocketException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}finally {//释放资源ds.close();}}
}public class UdpReceive {public static void main(String[] args) {//创建接收端的Sockettry {DatagramSocket ds = new DatagramSocket(6666) ;while(true){//创建一个接收容器byte[] bytes = new byte[1024] ;DatagramPacket dp = new DatagramPacket(bytes,bytes.length) ;//接收ds.receive(dp);//解析实际数据String receiveStr = new String(dp.getData(), 0, dp.getLength());//获取ipString ip = dp.getAddress().getHostAddress();//展示数据System.out.println("data from "+ip+"data is--->"+receiveStr);}} catch (SocketException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}finally {//接收不关闭//接收socket对象一一直开着}}
}

2.TCP通信

TCP特点:需要建立连接通道(就是以一种字节流的方式写入,读取)什么时候建立连接(服务器端如果监听到端口,客户端就立即和服务器端建立连接!)
TCP客户端写数据1)创建TCP客户端的Socket对象2)写数据3)释放资源
TCP服务器端的实现步骤:1)创建服务器端的Socket对象public ServerSocket(int port)throws IOException2)监听客户端连接public Socket accept()throws IOException 返回值就是当前监听到的客户端的Socket对象3)获取通道内的输入流public InputStream getInputStream() throws IOException4)读取数据:一次读取一个字节数组5)展示数据 而且获取ip地址//public InetAddress getInetAddress()
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("10.12.156.107",8888) ;//2)写数据//public OutputStream getOutputStream()throws IOExceptionOutputStream out = s.getOutputStream();//获取通道内的输出流对象out.write("hello,TCP".getBytes());//读取服务器端反馈的数据//3)释放资源s.close();}
}/* TCP服务器端的实现步骤:1)创建服务器端的Socket对象public ServerSocket(int port)throws IOException2)监听客户端连接public Socket accept()throws IOException 返回值就是当前监听到的客户端的Socket对象3)获取通道内的输入流public InputStream getInputStream() throws IOException4)读取数据:一次读取一个字节数组5)展示数据 而且获取ip地址//public InetAddress getInetAddress()    */public class ServerDemo {public static void main(String[] args) throws IOException {// 1)创建服务器端的Socket对象//public ServerSocket(int port)throws IOExceptionServerSocket ss = new ServerSocket(8888) ;System.out.println("服务器正在等待连接...");//2)监听客户端连接
//        public Socket accept()throws IOException 返回值就是当前监听到的客户端的Socket对象Socket socket = ss.accept(); //阻塞式方法//3)取通道内的输入流//public InputStream getInputStream() throws IOExceptionInputStream inputStream = socket.getInputStream();//4)读取数据:一次读取一个字节数组byte[] bytes = new byte[1024] ;int len = inputStream.read(bytes);//获取内容String clientStr = new String(bytes,0,len) ;//再去反馈数据//5)获取ipString ip = socket.getInetAddress().getHostAddress();//展示数据System.out.println("data from "+ip+" content is--->"+clientStr);//关闭ss.close();}
}
一个有回复的TCP通信
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("10.12.156.107",8888) ;//2)写数据//public OutputStream getOutputStream()throws IOExceptionOutputStream out = s.getOutputStream();//获取通道内的输出流对象out.write("hello,TCP".getBytes());//读取服务器端反馈的数据//获取通道内的输入流InputStream in = s.getInputStream();//读byte[] bytes = new byte[1024] ;int len = in.read(bytes);String fkMsg = new String(bytes,0,len) ;System.out.println("fkMsg:"+fkMsg);//3)释放资源s.close();}
}public class ServerDemo {public static void main(String[] args) throws IOException {// 1)创建服务器端的Socket对象//public ServerSocket(int port)throws IOExceptionServerSocket ss = new ServerSocket(8888) ;System.out.println("服务器正在等待连接...");//2)监听客户端连接
//        public Socket accept()throws IOException 返回值就是当前监听到的客户端的Socket对象Socket socket = ss.accept(); //阻塞式方法//3)取通道内的输入流//public InputStream getInputStream() throws IOExceptionInputStream inputStream = socket.getInputStream();//4)读取数据:一次读取一个字节数组byte[] bytes = new byte[1024] ;int len = inputStream.read(bytes);//获取内容String clientStr = new String(bytes,0,len) ;//服务器给客户端再去反馈数据,//获取通道内的输出流OutputStream outputStream = socket.getOutputStream();//写入到通道内的流对象中outputStream.write("ok,数据已经收到".getBytes());outputStream.flush();//5)获取ipString ip = socket.getInetAddress().getHostAddress();//展示数据System.out.println("data from "+ip+" content is--->"+clientStr);//关闭ss.close();}
}
可以连续发送的TCP通信
客户端:1)TCP客户端不断键盘录入数据,服务器端不断接收数据,然后展示数据2)TCP客户端文本文件(XXX.java文件)----->服务器端将文件进行读写复制,输出到当前项目的Copy.java文件中BuferedReader3)TCP客户端文本文件(XXX.jpg文件)----->服务器端将文件进行读写复制,输出到当前项目的Copy.jpg文件中BufferedInputStream
public class ClientDemo {public static void main(String[] args) {//创建客户端的SocketSocket socket = null ;try {socket  = new Socket("10.12.156.107",10010) ;//创建BufferedReaderBufferedReader br = new BufferedReader(new InputStreamReader(System.in)) ;//录入一行//读取一行String line = null ;while((line=br.readLine())!=null){//null只是作为 一个文件是否读完if("over".equals(line)){break ;}//获取通道内的输出流(字节流OutputStream)//封装通道内字节输出流//分步走//OutputStream outputStream = socket.getOutputStream();   //字节流---->字符流//创建字符缓冲输出流//BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(outputStream)) ;//一步走BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())) ;//给封装的通道内的流对象bw写一行bw.write(line);bw.newLine();bw.flush();}} catch (IOException e) {e.printStackTrace();}finally {//释放资源if(socket!=null){try {socket.close();} catch (IOException e) {e.printStackTrace();}}}//需要获取服务器端的反馈数据 (已经读完完毕了)}
}//服务器端不断读取数据并展示
public class ServerDemo {public static void main(String[] args) {//创建服务端的Socket,一直开启ServerSocket ss = null ;try {ss = new ServerSocket(10010) ;//ArrayList<Socket>:ArrayList存储一个列表:都是多个客户端 对象while(true){System.out.println("服务器正在等待连接");Socket socket = ss.accept();//不断监听,不断展示数据//获取通道内的输入流(InputStream)//封装通道内的输入流对象BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())) ;//一次读取一行String line = null ;while((line=br.readLine())!=null){ //阻塞式方法// //展示数据System.out.println(line);}//复制完毕之后,给客户端反馈}} catch (IOException e) {e.printStackTrace();}//服务器端不关闭}
}
发送文本文件并有反馈
客户端的一个文本文件,服务器端进行复制到指定的某个文件中 ,复制完毕了,服务器端需要给客户端反馈!(反馈的消息,客户端能不能获取到)加入反馈操作:出现客户端和服务器端互相等待的情况--->但是文件已经复制完毕!针对服务器端:不知道客户端是否还需要从通道内的输出流对象中写入数据(此时文件读写复制结束条件:只是null)文件读完毕的条件是null,但是TCP通过流的方式 要进行结束; 服务器端不知道客户端是否还需要写入数据,客户端等待着服务器反馈的数据!解决方案:1)自定义结束条件在客户端读完文件中,通知一下服务器端写入一行内容("886/over"),服务器端只要读取到886或者over2)可以使用客户端Socket的一个方法  标记(通知服务器端,客户端已经没有数据输出了)public void shutdownOutput()throws IOException
public class ClientTest {public static void main(String[] args) throws IOException {//将当前项目下的Test.java 客户端将文件写入到 服务器端,服务器端进行复制//创建客户端Socket对象Socket socket = new Socket("10.12.156.107",10086) ;//创建BufferedReader流对象,去操作当前项目下的Test.java文件BufferedReader br = new BufferedReader(new FileReader("Test.java")) ;//获取通道内字节输出流,写数据----封装通道内的字节流BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())) ;//一次读取一行,然后给通道内的流对象中写入过去String line = null ;while((line=br.readLine())!=null){//阻塞式方法bw.write(line);bw.newLine();bw.flush();}//方案1 :自定义结束条件:客户端通道内的流中已经没有数据了/*bw.write("over");bw.newLine();bw.flush();*///方案2:使用socket对象的方法socket.shutdownOutput(); //禁用套接字流输出,通知服务器端 客户端已经不会在写入数据了//客户端读取反馈//获取通道内字节输入流对象InputStream inputStream = socket.getInputStream();byte[] bytes = new byte[1024] ;int len = inputStream.read(bytes);//阻塞方法String fkMsg = new String(bytes,0,len) ;System.out.println("客户端到读取的反馈数据是:"+fkMsg);//关闭br.close();socket.close();}
}/*服务器端复制Test.java到当前项目下的Copy.java文件中*/
public class ServerTest {public static void main(String[] args) throws IOException {//创建服务器端SocketServerSocket ss = new ServerSocket(10086) ;Socket socket = ss.accept();//创建BufferedReader去读取通道内写入过来的数据,封装通道内的流对象BufferedReader br  = new BufferedReader(new InputStreamReader(socket.getInputStream())) ;//创建字符缓冲输出流,写入数据,输出到当前项目下的Copy.java文件中BufferedWriter bw = new BufferedWriter(new FileWriter("copy.java")) ;//一次读取一行String line  = null ;while((line=br.readLine())!=null){//阻塞方法  :可能客户端的文件已经null了,但是服务器端不知道!/* if("over".equals(line)){break ;}*/bw.write(line);bw.newLine();bw.flush();}//加入反馈操作//继续通道内输出流对象OutputStream outputStream = socket.getOutputStream();outputStream.write("数据已经收到了,已经复制完毕".getBytes());outputStream.flush();//释放资源bw.close();ss.close();}
}
客户端的图片文件
/*客户端的图片文件,服务器端将图片进行复制,并反馈给客户端*/
public class ClientImgDemo {public static void main(String[] args) throws IOException {//创建客户端的SocketSocket socket = new Socket("10.12.156.107",12306) ;//创建BuferedInputStream 读取图片文件  :d://mm.jpgBufferedInputStream bis = new BufferedInputStream(new FileInputStream("d://mm.jpg")) ;//写入到通道内流中同时 封装通道内的流BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream()) ;//一次读取一个字节数组byte[] buffer  = new byte[1024] ;int len = 0 ;while((len=bis.read(buffer))!=-1){//写bos.write(buffer,0,len);bos.flush(); //强制刷新,将缓冲的字节数全部写出}//通知服务器端,通道内输出流对象没有数据了socket.shutdownOutput();//读取反馈InputStream inputStream = socket.getInputStream();byte[] bytes = new byte[1024] ;int length = inputStream.read(bytes);System.out.println("反馈内容为:"+new String(bytes,0,length));//关闭资源bis.close();socket.close();}
}/* * 服务器端将图片进行复制,并反馈给客户端* 将图片文件写入到当前项目下的高圆圆.jpg*/
public class ServlerImgDemo {public static void main(String[] args)  throws IOException {ServerSocket ss  = new ServerSocket(12306) ;//监听Socket socket = ss.accept() ;//读取:封装通道内的字节输入流BufferedInputStream bis = new BufferedInputStream(socket.getInputStream()) ;//输出BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("高圆圆.jpg")) ;//一次读取一个字节数组byte[] bytes = new byte[1024] ;int len = 0 ;while((len=bis.read(bytes))!=-1){ //阻塞式方法bos.write(bytes,0,len);bos.flush();}//加入反馈OutputStream outputStream = socket.getOutputStream();outputStream.write("图片文件复制完毕".getBytes());outputStream.flush();//释放资源bos.close();ss.close();}
}

24.反射

什么是反射?能够获取当前某个类的字节码文件对象Class,那么就可以获取当前类的构造器并且创建当前类实例,还可以获取当前类的成员变量并去赋值,或者获取当前类的成员方法并去调用!

1.字节码文件

如何获取一个类的字节码文件对象?1)Object类的getClass()获取  获取当前某个类的实例(正在运行的类)2)任意Java类型的class属性3)Class类的静态功能public static Class<?> forName(String className)

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 ;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +", address='" + address + '\'' +'}';}
}
public class ReflectDemo {public static void main(String[] args) throws ClassNotFoundException {//获取Person类的字节码文件对象:ClassPerson p = new Person() ;Class c1 = p.getClass();System.out.println(c1);//class 全限定名称Person p2  = new Person() ;Class c2 = p2.getClass() ;System.out.println(c2);System.out.println(c1==c2);System.out.println(p==p2);//两个对象System.out.println("----------------------------");Class c3 = Person.class ;System.out.println(c3);System.out.println(c1==c3);System.out.println("-----------------------------");//知道某个一类的全限定名称了,也可以获取当前类的字节码文件对象// Class c4 = Class.forName("Person"); com.qf.reflect_03.Person //参数字符串:全限定名称Class c4 = Class.forName("com.qf.reflect_03.Person"); //com.qf.reflect_03.Person //参数字符串:全限定名称System.out.println(c4);System.out.println(c1==c4);//第二种方式和第三种使用  推荐第三种       因为参数为String------>就可以存储在配置文件中}
}

2.创建对象

1.获取构造方法:1)public Constructor<?>[] getConstructors():获取当前字节码文件对象中(正在运行的这个类)里面所有的公共的构造方法所在的对象2)public Constructor<?>[] getDeclaredConstructors():获取所有的构造器对象Constructor,返回构造器对象数组  包含私有化构造/默认的3)public Constructor<T> getDeclaredConstructor(类<?>... parameterTypes) :参数都是参数类型的字节码文件对象4)public Constructor<T> getConstructor(Class<?>... parameterTypes) :( ... :jdk5以后 可变参数 (参数数量未知) )获取指定的公共的单个的构造器对象    参数:需要书写的是当前参数类型的字节码文件对象public void setAccessible(boolean flag)参数为true,取消Java语言访问检查public T newInstance(Object... initargs): 参数为最终赋值的实际参数 (可变参数:实际参数未知)
/*现在需要使用反射(底层)如何创建p对象的!*/
public class ReflectDemo {public static void main(String[] args) throwsClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {//之前的写法Person p = new Person() ;System.out.println(p);System.out.println("-----------------------------------------");//使用反射的方式创建当前类实例//1)获取Person类的字节码文件对象Class personClass = Class.forName("com.qf.reflect_03.Person") ;//class com.qf.reflect_03.Person//2)获取构造器对象//Class类//public Constructor<?>[] getConstructors():获取当前字节码文件对象中(正在运行的这个类)里面所有的公共的构造方法所在的对象Constructor[] constructors = personClass.getConstructors();for (Constructor constructor : constructors) {System.out.println(constructor);//public com.qf.reflect_03.Person()}//public Constructor<?>[] getDeclaredConstructors():获取所有的构造器对象Constructor,返回构造器对象数组  包含私有化构造/默认的Constructor[] constructors = personClass.getDeclaredConstructors();for (Constructor constructor : constructors) {System.out.println(constructor);//结果://private com.qf.reflect_03.Person(java.lang.String,int,java.lang.String)//com.qf.reflect_03.Person(java.lang.String,int)//public com.qf.reflect_03.Person()}//获取某一个构造器对象Constructor//public Constructor<T> getConstructor(Class<?>... parameterTypes) :// ... :jdk5以后 可变参数 (参数数量未知)//获取指定的公共的单个的构造器对象    参数:需要书写的是当前参数类型的字节码文件对象Constructor constructor = personClass.getConstructor();//java.lang.String//通过构造器对象创建当前类的实例//public T newInstance(Object... initargs): 参数为最终赋值的实际参数 (可变参数:实际参数未知)Object obj = constructor.newInstance();System.out.println(obj); //p}
}
public class ReflectDemo2 {public static void main(String[] args) throws Exception {//之前的写法
//        Person p  = new Person("高圆圆",20) ;  //默认修饰符只能同一个包下访问//反射创建p对象//1)获取类的字节码文件对象Class clazz = Class.forName("com.qf.reflect_03.Person") ;//2)获取构造Constructor(构造方法所在对象)//Person(String name,int age)获取指定的构造函数对象   ,返回值都是单个构造函数//public Constructor<T> getDeclaredConstructor(类<?>... parameterTypes) :参数都是参数类型的字节码文件对象// 公共的构造函数对象:public Constructor<T> getConstructor(Class<?>... parameterTypes)Constructor constructor = clazz.getDeclaredConstructor(String.class, int.class);//通过构造器创建当前类的实例//getDeclaredConstructor//java.lang.IllegalAccessException: Class com.qf.reflect_04.ReflectDemo2  非法访问异常:因为当前构造函数式默认修饰符// can not access a member of class com.qf.reflect_03.Person with modifiers ""//取消Java语言访问检查(反射中使用到)//public void setAccessible(boolean flag)参数为true,取消Java语言访问检查constructor.setAccessible(true);Object obj = constructor.newInstance("高圆圆", 20);System.out.println(obj);//Person{name='高圆圆', age=20, address='null'}}
}

3.成员变量

获取方法:public Field[] getFields()throws SecurityException:  获取所有的公共的成员变量Fieldpublic Field[] getDeclaredFields(): 所有的字段所在的Field对象,这包括公共,受保护,默认(包)访问和私有字段,但不包括继承的字段。public Field getField(String name):参数为字段名称,获取单个成员变量public Field getDeclaredField(String name):  获取指定的单个的字段所在的Field对象 , 参数为"当前字段名称",这包括公共,受保护,默认(包)访问和私有字段,但不包括继承的字段。
public class ReflectDemo {public static void main(String[] args) throws Exception {//没有使用反射之前Person p = new Person() ;System.out.println(p);p.age = 20 ;//对象名.属性;System.out.println(p);System.out.println("-----------------------------");//反射的方式//1)获取Person类的字节码文件Class clazz = Class.forName("com.qf.reflect_03.Person") ;//方式1:直接获取当前类的实例//public T newInstance()Object obj = clazz.newInstance();System.out.println(obj);//方式2:通过获取构造函数对象,创建当前类实例/*  Constructor constructor = clazz.getConstructor();Object obj = constructor.newInstance();System.out.println(obj);*///2)Class类//public Field[] getFields()throws SecurityException    获取所有的公共的成员变量FieldField[] fields = clazz.getFields() ;for (Field field : fields) {System.out.println(field);//public int com.qf.reflect_03.Person.age}//public Field[] getDeclaredFields():所有的字段所在的Field对象// 这包括公共,受保护,默认(包)访问和私有字段,但不包括继承的字段。Field[] fields = clazz.getDeclaredFields() ;for (Field field : fields) {System.out.println(field);//private java.lang.String com.qf.reflect_03.Person.name// public int com.qf.reflect_03.Person.age// java.lang.String com.qf.reflect_03.Person.address}//现在访问name   private String name ;//public Field getDeclaredField(String name):获取指定的单个的字段所在的Field对象//参数为"当前字段名称"Field nameField = clazz.getDeclaredField("name"); //默认:null//Field提供方法//public void set(Object obj,Object value):给绑定在当前对象上的字段进行赋值//参数1:创建当前类的实例//参数2:value 赋值的实际参数//取消Java语言访问检查nameField.setAccessible(true);//赋值nameField.set(obj,"高圆圆");System.out.println(obj);System.out.println("-----------------------------------------------");//public int age ;//获取当前age所在Field对象//public Field getField(String name):参数为字段名称Field ageField = clazz.getField("age");//直接赋值ageField.set(obj,20);System.out.println(obj);System.out.println("-----------------------------------------");//  String address ; //地址 默认修饰符//获取Field对象Field addressField = clazz.getDeclaredField("address");//取消Java语言访问检查addressField.setAccessible(true);//赋值addressField.set(obj,"西安市");System.out.println(obj);}
}

4.成员方法

如何通过反射获取成员方法所在的Method,并能去调用1)public Method[] getMethods(): 获取所有的成员方法:公共的(包含他父类的所有的公共的方法)2)public 方法[] getDeclaredMethods(): 通过此表示类对象,包括公共,保护,默认(包)访问和私有方法,但不包括继承的方法3)public Method getMethod(String name,Class<?>... parameterTypes)参数1:方法名参数2:当前这个方法所携带的参数类型的Class4)public Method getDeclaredMetho(String name,Class<?> ..parameterTypes):  获取指定的单个的字段所在的成员方法 , 参数为"当前字段名称",这包括公共,受保护,默认(包)访问和私有字段,但不包括继承的字段。public Object invoke(Object obj,Object... args):将方法的实际参数绑定在当前类的实例上
public class ReflectDemo {public static void main(String[] args)  throws  Exception{//没有使用反射之前Person p = new Person() ;p.show();System.out.println("--------------------------");//直接反射方式获取//1)获取当前Person字节码文件对象Class clazz = Class.forName("com.qf.reflect_03.Person") ;Object obj =clazz.newInstance() ;//当前类实例//2)获取所有的成员方法:公共的(包含他父类的所有的公共的方法)//public Method[] getMethods()//public 方法[] getDeclaredMethods():通过此表示类对象,包括公共,保护,默认(包)访问和私有方法,但不包括继承的方法。
//        Method[] methods = clazz.getMethods();/* Method[] methods = clazz.getDeclaredMethods();for (Method method : methods) {System.out.println(method);}*///获取指定的方法 调用public void show()// public Method getMethod(String name,Class<?>... parameterTypes)//参数1:方法名//参数2:当前这个方法所携带的参数类型的ClassMethod showMethod = clazz.getMethod("show");//Method:底层调用方法//public Object invoke(Object obj,Object... args):将方法的实际参数绑定在当前类的实例上//参数1:就是当前类的实例//参数2:可变参数, 方法传递实际参数  若无参,则实际不用传递//返回值:如果当前方法本身有返回值,则返回ObjectshowMethod.invoke(obj) ;System.out.println("--------------------------------------");//private  String functioin(String str){//        return str ;//    }//调用Person类中function//获取function方法的Method对象//public Method getDeclaredMetho(String name,Class<?> ..parameterTypes).Method functonMethod = clazz.getDeclaredMethod("functioin", String.class);//取消Java语言访问检查:私有方法functonMethod.setAccessible(true);Object returnObj = functonMethod.invoke(obj, "hello,洪学佳,别睡了...");System.out.println(returnObj);// void method(String message,int num){//        System.out.println(message+num);//    }////    public int method2(){//        return 100 ;//    }}
}

5.应用

/** 反射的应用:*      现在有一个ArrayList<Integer>,里面有一些元素,*                  如何给ArrayList添加String类型的元素呢?*/
public class ReflectTest {public static void main(String[] rgs) throws Exception {//有一个ArrayList集合对象ArrayList<Integer> arrayList  = new ArrayList<>() ;arrayList.add(100) ;arrayList.add(50) ;arrayList.add(200) ;System.out.println(arrayList);// arrayList.add("hello") ;//1)获取当前集合实例所在的字节码文件对象//通过Object的getClass()获取当前实例所在的类的字节码对象Class clazz = arrayList.getClass();//System.out.println(obj);//System.out.println(clazz);//class java.util.ArrayList//获取当前类中 add方法所在的Method//public boolean add(E e)  ://参数就是任意Java类型 (Element)Method addMethod = clazz.getMethod("add", Object.class);//调用方法addMethod.invoke(arrayList, "hello");addMethod.invoke(arrayList, "world");addMethod.invoke(arrayList, "javaEE");System.out.println(arrayList);}
}
需求;现在有一个学生类以及工人类,两类都有一个love方法ReflectTest2在测试类中进行测试1)起初,创建的一个学生对象,调用love方法2)代码更改,创建一个工人类对象,调用love方法如何将上面的代码进行优化!Java设计原则:开闭原则:对修改关闭,对扩展开放 (在现有代码进程上,想办法进行扩展...)如果提供配置文件,以后只需要修改配置文件中内容,而不更改当前的代码!如果能将配置文件,如果能加载属性集合列表中className=com.qf.reflect_06.WorkermethodName=love就可以通过key--->valuecom.qf.reflect_06.Worker:创建当前类的字节码文件对象
/** 通过反射获取Person类的字节码文件对象并获取当前构造函数(带三个参数的构造函数)创建当前类实例**  private Person(String name,int age,String addrss)*/
public class ReflectDemo3 {public static void main(String[] args) throws Exception {//获取Person类的字节码文件对象Class clazz  = Class.forName("com.qf.reflect_03.Person");//获取构造器对象//public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)Constructor con = clazz.getDeclaredConstructor(String.class , int.class , String.class) ;//取消Java语言访问检查con.setAccessible(true);//通过构造器对象创建当前类实例Object obj = con.newInstance("高圆圆", 20, "西安市");System.out.println(obj);  //Person{name='高圆圆', age=20, address='西安市'}}
}
/*字节码文件:myClass.propertiesclassName=com.qf.reflect_06.WorkermethodName=love
*//*工人类*/
public class Worker {public void love(){System.out.println("爱生活,爱drink...,爱足球");}
}
/*学生类*/
public class Student {public void love(){System.out.println("爱学习,爱Java,爱高圆圆...");}
}public class ReflectTest2 {public static void main(String[] args) throws Exception {//1)现在学生类对象/* Student s1 = new Student() ;s1.love();*///需求改变:创建工人类对象/*Worker worker  = new Worker() ;worker.love();*///优化:提供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获取valueString 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) ;}
}

25.数据库

DDL语句:数据库定义语句

1.库的增删查改

1.查询当前mysql下所有的数据库
mysql8.0  自带的  跟5.5自带的不一样
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |    mysql默认的一些配置
| mysql              |    mysql库里面包含user表用户表 (权限用户)
| performance_schema |    mysql性能相关的库
| sakila             |    提供其他三个库 sakila sys world  提供了一些例库   练习sql语句
| sys                |
| world              |
| zy                 |  自定义的库(开发者自定义)
+--------------------+
7 rows in set (0.00 sec)
2.创建数据库

create database 库名 ;

方式1
mysql> create database mydb_01;
Query OK, 1 row affected (0.02 sec)

create database if not exists 库名;

方式2
mysql> create database if not exists mydb_02;
Query OK, 1 row affected (0.02 sec)
3.查看创建数据库的默认的字符集(了解)

show create database 库名;

mysql> show create database mydb_01;
+----------+-----------------------------------------------------------------------------------------------------------------------------------+
| Database | Create Database                                                                                                                   |
+----------+-----------------------------------------------------------------------------------------------------------------------------------+
| mydb_01  | CREATE DATABASE `mydb_01` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */ |
+----------+-----------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
4.修改数据库的字符集(了解)

alter database 库名 (default)可以省略 character set=字符集;

mysql> alter database mydb_01 default character set gbk ;
Query OK, 1 row affected (0.01 sec)
mysql> show create database mydb_01;
+----------+----------------------------------------------------------------------------------------------------+
| Database | Create Database                                                                                    |
+----------+----------------------------------------------------------------------------------------------------+
| mydb_01  | CREATE DATABASE `mydb_01` /*!40100 DEFAULT CHARACTER SET gbk */ /*!80016 DEFAULT ENCRYPTION='N' */ |
+----------+----------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)mysql>
5.删除库

drop database 库名;

drop database if exists 库名;

mysql> drop database mydb_02;
Query OK, 0 rows affected (0.02 sec)mysql> drop database if exists mydb_03;
Query OK, 0 rows affected (0.01 sec)mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mydb_01            |
| mysql              |
| performance_schema |
| sakila             |
| sys                |
| world              |
| zy                 |
+--------------------+
6.模糊查询mysql服务中所有的带character字符集的全局变量
show variables like '%character%' ;mysql> show variables like '%character%' ;
+--------------------------+---------------------------------------------------------+
| Variable_name            | Value                                                   |
+--------------------------+---------------------------------------------------------+
| character_set_client     | gbk                                                      |
| character_set_connection | gbk                                                     |
| character_set_database   | utf8mb4                                                 |
| character_set_filesystem | binary                                                  |
| character_set_results    | gbk                                                     |
| character_set_server     | utf8mb4                                                 |
| character_set_system     | utf8mb3                                                 |
| character_sets_dir       | C:\Program Files\MySQL\MySQL Server 8.0\share\charsets\ |
+--------------------------+---------------------------------------------------------+
8 rows in set, 1 warning (0.01 sec)如果出现中文乱码:character_set_client 客户端  utf8character_set_results  结果集 utf8改动字符集:临时解决中文乱码
mysql> set character_set_client=utf8;
Query OK, 0 rows affected, 1 warning (0.01 sec)mysql> set character_set_results=utf8;
Query OK, 0 rows affected, 1 warning (0.00 sec)mysql> show variables like '%character%' ;
+--------------------------+---------------------------------------------------------+
| Variable_name            | Value                                                   |
+--------------------------+---------------------------------------------------------+
| character_set_client     | utf8mb3                                                 |
| character_set_connection | gbk                                                     |
| character_set_database   | ut
f8mb4                                                 |
| character_set_filesystem | binary                                                  |
| character_set_results    | utf8mb3                                                 |
| character_set_server     | utf8mb4                                                 |
| character_set_system     | utf8mb3                                                 |
| character_sets_dir       | C:\Program Files\MySQL\MySQL Server 8.0\share\charsets\ |
+--------------------------+---------------------------------------------------------+
8 rows in set, 1 warning (0.00 sec)

2.表的增删改查

1.创建表
create table 表明(列名1 字段类型1,列名2 字段类型2,...列名n 字段类型n
) ; 数据库常用的字段类型
int------>默认int(11)  取的是当前实际长度 (推荐)id int,---编号          1 int(长度):指定长度id int(3)          1---->001 varchar(字符长度):字符串类型数据   '' "" 不写 引号  ,习惯去使用''或者双引号
double(值1,值2):小数类型  举例double(3,2) ----小数类型,3位数,小数点后保留2位123.56
日期类型date  仅仅表示日期,不表示时分秒"2021-8-12"datatime  不仅表示日期具体的时间"2021-8-12 17:31:00"timestap:时间戳  给表中插入数据, 显示当前插入/修改/删除/查询数据那一刻时间 (具体到秒"2021-8-12 18:00:01")   注意事项:就是给那一个库中创建表  使用哪个库(选择数据库名)use 库名;
mysql> use mydb_01;
Database changed
mysql>mysql> create table student(-> id int,-> name varchar(20),-> gender varchar(10),-> address varchar(50),-> age int-> )-> ;
Query OK, 0 rows affected (0.05 sec)
2.查询当前数据库中有哪些表

show tables ;

mysql> show tables;
+-------------------+
| Tables_in_mydb_01 |
+-------------------+
| student           |
+-------------------+
1 row in set (0.01 sec)
3.查询当前表的结构

desc 表名 ;

mysql> desc student;
+---------+-------------+------+-----+---------+-------+
| Field   | Type        | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+-------+
| id      | int         | YES  |     | NULL    |       |
| name    | varchar(20) | YES  |     | NULL    |       |
| gender  | varchar(10) | YES  |     | NULL    |       |
| address | varchar(50) | YES  |     | NULL    |       |
| age     | int         | YES  |     | NULL    |       |
+---------+-------------+------+-----+---------+-------+
5 rows in set (0.01 sec)
修改表
4.给student表添加一列

alter table 表名 add 字段名称 字段类型;

mysql> alter table student add email varchar(50) ;
Query OK, 0 rows affected (0.04 sec)
Records: 0  Duplicates: 0  Warnings: 0mysql> desc student;
+---------+-------------+------+-----+---------+-------+
| Field   | Type        | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+-------+
| id      | int         | YES  |     | NULL    |       |
| name    | varchar(20) | YES  |     | NULL    |       |
| gender  | varchar(10) | YES  |     | NULL    |       |
| address | varchar(50) | YES  |     | NULL    |       |
| age     | int         | YES  |     | NULL    |       |
| email   | varchar(50) | YES  |     | NULL    |       |
+---------+-------------+------+-----+---------+-------+
6 rows in set (0.01 sec)
5.修改表中的字段类型

alter table 表名 modify 字段名称 更改后的字段类型;

mysql> alter table student modify address varchar(30) ;
Query OK, 0 rows affected (0.07 sec)
Records: 0  Duplicates: 0  Warnings: 0mysql> desc student;
+---------+-------------+------+-----+---------+-------+
| Field   | Type        | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+-------+
| id      | int         | YES  |     | NULL    |       |
| name    | varchar(20) | YES  |     | NULL    |       |
| gender  | varchar(10) | YES  |     | NULL    |       |
| address | varchar(30) | YES  |     | NULL    |       |
| age     | int         | YES  |     | NULL    |       |
| email   | varchar(50) | YES  |     | NULL    |       |
+---------+-------------+------+-----+---------+-------+
6 rows in set (0.00 sec)
6.修改表中的字段名称

alter table 表名 change 旧列名 新列名 字段类型;

mysql> alter table student change gender sex varchar(10) ;
Query OK, 0 rows affected (0.02 sec)
Records: 0  Duplicates: 0  Warnings: 0mysql> desc student;
+---------+-------------+------+-----+---------+-------+
| Field   | Type        | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+-------+
| id      | int         | YES  |     | NULL    |       |
| name    | varchar(20) | YES  |     | NULL    |       |
| sex     | varchar(10) | YES  |     | NULL    |       |
| address | varchar(30) | YES  |     | NULL    |       |
| age     | int         | YES  |     | NULL    |       |
| email   | varchar(50) | YES  |     | NULL    |       |
+---------+-------------+------+-----+---------+-------+
6 rows in set (0.01 sec)
7.删除某一列字段

alter table 表名 drop 字段名称;

mysql> alter table student drop email;
Query OK, 0 rows affected (0.06 sec)
Records: 0  Duplicates: 0  Warnings: 0mysql> desc student;
+---------+-------------+------+-----+---------+-------+
| Field   | Type        | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+-------+
| id      | int         | YES  |     | NULL    |       |
| name    | varchar(20) | YES  |     | NULL    |       |
| sex     | varchar(10) | YES  |     | NULL    |       |
| address | varchar(30) | YES  |     | NULL    |       |
| age     | int         | YES  |     | NULL    |       |
+---------+-------------+------+-----+---------+-------+
5 rows in set (0.01 sec)
8.修改表的表名

alter table 旧表名 renameto 新表名;

mysql> alter table student rename to stu;
Query OK, 0 rows affected (0.03 sec)mysql> show tables;
+-------------------+
| Tables_in_mydb_01 |
+-------------------+
| stu               |
| teacher           |
+-------------------+
2 rows in set (0.01 sec)
9.复制一张表结构和以前表的结果一样

create table 新表名 like 旧表名;


mysql> create table teacher like student; //字段复制
Query OK, 0 rows affected (0.03 sec)mysql> show tables;
+-------------------+
| Tables_in_mydb_01 |
+-------------------+
| student           |
| teacher           |
+-------------------+
2 rows in set (0.01 sec)
10.删除表

drop tabble 表名;

drop table if exists 表名;

mysql> drop table if exists teacher;
Query OK, 0 rows affected (0.03 sec)mysql> show tables;
+-------------------+
| Tables_in_mydb_01 |
+-------------------+
| stu               |
+-------------------+
1 row in set (0.00 sec)

DML语句:操作表的记录

11.插入语句

1)**insert into 表名 values(值1,值2,值3…) ;**插入全表数据 :那么每一个参数值必须和字段类型匹配! (不会报错,警告)

mysql> insert into stu values(1,'高圆圆','女','西安市',30) ;
Query OK, 1 row affected (0.01 sec)

插入全表:一次性插入多条数据

2)insert into 表名 values(值1,值2…),(值1,值2…),(值1,值2…) ;

  INSERT INTO stu VALUES (3,'文章','男','西安市',35),(4,'马伊琍','女','上海市',42),(5,'德玛西亚','男','艾欧尼亚',25) ;

插入部分字段

3) insert into 表名(部分字段1,字段2…) values(值1,值2…)

INSERT INTO
stu(NAME,sex,address) VALUES('王宝强','男','咸阳市') ;-- 注意:插入部分字段,必须字段数量和插入值的数量必须匹配
-- 不管插入部分字段还全部字段,那么必须要和当前类型一致
12.最基本的查询:查全表数据

select * from 表名;

mysql> insert into stu values(1,'高圆圆','女','西安市',30) ;
Query OK, 1 row affected (0.01 sec)mysql> select * from stu ;
+------+--------+------+---------+------+
| id   | name   | sex  | address | age  |
+------+--------+------+---------+------+
|    1 | 高圆圆 | 女   | 西安市  |   30 |
+------+--------+------+---------+------+
1 row in set (0.01 sec)如果中文乱码
改动下面的字符集编码即可
mysql> show variables like '%character%' ;
+--------------------------+---------------------------------------------------------+
| Variable_name            | Value                                                   |
+--------------------------+---------------------------------------------------------+
| character_set_client     | gbk                                                     |
| character_set_connection | gbk                                                     |
| character_set_database   | gbk                                                     |
| character_set_filesystem | binary                                                  |
| character_set_results    | gbk                                                     |
| character_set_server     | utf8mb4                                                 |
| character_set_system     | utf8mb3                                                 |
| character_sets_dir       | C:\Program Files\MySQL\MySQL Server 8.0\share\charsets\ |
+--------------------------+---------------------------------------------------------+
8 rows in set, 1 warning (0.00 sec)mysql> set character_set_client = utf8;
Query OK, 0 rows affected, 1 warning (0.00 sec)mysql> set character_set_results = utf8;
Query OK, 0 rows affected, 1 warning (0.00 sec)
13.修改表的数据

语法:按条件修改 update

1)update 表名 set 字段名称 = 值 where 字段名称= 值;

-- 修改name是王宝强的将他的id设置为7
UPDATE stu SET id = 7 WHERE NAME = '王宝强' ;-- 修改id为7的age设置为37
UPDATE stu SET age = 37 WHERE id =  7 ;

一次修改多个字段
2)update 表名 set 字段名称1 =值1 ,字段名称2 =值2 where 条件;

-- 将id为的6的姓名修改为 '张三丰' ,性别修改为'男'
UPDATE stu
SET NAME = '张三丰',sex = '男'
WHERE   id =  6 ;

3)如果不带条件修改:就是批量修改

-- 将修改name为 '高圆圆'
UPDATE stu SET NAME = '高圆圆' ;    -- 一般都是带条件进行修改!
14.删除表中数据

1)带条件来删除
delete from 表名 where 字段名称 = 值; //删除指定的记录

-- 删除id = 6的这条记录
DELETE FROM stu WHERE id = 6 ;
-- 删除id = 6的这条记录
DELETE FROM stu WHERE id = 6 ;

2)删除全表数据
delete from 表名;

DELETE FROM stu ;

truncate table 表名;

TRUNCATE TABLE stu ;

删除全表的语法

delete from 表名;
truncate table 表名; 两个区别1)delete from 表名:只是删除全表数据;表的结构还存在,如果表中 存在主键并且自增长约束,那么不会受影响,下一次在插入数据继续在之前的基础上继续自增长!2)truncate table 表名 ; 将表中数据删除的同时删除了表,然后在创建一张一模一样空表,肯定影响自增长主键的值,再次插入数据,自增长从1开始...等价于drop table my_use;创建一个当前一模一样的表结构
-- 创建一张新的表 my_user表
CREATE TABLE my_user(id INT PRIMARY KEY AUTO_INCREMENT, -- 用户编号 主键加增长NAME VARCHAR(20),age INT ,gender VARCHAR(5)
) ;
INSERT INTO my_user(NAME ,age ,gender) VALUES('张三',20,'男'),('李四',22,'女'),('文章',25,'男')  ;
INSERT INTO my_user(NAME,age,gender) VALUES('王五',18,'男') ;
-- delete from my_user where id =  8 ;-- 删除全表数据
DELETE FROM my_user ;   -- 删除全部数据
TRUNCATE TABLE my_user ;SELECT * FROM my_user;

3.查询表的数据

DQL之基本的查询语句

1)查询全表数据

SELECT * FROM 表名 ;

实际开发中,* (通配符),一般查询全表数据,需要带全部字段

2)select 字段名称列表 from 表名;

SELECT   -- 指定全部字段id ,NAME,sex,address,age
FROM  stu ; -- 查询指定的字段
-- select 字段名称列表 from 表名;
SELECT id ,NAME ,address,age
FROM stu ;

3)查询指定字段时可以通过as 关键字指定别名,as可以省略

SELECTid AS '学生编号',NAME AS '姓名',address AS '地址',age AS '年龄'
FROM stu ;-- as 可以省略
SELECTid  '学生编号',NAME  '姓名',address  '地址',age  '年龄'
FROM stu ;
1.where条件查询
DQL带条件查询
where条件查询可以基本运算符:比较运算符(<,>,<=,>=,!=)/逻辑运算符(|| && /and /or)/赋值运算符 =where后面多个or   in(集合数据)    在两个值之间 between 值1 and 值2mysql 判断某个字段为null , is null  /is not null模糊查询 like聚合函数 count(列名)/max(列名)/min(列名)/sum(列名)/avg(列名)排序查询 order by分组查询 group by筛选查询 having分页查询limit
-- 创建一个学生表
CREATE TABLE student ( id INT, -- 编号NAME VARCHAR(20), -- 姓名age INT, -- 年龄 sex VARCHAR(5), -- 性别 address VARCHAR(100), -- 地址 math INT, -- 数学english INT -- 英语 );INSERT INTO student(id,NAME,age,sex,address,math,english) VALUES (1,'马云',55,'男',' 杭州',66,78),(2,'马化腾',45,'女','深圳',98,87),(3,'马景涛',55,'男','香港',56,77),(4,'柳岩 ',20,'女','湖南',76,65),(5,'柳青',20,'男','湖南',86,NULL),(6,'刘德华',57,'男','香港 ',99,99),
(7,'马德',22,'女','香港',99,99),
(8,'德玛西亚',18,'男','南京',56,65);
-- 条件查询
-- 查询年龄大于20岁的人的全部信息
SELECT id  '编号',NAME '姓名',age '年龄',sex '性别',address '地址',math '数学成绩',english '英语成绩'
FROM student
WHEREage > 20 ;
-- 查询年龄在20岁和30岁之间的学生信息
SELECT      *
FROMstudent
WHEREage >= 20 && age <=30 ; -- &&:Java的逻辑运算符-- 另一种语法
SELECT      *
FROMstudent
WHEREage >= 20 AND  age <=30 ;-- and mysql表示并列关系-- 另一种语法:mysql  在两个值之间 between 值1 and 值2
SELECT -- 查询部分字段 并且年龄在20-30NAME '姓名',age '年龄',address '地址',math '数学成绩',english '英语成绩'
FROM student
WHEREage
BETWEEN 20 AND 30 ;
-- 查询年龄是18或者20或者30岁的学生的编号,姓名,年龄以及地址   (|| 或者 or)
SELECTid  '编号',NAME '姓名',age '年龄',address '地址'
FROM student
WHERE age = 18 OR age = 20 OR age = 30 ;
-- mysql另一种语法 where 字段名称 in(多个值)
SELECTid  '编号',NAME '姓名',age '年龄',address '地址'
FROM student
WHERE age IN(18,20,30) ;
查询null
-- 查询英语成绩为null的学号编号,姓名,性别,地址.数学成绩信息
/* selectid ,name,sex,address,math
fromstudent
where english == null ; -- java中的用法可以这样用   == = (都不行)
*/
SELECTid ,NAME,sex,address,math,english
FROMstudent
WHERE english IS NULL ; -- mysql用法
-- 查询英语成绩不为null的人 ,is not null 的用法
SELECTid ,NAME,sex,address,math,english
FROMstudent
WHERE english IS NOT NULL ;
-- 查询英语和数学成绩总分的学生新
SELECT id 编号 ,NAME 姓名 ,sex 性别 , address '地址',-- (math+english) as '总分'(math+IFNULL(english,0)) '总分'
FROM student ;

**mysql 内置函数ifnull(值1,值2) ; **

IFNULL(english,0) :
-- 如果当前英语成绩为null,给默认值0ql
字段去重 distinct
-- 查询字段,对字段去重 (distinct)
SELECT DISTINCT address 地址 FROM student ;
-- 查询年龄不是20岁的学生信息SELECT  *
FROM  student
WHERE age != 20 ;  -- != Java中这种语法 !=
-- mysql中的不等于 <>
SELECT *
FROM student
WHEREage <> 20 ;
2.模糊查询
糊查询mysql服务中带字符集相关的变量 show variables  like '%character%' ;
模糊查询 like
select 字段列表  from 表名 where 字段名称 like  '%字符%' ;% :包含的指定的字符  使用'%字符值%' 模糊查询包含指定字符的信息_ :代表单个字符(一个_下划线代表一个字符)两个相结合使用: '_%字符值%_'  三个字符:中间字符包含指定的值进行模糊查询
-- 查询当前学生表中姓名包含马的学生信息
SELECT *
FROM student
WHERENAME
LIKE '%马%' ;
-- 查询第二个字符包含化的学生信息
SELECT*
FROMstudent
WHERE NAME
LIKE'_化%' ;
-- 查询姓名是三个字符的人
SELECT *
FROM student
WHERE NAME
LIKE'___' ;-- 应用场景: 搜索框中输入关键字查询---使用到模糊查询
3.聚合函数查询
聚合函数查询---- >查询结果:单行单列的数据count(列名) :总记录数     count(列名)查询总记录数的时候,一般都使用非业务字段查询max(列名): 最大值min(列名字段):最小值sum(字段名称):求和avg(列名):平均分select 聚合函数(列名) from 表名;

查询当前student这个表的全部总记录数

-- 如果使用english字段查询总记录数
SELECT COUNT(english) -- 使用业务字段查询(可能某个值为null,不会进行记录)
FROM student ;  -- 7条记录
-- 可以使用函数设置如果当前某个值null,给默认值
SELECT  COUNT(IFNULL(english,0)) 总记录数
FROMstudent;
-- 建议id来查询
SELECTCOUNT(id) 总条数
FROM student ;-- 查询数学的平均成绩 avg(列名)
SELECTAVG(math) '数学平均成绩'
FROMstudent ;   -- 79.5000-- 查询英语成绩---总成绩(求和 sum(列名))
SELECTSUM(IFNULL(english,0)) 英语总分FROMstudent ;-- 查询英语成绩的最高成绩
SELECTMAX(IFNULL(english,0)) 英语最高分
FROM student ;-- 查询数学成绩最低分
SELECTMIN(math) 数学最低分FROMstudent ;
-- 聚合函数使用最多的:count函数,avg函数
4.order by
排序查询:order by 字段名称  asc/desc (升序/降序)
select 字段列表 from 表名 order by 字段名 排序规则; -- 单个字段进排序
-- 数学成绩安装升序排序
SELECT*
FROMstudent
ORDER BY math  ;  -- 如果字段名称后面没有带排序规则:则默认升序排序-- 英语降序排序
SELECT NAME ,age,sex,address,IFNULL(english,0) 英语成绩
FROM student
ORDER BY english DESC ; -- 降序
-- 针对多个字段同时排序,当前第一字段值相等,则按照第二个字段的排序规则执行
-- select  字段列表  from 表名 order by 字段名称1 升序1 ,字段名称2 升序2;
-- 查询全表数据,数学成绩降序,英语成绩升序
SELECT*
FROMstudent
ORDER BY   math DESC,english ASC ;
5.group by
分组查询:group by  分组group by 分组字段;查询的时候可以查询分组字段, group by 后面不能使用聚合函数
-- 现在需要按照性别分组-----分组之后查询出总人数
-- 性别-- 男/女
SELECT   -- 查询分组字段sex '性别',COUNT(id) '人数'
FROMstudent
GROUP BY sex  ; -- 性别
-- 现在需要按照性别分组-----分组之后查询出总人数,数学的平均分
-- 条件:数学成绩不大于70分的人不参与分组;
SELECTsex '性别', -- 查询分组字段COUNT(id) '总人数',AVG(math) '数学平均成绩'
FROMstudent
WHERE   math > 70 -- 条件:数学成绩大于70分人参与分组
GROUP BY sex ; -- 性别分组
6.HAVING
筛选 havinghaving 必须置于group by 之后,where 置于 group by 之前group by不能聚合函数,但是having后面可以聚合函数
-- 现在需要按照性别分组-----分组之后查询出总人数,数学的平均分
-- 条件:数学成绩不大于70分的人不参与分组
-- 筛选条件:总人数大于2的一组
SELECTsex '性别', -- 查询分组字段COUNT(id) '总人数',AVG(math) '数学平均成绩'
FROMstudent
WHERE   math > 70 -- 条件:数学成绩大于70分人参与分组
GROUP BY sex  -- 性别分组
HAVING  COUNT(id) > 2 ;-- 优化
SELECTsex 性别, -- 查询分组字段COUNT(id) 总人数,AVG(math) 数学平均成绩
FROMstudent
WHERE   math > 70 -- 条件:数学成绩大于70分人参与分组
GROUP BY sex  -- 性别分组
HAVING  总人数 > 2 ;
having 与 where 的区别
where 子句1) 对查询结果进行分组前,将不符合where条件的行去掉,即在分组之前过滤数据,即先过滤再分组。 2) where 后面不可以使用聚合函数
having 子句 1) having子句的作用是筛选满足条件的组,即在分组之后过滤数据,即先分组再过滤。 2) having后面可以使用聚合函数
7.分页查询limit
select 字段列表 from 表名  limit 起始行数,每页显示多少条;limit 起始行数=(当前页码数-1)*每页显示的条数,每页显示条数;
-- 每页显示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 ;-- 查询全表
SELECT * FROM student ;

4.数据库约束

约束用户操作表的一种行为
1)默认约束
默认约束:防止出现非法数据null(没有插入造成null值)
当前没有给那个字段设置值的时候,此时默认约束就会起作用gender VARCHAR(2) DEFAULT '女'
如果没有默认约束:可能用户操作数据库的时候,插入非法数据(没有意义的数据)如果没有给某个字段赋值,默认值null
-- 创建一个新的表
CREATE TABLE test(id INT , -- 编号NAME VARCHAR(10) , -- 姓名gender VARCHAR(2) DEFAULT '女'  -- 性别  -- 默认约束 防止出现非法数据null(没有插入造成null值)
) ;
INSERT INTO test VALUES(1,'张三','男') ;
-- 可能用户操作数据库的时候,插入非法数据(没有意义的数据)-- 通过sql语句修改表的类型,删除默认约束
ALTER TABLE  test MODIFY gender VARCHAR(2) ;-- 修改表加入默认约束
ALTER TABLE  test MODIFY gender VARCHAR(2)  DEFAULT '女' ;DELETE FROM test WHERE id = 3 ;
2)非空约束
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(1,'张三',null) ;INSERT INTO test VALUES(2,'李四','13666668889') ;
-- INSERT INTO test VALUES(2,'李四','13666668888') ;-- 通过语句删除唯一约束
-- alter table test modify phone varchar(11) ; 错误语法
-- 删除唯一约束的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 ;
4)主键约束
主键约束 (非空+唯一特点) 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,'马三奇','男') ;
-- insert into test values(1,'马嘉钰','男') ;  id值重复 -- Duplicate entry '1' for key 'test.PRIMARY'
-- insert into test values(null,'雷郁','男') ;--  id直接插入null值 Column 'id' cannot be null-- 删除test 表的主键
alter table test drop primary key;
-- 添加主键
alter table test add primary key(id);

第六周 Java语法总结_设计原则_工厂模式_单例模式_代理模式(静态代理_动态代理)_递归_IO流_网络编程(UDP_TCP)_反射_数据库相关推荐

  1. UML类图、JAVA DesignMode 设计模式、设计原则

    全文2.6W余字,读完需要20分钟,介绍23种设计模式,每个模式都有案例与真实使用场景,能够帮助初学者快速了解设计模式,建立起对代码中设计模式的初步理解,要明确:设计模式只是帮助我们更好的设计代码架构 ...

  2. 什么是Java动态代理,如何实现一个动态代理例子

    Java动态代理 一.概述 1. 什么是代理 我们大家都知道微商代理,简单地说就是代替厂家卖商品,厂家"委托"代理为其销售商品.关于微商代理,首先我们从他们那里买东西时通常不知道背 ...

  3. Java的IO流与网络编程

    目录 一.概述 二.文件类(File) 1. File类的构造.获取属性 2. File类获取子文件或目录 3. File类文件重命名 4. File类的判断功能 5. File类创建.删除功能 三. ...

  4. java依赖倒转原则_设计原则之--依赖倒转原则

    [各位博友晚上好,又到了晚上的这个时间,感谢大家一直对Darren博客的支持,希望这篇文章对你有所帮助: 这几天一直在看设计模式:简单工厂模式,策略模式,单一职责原则,开放 [依赖倒转原则又称依赖倒置 ...

  5. 第三周 Java语法总结__static关键字__代码块__继承__this和super的区别__重写__final关键字__多态__抽象__接口__形参问题__包__权限修饰符__内部类

    文章目录 6.static关键字 1)静态static关键字的特点: 2)关于static关键字的使用注意事项 3)什么时候将变量定义为成员变量: 7.文档说明书: 8.代码块 9.继承 1)继承的概 ...

  6. 系统设计原则的重要性_设计原则的重要性及其对好的设计的影响

    系统设计原则的重要性 The principles of design are the most important part of any design process. Without these ...

  7. 代码设计的基础原则_设计原则:良好设计的基础

    代码设计的基础原则 As designers, it's our goal to pass information in the most pleasing way possible. Startin ...

  8. 第六周java实验报告四

    实验报告: 一.实验目的 (1)掌握类的继承 (2)变量的继承和覆盖,方法的继承,重载和覆盖的实现: 二.实验的内容 (1)根据下面的要求实现圆类Circle. 1.圆类Circle的成员变量:rad ...

  9. 举例说明层次分析的三大原则_LabVIEW面向对象编程_初窥门槛(2)_设计原则(SOLID)...

    该系列一共是9篇文章,本文是该系列的第二篇,是讲述通用的面向对象编程设计原则(SOLID),LabVIEW作为一门具备面向对象编程范式的图形化编程语言当然也要遵循上述的通用设计原则,当然除了接口隔离原 ...

最新文章

  1. Java经典面试题:一个线程两次调用start()方法会出现什么情况?
  2. VTK:科赫雪花用法实战
  3. 翻转字符串里的单词—leetcode151
  4. php设计模式之——建造者模式
  5. ClickHouse安装部署与SQL实战
  6. 喜欢独自喝茶的人是什么样的人
  7. C++/CLI思辨录之Object的对象布局
  8. 5月第四周.COM域名增7.3万居首 域名.XXX净减22个
  9. Nintendo Switch 解砖指引(翻译)
  10. Windows快捷命令
  11. 面试官问“你还有什么需要了解的吗”——应该这样回答
  12. React中文文档 9. 表单
  13. JS实现30分钟倒计时
  14. 科研入门必备知识之论文种类--Journal、magazine、transactions、proceedings
  15. 2018届春招面试回顾(二)
  16. c语言求两个字符串的交集,用c语言求两个集合的交集,并集,差集
  17. 人机协作机器人发展趋势_未来10年机器人三大发展趋势
  18. 微信小程序之实现常用日期格式-日历格式(二)
  19. ubuntu 硬盘情况占用分析
  20. 虚幻引擎进行世界场景构建的总览-学习UE4需要首先学习的部分

热门文章

  1. 天星数科首页CSS布局回顾
  2. 经典:linux shell 正则表达式(BREs,EREs,PREs)差异比较
  3. 网络技术 | Cisco Packet Tracer 6.2安装包 安装教程
  4. 如何下载顺义区卫星地图高清版大图
  5. python元组拆包
  6. 「Don‘t Make Me Think」 读后感
  7. 用python随机获取中文名字
  8. react脚手架创建项目报错,ReactDOM.render is no longer supported in React 18.
  9. Dragon之LoginServer
  10. 1+X Web前端开发初级考试 模拟试题(一)