21年_编程_Java_5个月学习_java笔记

13 篇文章 0 订阅

day8Java继承

Day8 JAVA、继承

1、继承

1.1 继承作用

不同的类存在相同的属性和方法把相同的属性和方法抽取到一个类中,

1.2子类和父类

关键字:extends
特点: 1.一个类只能继承一个类
2.子类无法访问父类私有的属性和方法
3.子类不会继承父类的构造方法
4.子类的所有构造方法默认存在 super();

1.3super关键字几种用法

super.属性 – 调用父类的属性
super.方法() – 调用父类的方法
super(参数列表) – 调用父类的构造方法

注意:this 和 super 调用构造方法都必须在构造方法的第一行,两者只能存在一个

1.4子类与父类的重写

1、重写
当父类方法满足不了子类需求,子类重写父类的方法
2、@Override:检验方法是否为重写方法
3、重写条件:

  • 1.必须发生在继承关系中
    2.方法名必须相同
    3.参数列表必须一致
    4.返回值类型必须与父类一致
    5.子类重写的方法访问修饰符权限必须与父类的一致或者比父类的更大

4、重写 vs 重载

  • 1.重载是方法的扩展,重写是方法的覆盖
    2.重载的参数列表必须不一致,重写的参数列表必须一致
    3.重载与返回值无关,重写必须返回值必须一致
    4.访问修饰符

5、几种修饰符以及使用范围

  • public – 公开的 protected –
    受保护的,同包下都可以使用,不同包只有子类可以使用 default – 默认的,只能在同包下使用 private
    – 私有的,只能在当前类中使用

6、关键字final

  • 1.final 修饰属性为常量,存在常量池 必须要手动初始化,属性名都为大写 与 static 一起使用为静态常量,一般当做状态值使用
    2.final 修饰方法,无法被重写
    3.final 无法修饰构造方法、构造代码块
    4.final 修饰的类没有子类,不能被继承

7、toString()方法
作用:集中打印所有的类成员

1.5、问题总结

day8、继承的问题

1.6、课程总结

今天主要讲,继承中的重写与重载,以及2个关键字的final和super的用法

day09、抽象、接口、多态

1、 抽象类

1.1为什么需要抽象类

1.父类方法的方法体无意义
2.子类没有重写父类的方法,不满足需求但是程序正常运行

1.2、关于abstract

1.abstract 修饰的方法为抽象方法,没有方法体,只能存在抽象类中
2.abstract 修饰的类为抽象类
3.普通子类继承抽象类,必须重写抽象父类的抽象方法
抽象类继承抽象类,可以有选择地重写抽象方法
4.抽象类不能被实例化,但是存在构造方法(子类调用)
5.抽象类存在构造代码块
6.抽象类存在抽象方法或者普通方法

抽象类
1、当普通父类存在子类必须重写的方法时,被重写的方法设置为抽象方法
2、抽象类不能重写

1.3、接口

1、接口的作用:功能的扩展
2、接口的几个要点
1.接口中的方法默认是公开抽象的,不能普通方法
2.接口只能被类实现(implements),不能被类继承
3.类可以实现多个接口
4.接口中的属性默认为公开静态常量
5.接口没有构造方法,更不能实例化对象
6.接口没有构造代码块
7.接口可以多继承接口,接口不能实现接口
8.JDK8 以后允许接口存在 static 或者 default 修饰的方法(JDK8的新特性)

1.4、多态

父类类型 对象名 = new 子类类型();
父类对象引用子类对象
接口类型 对象名 = new 实现类类型();
接口类对象引用实现类对象

使用多态创建的对象,无法使用子类(实现类)独有的方法

1.5、面向对象设计原则

开闭原则:
open:对外部代码持开放状态
close:对内部代码持关闭状态

简单记住:开口合里最单依

1.6、问题总结

day10

17、 课程总结

抽象、接口、多态

day11、内存和异常

1、内存

1.1 堆、栈、方法区

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.2、根据代码内存图解

栈:局部变量、栈帧(main)
堆:new 出来的对象、字符串常量池
方法区:字节码文件、静态的、运行时常量池图解部分

1.3、代码执行过程

1.加载字节码文件(.class)到方法区中
2.new User() 在堆里开辟空间
3.在栈中的栈帧开辟空间 User user ,引用堆里的对象
4.在堆里的字符串常量池中开辟 “瑶姐” 空间
5.栈里开辟空间 String name ,引用字符串常量池的 “瑶姐”
6.堆里对象的 name 属性引用栈里 String name 属性,最终引用的是字符串常量池的 “瑶姐”
7.销毁栈里的局部变量 String name
8.栈里开辟空间 int age,并赋值 18
9.把栈里 int age 的属性值赋值给堆里对象的 age 属性
10.销毁栈里的局部变量 int age
11.调用 toString() 打印对象信息

2、异常

2.1、错误的分类

Throwable:异常和错误的父类
1、Error:错误
2、 Exception:异常
1).受检性异常(一般异常)
编译时期会出现的异常
2).非受检性异常(运行时异常)
只有在运行时才会出现的异常

2.2、非常见受检性异常以及解决办法

异常解决办法
ArrayIndexOutOfBoundsException数组越界异常定义的时候不要超过数组的长度
NullPointerException – 空指针异常对象调用的时候不要为null
NullPointerException – 空指针异常对象调用的时候不要为null

2.3、异常处理

2.3.1、捕获异常:当知道如何处理异常的时候使用捕获异常

语法

try{
可能会出现异常的代码
}catch(异常类型 异常对象){
处理异常的方式
}

