设计模式、IO流

目录

设计模式

一、要素

 二、分类

三、简单工厂模式

四、工厂方法模式

五、单例设计模式

 1、如何保证类在内存中只有一个对象呢?

   2、单例模式的思想是什么?请写一个代码体现。

六、Runtime类的exec的和运行环境相连接的功能

File

一、构造方法

二、成员方法

三、判断功能

四、 高级获取功能

五、另一个重载功能

递归

一、方法递归

 二、前提条件

 三、伪代码

四、求5的阶乘!

五、删除文件

IO流

IO流的分类

一、字节流

字节输出流

 字节输入流

读写复制操作

二、字节缓冲流:缓冲区类(高效类)

特点:

字节缓冲输出流

 字节缓冲输入流

 读写复制操作

三、转换流

字符转换输出流:OutputStreamWriter

 字符转换输入流 :InputStreamReader 

四、转换流简化写法FileReader、FileWriter

五、 BufferedReader/BufferedWriter

 读写复制操作

六、字节流的逻辑串联!

1、字节流的逻辑串联

2、构造方法

3、合并复制文件

七、序列化与反序列化

1、序列化--ObjectOutputStream

 构造方法

2、反序列化  --ObjectInputStream

3、构造方法

4、一个实体类

 5、产生一个固定的序列化版本Id

 八、持久的  --Properties

1、格式

2、属性

3、特点

4、将文本文件中的内容读取到属性列表中Properties 加载

网络编程

1、网络编程三要素

2、特点

3、InetAddress:互联网ip地址

如何获取自己电脑上的ip地址

4、UDP

upd发送端

upd接收端

5、TCP

TCP客户端写数据

TCP服务器端的实现步骤:

6、反馈操作

目的

出现的问题

解决方案

反射

1、什么是反射?

2、如何获取一个类的字节码文件对象?

3、使用反射访问

4、访问

5、反射的应用

1)现在有一个ArrayList,里面有一些元素,如何给ArrayList添加String类型的元素?

2)现在有一个学生类以及工人类,两类都有一个love方法,ReflectTest2在测试类中进行测试

MySQL

一、入门

1、mysql库的管理

2、表的管理


设计模式

一、要素

名字 必须有一个简单,有意义的名字

问题 描述在何时使用模式

解决方案 描述设计的组成部分以及如何解决问题

效果 描述模式的效果以及优缺点

 二、分类

        创建型模式:简单工厂模式,工厂方法模式,抽象工厂模式,建造者模式,原型模式,单例模式。(6个)
        结构型模式:外观模式、适配器模式、代理模式、装饰模式、桥接模式、组合模式、享元模式。(7个)\
        行为型模式:模版方法模式、观察者模式、状态模式、职责链模式、命令模式、访问者模式、策略模式、备忘录模式、迭代器模式、解释器模式。(10个)

三、简单工厂模式

简单工厂模式概述 
      又叫静态工厂方法模式,它定义一个具体的工厂类负责创建一些类的实例 
优点
      客户端不需要在负责对象的创建,从而明确了各个类的职责 
缺点
      这个静态工厂类负责所有对象的创建,如果有新的对象增加,或者某些对象的创建方式不同,就需要不断的修改工厂 
类,不利于后期的维护 

四、工厂方法模式

工厂方法模式概述 
            工厂方法模式中抽象工厂类负责定义创建对象的接口,具体对象的创建工作由继承抽象工厂的具体类实现。 
优点
            客户端不需要在负责对象的创建,从而明确了各个类的职责,如果有新的对象增加,只需要增加一个具体的类和具体的 工厂类即可,不影响已有的代码,后期维护容易,增强了系统的扩展性 
缺点
            需要额外的编写代码,增加了工作量

五、单例设计模式

单例设计模式概述 
            单例模式就是要确保类在内存中只有一个对象,该实例必须自动创建,并且对外提供。 
优点
            在系统内存中只存在一个对象,因此可以节约系统资源,对于一些需要频繁创建和销毁的对象单例模式无疑可以提高系 统的性能。 
缺点
            没有抽象层,因此扩展很难。 
            职责过重,在一定程序上违背了单一职责

 1、如何保证类在内存中只有一个对象呢?

A:把构造方法私有

B:在成员位置自己创建一个对象

C:通过一个公共的方法提供访问

   2、单例模式的思想是什么?请写一个代码体现。

开发:饿汉式(是不会出问题的单例模式)

面试:懒汉式(可能会出问题的单例模式)

A:懒加载(延迟加载)

B:线程安全问题

        a:是否多线程环境 是

        b:是否有共享数据 是

        c:是否有多条语句操作共享数据 是

public class Teacher {
    private Teacher() {
    }
    private static Teacher t = null;
    public synchronized static Teacher getTeacher() {
    // t1,t2,t3
        if (t == null) {
        //t1,t2,t3
        t = new Teacher();
        }
       return t;
    }
}

public class TeacherDemo {
    public static void main(String[] args) {
        Teacher t1 = Teacher.getTeacher();
        Teacher t2 = Teacher.getTeacher();
           System.out.println(t1 == t2);
           System.out.println(t1);
           System.out.println(t2);
    }
}

 1、饿汉式

           1)构造方法私有:保证外界不能直接创建当前类对象
            2)在当前类的成员位置:创建当前类实例
            3)提供一个静态的功能,返回值就是当前类本身(需要当前类的实例)

public class Student {
    //成员变量
   // public  static Student s = new Student() ; //当前类实例
    private  static Student s = new Student() ; //当前类实例 (静态实例变量)
    private Student(){}

    //静态功能
    //返回是当前类本身
    public static Student getStudentInstance(){
        return s;
    }
}

2、懒汉式

  1)构造方法私有化
  2)在当前成员变量的位置声明变量:数据类型就是当前类 (私有的,静态的)
  3)提供静态功能,返回值还是当前类本身,
                  判断如果当前没有给当前类型变量为null,直接new 当期类的实例
                  如果不为null,就返回当前类的变量!

public class Worker {

    //成员变量位置声明变量w
    private static Worker w;//默认值null
    //构造方法私有化
    private Worker() {} //外界不能直接new 对象

   //改进:同步代码块---->静态的同步方法
    public synchronized static Worker getWorkerIntance(){ //锁对象:Worker.class
       // synchronized (w){
            //w1
            //先判断w变量为null
            if(w == null){ //当为null
                w = new Worker() ; //如果当前w变量为null,创建一个新的对象,返回
                return w;
            }
            return w ;
    }
}

六、Runtime类的exec的和运行环境相连接的功能

 Runtime:当前获取的当前本地运行环境的实例
     public int availableProcessors():获取本地计算机的处理器的数量
     public Process exec(String command):开启某个软件的进程(参数为字符串命令)

File

一、构造方法

file:文件和目录(文件夹)路径名的抽象表示

File(String pathname)  :参数就是指定的路径/如果没有指定路径(默认是在当前项目下),通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例

File(File parent, String child)  :从父抽象路径名和子路径名字符串创建新的 File实例。参数1:父目录地址    参数2:具体的子文件地址

二、成员方法

 public boolean createNewFile()   throws IOException 表示创建文件 :如果不存在,则创建

 public boolean mkdir():创建文件夹,如果不存在,则创建;否则就返回false

 public boolean mkdirs() :创建多个文件,如果父目录不存在,则创建

 public boolean delete() :删除文件者文件夹(如果删除文件夹,文件夹必须为空目录)

 public boolean renameTo(File dest) :重命名

三、判断功能

public boolean canRead()是否可读
public boolean canWrite()是否可写
public boolean exists():是否存在
public boolean isFile():是否是文件
public boolean isDirectory():是否是文件夹
public boolean isHidden():是否隐藏

四、 高级获取功能

public long length()
public String getName():获取抽象路径名所表示的文件或者目录的名称
public File[] listFiles():获取某个目录下的所有的文件以及文件夹的File数组
public String[] list():获取某个抽象路径名所表示的文件以及目录的字符串数组

五、另一个重载功能

public File[] listFiles(FilenameFilter filter)

String[] list(FilenameFilter filter)

boolean accept(File dir,String name):测试指定文件是否包含在文件列表中, 返回如果true,将文件添加到文件列表中

 

        //描述下D盘
        File srcFile = new File("D://") ;

        //获取当前D盘下的所有文件以及文件夹File数组,并进行文件名过滤
        //public File[] listFiles(FilenameFilter filter)
        File[] files = srcFile.listFiles(new FilenameFilter() {//接口的匿名内部类
            @Override
            public boolean accept(File dir, String name) {
                //返回true:表示将指定文件添加列表文件中
                //描述文件所表示抽象路径File
                File file = new File(dir, name);

                //两个条件:file是文件并且file的文件名称以".jpg结尾"
                return file.isFile() && file.getName().endsWith(".jpg");
            }
        });
        if(files!=null){
            for(File f :files){
                System.out.println(f.getName());
            }
        }

递归

一、方法递归

方法调用方法本身的一种现象,并非是方法嵌套方法

 二、前提条件

1)必须有一个成员方法
2)必须有方法递归的出口条件(结束条件),如果没有出口条件,就是死递归...
3)还存在一定的规律

 三、伪代码

 public void show(int n){ //50   调用
             if(n<0){
                 System.out.println(n) ;
              }
              n -- ;//49
              show(n) ;
          }

四、求5的阶乘!

public class DiGuiDemo {
   public static void main(String[] args) {

       System.out.println("5的阶乘是:"+jieCheng(5));
   }

    //递归:需要考虑(一定要有规律)
    private static int jieCheng(int i) {
       if(i==1){
           return 1 ;
       }else{
           return i * jieCheng(i-1) ;
       }
    }
}

五、删除文件

            需求:使用递归方式去删除D盘某个demo文件夹中有很多个目录, 每个目录中可能还有目录,删除这些所有目录中的带.java文件的文件!

public class DiGuiTest {
    public static void main(String[] args) {

         //描述D盘的demo文件夹
         File srcFloder = new File("d://demo") ;
         //调用递归删除的方法
        deleteFloder(srcFloder) ;
    }

    public static void deleteFloder(File srcFloder) {
        //获取srcFloder下的所有的文件以及文件的File数组
        File[] fileArray = srcFloder.listFiles();
        if(fileArray!=null){
            for(File file:fileArray){
                //获取到每一个file对象
                //如果file是文件夹,继续回到deleteFloder(srcFloder) ; 删除文件夹
                if(file.isDirectory()){
                    deleteFloder(file) ;
                }else{
                    //判断是文件,必须以.java结尾 文件
                    if(file.getName().endsWith(".java")){
                        //删除的同时----获取名称
                        System.out.println(file.getName()+"------------"+file.delete());
                    }
                }

            }
            //删除文件夹
            System.out.println(srcFloder.getName()+"----"+srcFloder.delete());
        }
    }
}

IO流

IO流的分类

按流的方向

           输入流:读入数据

           输出流:写出数据

按类型

           字节流

                 字节输入流:InputStream:表示输入字节流的所有类的超类(父类)

                 字节输出流:OutputStream:表示字节输出流的所有类的超类

           字符流

                字符输入流:Reader表示输入字符流的抽象类

                字符输出流:Writer表示输出字符流的抽象类

一、字节流

字节输出流

1、字节输出流  OutputStream的抽象类

子类进行实例化FileOutputStream:将指定的内容写到文件中

2、实现步骤

1)创建文件输出流对象 :FileOutputStream(String name) :推荐:可以指定参数地址
        FileOutputStream(File file)
2)写数据
        public void write(int b) throws IOException 写一个字节
        public void write(byte[] bytes) throws IOException 写一个字节数组
        public void write(byte[] bytes,int off,int len) throws IOException:写一部分字节数组
3)关闭资源

3、字节输出流

  private static void method2() {
        FileOutputStream fos = null ;
        //alt+ctrl+t--->
        try {
           fos = new FileOutputStream("fos2.txt") ;
            //写数据
            fos.write("hello,我来了".getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            //释放资源
                if(fos!=null){
                    try {
                        fos.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
              }
        }
    }

 字节输入流

1、字节输入流  InputStream

子类:FileInputStream

2、实现步骤

需要读取当前项目下的fis.txt文件

 1)创建文件字节输入流对象,指向 fis.txt
                public FileInputStream(String name) throws FileNotFoundException
2)读内容
                read(byte[] bytes):一次读取一个字节数组
                read():一次读取一个字节
3)释放资源

3、 一次读取一个字节