当 try 块中的代码出现异常,try 块则结束运行,当前方法继续运行

2.3.1、声明异常类型,关键字 throws

当程序出现异常,会中止当前方法,不再继续运行 当方法中有异常抛出,调用方需要处理异常 当不知道如何处理异常或者相关代码出现异常会导致后续程序运行错误时需要统一处理

2.3.2、使用finally关键字

不论如何都会执行,几种特殊的情况,try和finally都有return时,如果try return 1 finally return 2;这种情况会返回2之外,其它种情况均以try为主。

2.4、总结

今日学内存,内存有栈、方法区、堆,还有异常类,异常类有系统的异常、也有自定义的异常。

day12、常用类

1、包装类

1.1概念

基本数据类型,一共有8种. 可以进行计算,但是功能上依然不够用,JDK提供了一套基本数据类型的包装类,功能增强,全部在lang包

基本数据类型对应的包装类
byteByte
shortShort
intInteger
longLong
floatFloat
doubleDouble
booleanBoolean
charCharacter

基本数据类型的包装类的最重要功能 : 实现类基本数据类型和String的互转

1.2、自动装箱和拆箱

  • 自动装箱 : 基本数据类型自动转成引用类型 int -> Integer
  • 自动拆箱 : 引用类型自动转成基本数据类型 Integer ->int

2、String类

2.1、equals与“==”

自定义对象需要比较内容必须要重写 equals() ,
否则调用的是父类 Object 的 equals() 比较的是内存地址

2.2、各种方法

3、StringBuilder类

3.1特点

可变字符序列
StringBuffer:线程安全的可变字符序列
StringBuilder:线程不安全的可变字符序列

3.2、常用方法

append、insert、reverse、deleteCharAt

4、时间类

Date:时间类
  •  SimpleDateFormat:格式化类
    

5、精准运算

BigDecimal:进行精准运算
BigInteger:大长度的 int 包装类

6、System:系统类

//强制执行垃圾回收机制方法
//System.gc();

7、总结

常用类、String、StringBuilder、Date、System、BigDecimal

Day13、集合

1、几种类

1.1、内部类

属性:
实例属性(成员属性)
局部属性
静态属性
内部类:定义在类中的类,存在一些相同性质的属性和方法,抽取起来成为内部类
实例内部类
局部内部类
静态内部类
匿名内部类

1.2 、其它类的说明

实例内部类服务于外部类,
局部内部类服务于方法,【实例化在方法内实例化】
静态内部类可以用类调用

1.3、 匿名内部类

匿名内部类,就是没有名字的内部类,只能写在方法中,为了简化代码书写.

简化 : 实现类,实现接口,重写方法,创建对象. 或者是子类继承父类,重写方法,创建对象.代码上少内容,
匿名内部类: 减少了类的创建,只适用于方法被调用一次或者少次的情况

  • 匿名内部类使用的前提 :

    • 必须有接口实现,或者是类的继承

    • 格式 :

2、集合

2.1、总体的框架

集合的三种遍历

package com.qf.ran.list;

import java.util.ArrayList;
import java.util.Iterator;

/**
 * @author Ran
 * @since JDK 1.8
 */
public class Demo05 {
    public static void main(String[] args) {
        ArrayList list = new ArrayList();
        list.add("a");
        list.add("b");
        list.add("c");
        list.add("d");
        System.out.println("-----for循环----");
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }

        System.out.println("-----foreach----");
        for(Object obj :list){
            System.out.println(obj);
        }

        System.out.println("-----迭代器-----");
        //通过调用 iterator() 获取迭代器对象
        Iterator it = list.iterator();
        //it.hasNext() 判断是否还有元素
        while(it.hasNext()){
            //it.next() 返回下一个元素,指向下一个元素
            Object obj = it.next();
            System.out.println(obj);
        }

        System.out.println("-----lambda表达式(JDK8)----");
        list.forEach(obj -> System.out.println(obj));
    }
}

  • Collection:每次只存储一个对象( 集合只能存储对象)

        List:有序可重复
            ArrayList:底层是动态数组
            LinkedList:底层是双向链表
            Vector:底层是动态数组,线程安全的集合
            Stack:模拟栈的集合,底层也是链表,线程安全的集合
        Set:
            TreeSet:
           HashSet:
        Queue:
            LinkedList:队列
    
  • Map:每次存储2个对象,以key-value形式存储

            HashMap:
            TreeMap:
    

迭代器:只服务 Collection 底下的集合
泛型:约束集合存储的数据类型

2.2、ArrayList集合

1、概念
底层是动态数组,通过无参构造发放创建对象集合,在第一次添加对象时, 容量会扩容为10,当容量满的时候扩容为原来的1.5倍
2、常用方法
增:add、删:remove、retainAll 查:

2.3、LinkedList

1、概念
底层是双向链表,first 指向第一个节点,没有索引,理论上长度无限制

ArrayList vs LinkedList
1.底层结构不同 2.ArrayList 查询比 LinkedList 快
3.如果不存在扩容,ArrayList 末尾追加比 LinkedList 快
4.中间插入和中间删除根据不同的情况效率不一致
5.ArrayList 比 LinkedList 修改对象快
6.ArrayList 长度有限,LinkedList 长度理论上无限

2、常用方法

  • void addFirst(E e) 元素插入到链表开头
  • void addLast(E e) 元素插入到链表结尾
  • E getFirst() 获取链表开头的元素
  • E getLast() 获取链表结尾的元素
  • E removeFirst() 移除链表开头的元素
  • E removeLast() 移除链表结尾的元素
  • void push(E e)元素推入堆栈中
  • E pop()元素从堆栈中弹出