public class FileInputStreamDemo {
    public static void main(String[] args) {
        //创建一个字节输入流对象
        FileInputStream fis = null ;
        try {
           fis  = new FileInputStream("DiGuiTest.java") ; 
            //读取内容 
            //使用循环优化:  结束条件:获取的字节数为-1
            //当前不知道循环多少次:while循环
           int by = 0 ; //字节数为0
           while((by=fis.read())!=-1) {
               System.out.print((char)by);
           }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            //释放资源
            if(fis!=null){
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

4、一次读取一个字节数组

public class FileInputStreamDemo2 {
    public static void main(String[] args) {
        //创建字节输入流对象
        FileInputStream fis = null ;
        try {
            fis = new FileInputStream("fis2.txt") ;

         //创建一个数组:长度:1024或者1024的整数倍
          byte[] buffer = new byte[1024] ;   //长度虽然1024个长度
          int len = 0 ;
          while((len=fis.read(buffer))!=-1){
              //每次获取的从0开始获取实际字节长度
              System.out.println(new String(buffer,0,len)) ;
          }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

读写复制操作

字节流一次读写复制一个字节

    private static void method(String srcFile, String destFile) {
        FileInputStream fis  = null ;
        FileOutputStream fos = null ;
        try {
            //  封装源文件:FileInputStraem(String pathname)
            //字节输入流
            fis = new FileInputStream(srcFile) ;
            //字节输出流
            // 封装目的地文件:FileOutputStream(String pathname)
            fos = new FileOutputStream(destFile) ;

            //读写复制操作
            //一次读取一个字节
            int by = 0 ;
            while((by=fis.read())!=-1){
                //没有读完,继续复制 :写一个字节
                fos.write(by);

            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {

            try {
                fos.close();
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

字节流一次读写复制一个字节数组

   private static void method2(String srcFile, String destFile) {
        FileInputStream fis  = null ;
        FileOutputStream fos = null ;
        try {
            //  封装源文件:FileInputStraem(String pathname)
            //字节输入流
            fis = new FileInputStream(srcFile) ;
            //字节输出流
            // 封装目的地文件:FileOutputStream(String pathname)
            fos = new FileOutputStream(destFile) ;

            //读写复制操作
            //一次读取一个字节数组
            byte[] bytes = new byte[1024] ;
            int len = 0 ;
            while((len=fis.read(bytes))!=-1){
                //赋值
                //fos流对象中写
                //带上len的使用
                fos.write(bytes,0,len);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }finally {

            try {
                fos.close();
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

二、字节缓冲流:缓冲区类(高效类)

特点:

缓冲流的特点:提供缓冲区大写:1024的8倍  还是通过底层流提高读速度(FileInputStream)

字节缓冲输出流

BufferedOutputStream(OutputStream out)       这个:默认缓冲区大小 足够大了  8kb

 字节缓冲输入流

BufferedInputStream(InputStream in) :默认缓冲区大写 (足够大了)

 读写复制操作

1、字节缓冲流一次读取一个字符

  private static void copyMp4_3(String srcFile, String destFile) {
        BufferedInputStream bis  = null ;
        BufferedOutputStream bos = null ;
        try {
            bis = new BufferedInputStream(new FileInputStream(srcFile)) ;
            bos = new BufferedOutputStream(new FileOutputStream(destFile)) ;
            //读写操作
            int by = 0 ;
            while((by=bis.read())!=-1){
                bos.write(by);
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                bos.close();
                bis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

2、字节缓冲流一次读取一个字符数组

 private static void copyMp4_4(String srcFile, String destFile) {
        BufferedInputStream bis  = null ;
        BufferedOutputStream bos = null ;
        try {
            bis = new BufferedInputStream(new FileInputStream(srcFile)) ;
            bos = new BufferedOutputStream(new FileOutputStream(destFile)) ;
            //读写操作
            byte[] bytes = new byte[1024] ;
            int len = 0 ;
            while((len=bis.read(bytes))!=-1){
                bos.write(bytes,0,len);
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                bos.close();
                bis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

三、转换流

字符转换输出流:OutputStreamWriter

提供子类:字符转换输出流: 字节输出流通向字符输出流的桥梁!

OutputStreamWriter  字符转换输出流

public  OutputStreamWriter(OutputStream out)  使用平台默认编码集写入数据

public  OutputStreamWriter(OutputStream out,String charsetName)  使用指定的字符集进行编码 写入数据

 1、写入数据

write(String str)
write(int ch):写入字符: 字符--->对应的ASCII码表
write(char[] ch)
write(char[] ch,int off,int len)
write(String str,int off,int len)

 //创建字符缓冲输出流对象
 OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("osw.txt")) ;

 osw.write("hello,字符流我来了");
 osw.write(97);
 char[] chs = {'A','B','C','D','E'} ;
 osw.write(chs);

 osw.write(chs,2,2);
 //使用flush():刷新字符输出流
 osw.flush();
 //关闭资源,释放相关的资源
 osw.close();  //关闭之前,flush

 字符转换输入流 :InputStreamReader 

InputStreamReader  字符转换输入流

public  InputStreamReader(InputStream in)   使用平台默认解码集进行读

public  InputStreamReader(InputStream in,String charsetName)  使用指定的解码集进行读

 字符转换流一次读取一个字符、一次读取一个字符数组

//创建字符转换输入流对象
 InputStreamReader isr = new InputStreamReader(new FileInputStream("osw.txt")) ;

 //读一个字符
    int ch = 0; 
    while ((ch = isr.read()) != -1) {
         System.out.print((char) ch); 
    }
        // 释放资源 
        isr.close();


 //读一个字符数组
        char[] chs = new char[1024] ;
        //实际字符数
        int len = 0 ;
        while((len=isr.read(chs))!=-1){
            //打印控制台上:每次获取的实际长度
            System.out.println(new String(chs,0,len));

        }
        //释放资源
        isr.close();

四、转换流简化写法FileReader、FileWriter

读取数据:

FileReader(File file)
FileReader(String pathname)

写数据
FileWriter(File file)
FileWriter(String filename)

转换流简化写法一次读取一个字符、一次读取一个字符数组

        //1)封装源文件:
        FileReader fileReader = new FileReader("ReaderDemo.java") ;
        //2)封装目文件
        FileWriter fileWriter = new FileWriter("D://Demo.java") ;

        //一次读取一个字符
        int by = 0 ; //实际字符数
        while((by=fileReader.read())!=-1){
            fileWriter.write(by) ;
            fileWriter.flush() ;
        }

        //一次读取一个字符数组
        char[] charArray = new char[1024] ;
        int len = 0 ;
        while((len=fileReader.read(charArray))!=-1){
            //写入实际字符数
            fileWriter.write(charArray,0,len);
            fileWriter.flush();
        }

        //关闭
        fileWriter.close();
        fileReader.close();

五、 BufferedReader/BufferedWriter

  BufferedReader  ---- 键盘录入数据
  BufferedReader(Reader in)

创建使用默认大小的输入缓冲区的缓冲字符输入流
            BufferedReader(Reader in, int size)  :指定缓冲区大小
          特有功能:public String readLine()     :一次读取一行内容

BufferedWriter  --字符缓冲输出流
    BufferedWriter(Writer out) :创建默认的缓冲区大小:  
            默认大小:defaultcharbuffersize:8192(默认值足够大)
   BufferedWriter(Writer out, int sz)  :指定的大小
   public void newLine() throws IOException:写入行的分隔符号

  BufferedReaer/BufferedWrite 
                一次读取一个字符
                一次读取一个字符数组
 特有功能:
                   利用BufferedReader的readLine()读取一行
                   利用BufferedWriter写一行,然后换行

 读写复制操作

public class CopyFile {
    public static void main(String[] args) {
        
        BufferedReader br = null ;
        BufferedWriter bw = null ;
        try {
            //封装源文件:前项目下的    ReaderDemo.java
             br = new BufferedReader(new FileReader("ReaderDemo.java")) ;
             bw = new BufferedWriter(new FileWriter("copy.java")) ;

             //使用特有功能读取一行内容
            String line = null ;
            while((line=br.readLine())!=null){
                //读取一行,bw写一行并换行,然后刷新
                bw.write(line);
                bw.newLine();
                bw.flush();;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                bw.close();
                br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

六、字节流的逻辑串联!

1、字节流的逻辑串联

SequenceInputStream:

可以将两个或者是两个以上的文件进行读的操作 ,只能操作源文件

2、构造方法

public SequenceInputStream(InputStream s1,InputStream s2)

                         参数1和参数2:分别要读取的字节输入流对象 

3、合并复制文件

 (1)将当前项目下的BufferedWriterDemo.java+copy.java文件---->复制到当前项目下b.java文件

        //创建两个字节输入流对象
        InputStream is = new FileInputStream("BufferedWriterDemo.java") ;
        InputStream is2 = new FileInputStream("copy.java") ;

        //public SequenceInputStream(InputStream s1,InputStream s2)
        //创建字节合并流
        SequenceInputStream sis = new SequenceInputStream(is,is2) ;

        //封装目的地文件:
      BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("b.java")) ;

        //一次读取一个字节数组
        byte[] bytes = new byte[1024] ;
        int len = 0 ;
        while((len = sis.read(bytes))!=-1){
            bos.write(bytes,0,len);
        }
        //释放资源
        bos.close();
        sis.close();

(2)将两个以上的文件进行读取

public  SequenceInputStream(Enumeration<? extends InputStream> e) : 

                Vector<InputStream>  -- 创建集合

                add(添加多个字节输入流对象)  -- 添加对象

        //public SequenceInputStream(Enumeration<? extends InputStream> e)
        //需要三个字节输入流对象
        InputStream is1 = new FileInputStream("BufferedWriterDemo.java") ;
        InputStream is2 = new FileInputStream("ReaderDemo.java") ;
        InputStream is3 = new FileInputStream("CopyMp4.java") ;

        //创建一个Vector集合
        Vector<InputStream> vector = new Vector<>() ;

        //添加流对象
        vector.add(is1) ;
        vector.add(is2) ;
        vector.add(is3) ;

        //public Enumeration<E> elements() ---- >类似于Collection的Iterator迭代器
        Enumeration<InputStream> enumeration = vector.elements();

        //创建合并流对象  封装源文件
        SequenceInputStream sis = new SequenceInputStream(enumeration);

        //创建字节缓冲输出流对象
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("d://hello.java")) ;

        //一次读取一个字节
        int by = 0 ;
        while((by=sis.read())!=-1){
            bos.write(by);
            bos.flush();
        }

        bos.close();
        sis.close();

七、序列化与反序列化

1、序列化--ObjectOutputStream

将某个实体对象写入到流对象中---->将一个对象变成 流数据

 构造方法

protected ObjectOutputStream()

protected ObjectOutputStream(OutputStream out) :将某个对象通过底层的基本字节输出进行写的动作

public final void writeObject(Object obj) throws IOException

2、反序列化  --ObjectInputStream

将流数据----还原成 "对象"

3、构造方法

public ObjectInputStream(InputStream in)

public final Object readObject()  throws IOException,  ClassNotFoundException

public class ObjectStreamDemo {
    public static void main(String[] args) throws IOException, ClassNotFoundException {

       myWrite() ;//写
       myRead() ;//读
    }

    //反序列化
    private static void myRead() throws IOException, ClassNotFoundException {
        //创建反序列化流对象
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("oos.txt")) ;

        //读
        //public final Object readObject()
        Object object = ois.readObject();
        //关闭流
        ois.close();
        System.out.println(object);//toString()
    }

    //序列化
    //将Person p = new Person("高圆圆",42) ;---->变成流对象 进行传输
    private static void myWrite() throws IOException {
        //创建Person对象
        Person p = new Person("高圆圆",42) ;

        //protected ObjectOutputStream(OutputStream out):创建一个序列化流对象
       ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("oos.txt")) ;

        //将p对象写入到oos流对象中
        //public final void writeObject(Object obj)throws IOException
        oos.writeObject(p);

        //释放资源
        oos.close();
    }
}

4、一个实体类

1)当前类必须为具体类 class 类名{}
2)必须存在私有字段(私有成员变量)
3)必须提供公共的setXXX()/getXXX()
4)如果当前类需要在网络中进行传输(分布式系统中)必须implements Serializable

 5、产生一个固定的序列化版本Id

file--->setting---->editor---->Inspections----->java---->序列化serializion issue
                            --->serializable class  打上对钩即可!

//产生一个固定的序列化版本Id
private static final long serialVersionUID = 8988325735017562383L; //常量值

 八、持久的  --Properties

1、格式

Properties extends Hashtable<K,V> ,它没有泛型,Key和Value都是String

2、属性

表示一组持久的属性。 Properties可以保存到流中或从流中加载。
属性列表中的每个键及其对应的值都是一个字符串。

3、特点

 1)可以使用Map的功能
          put(K ,V)
          遍历:
              keySet()通用

 2)有自己特有功能添加元素和遍历
              public Object setProperty(String key,String value):给属性列表中添加属性描述(key和value)
              public Set<String> stringPropertyNames():获取属性列表中的所有的键
              public String getProperty(String key):在属性列表中通过键获取值

         //Properties() :空参构造
        Properties properties = new Properties() ;
         //创建一个空的属性列表
        Properties prop = new Properties() ;
        prop.setProperty("张三","30") ;
        prop.setProperty("李四","40") ;
        prop.setProperty("王五","35") ;
        prop.setProperty("赵六","45") ;

        //遍历:
        Set<String> set = prop.stringPropertyNames();//获取所有键
        for(String key:set){
            String value = prop.getProperty(key);
            System.out.println(key+"---"+value);

4、将文本文件中的内容读取到属性列表中Properties 加载

 将字节输入流或者字符输入中所在的文件中的内容加载属性列表中
                void load(Reader reader)
                void load(InputSteram in)

将Properties里面存储的内容----->保存到某个目录的xxx配置文件中 保存
                 public void store(Writer writer,String comments)
                 public void store(OutputStream out,String comments)
                 将属性列表中的内容保存到指定字节输出流/字符输出流所指向那个文件中

        将一个文本文件中属性,加载到属性集合列表(Properties)中,并将这些数据 ---->保存到另一个文件中

public class PropertiesDemo2 {
    public static void main(String[] args) throws IOException {
//        myLoad() ;
         myStore() ;
    }

    //将属性集合类中的内容 ---保存到指定文件中
    private static void myStore() throws IOException {
        Properties prop = new Properties() ;

        //添加key-value
        prop.setProperty("张三丰","56") ;
        prop.setProperty("吴奇隆","60") ;
        prop.setProperty("成龙","65") ;
        prop.setProperty("刘德华","70") ;

        //public void store(Writer writer,String comments):
        //参数2:给当前属性列表中加入一个描述
        //保存指定的文件中
        prop.store(new FileWriter("user.txt"),"name's list'");

        System.out.println("保存完毕");

    }

    //加载:需要将names.txt文件加载到属性列表中,然后遍历
    private static void myLoad() throws IOException {
        //创建一个空的属性列表
        Properties prop = new Properties() ;
        System.out.println(prop);

        //void load(Reader reader)
      //  Reader r = new FileReader("names.txt") ;//names.txt是在当前项目下路径下
        // prop.load(r) ;

        //读取src路径下的names.properties  (类路径)
        //使用步骤
        //1)获取当前类所在的字节码文件对象
        Class clazz = PropertiesDemo2.class ;
        //2)获取当前类所在的类加载器Class:public ClassLoader getClassLoader()
        ClassLoader classLoader = clazz.getClassLoader();
        //3)在类加载器中:获取当前资源文件(配置文件names.proprites)所在的输入流对象
        //public InputStream getResourceAsStream(String name) {
        InputStream inputStream = classLoader.getResourceAsStream("names.properties");
        //将inputStream加载到属性集合类中
//        void load(InputSteram in)
        prop.load(inputStream);

        System.out.println(prop);

        Set<String> keySet = prop.stringPropertyNames();
        for(String key:keySet){
            String value = prop.getProperty(key);
            System.out.println(key+"---"+value);
        }
    }
}

网络编程

1、网络编程三要素

ip:IP地址
port:端口号
协议:
                        udp协议
                           1)不需要建立连接通道
                           2)属于一种不可靠连接
                           3)发送文件大小限制的
                           4)执行效率高 (不同步的)
                      TCP/Ip协议
                         1)建立连接通道
                         2)属于安全连接(可靠连接)
                         3)发送文件(使用基本字节流),相对udp协议来说没有限制
                         4)执行效率低(同步的)

2、特点

 发送端/客户端
接收端/服务器端  这两端必须存在Socket对象

3、InetAddress:互联网ip地址

获取InetAddress:ip地址对象
    public static InetAddress getByName(String host):参数:主机名称(计算机电脑名称)
    public String getHostAddress():获取ip地址字符串形式

如何获取自己电脑上的ip地址

public class NetDemo {
   public static void main(String[] args) throws UnknownHostException {
       //如何获取自己电脑上的ip地址----》String形式!
       InetAddress inetAddress = InetAddress.getByName("DESKTOP-4KUN8QI");//主机名
       String ip = inetAddress.getHostAddress();
       System.out.println(ip);
   }

4、UDP

upd发送端

  1)创建Socket对象
  2)发送内容  :内容数据一种数据报文(报包)DatagramPacket
  3)释放资源

public class UdpSend {
    public static void main(String[] args) throws IOException {
        //1)创建Socket对象
        //DatagramSocket:发送和接收数据报数据包的套接字。
        //public DatagramSocket() throws SocketException
        DatagramSocket ds = new DatagramSocket() ;
        //2)创建一个数据报包对象DatagramPacket
        //DatagramPacket(byte[] buf, int length, InetAddress address, int port)
        //参数1:当前数据的字节数组
        //参数2:当前数据的长度
        //参数3:InetAddress:ip地址对象
        //参数4:绑定的端口号
        byte[] bytes = "hello,马三奇".getBytes() ;
        int length = bytes.length ;
               //public static InetAddress getByName(String host)
        InetAddress inetAddress = InetAddress.getByName("10.12.156.107");
        int port = 12306 ;
        DatagramPacket dp = new DatagramPacket(bytes,length,inetAddress,port) ;
        //3)发送数据报包
        //public void send(DatagramPacket p)
        ds.send(dp);
        //4)释放资源
        ds.close();
    }
}

upd接收端

 1)创建Socket对象
2)创建一个接收容器:数据报包:DatagramPacket
3)接收
4)解析容器的的实际数据大小
5)展示发送端发送的数据

public class UdpReceive {
    public static void main(String[] args) throws IOException {
        //)创建Socket对象
        //public DatagramSocket(int port)
        DatagramSocket ds = new DatagramSocket(12306) ;
        //2)创建一个接收容器:数据报包:DatagramPacket  实际数据没有这么大
        //public DatagramPacket(byte[] buf, int length)
        //自定义字节缓冲区
        byte[] bytes = new byte[1024] ;
        int lentgth = bytes.length ;
        DatagramPacket dp = new DatagramPacket(bytes,lentgth);
​
        //3)public void receive(DatagramPacket p)
        ds.receive(dp);
​
        //4)解析实际数据
        //byte[] getData()   获取实际字节数
        //返回数据缓冲区。
        //int getLength()   获取实际长度
        byte[]  bytes2 = dp.getData();
        int length2 = dp.getLength();
        String receiverStr = new String(bytes2,0,length2) ;
        //获取ip地址
        //InetAddress getAddress()
        //InetAddress
        //public String getHostAddress():
        String ip = dp.getAddress().getHostAddress();
        //展示数据
        System.out.println("data from "+ip+" ,content is :"+receiverStr);
    }
}
​

5、TCP

TCP客户端写数据