2.4、部分底层的代码图解分析

Day14、Set集合

1、set集合的特点

无序不可重复

2、TreeSet

2.1特点

  • 无序可排序,不可重复,不能存储 null 对象的集合底层是红黑树(平衡二叉树)
  • TreeSet 存储的对象必须实现自然排序或者在创建 TreeSet 对象的时候传递比较器

2.2、自然排序

  • 存储进 TreeSet 集合的对象类必须实现 Comparable 接口,compareTo() ,在 compareTo() 制定比较规则,返回正数往右子树方向 返回负数往左子树方向,返回 0 则不存储。
  • compareTo() 方法中的 this 代表即将要存储进集合的对象,参数为已存储的对象

2.3、比较器:

  • 创建比较器类实现 Comparator 接口,重写 compare() ,
  • 在 compare() 制定比较规则,返回正数往右子树方向
  • 返回负数往左子树方向,返回 0 则不存储。
  • compare() 方法中第一个参数是即将要存储进集合的对象,第二个参数是已存储的对象
  • 在创建 TreeSet 集合对象的时候,通过构造方法传递比较器对象

自然排序 vs 比较器

1.使用自然排序会改变存储对象类的结构
2.使用比较器会额外创建多一个类
3.当自然排序和比较器都存在的时候,使用比较器的规则进行排序

2.4、总结

TreeSet底层是用TreeMap类,而TreeMap类底层是红黑树,使用TreeyMap对自定义对象进行排序,需要在本类中写CompareTo方法,并且该类需要实现Comparable接口,或者在定义TreeyMap对象时传递Comparator的实现类,也就是自定义比较器,然后传入。

Day、15Hashmap、 treeMap

1、Map与collection的比较

Collection:每次只操作一个对象

2、Map

Map:每次是以key-value的形式操作对象 HashMap:key是无序不可重复 value可重复当 key 相同的时候,value 会覆盖
存储自定义对象,key 需要重写 hashCode() 和 equals()

Day16、IO流

1、File

1.1、作用
文件和目录路径名的抽象表示,操作文件目录的增删查,
1.2、常用方法
getPath()、getAbsolutePath())、file.exists()、file.lastModified()、listFiles()、delete()
1.3、其他
需要遍历其他选项,需要递归遍历

2、IO流

1、Io流的作用
对文件进行读和写操作,IO流是一个万能流,对所有文件都能进行操作。
2、IO流的分类

  • 按照数据传输的方向划分:以程序为参照物

               输入流     文件  ->  程序      读取
               输出流     程序  ->  文件      写出
    
  • 按照读写单位

              字节流     --  byte
           字符流     --  char
    
  • 根据功能划分

             基础流
               包装流
    

3、常用方法

write(),read;

Day17、IO流2

1、按照功能划分

  • 基础流(节点流):直接与磁盘交互

字节流: FileInputStream、 FileOutputStream
字符流:InputStream、OutputStream
两者的的区别:
字符流多了:是char字节为单位、字节流可以处理所有文件、而字符流只能处理文本。

  • 包装流(处理流):基于节点流的基础上,通过缓冲区进行读写操作

  • 自带缓冲区的流

    • 字节流
    • 字符流

2、缓冲字节流

2.1、默认大小以及其它

  • 带缓冲区的字节流 – 缓冲区默认大小为8192
  • 如果不关流,数据是不会输出到文件中

2.2、两种方式存入池畔

  • 缓冲区满了或者超过缓冲区的大小,会自动刷新(关闭流)
  • 手动刷新

2.3、字节流的输入、输出对应的类

  • BufferedOutputStream:输出流对应的类(写进池畔)

常用方法:writer();
构造方法的注意点,要传入基础流

  • BufferedInputStream:输入流对应的类(读进程序)

    常用方法:read();

3、缓冲字符流()

3.1、缓冲输出输出流对应类

BufferedReader、BufferedWriter

3.2、带缓冲区BufferedWriter的字符流特有方法

  • newLine() 换行,是BufferedWriter独有的方法
  • readLine() 读取一行字符,是BufferedReader独有的方法

4、转换流

1、转换流:字节通向字符的桥梁 
     InputStreamReader:把文件中的字节转化成程序中的字符
     OutputStreamWriter:把程序中的字符转换成文件中的字节
     指定编码格式进行读写操作 本质上字符流

5、对象流:

  • ObjectInputStream:对象输入流

  • ObjectOutputStream:对象输出流

使用对象流存储对象信息 – 需要存储的对象类实现 Serializable 接口,实现序列化

  • 使用对象流进行对象的读写本质上是在进行序列化和反序列化
  • 写入对象为序列化
  • 读取对象为反序列化
  • 序列化和反序列化必须同一个序列号
  • 私有的静态常量不会被序列化
  • 私有的 transient 属性不会被序列化

Day18、随机、打印、内存、流,线程

1、随机访问流

1.1、类名以及特点

  • RandomAccessFile:
    • 1.拥有偏移量(指针)
    • 2.一个类可以创建不同的对象完成写出和读取
    • 3.每次实例化对象,偏移量都从0开始
    • 4.每次实例化对象不会清空对象,只会从偏移量开始的位置覆盖写入
    • 5.可以在文件指定位置开始读写操作

1.2、应用

  • 设置偏移量
    • ranW.seek(4);
  • 断点续传

2、打印流(PrintStream)

2.1、特点

  • 打印流:只有输出没有输入,直接打印数据

    • PrintStream:打印字节流

    • PrintWriter:打印字符流

2.2、重定向

//输出重定向
    @Test
    public void method02() throws FileNotFoundException {
        // System.out 标准输出流     --  目标源固定为控制台
        System.out.println("有道无术");
        //更改目标源
        System.setOut(new PrintStream("io5.txt"));
        System.out.println("术尚可求");
    }

    //输入重定向
    public static void main(String[] args) throws FileNotFoundException {
        //更改来源
        System.setIn(new FileInputStream("2.txt"));
        //System.in 标准输入流   --  来源固定为控制台
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入字符串");
        String str = sc.next();
        System.out.println("str:"+str);
    }

3、内存流

  • 内存流:
    • ByteArrayOutputStream:程序 -> 内存
    • ByteArrayInputStream:内存 -> 程序
    • 1.相对其他 IO 流操作的数据量少,效率高
    • 2.无法关闭的流

4、多线程

1、概念

  • 进程:程序执行的基本单位,由一个或者多个进程组合而成* 线程:CPU调度的基本单位

2、多线程的实现方式

  • 1.自定义线程类继承 Thread 类,重写 run() 实例化线程类对象,通过对象调用 start() 启动线程
  • 自定义任务类实现 Runnable 接口,重写 run() 实例化任务类,实例化 Thread 类,通过构造方法传递任务类对象* 通过 Thread 类对象调用 start() 启动线程
  • 3.自定义类实现 Callable 接口,重写 call(),拥有返回值
  • 4.通过线程池创建线程

Day19、线程

1、线程安全

  1. 程安全问题:多个线程同时异步访问临界资源,可能会出现数据混乱

  2. 同步锁:synchronized

    *          线程安全问题:多个线程同时异步访问临界资源,可能会出现数据混乱
 *              1.同步锁:synchronized
 *                  1.1 同步代码块:
 *                          把需要进行同步的代码存放到代码块中,添加同步锁和同步监视器
 *                          需要多个线程访问的时候同步监视器为同一个对象,
 *                          当其中一条线程进入同步代码块后,其他线程会等待进入同步代码块的线程执行完毕后才能进入
 *                  1.2 同步方法:
 *                          同步锁修饰的方法为同步方法,同步监视器为方法本身
 *                          要求多个线程执行到方法时,方法必须是同一个方法,方法为静态的或者是方法存在的对象只有一个
 *

2、wait() vs sleep()

  • 1.wait() 来自 Object 类,sleep() 来自 Thread 类
  • 2.sleep()当线程在同步区域中进入休眠,不会释放资源
  • wait() 当线程再同步区域中进入等待,会释放资源
  • 3.wait() 调用必须通过同步监视器在同步区域中调用
  • 4.sleep() 会自动唤醒,wait() 不会自动唤醒,需要调用 notify() 或者 notifyAll() 唤醒
  • notify() 唤醒先进入等待的线程
  • notifyAll() 唤醒所有的线程,后等待的线程先唤醒

3、Lock

  • Lock:显式获取锁释放锁,本质是接口 ReentrantLock:可重入互斥锁,多个线程必须调用同一个对象
  • /构造方法传递 true 代表 lock 为公平锁private Lock myLock = new ReentrantLock(true);
  • //获取锁 myLock.lock();
  • //释放锁 myLock.unlock();

4、线程池

1、线程池:减少线程的创建和销毁时间
2、线程池的创建

  • 创建只有一条线程的线程池 ExecutorService pool =Executors.newSingleThreadExecutor()
  • //创建指定线程数量的线程池 – 创建3条线程 /*ExecutorService pool = Executors.newFixedThreadPool(3);
  • //创建带有缓冲区的线程池 /* ExecutorService pool = Executors.newCachedThreadPool();
  • //关闭线程池 pool.shutdown();*/

Day20、线程

1、异常

ConcurrentModificationException

2、守护线程

当非守护线程销毁的时候,守护线程跟着销毁

3、解决读写冲突

CopyOnWriteArrayList

4、线程的合并

Day21、反射

1、反射

1.1反射:在运行状态中动态地获取类对象的属性和调用类对象的方法
1.2、反射的应用

  • 通过反射对象修改实例对象中属性
  • 通过反射对象调用私有方法
  • 通过反射对象调用构造方法实例化对象

1.3、反射对象的4种创建方法

//实例对象
        User user1 = new User(1, "zs");
        //实例对象
        User user2 = new User(2, "ls");

        //获取反射对象
        //1.Class.forName("完整的类路径")
        Class<?> clazz1 = Class.forName("com.qf.ran.reflect.User");
        //2.通过对象名调用 getClass()
        Class<? extends User> clazz2 = user1.getClass();
        Class<? extends User> clazz3 = user2.getClass();
        //3.通过类名.class
        Class<User> clazz4 = User.class;
        System.out.println(clazz1 == clazz2);
        System.out.println(clazz2 == clazz3);
        System.out.println(clazz3 == clazz4);

1.4、通过反射修该私有方法、变量的具体步骤

package com.qf.Day21.reflect;

import java.lang.reflect.Field;

/**
 * @author Ran
 * @since JDK 1.8
 *
 *          通过反射对象修改实例对象中属性
 */
public class Demo02 {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        User user = new User(1, "zs");
        System.out.println("反射前:"+user);
        //1.获取反射对象
        Class<? extends User> clazz = user.getClass();
        //2.通过反射对象获取属性对象
        Field field = clazz.getDeclaredField("id");
        //3.打开访问权限
        field.setAccessible(true);
        //4.通过属性对象操作指定实例对象的属性
        int id = (int)field.get(user);
        System.out.println("id:"+id);
        //第一个参数为要修改属性的对象,第二个参数为要修改的属性值
        field.set(user,2);
        System.out.println("反射后:"+user);
    }
}