     1)创建TCP客户端的Socket对象
     2)写数据
     3)释放资源  

public class ScoketDemo {
    public static void main(String[] args) throws IOException {
        //1)创建TCP客户端的Socket对象
       // public Socket(String host, int port)throws UnknownHostException, IOException
        //参数1:主机名称/或者ip地址字符串形式
        //参数2:指定的端口(0-65535(不包含0-1024))
        Socket s = new Socket("192.168.0.7",8888) ;
​
        //2)写数据
        //public OutputStream getOutputStream()throws IOException
        OutputStream out = s.getOutputStream();//获取通道内的输出流对象
        out.write("hello,TCP".getBytes());
​
        //读取服务器端反馈的数据
​
        //3)释放资源
        s.close();
    }
}

TCP服务器端的实现步骤:

      1)创建服务器端的Socket对象
            public ServerSocket(int port)throws IOException
     2)监听客户端连接
           public Socket accept()throws IOException 返回值就是当前监听到的客户端的Socket对象
     3)获取通道内的输入流
          public InputStream getInputStream() throws IOException
     4)读取数据:一次读取一个字节数组
     5)展示数据 而且获取ip地址
          ublic InetAddress getInetAddress()

public class ServerDemo {
    public static void main(String[] args) throws IOException {
​
        // 1)创建服务器端的Socket对象
        //public ServerSocket(int port)throws IOException
        ServerSocket ss = new ServerSocket(8888) ;
        System.out.println("服务器正在等待连接...");
​
        //2)监听客户端连接
//        public Socket accept()throws IOException 返回值就是当前监听到的客户端的Socket对象
        Socket socket = ss.accept(); //阻塞式方法
        //3)取通道内的输入流
        //public InputStream getInputStream() throws IOException
        InputStream inputStream = socket.getInputStream();
        //4)读取数据:一次读取一个字节数组
        byte[] bytes = new byte[1024] ;
        int len = inputStream.read(bytes);
        //获取内容
        String clientStr = new String(bytes,0,len) ;
​
        //再去反馈数据
​
        //5)获取ip
        String ip = socket.getInetAddress().getHostAddress();
        //展示数据
        System.out.println("data from "+ip+" content is--->"+clientStr);
        //关闭
        ss.close();
    }
}

6、反馈操作

目的

客户端的一个文本文件,服务器端进行复制到指定的某个文件中 ,复制完毕了,服务器端需要给客户端反馈!(反馈的消息,客户端能不能获取到)

出现的问题

加入反馈操作:出现客户端和服务器端互相等待的情况--->但是文件已经复制完毕!
    针对服务器端:不知道客户端是否还需要从通道内的输出流对象中写入数据(此时文件读写复制结束条件:只是null),文件读完毕的条件是null,但是TCP通过流的方式 要进行结束; 服务器端不知道客户端是否还需要写入数据,客户端等待着服务器反馈的数据!

解决方案

1)自定义结束条件
    在客户端读完文件中,通知一下服务器端
       写入一行内容("886/over"),服务器端只要读取到886或者over
2)可以使用客户端Socket的一个方法  标记(通知服务器端,客户端已经没有数据输出了)
    public void shutdownOutput()throws IOException

反射

1、什么是反射?

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

2、如何获取一个类的字节码文件对象?

     1、 Object类的getClass()获取  获取当前某个类的实例(正在运行的类)
           Person p = new Person() ;
           Class c1 = p.getClass();
     
     2、 任意Java类型的class属性
            Class c3 = Person.class ;

      3、 Class类的静态功能 public static Class<?> forName(String className)
            Class c4 = Class.forName("com.qf.reflect_03.Person"); 