package com.qf.Day21.reflect;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @author Ran
 * @since JDK 1.8
 *
 *          通过反射对象调用私有方法
 */
public class Demo03 {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        User user = new User();
        //通过实例对象无法调用私有方法
        //user.method01();

        //1.获取反射对象
        Class<? extends User> clazz = user.getClass();
        //2.通过反射对象获取方法对象
        Method method01 = clazz.getDeclaredMethod("method01");
        //3.打开访问权限
        method01.setAccessible(true);
        //4.调用指定对象的方法
        method01.invoke(user);


        //通过反射对象获取方法对象
        //第一个参数为方法名,后续的参数为方法参数类型的反射对象
        Method method02 = clazz.getDeclaredMethod("method02", String.class, int.class);
        //打开访问权限
        method02.setAccessible(true);
        //调用指定对象的方法
        int num = (int)method02.invoke(user, "zs", 18);
        System.out.println("通过反射调用方法返回的数据:"+num);
    }
}

package com.qf.Day21.reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
 * @author Ran
 * @since JDK 1.8
 *
 *          通过反射对象调用构造方法实例化对象
 */
public class Demo04 {
    public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        //1.获取反射对象
        Class<Student> clazz = Student.class;
        //无参构造方法非私有化        --  创建对象的一种方式
        //Student stu = clazz.newInstance();

        //2.通过反射对象获取构造方法对象
        Constructor<Student> constructor = clazz.getDeclaredConstructor(int.class,String.class);
        //3.打开访问权限
        constructor.setAccessible(true);
        //4.通过构造方法对象创建实例对象
        //传递的参数为构造方法接收的参数
        Student stu = constructor.newInstance(10, "ls");
        System.out.println("通过反射创建的对象:"+stu);

        //获取类的完整路径
        String name = clazz.getName();
        //获取类名
        String simpleName = clazz.getSimpleName();
        System.out.println("name:"+name);
        System.out.println("simpleName:"+simpleName);
    }
}

1.5properties应用反射配置文件的流程

//加载配置文件的类
        Properties properties = new Properties();
        //从流中读取配置信息
        //Demo01.class.getClassLoader() 根据反射对象获取类加载器
        //getResourceAsStream() 默认从配置文件目录中加载配置文件,如果没有配置文件目录则从src获取
        properties.load(Demo01.class.getClassLoader().getResourceAsStream("doll.properties"));
        //properties.load(new FileInputStream("src/doll.properties"));
        String type = properties.getProperty("doll");

2.设计模式

1.1、什么是设计模式

  • 一套程序员长期累积总结规划的设计思想

1.2、设计模式的分类

  • 1.创建型模式(5):只关注对象创建,用于解耦对象的实例
    • 单例模式
    • 工厂模式
    • 抽象工厂模式
    • 建造者模式,
    • 原型模式
  • 2结构型模式(7)只关注对象的结构,把类或者对象结合起来形成更加强大的结构
    • 装饰者模式,适配器模式,组合模式,代理模式,亨元模式,外观模式,桥接模式
  • 3.行为型模式(11):只关注对象的行为,关注类和对象如何进行交互以及划分职责
    • 观察者模式,策略模式,模板模式,解析器模式,备忘录模式,状态模式,中介者模式、命令模式,责任链模式,迭代器模式,访问模式

1.3、单例模式

  • 实现步骤
    • 私有修饰构造方法
    • 自己创建自己的对象
    • 方法get,返回本类对象
  • 1、饿汉

    • 在类加载时就完成了初始化,但是加载比较慢,获取对象比较快,类创建的同时就已经创建好一个静态的对象供系统使用,以后不在改变。
  • 2、懒汉

    • 在类加载的时候不被初始化,懒汉式是延时加载,他是在需要的时候才创建对象。

一个线程判断完变量 s=null,还没有执行new对象,被另一个线程抢到CPU资源,同时有2个线程都进行判断变量,对象创建多次

package com.qf.Day21.single;

/**
 * @author Ran
 * @since JDK 1.8
 *
 *          设计模式:一套程序员长期累积总结规划的设计思想
 *              1.创建型模式(5):只关注对象创建,用于解耦对象的实例
 *                      单例模式,工厂模式,抽象工厂模式,建造者模式,原型模式
 *              2.结构型模式(7):只关注对象的结构,把类或者对象结合起来形成更加强大的结构
 *                      装饰者模式,适配器模式,组合模式,代理模式,亨元模式,外观模式,桥接模式
 *              3.行为型模式(11):只关注对象的行为,关注类和对象如何进行交互以及划分职责
 *                      观察者模式,策略模式,模板模式,解析器模式,备忘录模式,状态模式,中介者模式
 *                      命令模式,责任链模式,迭代器模式,访问模式
 *
 */
public class Demo01 {
    public static void main(String[] args) {
        //饿汉式
        Single1 instance1 = Single1.getInstance();
        Single1 instance2 = Single1.getInstance();
        System.out.println(instance1 == instance2);

        //懒汉式
        Single2 instance3 = Single2.getInstance();
        Single2 instance4 = Single2.getInstance();
        System.out.println(instance3 == instance4);
    }
}

//饿汉式
class Single1{
    private static Single1 single = new Single1();

    //1.私有化构造方法
    private Single1(){

    }
    //2.提供一个给外界调用获取对象的方法
    public static Single1 getInstance(){
        return single;
    }
}

//懒汉式
class Single2{
    private static Single2 single;
    //私有化构造方法
    private Single2(){

    }
    //提供一个给外界调用获取对象的方法
    public static Single2 getInstance(){
        if(single == null){
            single = new Single2();
        }
        return single;
    }
}

1.4、工厂模式

  • 概述
    简单工厂模式,又称为静态工厂方法(Static Factory Method)模式,它属于类创建型模式。在简单工厂模式中,把产品的生产方法封装起来放进工厂类,工厂类可以根据参数的不同返回不同产品类的实例。工厂类就是用来生产产品的类,把生产产品的方法放到工厂类里面去,工厂类里面用switch语句控制生产哪种商品,使用者只需要调用工厂类的静态方法就可以实现产品类的实例化。

Day22、json格式、gson、 fastjson、枚举、注解、 lambda表达式

1、json: 解析 json 格式的对象、解析复杂的 JSON 格式对象

1.1.json本质:传输数据的格式,本质上是字符串
1.2、使用步骤:

  • 创建 JSONObject 对象
    • 根据属性获取属性值:jsonObject.getInt(“id”);
    • 根据对象名获取 JSONObject 对象: jsonObject.getJSONObject(“score”);
    • /根据索引获取数组中的 JSONObject 对象:array.getJSONObject(i);

1.3、通过gson解析对象

  • 创建 Gson 对象 Gson gson = new Gson();
    • {}普通对象:fromJson(json1, Student.class);
    • 解析数组结构的 json 格式数据[{id:1,name:‘zs’},{id:2,name:‘ls’},{id:3,name:‘ww’}],
 TypeToken<ArrayList<Student>> typeToken = new TypeToken<ArrayList<Student>>(){};
        ArrayList<Student> list = gson.fromJson(json, typeToken.getType());
        for (Student stu:list) {
            System.out.println(stu);
        }

1.4、使用 fastjson 解析 json 格式数据

  • 不用创建fastjson ,用类名调用
  • 简单对象: Student stu = JSON.parseObject(json1, Student.class);
  • 复杂对象:List list = JSON.parseArray(json3, Student.class);

2、枚举

2.1 枚举的概述

枚举是 Java 中一种特殊的类,它可以定义固定数量的枚举实例,例如: 性别、交通信号灯、季节等等

2.2 为什么要使用枚举

假设我们要定义一个人类,人类中包含姓名和性别。通常会将性别定义成字符串类型,效果如下:

public class Person {
    private String name;
    private String sex;

    public Person() {
    }

    public Person(String name, String sex) {
        this.name = name;
        this.sex = sex;
    }
	
    // 省略get/set/toString方法
}
public class Demo01 {
    public static void main(String[] args) {
        Person p1 = new Person("张三", "男");
        Person p2 = new Person("张三", "abc"); // 因为性别是字符串,所以我们可以传入任意字符串
    }
}

不使用枚举存在的问题:可以给性别传入任意的字符串,导致性别是非法的数据,不安全。

2.3 作用

一个方法接收的参数是固定范围之内的时候,那么即可使用枚举类型

2.4 格式
enum 枚举名 {
    第一行都是罗列枚举实例,这些枚举实例直接写大写名字即可。
}
2.5 入门案例
  1. 定义枚举:MALE表示男,FEMALE表示女
enum Gender {
    MALE, FEMALE; // 男,女
}
  1. Perosn中的性别有String类型改为Sex枚举类型
public class Person {
    private String name;
    private Gender gender;

    public Person() {
    }

    public Person(String name, Gender gender) {
        this.name = name;
        this.gender = gender;
    }
    // 省略get/set/toString方法
}
  1. 使用是只能传入枚举中的固定值
public class Demo02 {
    public static void main(String[] args) {
        Person p1 = new Person("张三", Gender.MALE);
        Person p2 = new Person("张三", Gender.FEMALE);
        Person p3 = new Person("张三", "abc");
    }
}
2.6 枚举中添加成员变量和成员方法

枚举的本质是一个类,所以枚举中还可以有成员变量,成员方法等。

public enum Gender {
    MALE("male"), FEMALE("female");
    public String tag;

    Sex(String tag) {
        this.tag = tag;
    }

    public void showTag() {
        System.out.println("它的性别标志是: " + tag);
    }
}
public class Demo03 {
    public static void main(String[] args) {
        Person p1 = new Person("张三", Sex.BOY);
        Person p2 = new Person("张三", Sex.GIRL);

        Sex.BOY.showTag();
        Sex.GIRL.showTag();
    }
}

3、注解

3.1、注解的作用

  • 注解作用:元数据,一种代码级别的说明,增强代码的作用性
  • 元注解:作用在注解上的注解

3.2、常见的元注解

Target:指定被修饰的注解的生命周期(应用场景)
ElementType.TYPE,指定被修饰的注解只能修饰类、接口、枚举和注解
ElementType.FIELD,指定被修饰的注解只能修饰全局属性
ElementType.METHOD,指定被修饰的注解只能修饰普通方法
ElementType.PARAMETER,指定被修饰的注解只能修饰方法中的参数
ElementType.CONSTRUCTOR,指定被修饰的注解只能修饰构造方法
ElementType.LOCAL_VARIABLE,指定被修饰的注解只能修饰方法体中定义的属性
ElementType.ANNOTATION_TYPE,指定被修饰的注解只能修饰注解
ElementType.TYPE_PARAMETER,指定被修饰的注解只能修饰泛型
ElementType.TYPE_USE指定被修饰的注解不能修饰无返回值的方法
Retention;修饰注解保留在什么情况下
RetentionPolicy.SOURCE指定被修饰的注解只保留在源代码中
RetentionPolicy.CLASS指定被修饰的注解保留字节码文件中
RetentionPolicy.RUNTIME指定被修饰的注解在运行时也依旧保留