3、使用反射访问

创建Person类

public class Person {
​
    //成员变量
     private String name ;//姓名 私有
     public int age ; //年龄  默认
     String address ; //地址 默认修饰符
​
    //无参构造方法:公共的
    public Person(){}
​
    //提供带两个参数的构造方法,默认修饰符
    Person(String name,int age){
        this.name = name ;
        this.age = age ;
    }
​
    //提供三个参数的构造方法,私有的
    private Person(String name,int age,String addrss){
        this.name = name ;
        this.age = age ;
        this.address = addrss ;
    }
​
    //提供一些成员方法(非静态)
    public void show(){
        System.out.println("show Person");
    }
    private  String functioin(String str){
        return str ;
    }
​
    void method(String message,int num){
        System.out.println(message+num);
    }
​
    public int method2(){
        return 100 ;
    }
​
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", address='" + address + '\'' +
                '}';
    }
}

4、访问

访问成员方法
一、   Class类
  public Constructor<?>[] getConstructors():获取当前字节码文件对象中(正在运行的这个类)里面所有的公共的构造方法所在的对象
  public Constructor<?>[] getDeclaredConstructors():获取所有的构造器对象Constructor,返回构造器对象数组  包含私有化构造/默认的
二、  获取所有的成员方法:公共的(包含他父类的所有的公共的方法)
     public Method[] getMethods()
     public 方法[] getDeclaredMethods():通过此表示类对象,包括公共,保护,默认(包)访问和私有方法,但不包括继承的方法。

public class ReflectDemo {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException {
       //Person p = new Person();
       //Class clazz = p.getClass();
​
       Class clazz = Person.class;
​
       // Class clazz = Class.forName("反射.ReflectDemo");
​
        //方式1:直接获取当前类的实例
        //    private String name;
        //    public int age;
        //    String diqu;
        Object obj = clazz.newInstance();
​
        Field nameField = clazz.getDeclaredField("name");
        nameField.setAccessible(true);
        nameField.set(obj,"李娜");
       // System.out.println(obj);
​
        Field ageFiled = clazz.getField("age");
        ageFiled.set(obj,24);
        //System.out.println(obj);
​
        Field diquField = clazz.getDeclaredField("diqu");
        diquField.setAccessible(true);
        diquField.set(obj,"临汾");
        System.out.println(obj);
​
        // public void show()
        Method showMethod = clazz.getDeclaredMethod("show");
        showMethod.invoke(obj);
​
        //private  String functioin(String str)
        Method functioin = clazz.getDeclaredMethod("functioin", String.class);
        //取消Java语言访问检查:私有方法
        functioin.setAccessible(true);
        Object o = functioin.invoke(obj, "该上课了");
        System.out.println(o);
​
        //void method(String message,int num)
        Method method1 = clazz.getDeclaredMethod("method", String.class, int.class);
       // method1.setAccessible(true);
        method1.invoke(obj,"上数学",30);
​
        //public int method2()
        Method method3 = clazz.getDeclaredMethod("method2");
        Object invoke = method3.invoke(obj);
        System.out.println(invoke);
​
     //获取某一个构造器对象Constructor
     //public Constructor<T> getConstructor(Class<?>... parameterTypes) :// ... :jdk5以后 可变参数 (参数数量未知)
     //获取指定的公共的单个的构造器对象    参数:需要书写的是当前参数类型的字节码文件对象
     Constructor constructor = clazz.getConstructor();//java.lang.String
     //通过构造器对象创建当前类的实例
     //public T newInstance(Object... initargs): 参数为最终赋值的实际参数 (可变参数:实际参数未知)
     Object obj1 = constructor.newInstance();
     System.out.println(obj1); //p
​
     //获取构造器对象
     //public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
     Constructor con = clazz.getDeclaredConstructor(String.class,int.class,String.class) ;
     //取消Java语言访问检查
     con.setAccessible(true);
     //通过构造器对象创建当前类实例
     Object obj2 = con.newInstance("高圆圆", 20, "西安市");
     System.out.println(obj2);//Person{name='高圆圆', age=20, address='西安市'}
    }
}

5、反射的应用

1)现在有一个ArrayList<Integer>,里面有一些元素,如何给ArrayList添加String类型的元素?

public class ReflectTest {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
​
        //有一个ArrayList集合对象
        ArrayList<Integer> arrayList = new ArrayList<>();
        arrayList.add(100);
        System.out.println(arrayList);
​
        //1)获取当前集合实例所在的字节码文件对象
        //通过Object的getClass()获取当前实例所在的类的字节码对象
        Class<? extends ArrayList> aClass = arrayList.getClass();
        //System.out.println(clazz);//class java.util.ArrayList
        
        //System.out.println(obj);
        //获取当前类中 add方法所在的Method
        //public boolean add(E e)  ://参数就是任意Java类型 (Element)
        Method add = aClass.getMethod("add", Object.class);
        add.invoke(arrayList, 20);
        System.out.println(arrayList);
    }
}

2)现在有一个学生类以及工人类,两类都有一个love方法,ReflectTest2在测试类中进行测试

Java设计原则:
              开闭原则:对修改关闭,对扩展开放 (在现有代码进程上,想办法进行扩展...)

               如果提供配置文件,以后只需要修改配置文件中内容,而不更改当前的代码!

              如果能将配置文件,如果能加载属性集合列表中
              className=com.qf.reflect_06.Worker
              methodName=love

               就可以通过key--->value

              com.qf.reflect_06.Worker:创建当前类的字节码文件对象

学生类:Student

public class Student {
    public void love(){
        System.out.println("爱学习,爱Java,爱高圆圆...");
    }
}
工人类:Worker

public class Worker {
    public void love(){
        System.out.println("爱生活,爱drink...,爱足球");
    }
}
测试:ReflectTest2

public class ReflectTest2 {
    public static void main(String[] args) throws Exception {
​
        //优化:提供src(类路径下提供配置文件)myClass.properties
        //1)读取src下面的myClass.properties
        //获取资源文件所在的输入流对象
        InputStream inputStream = ReflectTest2.class
                .getClassLoader().
                getResourceAsStream("myClass.properties");
​
        //创建属性集合列表:空的
        Properties prop = new Properties() ;
        //将指定的配置文件所在的输入流加载属性列表中
        prop.load(inputStream);
        System.out.println(prop);
​
        //可以通过可以key获取value
        String className = prop.getProperty("className") ; //当前类的全限定名称
        String methodName = prop.getProperty("methodName") ;
​
        //通过反射创建当前类的字节码文件对象
        Class clazz = Class.forName(className) ;
        //创建当前类的实例 (解耦)
        Object obj = clazz.newInstance() ;
        //通过clazz字节码文件对象获取当前成员方法所在的Method类对象
        Method method = clazz.getMethod(methodName) ;
        method.invoke(obj) ;
    }
}

// myClass.properties

    lassName=com.qf.reflect_06.Worker
    methodName=love

MySQL

一、入门

1、mysql库的管理

1、查看所有数据库

show databases;

2、 创建数据库

create database 库名;

3、查看数据库,创建数据语句

show create database 库名;

4、删除数据库

drop database 库名;

2、表的管理

1、查看所有的表

show tables;

2、创建表

create table 表名(    -- 内容
    id INT,
    NAME VARCHAR(20),
    age INT,
    gender VARCHAR(20),
    math INT,
    english INT,
    chinese INT
    );

3、 查看表sql格式

show create table 表名 ;

4、查看表格格式

desc 表名 ;

5、删除表

drop table 表名 ;

6、管理数据-增删改

插入数据

-- insert into 表名 values (值);
INSERT INTO stydent92class VALUES (1,'王彦登',24,'男',98,56,85);

修改数据

-- update 表名 set 列明=值 where 条件;
UPDATE stydent92class SET math = 145 WHERE id = 1 ;

删除数据

-- delete from 表名 where 条件;   带条件删除数据
-- delete from 表名 ;删除全表数据,表的结构还存在
-- truncate table 表名;-- 删除所有数据,再创建一张一模一样的表

删除全表的语法

    delete from 表名
    truncate table  表名; 两个区别
    
    1)delete from 表名:只是删除全表数据;表的结构还存在,
        如果表中 存在主键并且自增长约束,那么不会受影响,下一次在插入数据
        继续在之前的基础上继续自增长! 
    2)truncate table 表名 ; 
        将表中数据删除的同时删除了表,然后在创建一张一模一样空表,
        肯定影响自增长主键的值,再次插入数据,自增长从1开始...
        
        等价于
            drop table my_use;
            创建一个当前一模一样的表结构

7、查询数据

-- DQL带条件查询

-- where条件查询
--  可以基本运算符:比较运算符(<,>,<=,>=,!=)/逻辑运算符(|| && /and /or)/赋值运算符 =
--  where后面多个or    in(集合数据)    在两个值之间 between 值1 and 值2
--  mysql 判断某个字段为null , is null  /is not null

-- 模糊查询 like

-- 聚合函数 count(列名)/max(列名)/min(列名)/sum(列名)/avg(列名)
-- 排序查询 order by
-- 分组查询 group by
-- 筛选查询 having
-- 分页查询 limit

(1)查询所有列

-- select * from 表名 ;