3.3、自定义注解
语法: @interface 注解名{}

4、 Lambda表达式

4.1、作用
lambda表达式:
4.2、 函数式接口
1、自定义函数式接口作用:
只要确保接口中有且仅有一个抽象方法即可

修饰符 interface 接口名称 {
    public abstract 返回值类型 方法名称(可选参数信息);
    // 其他非抽象方法内容
}

2、函数式接口的分类

  • 消费型接口的抽象方法特点:有形参,但是返回值类型是void
  • 供给型接口这类接口的抽象方法特点:无参,但是有返回值
  • 这里接口的抽象方法特点:有参,但是返回值类型是boolean结果。
  • 这类接口的抽象方法特点:既有参数又有返回值
    3、 Lambda表达式语法
(形参列表) -> {Lambda}
2.5 方法引用与构造器引用

Lambda表达式是可以简化函数式接口的变量与形参赋值的语法。而方法引用和构造器引用是为了简化Lambda表达式的。当Lambda表达式满足一些特殊的情况时,还可以再简化:

(1)Lambda体只有一句语句,并且是通过调用一个对象的/类现有的方法来完成的

例如:System.out对象,调用println()方法来完成Lambda体

​ Math类,调用random()静态方法来完成Lambda体

(2)并且Lambda表达式的形参正好是给该方法的实参

例如:t->System.out.println(t)

​ () -> Math.random() 都是无参

2.5.1 方法引用

方法引用的语法格式:

(1)实例对象名::实例方法

(2)类名::静态方法

(3)类名::实例方法

说明:

  • ::称为方法引用操作符(两个:中间不能有空格,而且必须英文状态下半角输入)
  • Lambda表达式的形参列表,全部在Lambda体中使用上了,要么是作为调用方法的对象,要么是作为方法的实参。
  • 在整个Lambda体中没有额外的数据。

Day23、网络编程

1.TCP与UDP协议

通信的协议还是比较复杂的,java.net 包中包含的类和接口,它们提供低层次的通信细节。我们可以直接使用这些类和接口,来专注于网络程序开发,而不用考虑通信的细节。

java.net 包中提供了两种常见的网络协议的支持:

  • UDP:用户数据报协议(User Datagram Protocol)。

    • **非面向连的,不可靠的:**UDP是无连接通信协议,即在数据传输时,数据的发送端和接收端不建立逻辑连接。简单来说,当一台计算机向另外一台计算机发送数据时,发送端不会确认接收端是否存在,就会发出数据,同样接收端在收到数据时,也不会向发送端反馈是否收到数据。

      由于使用UDP协议消耗资源小,通信效率高,所以通常都会用于音频、视频和普通数据的传输例如视频会议都使用UDP协议,因为这种情况即使偶尔丢失一两个数据包,也不会对接收结果产生太大影响。

      但是在使用UDP协议传送数据时,由于UDP的面向无连接性,不能保证数据的完整性,因此在传输重要数据时不建议使用UDP协议。

    • 大小限制的:数据被限制在64kb以内,超出这个范围就不能发送了。

    • 数据报(Datagram):网络传输的基本单位

  • TCP:传输控制协议 (Transmission Control Protocol)。

    • 面向连接的,可靠的:TCP协议是面向连接的通信协议,即传输数据之前,在发送端和接收端建立逻辑连接,然后再传输数据,它提供了两台计算机之间可靠无差错的数据传输。是一种面向连接的、可靠的、基于字节流的传输层的通信协议,可以连续传输大量的数据。类似于打电话的效果。

      这是因为它为当一台计算机需要与另一台远程计算机连接时,TCP协议会采用“三次握手”方式让它们建立一个连接,用于发送和接收数据的虚拟链路。数据传输完毕TCP协议会采用“四次挥手”方式断开连接。

      TCP协议负责收集这些信息包,并将其按适当的次序放好传送,在接收端收到后再将其正确的还原。TCP协议保证了数据包在传送中准确无误。TCP协议使用重发机制,当一个通信实体发送一个消息给另一个通信实体后,需要收到另一个通信实体确认信息,如果没有收到另一个通信实体确认信息,则会再次重复刚才发送的消息。

  • **三次握手:**TCP协议中,在发送数据的准备阶段,客户端与服务器之间的三次交互,以保证连接的可靠。

    • 第一次握手,客户端向服务器端发出连接请求,等待服务器确认。

    • 第二次握手,服务器端向客户端回送一个响应,通知客户端收到了连接请求。

    • 第三次握手,客户端再次向服务器端发送确认信息,确认连接。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gw3y32C9-1640171293882)(imgs/1564020243342.png)]

  • **四次挥手:**TCP协议中,在发送数据结束后,释放连接时需要经过四次挥手。
    • 第一次挥手:客户端向服务器端提出结束连接,让服务器做最后的准备工作。此时,客户端处于半关闭状态,即表示不再向服务器发送数据了,但是还可以接受数据。
    • 第二次挥手:服务器接收到客户端释放连接的请求后,会将最后的数据发给客户端。并告知上层的应用进程不再接收数据。
    • 第三次挥手:服务器发送完数据后,会给客户端发送一个释放连接的报文。那么客户端接收后就知道可以正式释放连接了。
    • 第四次挥手:客户端接收到服务器最后的释放连接报文后,要回复一个彻底断开的报文。这样服务器收到后才会彻底释放连接。这里客户端,发送完最后的报文后,会等待2MSL,因为有可能服务器没有收到最后的报文,那么服务器迟迟没收到,就会再次给客户端发送释放连接的报文,此时客户端在等待时间范围内接收到,会重新发送最后的报文,并重新计时。如果等待2MSL后,没有收到,那么彻底断开。