-- 查询年龄在20岁和30岁之间的学生信息(1)
SELECT  *  FROM  stydent92class  WHERE  age > 20 AND age < 30 ;
-- 在两个值之间 between 值1 and 值2(2)
SELECT  *  FROM  stydent92class  WHERE  age  BETWEEN 20 AND 30 ;

--  查询年龄是18或者20的学生的编号(|| 或者 or)(1)
SELECT  *  FROM stydent92class  WHERE  age = 18 || age = 20 ;
-- 查询年龄是18或者20的学生的编号 :IN (2)
SELECT * FROM stydent92class WHERE age IN (18,20);

-- 查询语文成绩为null的学号编号 : is null
SELECT * FROM stydent92class WHERE chinese IS NULL;
-- 查询语文成绩不为null的学号编号: is not null
SELECT * FROM  stydent92class WHERE chinese IS NOT NULL;

(2)as 可以省略 -- 查询时指定别名

SELECT
    id AS 92班,
    SUM(IFNULL(chinese,0)) AS 语文总分,
    AVG(math) AS 数学平均分,
    MAX(english) AS 英语最高分,
    MIN(english) AS 英语最低分
FROM
    stydent92class;

(3)distinct -- 去除重复数据

(4)查询年龄大于 20 的总数 : <> !=

SELECT * FROM stydent92class WHERE age <> 20 ;

(5)模糊查询 like

-- 模糊查询mysql服务中带字符集相关的变量 show variables    like '%character%' ;
-- 模糊查询 like
-- select 字段列表  from 表名 where 字段名称 like  '%字符%' ;

% :包含的指定的字符  使用'%字符值%' 模糊查询包含指定字符的信息
_ :代表单个字符(一个_下划线代表一个字符)
    两个相结合使用: '_%字符值%_'  三个字符:中间字符包含指定的值进行模糊查询

-- 查询第二个字符包含化的学生信息
SELECT * FROM student WHERE  NAME LIKE '_%化%' ;

(6) 聚合函数查询--单行单列的数据

-- count(列名) :总记录数
-- max(列名): 最大值
-- min(列名字段):最小值
-- sum(字段名称):求和
-- avg(列名):平均分
-- select 聚合函数(列名) from 表名;

-- ifnull  
-- 查询英语成绩的最高成绩
SELECT  MAX(IFNULL(english,0)) 英语最高分 FROM  student ;

(8) 排序查询

order by 字段名称  asc/desc (升序/降序)
-- select 字段列表 from 表名 order by 字段名 排序规则; -- 单个字段进排序
SELECT
    *
FROM
    student
ORDER BY  
    math DESC,
    english ASC ;

(9)分组查询

-- group by   :group by 后面不能使用聚合函数
-- 现在需要按照性别分组-----分组之后查询出总人数,数学的平均分
-- 数学成绩不大于70分的人不参与分组;
SELECT
    sex '性别', -- 查询分组字段
    COUNT(id) '总人数',
    AVG(math) '数学平均成绩'
FROM
    student
WHERE  
    math > 70 -- 条件:数学成绩大于70分人参与分组
GROUP BY
    sex ; -- 性别分组

(10)筛选

-- having
-- having 必须置于group by 之后,where 置于 group by 之前
-- group by不能聚合函数,但是having后面可以聚合函数

SELECT
    sex 性别, -- 查询分组字段
    COUNT(id) 总人数,
    AVG(math) 数学平均成绩
FROM
    student
WHERE  
    math > 70 -- 条件:数学成绩大于70分人参与分组
GROUP BY
    sex  -- 性别分组
HAVING  
    总人数 > 2 ;   

(11)分页查询

-- limit
-- select 字段列表 from 表名  limit 起始行数,每页显示多少条;

-- 每页显示3条记录
-- 查询第一页的数据
-- limit 起始行数=(当前页码数-1)*每页显示的条数,每页显示条数;
SELECT * FROM student LIMIT 0,3 ;
-- 查询第二页的数据
SELECT * FROM student LIMIT 3 ,3 ;
-- 查询第三页数据
SELECT * FROM student LIMIT 6,3 ;
-- 第四页数据
SELECT * FROM student LIMIT 9,3 ;

8、数据库约束

(1)默认约束 default

default  默认约束 防止出现非法数据null(没有插入造成null值)
-- 添加约束
ALTER TABLE  test MODIFY gender VARCHAR(2)  DEFAULT '女' ;
-- 通过sql语句修改表的类型,删除默认约束
ALTER TABLE  test MODIFY gender VARCHAR(2) ;

(2)非空约束 not null

DROP TABLE test ;
CREATE TABLE test(
    id INT ,
    NAME VARCHAR(10) NOT NULL  -- 非空约束
);

INSERT INTO test VALUES(1,NULL) ; -- 直接插入null值
-- insert into test (id) values(1) ; 没有给姓名赋值

INSERT INTO test VALUES(1,'') ; -- 存在值,只是空字符 和null不一样

-- 删除非空约束
ALTER TABLE test MODIFY NAME VARCHAR(10) ;
UPDATE test SET NAME = '高圆圆' WHERE id = 1 ;
INSERT INTO test VALUES(2,NULL) ; -- Column 'NAME' cannot be null

-- 修改表,加入非空约束
ALTER TABLE test MODIFY NAME VARCHAR(10) NOT NULL  ;
DELETE FROM test WHERE id = 2 ;

(3) 唯一约束 nuique

DROP TABLE test;
CREATE TABLE test(
    id INT ,
    NAME VARCHAR(10),
    phone VARCHAR(11) UNIQUE -- 唯一约束 :可以有null值,不能重复
) ;
INSERT INTO test VALUES(1,'张三','13666668888') ;
INSERT INTO test VALUES(2,'李四','13666668889') ;

-- 通过语句删除唯一约束
-- 删除唯一约束的sql  alter table test drop index 字段名称;  
ALTER TABLE test DROP INDEX phone ;

INSERT INTO test VALUES(4,'赵六','13666668878') ;
DELETE FROM test WHERE id = 4 ;

-- 添加唯一约束
ALTER TABLE test MODIFY phone VARCHAR(11) UNIQUE ;   -- unique

(4)主键约束 primary key

-- 主键约束 (非空+唯一特点) primary key
-- 都会给当前非业务字段去设置主键(xxid)
DROP TABLE test  ;
CREATE TABLE test(
    id INT PRIMARY KEY ,   -- 非业务字段
    NAME VARCHAR(10),
    gender VARCHAR(2)
) ;

INSERT INTO test VALUES(1,'洪学佳','男'),(2,'马三奇','男') ;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

彦登的登

动力来源

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值