3.1.2 开发步骤

1、服务器端

服务器 程序的工作过程包含以下四个基本的 步骤:

  • 调用 ServerSocket(int port) :创建一个服务器端套接字,并绑定到指定端口上。用于监听客户端的请求。
  • 调用 accept() :监听连接请求,如果客户端请求连接,则接受连接,返回通信套接字对象。
  • 调用 该Socket 类对象的 getOutputStream() 和 getInputStream () :获取输出流和输入流,开始网络数据的发送和接收。
  • 关闭Socket 对象:客户端访问结束,关闭通信套接字。
2、客户端

客户端Socket 的工作过程包含以下四个基本的步骤 :

  • 创建 Socket :根据指定服务端的 IP 地址或端口号构造 Socket 类对象。若服务器端响应,则建立客户端到服务器的通信线路。若连接失败,会出现异常。
  • 打开连接到 Socket 的输入/ 出流: 使用 getInputStream()方法获得输入流,使用getOutputStream()方法获得输出流,进行数据传输
  • 按照一定的协议对 Socket 进行读/ 写操作:通过输入流读取服务器放入线路的信息(但不能读取自己放入线路的信息),通过输出流将信息写入线路。
  • 关闭 Socket :断开客户端到服务器的连接,释放线路
package com.qf.day23.network1;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 服务端
 */
public class Server {
    public static void main(String[] args) {
        //1.建立服务器套接子
        try {
            ServerSocket serverSocket = new ServerSocket(8888);
            //2、等待客户端连接
            Socket accept = serverSocket.accept();
            //3、模拟第二次握手,接受客户端的消息
            InputStream inputStream = accept.getInputStream();
            byte[] bytes = new byte[1024];
            //len指的是返回的字节数
            int len = inputStream.read(bytes);
            System.out.println(new String(bytes,0,len));

            //第三次握手,服务端返回shuju
            OutputStream outputStream = accept.getOutputStream();
            outputStream.write("服务端:什么事呀".getBytes());

            //接受并打印客户端的消息
            len = inputStream.read(bytes);
            System.out.println(new String(bytes,0,len));
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

package com.qf.day23.network1;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

/**
 * 客户端
 */
public class Client {
    public static void main(String[] args) {
        Socket socket = null;
        OutputStream outputStream = null;
        InputStream inputStream = null;
        //连接服务器
        try {
            socket = new Socket("127.0.0.1", 8888);
            //模拟第一次握手
            outputStream = socket.getOutputStream();
            outputStream.write("客户端:喂喂喂".getBytes());

            //接受来自服务端的消息1
           inputStream = socket.getInputStream();
            byte[] bytes = new byte[1024];
            int len = inputStream.read(bytes);
            System.out.println(new String(bytes,0,len));

            //在发送给服务端消息2
            outputStream.write("客户端:没事,就是想你了".getBytes());


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

        }

    }
}

4、udp协议

操作步骤

package com.qf.day23.udp1;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;

/**
 * @author Ran
 * @since JDK 1.8
 */
public class Client2 {
    public static void main(String[] args) throws IOException {
        //1.创建一个包含端口号的 UDP 套接字
        DatagramSocket socket = new DatagramSocket(9999);

        //接收数据
        byte[] b = new byte[1024];
        DatagramPacket packet = new DatagramPacket(b, b.length);
        //接收数据报包    --  阻塞
        socket.receive(packet);
        System.out.println(new String(packet.getData(),0,packet.getLength()));

        //发送数据
        b = "客户端2:术尚可求".getBytes();
        packet = new DatagramPacket(b,b.length, InetAddress.getByName("127.0.0.1"),8888);
        //发送数据
        socket.send(packet);

        socket.close();

    }
}

Day24、正则表达

1、所以正则表达式有三个主要用途:

  • 模式验证: 检测某个字符串是否符合规则,例如检测手机号、身份证号等等是否符合规范
  • 匹配读取: 将目标字符串中满足规则的部分读取出来,例如将整段文本中的邮箱地址读取出来
  • 匹配替换: 将目标字符串中满足标准的部分替换为其他字符串,例如将整段文本中的"hello"替换成"haha"

2、具体分类

正则表达式 : 专门用于处理字符串的技术 (正则大神)

  • 字符类 :

    • [abc] 字符串的这个位置只能是abc
    • [^abc] 字符串的这个位置不能是abc
    • [a-zA-Z] 字符串的这个位置必须是字母,52个
    • [^a-zA-Z] 字符串的这个位置必须不能是字母,52个
  • 数字类:

    • [0-9] 字符串的这个位置只能是数字
    • [^0-9] 字符串的这个位置不能是数字
    • [\d] 等同于 [0-9]
    • [\D] 等同于 [^0-9]
  • 预定义字符 :

    • . 匹配所有的字符
    • [\d] 等同于 [0-9]
    • [\D] 等同于 [^0-9]
    • [\w] 文字字符,包含数字,字母,下划线 [a-zA-Z0-9_]
    • [\W] 文字字符,不能包含数字,字母,下划线 [^a-zA-Z0-9_]
  • 数量词 :

    • X{m} X这个字符只能出现m次 a{3}
    • X{m,} X这个字符至少出现m次
    • X{m,n} X这个字符至少出现m次,不超过n次
    • X? X这个字符出现一次,或者一次也没有
    • X* X这个字符出现零次或者多次
    • X+ X这个字符出现至少一次
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值