Java_Web笔记汇总_火热更新中。。。

Java后端工程师养成记 专栏收录该内容
2 篇文章 0 订阅

零、历史和特点

1.历史

(1)作者:James-Gosling

(2)主要发展历程

1995.5.23
	SUN公司  正式发布了Java语言
1996年1月    开发工具包JDK1.0
1997年2月    JDK1.1版本问世
1998年12月  JavaEE企业版
1999年6月
	Java第二代平台JDK1.2	细化了三个不同的小版本(不同方向)
	(J2SE)Java2  Standard  Edition	Java第二代平台标准版   桌面级  C/S
	(J2EE)Java2  Enterprise Edition	Java第二代平台企业版   企业级  B/S
	(J2ME)Java2  Micro  Edition		Java第二代平台微型版   移动端
2000--2002
	JDK1.3    JDK1.4
	大幅度提升了Java性能
2004年5月
	JDK1.5版本发布	很多新的特性   Java5
2005年6月
	Java6   最经典的版本   留存最久的版本
2009年
	Oracle  并购   74亿$
	Java易主
2011年	Oracle   Java7
2014年	Java8
2017年	Java9

(3)环境搭建

  • JVM:Java Virtual Machine是Java虚拟机

    内存中开辟一块空间	源文件   编译   字节码
    
    		Java计算机高级编程语言
    		程序存储在哪里?-----程序就是英文----存储在一个地方(文件)
    		我们写完的程序--计算机不认识--编译   我们写好的源文件编译成计算机识别的字节码文件
    		最终有两个文件   源文件    字节码文件  两个文件存在哪?--硬盘上
    		计算机的硬件组成
    		内存(条形 8G 芯片 寻址 临时执行使用)  硬盘(矩形 1T 机械 扇区 永久性保存)
    
    		硬盘上的文件  不同的格式  后缀名区分不同的格式
    		.txt  .doc  .ppt  .xls  .mp4  .mp3  .rar  .exe  运行环境支持
    		源文件.java(文本文档打开)	字节码.class
    
  • JRE:Java Runtime Environment是Java运行环境

    运行别人写好的java程序
    
  • JDK:Java Development Kit是Java开发工具包

    开发时需要用到的工具
    		javac.exe	编译工具
    		java.exe   执行工具	底层doc命令窗口中看到效果
    JDK中包含了JRE。
    

2.特点

(1)跨平台性

在不同厂商的芯片,不同版本的操作系统,均可运行。

(2)面向对象

  • 特征:封装、继承、多态、抽象

(3)简单性

省去了C++多继承,指针等

(4)健壮性(鲁棒性)

垃圾回收机制,异常处理机制

(5)多线程性

并行操作,提高执行性能。

(6)大数据开发

一、Java基础

1.基础部分

(1)基本数据类型

  • 命名规范和规约

    规范:必须要遵守的
    	名字中可以有字母,区分大小写;
    	数字(0-9),不能以数字开头;
    	可以有符号_和$;
    	中文也可以,不推荐。
    规约:要求见名知意,不做强制要求。
    	类名字:首字母大写,后面驼峰命名。例如:SuperPerson
    	属性/方法/变量:首字母小写,后面驼峰命名。例如:superPerson
    	构造方法:与类名一致。例如:SuperPerson
    	静态常量:全部字母大写,通过_分割。例如:SUPER_PERSON
    	包名字:所有字母均小写,不要有别的字符。例如:domeone
    	私有属性对应方法:getName,setName;
    	均不能和Java关键字冲突。
    
  • 基本数据类型有8个

    4整型:byte,short,int,long
    	byte:1字节,-128到127
    	short:2字节,-32768到32767
    	int:4字节,-2147483648到2147483647
    	long:8字节
    2浮点型:float,double
    	float:4字节
    	double:8字节
    1字符型:char
    	char:2字节
    1布尔型:boolean
    	boolean:1位
    

(2)常量与变量

  • 常量

    常量代表是程序运行过程中  不能再次改变的值
    1.固定不变的值:比如π=3.14。。。
    2.特殊的常量String
    3.自己定义:final int UP = 1;
    
  • 变量

    程序执行过程中可以改变的
    变量是一个内存空间(小容器)
    变量空间在创建(声明)的时候  
    必须指定数据类型  变量空间的名字
    变量空间   里面只能存储一个内容(值  引用)
    变量空间内的内容可以改变
    
  • 变量创建

    float e = 3.4F;
    	从double转化到float会有损失
    byte a = 1;
    long d = 2147483648L;
    	-2147483648    2147483647是int类型的取值范围
    	如果创建的常量值超过以上范围
    	程序编译检测的时候会认为  数字太大
    	如果我们真的需要那么大的数字  必须在后面加L告知
    char a = 'a';
    String a = "Hello";
    变量a存在栈内存中,常量1存在常量缓冲区中。
    
  • 注释

    1.单行注释:
    	//这里是注释
    2.多行注释
    	/*
    		这里是注释
    		这里是注释
    	*/
    3.文档注释
    	/**
    		这里是文档注释
    	*/
    

(3)类型转化问题

  • 同种数据类型之间是可以直接进行转化的

    int a = 1;int b = a;
    float x = 3.4;float y = x;
    
  • 数据类型不同之间的转化

    基本类型----基本类型之间   可以直接转换(自动 强制)
    引用类型----引用类型之间   可以直接转换(自动 强制--上转型 下转型)
    基本类型----引用类型之间   不可以直接转换(间接--包装类/封装类)
    
  • 保证大数据类型一致的前提下

    1.都是整型或都是浮点;
    	大空间可以直接存储小空间的数据;
    	byte a = 1;int b = a;
    	float x = 3.4F;double y = x;
    	小空间想存储大空间数据,需要强制转换。
    	int a = 1;byte b = (byte)a;
    	double x = 3.4;float y = (float)x;
    2.整型和浮点
    	浮点型可直接存储一个整型
    	int a = 1;float b = a;
    	整型想存放浮点型需要强制转换
    	float x = 3.4F;int y = (int)x;
    3.整型和字符
    	char x = 'a';int y = x;
    	int x = 97;char y = (char)x;
    	
    

(4)运算符号

  • 单目运算符

    ++
    --
    
  • 双目运算符

    算术运算
    	+、-、*、/、%
    赋值运算
    	=、+=、-=、*=、/=、%=
    关系运算
    	>、>=、<、<=、!=、==、instance of、&、&&、|、||、!、^
    位运算
    	&、|、^、~、>>、<<、>>>
    	
    		           6					-6
    原码:00000000 00000000 00000000 00000110	10000000 00000000 00000000 00000110
    反码:00000000 00000000 00000000 00000110	11111111 11111111 11111111 11111001  符号不动 其余取反
    补码:00000000 00000000 00000000 00000110  11111111 11111111 11111111 11111010  反码+1
    计算机中不管是整数还是负数 存储的形式都是以补码形式来存储
    注意 反码是一种表示形式  取反是一个计算过程(每一个位置都取反)
    
    		6<<2 =24
    		00000000 00000000 00000000 00000110
             00000000 00000000 00000000 00011000
    		相当于乘以2的位移次幂
    		
    		6>>1==3
    		00000000 00000000 00000000 00000110
    		00000000 00000000 00000000 00000011
    		相当于除以2的位移次幂
    
    		-6>>>1
    		11111111 11111111 11111111 11111010
    		?11111111 11111111 11111111 1111101
    		>>保留符号位置 1  填1
    		>>> 不保留符号 不管是什么 都填0
    

(5)语法结构

  • 分支结构

    1.单分支结构if(boolean)...else if(boolean)...else...
    2.多分支结构switch(byte,short,int,char) 1.5enum,1.7String
    	case,default,break;
    
  • 循环结构

    for(int i = 0;i<10;i++)
    for(int i:array)
    while()
    do{}...while()
    break,continue
    

(6)数组

  • 数组的特点

    1.数组本身是一个引用数据类型
    2.数组是在堆内存中的一串连续的地址存在
    3.数组在初始化时必须指定长度
    4.堆内存的数组空间长度一旦确定  不能再次发生改变
    5.栈内存的变量中存储的是数组的地址引用
    6.数组内部存储的类型可以是基本的 也可以是引用
    
  • 数组的定义

    数据类型[] 数组名字;
    int[] a;
    String[] x;
    
  • 数组的赋值

    静态初始化:
    	int[] a = new int[] {1,2,3};
    	int[] a = {2,3,4};
    动态初始化:
    	int[] b = new int[5];
    	整型默认值:0
    	浮点型默认值:0.0
    	字符型默认值:'',unicode码为(’\u0000’)
    	布尔型默认值:false
    	引用数据默认值:null
    
  • 数组的访问遍历

    1.索引从0开始至数组长度-1
    	int[] a = new int[10];
    	访问a[0]-a[a.length-1]即a[0]-a[9]
    2.遍历
    	for(int i = 0;i<a.length;i++){
    		System.out.println(a[i]);
    	}
    	for(int i : a){
    		System.our.println(i);
    	}
    
  • 基本类型和引用类型存储空间异同

    所有的变量空间都存储在栈内存
    变量空间可以存储基本数据类型  也可以存储引用数据类型
    如果变量空间存储的是基本数据类型  存储的是值  一个变量的值改变  另一个不会跟着改变
    如果变量空间存储的是引用数据类型  存储的是引用(地址)  一个变量地址对应的值改变 另一个跟着改变
    
  • 二维数组

    int[][] a = new int[3][2];
    int[][] b = {{1,2},{1},{2,3}}
    int[][] b = new int[][]{{1,2},{1},{2,3}}
    

2.面向对象

(1)属性设计

  • 静态描述特征–特征–属性–又称成员变量

    1.基本格式如下:
    	权限修饰符 [特征修饰符] 数据类型 属性名字 [= 值];
    private static final int age = 18;	//静态常量
    public String name;		//默认值为null
    

(2)方法设计

  • 动态动作行为–做事–方法

    1.基本格式如下:
    权限修饰符 [特征修饰符] 返回值类型 方法名字([参数列表])[抛出异常][{
    	方法体;
    }]
    2.形参和实参
    	形参可以理解为是方法执行时的临时变量空间  x
    	实参可以理解为是方法调用时传递进去的参数  a
    	方法调用时会将实参的内容传递给形参
    	如果内容是基本类型  传递的 是值    形参改变  实参不变
    	如果内容是引用类型  传递的 是引用  形参改变  实参跟着改变
    
  • 方法重载Overload

    1.概念:一个类中的一组方法,相同的方法名字,不同的参数列表,这样的一组方法构成了方法重载。
    	参数列表的不同体现在哪里?
    	参数的个数   参数的类型   参数的顺序
    2.动态参数列表,JDK1.5之后
    	int...x,类型固定,个数可以动态,0-n均可。
    	本质是一个数组,有length属性,有[index]
    	动态参数列表的方法   不能  与相同意义的数组类型的方法构成方法重载  本质是一样的
    	动态参数列表的方法 可以不传参数 相当于0个 数组的方法 必须传递参数
    	动态参数列表在方法的参数中只能存在一份儿  且必须放置在方法参数的末尾
    

(3)构造方法和块

  • 构造方法

    1.作用
    	用来创建当前类的对象(方法 很特殊)
    2.写法
    	权限修饰符  与类名一致的方法名 (参数列表) [抛出异常]{
    		一件事情  创建一个对象(当前类Person)
    		返回对象;
    	}
    3.用法
    	通过new关键字调用
    4.特点
    	1.每一个类都有构造方法,若自己在类中没有定义,系统会默认提供一个无参数的构造方法;若在类中自己定义了构造方法,则默认无参数的构造方法即被覆盖
    	2.构造方法是否存在方法重载?----存在构造方法重载
    
  • 程序块

    1.作用
    	跟普通方法一样 做事情的
    2.写法
    	可以认为程序块是一个  没有修饰符 没有参数 没有返回值 没有名字的特殊方法
    		{
    		}
    3.用法
    	块也需要调用才能执行 我们自己调用不到(没有名字)
    	每一次我们调用构造方法之前   系统会帮我们自动的调用一次程序块 让他执行一遍
    4.特点
    	没有重载概念,可以在类中定义多个程序块。
    	块可以在里面写一些程序   我想要在创建对象之前执行
    
  • this关键字

    1.是一个关键字(指代词)  代替的是某一个对象  (当前调用属性或方法时的那个对象)
    2.this可以调用什么?  属性  方法  可以
    	this可以调用构造方法么?  可以  在一个构造方法内可以调用另一个构造方法
    	通过this();  省略了构造方法的名字(必须与类名一致)
    	必须在另一个构造方法内调用  必须在程序的第一行
    
    

(4)小结

类中的四个成员
	1.属性 -- 静态描述特征(存值)
		权限修饰符 [特征修饰符] 属性类型 属性名字 [= 值];
	2.方法 -- 动态描述行为(做事情)
		权限修饰符 [特征修饰符] 返回值类型 方法名字 ([参数列表]) [抛出异常] [{方法体}]
		最主要的是方法设计的参数及返回值问题  传递 调用 执行 内存
	3.构造方法 -- 创建当前类对象(做事情 唯一的事情)
		权限修饰符 与类名相同的方法名 ([参数列表]) [抛出异常] {方法体}
	4.程序块 -- 一个特殊的方法(没名 做事情 不用我们调用 构建对象之前调用)
		{方法体}
	5.this关键字的使用
		用来代替某一个对象
		可以调用一般属性或一般方法  放置在任何类成员中
		可以调用构造方法  只能放在另一个构造方法内 只能放在程序的第一行
	6.类的加载及对象的创建(内存原理 机制)

(4)类的关系

  • 泛化(继承,实现)

    继承is-a
    	1.子类继承父类,通过一个关键字	extends
    	2.子类的对象可以调用父类中的(public protected)属性和方法  当做自己的来用
    	3.子类可以添加自己独有的属性和方法
    	4.子类从父类中继承过来的方法不能满足子类需要,可以在子类中重写(覆盖)父类的方法  更多指的是内容
    	5.每一个类都有继承类,如果不写extends关键字,默认继承Object,如果写了extends则继承后面那个父类
    	6.Java中继承是单个存在的(单继承),每一个类只能有一个继承类(在extends关键字后面只能写一个类)
    		可以通过传递的方式实现多继承的效果,后续还会有实现
    	7.继承在内存中的存储方式
    	8.this与super关键字的区别
    		this和super都是代替对象
    		this代替的是执行属性或方法是的当前这个对象
    		super代替的是当前对象的父类对象
    		this和super都可以调用一般的属性或方法,放置在类成员的任意位置
    		方法之间是可以来回调用的(编译好用),执行时注意StackOverflowError的问题
    		this和super都可以调用构造方法,只能放在另一个构造方法第一行  this()	super()
    		当利用this或super调用构造方法时,他们两个不能同时出现(他们都想抢占第一行,冲突啦)
    
    • Object类

      可以理解为Object类非常重要,是任何一个引用类型的父类(直接或间接的继承Object),Object没有父类
      		Object类中的方法
      			hashCode()	将对象在内存中的地址经过计算得到一个int型整数
      					public native int hashCode();
      			equals()		用来比较两个对象的内容,Object默认效果是==
      					==可以比较基本类型(比较值),可以比较引用类型(比较地址)
      					equals方法时Object类中继承过来的方法,默认效果比较地址
      					如果想要改变其规则,可以进行方法重写
      					public boolean equals(Object obj){
      						return (this == object);
      					}
      			toString()		打印输出时将对象变成String字符串
      					public String toString(){
      						return this.getClass().getName()+"@"+Integer.toHexString(this.hashCode());
      					}
      			getClass()		获取对象对应类的类映射(反射)
      			wait()		线程进入挂起等待状态
      			notify()		线程唤醒
      			notifyAll()		唤醒所有线程
      			finalize()析构方法,clone()	这两个方法都是protected修饰符修饰
      
    • 重写和重载的区别

      		方法重写override					方法重载overload
      		1.类	产生两个继承关系的类				一个类中的一组方法
      			子类重写父类的方法
      		2.权限	子类可以大于等父类			没有要求
      		3.特征	final static abstract		没有要求
      			父类方法是final	子类不能重写
      			父类方法是static	子类不存在
      			父类方法是abstract	子类必须重写
      			(子类是具体必须重写,否则子类是抽象类,可以不重写)
      		4.返回值	子类可以小于等于父类			没有要求
      		5.名字	子类与父类一致					一个类中的好多方法名必须一致
      		6.参数	子类与父类一致				每一个方法的参数必须不一致(个数 类型 顺序)
      		7.异常	运行时,编译时				没有要求
      			如果父类方法抛出运行时异常
      			子类可以不予理会
      			如果父类方法抛出编译时异常
      			子类抛出异常的个数少于等于父类
      			子类抛出异常的类型小于等于父类
      		8.方法体	子类的方法内容与父类不一致	每一个重载的方法,执行过程不一样
      
      
  • 包含(组合,聚合,关联)

    • 包和导包

      类的个数变多了--->需要管理类--->包package(可以理解为是一个文件夹)
      		类的第一行会出现package关键字
      		如果package和import同时出现
      		先写package后写import
      		package只能有一个,import可以有多个
      
    has-a	包含关系(组合,聚合,关联)
    		从亲密程度来讲不太一样
    		组合-->人和大脑	人和心脏的关系
    			整体和部分的关系,不可分割,要出现都出现,要消亡都消亡
    		聚合--->汽车和车轮子	电脑和主板
    			整体和部分的关系	创建时有可能是分开的
    		关联--->人有汽车	人有电脑
    			整体和部分的关系,可以分割,后来形成在一起
    		从Java程序来描述这样的关系,通过一个类的对象当做另一个类的属性来存储
    
  • 依赖(need-a)

    use-a(need-a)	依赖关系
    		屠夫 杀  猪			农夫 养猪
    		一个类屠夫
    			可以做一件事   杀猪
    			需要一头猪
    		不是整体和部分的关系,某一件事情产生了关系
    		临时组合在一起,这件事情一旦做完即解散
    		Java程序体现的形式:
    		一个类的方法中使用到了另一个类的对象
    			第一个可以在方法中传递参数
    			第二个可以在方法中自己创建
    

    设计类的关系遵循的原则:高内聚低耦合

    耦合度:紧密,继承(实现)>包含>依赖
    

3.特殊关键字

(1)修饰符

  • 描述一个类

    修饰符,特征符,class,类名{
    		属性	权限	特征	类型	名字
    		方法	权限	特征	返回值	名字	参数	异常	执行体
    		构造方法	权限	名字	参数	异常	执行体
    		程序块	执行体
    }
    
  • 修饰符

    权限修饰符
    		public		公共的
    		protected		受保护的
    		默认不写		默认的
    		private		私有的
    特征修饰符
    		final		最终的,不可更改的
    		static		静态的
    		abstract		抽象的
    		native		本地的
    		*transient		瞬时的,短暂的--->序列化
    		*synchronized	同步的,线程问题
    		*volatile		不稳定的
    
    • 权限修饰符

      public		公共的	本类	同包	子类	当前项目中任意位置只要有对象都可以访问
      protected	保护的	本类	同包	子类(通过子类对象在子类范围内部访问)
      默认不写	 默认的	本类	同包
      private		私有的	本类
      1.能修饰什么
      2.范围如何
      		权限修饰符可以用来修饰,类本身,和类中的成员,除了程序块
      		权限修饰符用来修饰类的时候只有两个可以用(public,默认不写)
      		权限修饰符都可以用来修饰类中的其他成员
      
    • 特征修饰符

      • final

        最终的,不可更改的
        修饰变量
        			如果在定义变量时没有赋初始值
        			给变量一次存值的机会(因为变量在栈内存空间内,没有默认值,如果不给机会,就没法用了)
        			一旦变量被存储了一个值,若用final修饰后,则不让再次改变--->相当于常量
        			注意变量类型是基本类型还是引用类型
        			如果修饰的变量是基本数据类型,则变量内的值不让更改--->常量
        			如果修饰的变量是引用数据类型,则变量内的地址引用不让更改--->对象唯一
        修饰属性
        			全局变量,存储在堆内存的对象空间内的一个空间
        			属性如果没有赋值,有默认值存在的
        			属性用final修饰后,必须给属性赋初值,否则编译报错
        			特点与修饰变量一致
        			注意变量类型是基本类型还是引用类型
        			如果修饰的变量是基本数据类型,则变量内的值不让更改--->常量
        			如果修饰的变量是引用数据类型,则变量内的地址引用不让更改--->对象唯一
        修饰方法
        			方法是最终的方法,不可更改
        			子类继承父类的方法,将父类的方法重写(覆盖)
        			final修饰的方法,要求不可以被子类重写(覆盖)
        修饰类本身
        			类是最终的,不可以更改
        			(太监类 无后)此类不可以被其他子类继承	
        			通常都是一些定义好的工具类
        			Math	Scanner	Integer	String
        
      • static

        静态的:
        1.可以修饰:修饰属性,修饰方法,*修饰块,修饰类(内部类)
        2.特点:
        		1.静态元素在类加载时就初始化啦,创建的非常早,此时没有创建对象
        		2.静态元素存储在静态元素区中,每一个类有一个自己的区域,与别的类不冲突
        		3.静态元素值加载一次(只有一次),全部类对象及类本身共享
        		4.由于静态元素区加载的时候,有可能没有创建对象,可以通过类名字直接访问
        		5.可以理解为静态元素不属于任何一个对象,属于类的
        		6.内存管理,栈内存创建开始用完及回收,堆内存通过GC回收,静态元素区GC无法管理
        			静态元素去Garbage Collection无法管理,可以粗暴的认为常驻内存
        		7.非静态成员(堆内存对象里)中可以访问静态成员(静态区)
        		8.静态成员中可以访问静态成员(都存在静态区)
        		9.静态成员中不可以访问非静态成员
        			(个数,一个出发访问一堆相同名字得东西,说不清)
        			(静态元素属于类,非静态成员属于对象自己)
        		10.静态元素中不可以出现this或super关键字(静态元素属于类)
        
      • native

        本地的
        	Java源代码中看到native就已经再也看不见后续代码
        	后续会调用其他的编程语言C++,C执行内存的操作,帮我们操作内存
        	Object类中的一个方法   hashCode
        
      • abstract

        抽象的
        1.可以修饰什么
        		修饰方法
        			用abstract修饰符修饰的方法,只有方法的结构,没有方法执行体叫做抽象方法
        			当然注意native修饰的方法虽然也没有方法体,但是不是抽象方法 ,只是执行的过程是其他语言写的,看不到
        		修饰类
        			用abstract修饰符修饰的类,叫做抽象类
        2.修饰后有什么特点
        		抽象类中必须有抽象方法么?	不是必须含有抽象方法的
        		抽象方法必须放在抽象类中么?	们目前来看必须放在抽象类中(或接口中),普通类是不允许含有抽象方法的
        3.研究一下什么叫做抽象类,抽象类有什么特点?(通常是用来描述事物的,还不是很具体)
        		1.类里有什么 成员
        			属性	可以含有一般的属性,也可以含有private,static,final等等;
        			方法	可以含有一般的方法,也可以含有private,static,final等等;
        				注意:抽象类中是允许还有抽象方法的(只有方法结构,没有方法执行体的方法)
        			块	可以含有一般的程序块,也可以含有static程序块
        			构造方法	可以含有构造方法,包括重载
        		2.类如何使用,创建对象
        			抽象类还有构造方法,但是我们不能通过调用构造方法直接创建对象
        			抽象类只能通过子类单继承来做事
        			为什么不让我们调用构造方法创建对象?为什么还有呢?
        		3.类和类的关系
        			抽象类------直接单继承------抽象类	可以
        			抽象类------直接单继承------具体类	可以(用法通常不会出现)
        			具体类------直接单继承------抽象类	不可以(将父类的抽象方法具体化 或 子类也变成抽象类)
        		4.小问题
        			抽象类中能不能没有抽象方法,全部都是具体成员	可以
        			抽象类中能不能没有具体成员,全部都是抽象方法	可以---->抽象类抽象到极致,质的变化---->接口
        			接口可以理解为是抽象类抽象到极致---->还是一个类的结构,不能用class修饰,改用interface修饰
        			public interface Test {
        				
        			}
        5.什么是接口(通常是用来定义规则的)
        			接口也是一个类的结构,只不过用interface修饰,替换原有的class
        			1.有什么成员
        				属性	不能含有一般的属性;只能含有公有的静态的常量(public static final默认不写也可以)
        				方法	不能还有一般的方法;只能含有公有的抽象的方法(default修饰具体方法;public默认不写也可以)
        				块	不能含有一般的程序块,也不能含有static块(块本身就是具体的,接口中不让有具体的)
        				构造方法	不能含有构造方法
        			2.如何使用,创建对象
        				不能创建对象
        				只能通过子类多实现(implements)来做事
        			3.与别的类结构关系
        				接口不能继承别的类	最抽象
        				抽象类----直接多实现----接口	可以
        				具体类----直接多实现----接口	不可以(必须将接口中的抽象方法具体化或自己变成抽象类)
        				*接口----多继承----接口	可以
        

(2)类的加载顺序

  • 加载顺序

    存在继承关系的类,加载机制,及执行过程
    	加载类的过程--静态元素已经加载
    	Person person = new Person();
    	1.加载父类
    	2.父类会产生自己的静态空间	属性,方法,块,执行块
    		执行静态块
    	3.加载子类
    	4.子类会产生自己的静态空间	属性,方法,块,执行块
    		执行静态块
    --------------------------------------------------------------------------------------------
    	5.开辟对象空间
    	6.加载父类的非静态成员	属性,方法,块,构造方法
    	7.	执行块,执行父类的构造方法
    	8.加载子类的非静态成员	属性,方法,块,构造方法
    	9.	执行块,执行子类的构造方法
    	10.将对象空间的地址引用交给	变量来存储
    

(3)特殊类

  • 内部类

    成员内部类
    		将类的定义直接放在另一个类中,与成员并列
    		可以用任何的修饰符来修饰
    		内部类可以直接使用外部类的成员
    		若内部类与外部类成员重名,通过外部类.this.name
    		如果想要使用内部类的属性和方法,必须创建对象,通过外部类对象操作
    			Demo d = new Demo();
    			InnerDemo id = d.new InnerDemo();
    		注意内部类命名:外部类$内部类.class
    	局部内部类
    		将类的定义放在类成员中,与局部变量并列
    		局部内部类只能用abstract和final来修饰
    		在不同的方法中定义重名的局部内部类
    		注意局部内部类命名:外部类$1内部类.class
    		局部内部类可以访问外部类成员,属性内部类也能访问局部变量,要求局部变量必须为final修饰
    	匿名内部类
    		将类直接定义在类中,或者类成员中,成员匿名内部类,局部匿名内部类
    		匿名内部类没有类的所有结构(名字,修饰符)只有类体
    		通常会在抽象类或接口创建的后面使用,当然具体的类也可以有匿名子类
    		匿名内部类没有构造方法,也不能用任何修饰符来修饰
    		public interface Test() {
    			public void test();
    		}
    		public class TestMain() {
    			public statc void main(String[] args) {
    				Test t = new Test(){
    					public void test(){
    
    					};
    				}
    			}
    		}
    	静态内部类
    		只能在类中定义,作为成员
    		静态内部类不需要外部类对象操作,可以直接创建对象
    		静态内部类可以访问外部类的静态成员
    
  • 枚举类

    枚举类
    	一个类中的对象,认为个数有限且固定的,可以将每一个对象一一列举出来
    	1.试一试若没有枚举类型的时候,如何手动设计(静态常量,单例模式),Day(类,当做描述星期,7个对象)
    		private构造方法
    		public static final属性 = new
    	2.JDK1.5版本之后可以直接定义enum类型
    		我们自己定义的enum类型直接默认继承Enum(java.lang包)
    		我们自己定义的enum类型不能再写extends,但是可以实现
    		Enum类型
    			有两个属性
    			name--->枚举对象的名字,name()获取name属性
    			ordinal--->枚举对象在类中罗列的顺序,类似index,也从0开始,ordinal()获取序号
    			一些常用的方法
    			valueOf()	通过给定的name获取对应的枚举对象
    			values()	获取全部的枚举对象---->返回一个数组Day[]
    			compareTo()	可以比较两个枚举对象   int
    			toString()		由于这个方法没有final修饰,可以覆盖(重写)
    	3.switch内部判断枚举的应用
    		Day day = Day.valueOf(key);
    		switch(){
    		}
    	4.我们也可以在enum中描述自己的一些属性或方法
    		必须在enum类中第一行,描述一下枚举的样子,最后需要分号结束
    		可以定义自己的属性
    		类创建的过程中,帮我们创建枚举类型的对象
    		需要给枚举类型提供对应样子的构造方法,构造方法只能private修饰,可以重载
    
  • Scanner类

    1.所属的包java.util包,需要import导包
    2.通过一个带输入流的构造方法创建对象
    3.常用方法  nextInt(),nextFloat(),next(),nextLine()	
    
  • System类

    1.所属的包java.lang包,不需要导入
    2.不需要创建对象,通过类名就可以访问
    3.有三个属性及若干的方法
    		三个属性out in err
    		几个方法gc() exit(0);
    		currentTimeMillis()//返回当前时间的毫秒值
    

(4)小结

所有面向对象的编程思想
	如何描述类
		类成员四个;方法
	如何创建对象
		执行类成员
	类之间的关系
		is-a;has-a;use-a
	类中特征
		权限;特征
	类之间的设计问题
		设计模式:单例、策略、适配器
	类中的一些细节
		内部类、枚举类
	内存机制的问题
		类创建在哪儿,对象创建在哪里,继承关系,静态成员,方法执行
		栈内存<---Person p = new Person();--->堆内存
		栈内存:创建开始,用完即回收,StatckOverflowError
		方法区:类、常量、静态,只有一份回收不了
		堆内存:new创建的对象,Garbage Collection垃圾回收器

	Runtime类之中提供了几个管理内存的方法
		maxMemory		堆内存总大小
		totalMemory		可用的内存大小
		freeMemory		未用的内存大小
		堆内存溢出错误OutOfMemoryError:java heap space
	Object类中有一个finalize方法,如果重写也能看见对象回收
	GC系统提供的一个线程,回收算法
  • 内存管理

    内存管理的问题
    		栈内存:变量空间,方法执行临时空间,从创建开始执行完毕,立即回收
    		堆内存,我们自己new申请对象空间,垃圾回收器GC,对象空间没有任何引用指向视为垃圾
    		方法区,常量,类模板,静态成员,有且只有一份,不回收
    		
    		public class test{
    			public Person p = new Person();
    		}
    		Test t = new Test();
    		Person p = t.p;
    		p = null;
    		t.p = bull;
    		System.gc();
    为了能看到对象被回收的效果
    		1.重写类中的finalize()方法,从Object继承过来的
    		2.Runtime类,单例模式,Runtime.getRuntime();获取对象
    			long x = maxMemory,totalMemory,freeMemory
    			OutOfMemoryError	堆内存溢出错误
    			StackOverflowError	栈内存溢出错误
    

4.包装类

  • byte-Byte、short-Short、int-Integer、long-Long
    float-Float、double-Double、char-Character、boolean-Boolean
    
  • 1.八个包装类都在同一个包下,java.lang包,不要用import导包,直接使用即可。
    2.八个包装类中有六个是与数字相关,都默认继承父类Number
    3.八个包装类都实现了Serializable,Comparable
    4.八个包装类都有带自己对应类型参数的构造方法
    	   八个包装类有七个(除了Character)还有构造方法重载,带String类型
    		new Integer(10);
    		new Integer("10");
    5.创建对象,对象调用属性/方法
    		new Integer("abc");	------>NumberFormatException
    		有六个与数字相关的类型都继承Number,xxxValue();将一个包装类型转化为对应的基本类型(拆包)
    		toBinaryString(int i);		//转换成二进制数字
    		toHexString(int i);		//转换成十六进制数字
    		toOctalString(int i);		//转换成十进制数字
    6.经常在笔试中出现的问题
    		Integer i1 = 10;
    		Integer i2 = 10;
    		Integer i3 = new Integer(10);
    		Integer i4 = new Integer(10);
    		System.out.println(i1 == i2);	
    		//true//注:若i1和i2数字范围超过127或小于-128;则i1 == i2为false
    		System.out.println(i1 == i3);	//false
    		System.out.println(i3 == i4);	//false
    		System.out.println(i1.equals(i2));	//true
    		System.out.println(i1.equals(i3));	//true
    		System.out.println(i3.equals(i4));	//true
    
    1.==与equals()的区别
    		==可以比较基本数据类型,也可以比较引用数据类型(变量中存储的内容)
    		如果比较基本类型,比较的是变量中存储的值
    		如果比较引用数据类型,比较的是变量中存储的地址引用
    		equals()是Object类中继承过来的方法,每一个引用类型都可以调用
    		默认继承的equals()方法比较与==一致,如果想要改变比较规则,可以重写equals()方法
    		由于Integer类就重写了equals()所以Integer比较的是数值
    2.考察Integer类加载的时候,自己有一个静态的空间
    		空间内立即加载Integer类型的数组内存储256个Integer对象,-128~127
    		如果我们用的对象范围在这之内Integer i1 = 10;直接去静态区中找对应的对象
    		如果我们用的对象范围超出了这个Integer i1 = 1000;会帮我们创建一个新的Integer对象
    

5.数学相关

(1)Math

1.所属的包java.lang
2.Math构造方法是私有的,我们不能直接调用创建对象
3.由于Math中提供的属性及方法都是static,不需要创建对象
4.常用的方法
		abs()返回给定数字的绝对值
		double = ceil()向上取整
		double = floor()向下取整
		double = rint()临近的数,如果两边距离一样,则返回偶数
		double = round()四舍五入的整数
		max(a,b)	(参数int,long,float,double)
		min(a,b)	
		pow(a,b)a的b次方(参数int,long,float,double)
		sqrt(a)获取给定参数的平方根值
		random()随机产生一个 [0.0----1.0)之间的数
5.Math.random()计算小数的时候精确程度可能有些损失
		0-9之间的随机整数
		int value = (int)(Math.random()*10);
		5.0-10.9之间的小数
		(Math.random()*6)+5
		0.0---0.99999 * 6
		(0.0---5.49999)+5

(2)Random

1.在java.util包中的类,需要import导入
2.没有任何继承关系,默认继承Object类
3.查找构造方法--->如何创建对象
		Random r = new Random();
4.类中提供的常用方法
		r.nextInt();	随机产生一个int取值范围的整数,有正有负
		r.nextInt(int bound);	随机产生一个[0,bound)取值范围的整数
			注意bound必须为正数,否则会出现如下的运行时异常
			IllegalArgumentException
		r.nextFloat()  随机产生一个[0.0,1.0)
		r.nextBoolean() 随机产生一个boolean类型的值true,false

(3)UUID

1.所属的包 java.util,需要import导入
2.没有任何继承关系,默认继承Object类
3.构造方法有,没有无参数的,通常不会创建对象
		UUID uuid = UUID.randomUUID();
		System.out.println(uuid.toString);//数据库表格主键 primary key
		产生一个32位的随机元素,每一个位置是一个16进制的数字

(4)BigInteger

大整数
1.所属的包java.math,需要import导入
2.继承自Number
3.如何创建对象,提供的构造方法全部都是带参数的
		通常利用带String参数的构造方法创建这个类的对象
		BigInteger bi = newBigInteger("123");
4.类中常用方法
		做四则运算
		add()	subtract()	multiplt()	divide()
5.小例子,设置一个方法,用来计算给定数字的阶乘
		public BigInteger factorial(int num) {
			BigInteger result = new BigInteger("1");
			for(int i = 1;i<=num;i++) {
				result = result.multiply(new BigInteger(i+""));
			}
			return BigInteger;
		}

(5)BigDecima

超过double取值范围
1.所属的包java.math,需要import导入
2.继承Number类
3.通常也是可以通过 带String参数构建对象
4.类中的常用方法
		做四则运算
		add()	subtract()	multiply()	divide()
		两个参数 前面是保留小数点之后的位数,后面参数是设置的模式
		对象.setScale(2.BigDecimal.ROUND_DOWN);

(6)DecimalFormat

将小数点之前和之后的位数都能处理的类---->格式化
1.所属的包java.text
2.import导入才能使用
3.通过带String参数的构造方法创建一个格式化对象	0,#
4.调用format方法将一个小数格式化成一个字符串
		DecimalFormat df = new DecimalFormat("000.###");
		String value = df.format(123.4567);
		System.out.println(value);	//123.457,默认为四舍五入

(7)小结

1.Math类	java.lang包
		所有属性和方法都是静态的不需要创建对象
		abs(),max(),min(),ceil(),floor(),round(),sqrt(),pow(),random()
2.Random类 java.util包
		需要导包,通过无参构造方法创建对象
		nextInt(),nextInt(int bound),nextFloat(),nextDouble(),nextBoolean()
3.UUID类 java.util包
		UUID uuid = UUID.randomUUID();
		uuid.toString();	32位,16进制的元素
4.BigInteger类,BigDecimal类,java.math包
		需要导包,通过带String参数的构造方法创建对象
		add(),substract(),multiply(),divide()
		Decimal对象.setScale(位数,设置格式);设置小数点之后保留的位数
5.DecimalFormat类,java.text包----->格式化
		导包使用,通过带String参数的构造方法创建对象,String---->一种格式
		DecimalFormat df = new DecimalFormat("000.###");	//# 0
		String value = df.format(123.4567);//给定的数字格式化成上述的效果

6.日期相关

(1)Date

1.通常使用的是java.util包
2.导包,拿来使用,构建对象
3.通常使用无参的构造方法,或者带long构造方法
4.Date类中常用的方法
		before();after();
		setTime();getTime();------>long
		compareTo(); -1,1,0
5.可以处理一个Date日期的格式

(2)DateFormat

1.包java.text需要导包使用
2.此类是一个抽象类,不能创建对象,子类来使用
3.SimpleDateFormat类,是DateFormat的子类
4.调用带String参数的构造方法创建format对象
		DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		String value = df.format(new Date());

(3)Calendar

1.所属的包java.util,需要导包
2.有构造方法,用protected修饰的,通常访问不到,通常会调用默认的getInstance();
3.常用方法
		after(),before();
		setTime(),getTime()---->Date
		getTimeInMillis()---->time
		getTimeZone()---->TimeZone
		Calendar里面包含一个date属性,可以操作date的某一个局部信息
		set get
		calendar.set(Calendar.YEAR,2015);
		int year = calendar.get(Calendar.YEAR);

(4)TimeZone

1.java.util类
2.可以通过calendar对象.getTimeZone()获取或TimeZone.getDefault();
3.常用方法
		tz.getID();-----> Aisa/Shanghai
		tz.getDisplayName()----->中国标准时间

(5)小结

0.System类,java.lang包
		in,out对象属性,gc();exit(0);
		long time = System.currentTimeMillis();//获取当前系统时间--->1970-1-1 08:00:00 毫秒形式
1.Date类,java.util包(java.sql)
		无参数构造方法new Date(); new Date(long time);
		after(); before(); compareTo();
		setTime(); getTime();
2.SimpleDateFormat类,java.text包
		DateFormat类的子类
		带String参数的构造方法,new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		String value = 对象.format(new Date());		
3.Calendar类,java.util包
		需要通过类中的一个方法创建对象
		Calendar c = Calendar.newInstance();	//默认当前系统时间的一个对象
		after()、before()、setTime()、getTime()
		set(Calendar.YEAR,2015)、get(Calendar.YEAR);
		getTimeInMillis();
		getTimeZone();//获取对应的时区
4.TimeZone类,java.util包
		需要通过类中的一个方法创建对象
		TimeZone tz = TimeZone.getDefault();
		getID();	getDisplayName();

7.字符串

(1)String

0.常见的String笔试题
			== equals方法的区别
				==可以比较基本类型,可以比较引用类型
				比较基本类型比较值,比较引用类型比较地址
				equals只能比较引用类型(方法)
				默认比较地址this == obj
				如果相扰修改其比较规则,可以重写equals方法
				通常重写equals方法时会伴随着重写hashCode方法
				比如String类,比如Integer类
			*String的不可变特性	
				长度及内容			
			String与StringBuffer的区别
			StringBuffer与StringBuilder的区别
			String对象的存储
				"abc"---->字符串常量池
				new String("abc");---->堆内存
				"a"+"b"+"c"+"d"		//中间产生了7个对象
			*String中常用的方法
		1.存在哪儿  java.lang包
			没有任何继承关系,实现三个接口Serializable,CharSequence,Comparable
		2.实现了三个接口,Serializable,CharSequence,Comparable<String>
		3.如何创建对象
			String str = "abc";	直接将字符串常量赋值给str(字符串常量池)
			String str = new String();	//String str = "";	//无参数的构造方法创建空的String对象
			String str = new String("abc");//String str = "abc";//有参数的构造方法创建String对象
			String str = new String(byte[]);	//将数组中的每一个元素转化成对应的char组合成String
			String str = new String(char[]);//将数组中的每一个char元素拼接成最终的String
		4.String的不可变特性
			String类中包含一个private final char[] value;
			体现在两个地方,长度及内容
			长度---->final修饰的数组,数组长度本身不变,final修饰数组的地址也不变
			内容---->private修饰的属性,不能再类的外部访问
			在String类中包含一个数组
			private final char[] value;//存储String中的每一个字符
			final最终的不可改变的---->地址不让改变,数组的长度本身不可变
			private私有的当前类中---->数组的内容也不能改变	
		*5.常用的方法
			1.boolean = equals(Object obj);
				//继承自Object重写了,比较两个字串中的字面值是否相等
			2.int = hashCode();
				//继承自Object重写了,
				//将当前字符串的每一个元素拆开,
				//加上索引乘以31;
				//h0 = 0*31+char[0];h1 = h0*31+char[1];
			3.int = compareTo(String str);
				//实现自Comparable接口,实现了,按照字典索引的顺序比较
			4.String = toString();
				//继承自Object重写了,不再输出类名@hashCode,输出字符串的字面值
-----------------------------------------------------------------------------------
			常用方法
			6.char = charAt(int index);	//返回给定index对应位置的那个char值
			7.int = codePointAt(int index);	//返回给定index对应位置的那个char所对应的code值
			8.int = length();		//返回字符串的长度
			9.String = concat(String str);	//返回拼接后的字符串,效率比直接+连接好
			10.boolean = contains(CharSequence s);
			判断给定的字符串s是否在字符串中存在
			11.boolean = startsWith(String prefix);
		   		boolean = endsWith(String suffix);
				判断此字符串是否已xx开头/结尾
			12.byte[] = getBytes();------->getBytes(String charsetName);	//设置拆字符串使用的编码,避免中文乱码
		     	char[] = toCharArray();	'我' '爱' '你' '中' '国'
				将当前字符串转化成数组
			13.int index = indexOf(String/int[,int fromIndex]);
				找寻给定元素在字符串中第一次出现的索引位置,若字符串不存在,则返回-1
		     	int index = lastIndexOf(String/int[,int fromIndex]);
				找寻给定元素在字符串中最后一次出现的索引位置,若字符串不存在,则返回-1
			14.boolean = isEmpty();
				判断当前字符串是否为空字符串(length是否为0)
				注意:与null之间的区别
			15.replace();	换全部匹配的字串
		     	replaceAll();	换全部匹配的字串
		     	replaceFirst();	换第一次出现的那个字串
				将给定的字符串替换成为另外的字符串
			16.split(String regex[,int limit]);
				按照给定的表达式将原来的字符串拆分开
			17.String = substring(int beginIndex[,int endIndex]);
				将当前的字符串截取一部分
				从beginIndex开始至endIndex结束 [beginIndex,endIndex)
				若endIndex不写,则默认到字符串最后
			18.String = toUpperCase();
		     	String = toLowerCase();
				将全部字符串转换成大写/小写
			19.String = trim();
				去掉字符串前后的空格
			20.boolean = matches(String regex);
				regular有规律的,expression表达式
				正则表达式
6.常用的方法
			第一梯队(重写)
				equals()、hashCode()、compareTo()、toString()
			第二梯队(常用)
				charAt()、codePointAt()、indexOf()、lastIndexOf()
				substring()、split()、replace()、length()
				concat()、contains()、trim()
				getBytes()、toCharArray()、matches()
			第三梯队(一般)
				toUpperCase()、toLowerCase()
				startsWith()、endsWith()、isEmpty()

(2)StringBuffer和StringBuilder

1.所属的包 java.lang包
2.继承AbstractStringBuilder,间接继承Object,实现接口Serializable,CharSequence,Appendable
		StringBuffer/StringBuilder没有compareTo方法
		StringBuffer/StringBuilder含有一个String没有的方法  append();拼接
3.特性
		可变字符串	char[] value;
4.对象的构建
		//无参数构造方法,构建一个默认长度16个空间的对象  char[16]
		StringBuffer stringBuffer = new StringBuffer();
		//利用给定的参数,构建一个自定义长度空间的对象 char[20]
		StringBuffer stringBuffer2 = new StringBuffer(20);
		//利用带String参数的构造方法,默认数组长度为字符串长度+16个
		StringBuffer stringBuffer3 = new StringBuffer("abc");
5.StringBuilder中常用的方法
		最主要的方法 append() 频繁的拼接字符串的时候使用此方法,提高性能
		ensureCapacity(int minimumCapacity);	确保底层数组容量够用
		capacity();//字符串底层char[]的容量
		length();//字符串有效元素个数(长度)
		setLength();//设置字符串的有效元素个数
		char = charAt(int index);
		int = codePointAt(int index);
		String = substring(int start[,int end]);
			注意需要接受返回值,看见截取出来的新字符串效果
		StringBuilder = delete(int start[,int end]);
			StringBuilder类中独有的方法String类没有
			将start到end之间的字符串删掉,不用接受返回值就看到效果了
		StringBuilder = deleteCharAt(int index);
			String类中没有的方法
			将给定index位置的某一个字符删除掉
		int = indexOf(String str[,int formIndex]);
		int = lastIndexOf(String str[,int formIndex]);
			找寻给定的str在字符串中第一次出现的索引位置,带第二参数,则从某一个位置开始查询
		insert(int index,value);
			将给定的value插入在index位置之上
		replace(int start,int end,String str);
			将start和end之间的部分替换成str
			builder.replace(2,5,"6666");
		setCharAt(int index,char value);
			将index位置的字符改成给定的value
		toString()
			将StringBuilder对象,构建成一个string对象返回
		trimToSize()
			将数组中无用的容量去掉,变成length长度的数组,即将容量变成和length一样大

(3)正则表达式

	Regular有规律的	Expression表达式

	正则表达式regex
		一个带有一定规律的表达式
		匹配字符串格式的
	正则表达式通常的作用如下:
	1.字符串的格式校验		String类中提供的一个方法 boolean = str.matches("regex");
	2.字符串的拆分及替换	String类中提供的方法 replace,split
	3.字符串的查找		Pattern模式	Matcher匹配器

		如下的所有都用来描述字符的信息
		[abc]		abc其中的一个字符
		[^abc]		除了abc之外的一个字符
		[a-zA-Z]		表示必须是这两个范围内的其中一个字符
		[a-z&&[^def]]	表示a-z中除了def之外的其中一个字符	
		|		或者
		.代表任意一个字符
		\d  digit数字	[0-9]
		\D  非数字		[^0-9]
		\s   space留白	一个空格,一个回车,一个换行、、、
		\s   非留白	
		\w  word单词	[0-9a-zA-Z[_]]
		\W 非单词		[^0-9a-zA-Z[_]]
		
		如下的所有都用来描述字符出现的次数
		?	出现0或1次
		*	出现0或n次
		+	出现1次以上
		{n}	出现n次
		{n,}	出现n次以上
		{n,m}	出现n-m次

	字符串的查找
		//1.利用Pattern类创建一个模式,理解为是一个正则表达式对象
		Pattern pattern = Pattern.compile("\\d{6}");
		//2.需要提供一个字符串
		String value = "123456sfsa666666ldfjglj888222";
		//3.利用pattern对象创建一个匹配器
		Matcher matcher = pattern.matcher(str);
		//4.寻找字符串中出现满足上述格式的字串
		while(matcher.find()) {
			System.out.println(matcher.group());
		}

(4)小结

知识总结
1.StringBuilder类不一定需要,是为了避免String频繁拼接修改字符串信息的时候才用的
		底层数组是可变的,提高了性能
2.常用方法
		与String类不同的独有方法
			append(),insert(),delete(),deleteCharAt(),reverse()
		与String类相同的方法
			length(),charAt(),codePointAt(),indexOf(),lastIndexOf()
			substring,replace()名字相同,用法不一致
		不是很常用的方法
			ensureCapacity(),capacity(),setLength(),trimToSize(),setCharAt()
3.String家族笔试中经常容易考察的知识点
		1.String所属的包,继承关系,实现接口
			java.lang,继承Object,接口Serializable,CharSequence,Comparable
		2.String构建方式
			常量,构造方法
		3.String对象内存结构
			字符串常量区,new堆内存对象
			== equals()区别
			"a"+"b"+"c"
		4.String不可变特性
			长度及内容
		5.String中常用方法---与StringBuilder的区别
			concat(),toUpperCase();
		6.String和StringBuilder区别 | String和StringBuffer区别
			String不可变字符串
				JDK1.0
				有一个接口Comparable
				不可变体现在长度及内容
				有一些方法StringBuilder没有 concat(),compareTo,toUpperCase()
			StringBuilder可变字符串
				JDK1.5
				有一个接口Appendable
				可变字符串,没有final修饰,底层可以进行数组扩容
				有一些方法String没有,append(),insert(),delete(),reverse()
		7.StringBuffer和StringBuilder的不同
			StringBuffer早期版本1.0
			StringBuilder后来的版本1.5
			早期版本 线程同步	  安全性比较高  执行效率相对较低
			后期版本 线程不同步   安全性比较低  执行效率相对较高

8.集合

Collection:存储的都是value
	|-List:有序可重复
		|-Vector:ArrayList早期版本
		|-ArrayList:集合
		|-Stack:栈
		|-LinkedList:链表
	|-Queue:队列,先进先出
	|-Set:无序无重复
		|-HashSet
		|-TreeSet
Map:存储的是以key-value形式存在,key无序无重复,value无序可重复
	|-HashMap:key无序无重复,value无序可重复
	|-TreeMap:自然有序,按照Unicode编码自然有序

(1)ArrayList

底层就是一个数组
		所属的包 java.util
		如何创建对象
		无参数构造方法,带默认空间的构造方法,带collection参数的构造方法
		常用的方法--->小容器
			存 add
			取 get
			删 remove
			改 set
			个数 size
			清除 clear
			
			add(E e)			add(int index,E e)
			addAll(Collection c)	并集	addAll(int index,Collection c)
			clear();	将集合内的全部元素清除
			boolean = contains(Object);	找寻某一个给定的元素是否在集合中拥有
			ensureCapacity(int mincapacity);
			E = get(int index);
			int = indexOf(Object obj);
			int = lastIndexOf(Object obj);
			boolea = isEmpty();
			iterator();//迭代器,1.5之后增强for
			remove(int index)	remove(Object obj);
			removeAll();	差集
			retainAll();	交集
			E = set(int index,E value);
			int = size();
			List = sublint(2,4);
			Object[] Array = toArray();
			toArray(new Integer[list.size()]);
			trimToSize();//变成有效元素个数那么长
  • 泛型

    关于泛型的问题:
    		由于ArrayList底层是一个Object[]  什么类型都可以存进去
    		取出来的时候多态的效果,需要自己造型,显得用起来非常的麻烦
    		JDK1.5之后---->泛型
    		用来规定数据类型的,定义的时候用一个符号代替某种类型
    		在使用的时候用具体的数据类型,将定义的那个符号替换掉
    		ArrayBox<T>
    		泛型可以用在哪里?
    		1.泛型类
    			类定义的时候描述某种数据类型,集合的使用就是这样
    		2.泛型接口
    			与泛型类的使用基本一致
    			public interface Test<X>{
    				public X value;
    			}
    			public class Son<X> implements Test<X>{}
    		3.泛型方法
    			方法调用是传参数,方法的泛型与类无关,带有泛型的方法可以不放在带有泛型的类中
    		4.高级泛型,规范边界,extends,super
    

(2)LinkedList

1.java.util包
2.底层使用双向链表的数据结构形式来存储
		适合于插入或删除,不适合遍历轮询
3.构建对象
		无参数构造方法,带参数的构造方法(Collection)
		ArrayList<String> arrayList = new ArrayList<String>();
		LinkedList<String> linkedList = new LinkedList<String>(array);
4.常用的方法
		增删改查 add();remove();set();get();size();		offer();poll();peek();
		addAll();addFirst();addLast();clear();contains();
		element();getFirst();getLast();indexOf();lastIndexOf();
		.......
5.插入删除的特性是否像想象的那样
		对比ArrayList,LinkedList

(3)Set

  • Set:无序无重复

    1.具体的实现类
    		HashSet
    		TreeSet
    2.基本的使用
    3.无序	无重复
    	无序:我们使用集合存放元素的顺序,集合内取出来的顺序不一致
    
  • HashSet

    1.java.util
    2.如何创建对象,无参数,有参数
    3.集合容器的基本使用
    			增删改查
    			boolean = add(value);addAll(Collection c);retainAll(Collection c);removeAll(Collection c)
    			boolean = remove(Object);
    			没有修改方法
    			iterator()	获取一个迭代器对象
    			size()
    4.无重复的原则
    			首先通过String类型和Person类型存储
    			大概猜测,无重复的原则,利用equals方法进行比较
    			如果我们想要让Person对象的name一致,认为是同一个对象
    			我们可以重写equals方法
    			重写了equals方法,发现还没有产生无重复的效果
    			证明可能原则不止equals一个方法这么简单
    			还有另一个规则同时起着作用 hashCode方法,int
    			五个Person对象只剩一个,第一次存储的,还是最后一次存储的?
    			set集合是发现重复的元素,拒绝存入,存储的是第一个
    
  • TreeSet

    无序无重复 java.util
    			无参数构造方法,带Collection构造方法
    			基本常用方法
    				add(E e),iterator(),remove(E e),没有修改,size()
    			无重复的规则是如何实现的?
    				treeSet集合本身有顺序,我们值得无序存入的和取出来的不一致
    				comparaTo---->String类,按照字母的自然顺序排布(Unicode)
    				如果想要把自己写的类型,比如Person对象存入TreeSet集合里
    				不能随意的存储,需要让自己写的类先实现Comparable接口
    

(4)Map

  • Map

    映射	通过某一个key可以直接定位到一个value值
    	存储的方式以  键值对 存储,key-value
    	key无序无重复,value无序可重复
    	key无序还是一样,指的是存入顺序与取得顺序不一致
    	key无重复当然指的是,元素不能一致
    
  • HashMap

    1.包 java.util
    2.如何创建对象
    3.基本方法
    		增删改查
    		value = put(key,value);
    		putAll(Map);
    			存放一组映射关系	key-value
    			1.key存储的顺序与取得的顺序不同
    			2.不同的key可以存储相同的value
    			3.key若有相同的,则将原有的value覆盖而不是拒绝存入(跟set刚好相反)
    		value = remove(key);
    		boolean = remove(key,value);
    			按key删除或按映射删除
    		put(key,value1);	put(key,value2);
    		E = replace(key,newValue);
    		replace(key,oldValue,newValue);
    			按照key或映射进行修改
    		E = get(key);
    			按照key值查询得到value
    		遍历map集合?
    			获取到所有的key,遍历key,通过key获取value
    			Set = keySet()获取全部的key
    			Set<> set = map.kaySet();
    			Iterator it = set.iterator();
    			while(){}
    			Set<Entry> = entrySet();获取全部的entry对象
    			Set<Map.Entry<,>> entrys = map.entrySet();
    			Iterator<Map.Entry<,>> it = entrys.iterator();
    			while(it.hasNext()){
    				Map.Entry<,> entry = it.next();
    				Integer key = entry.getKey();
    				String value = entry.getValue();
    				System.out.println(key+"----"+value);
    			}
    		size();
    	4.除了上述几个常用的方法外,其他API中提供的方法
    		clear();containsKey(key);containsValue(value);
    		getOrDefault(key,defaultValue);如果key存在,就返回对应的value,若没有找到key,则返回defaultValue
    		isEmpty();
    		putAll(map);
    		putIfAbsent(key,value);如果key存在,则不存入;如果key不存在,则存入映射
    	5.map集合在什么情形下用?
    		1.想要存储一组元素
    			数组or集合	如果存储的元素以后长度不变用数组,如果长度以后不确定,用集合
    		2.如果发现长度以后不确定----->集合
    			List Set Map
    			List家族有序的,存储有顺序用这个
    				ArrayList(vector)		更适合额遍历轮询
    				LinkedList		更适合插入和删除
    				Stack			LIFO
    			Set家族无重复,存储元素希望自动去掉重复元素用这个
    				Hash	性能更高
    				Tree	希望存进去的元素在自动去重复,同时还能自动排序
    			Map家族k-v,通过唯一的k快速找寻v用这个
    				Hash	性能更高
    				Tree	希望存进去的的元素key自动排序
    	6.登录小程序
    		能体会每一个不同集合的特点
    	7.HashMap底层的数据结构存储
    		散列表的形式	数组+链表
    		Person对象存入HashMap中?可以
    		hashCode方法---->不同的对象,可以产生相同的hashCode码的
    		不同的hashCode码---->不同的对象
    
  • TreeMap

    TreeMap		自然有序,按照Unicode编码自然有序
    	1.java.util包
    	2.构造方法
    		无参数,带map参数
    	3.常用方法
    		put,get,remove,replace,size
    	4.底层数据结构的存储
    		红黑二叉树
    

(5)小结

  • ArrayList

    1.底层是利用(动态)数组形式实现	1.5
    	2.ArrayList特点适合遍历轮询,不适合插入删除
    	3.如何创建一个ArrayList对象
    		无参数构造方法,带默认容量构造方法
    	4.ArrayList中常用的方法
    		增删改查 add(E e),remove(index),set(index,value),get(index),size()
    		类中其他常用的方法
    			addAll并集  removeAll()差集   retainAll()交集
    			indexOf()  lastIndexOf()  contains()  List=subList()
    			isEmpty()  clear()  ensureCapacity()  iterator();迭代器
    			toArray(T[] x);  trimToSize();  
    	5.泛型
    		用来规定数据类型
    		注意:泛型,造型
    		在类或接口描述的时候,可以通过某种符号来表示一个未知的类型
    		在类型使用的时候,需要一个具体类型来代替
    		注意:泛型需要使用引用数据类型类代替
    		1.泛型类  2.泛型接口  3.泛型方法  4.方法参数泛型限制
    
  • Vector

    Vector类
    	1.java.lang包
    	2.是ArrayList集合的早期版本	(StringBuffer早期和StringBuilder后来)
    		Vector底层也是利用(动态)数组的形式存储
    		Vector是线程同步的(synchronized)  安全性高  效率低
    	3.扩容方式与ArrayList不同
    		默认是扩容2倍,可以通过构造方法创建对象时修改这一机制
    	4.构造方法
    	5.常用方法
    
  • Stack

    栈
    1.java.util包
    2.构造方法只有一个无参数
    3.除了继承自Vactor类的方法外,还有几个特殊的方法
    		push(E e)将某一个元素压入栈顶(add())
    		E = pop()将某一个元素从栈顶去除并删掉(E = remove())
    		E = peek()查看栈顶的一个元素,不删除(E = get())
    		boolean = empty()判断栈内元素是否为空(isEmpty())
    		int search()查找给定的元素在栈中的位置(indexOf())
    4.中国象棋  悔棋
    		栈中存储每一次操作的步骤
    		撤销功能
    
  • Queue

    1.java.util		通常子类LinkedList,ArrayDeque
    2.通常无参数构造方法创建
    3.一般方法
    		add()
    		element()----->get()
    		remove()
    
    		boolean = offer(E e);//相当于add(),不会抛异常
    		E = peek();//相当于element()方法
    		E = poll();//剪短----->相当于remove()
    4.双十一零点秒杀
    		所有进入秒杀系统的人进入队列
    
  • LinkedList

    1.java.util包
    2.底层使用双向链表的数据结构形式来存储
    		适合于插入或删除,不适合遍历轮询
    3.构建对象
    		无参数构造方法,带参数的构造方法(Collection)
    		ArrayList<String> arrayList = new ArrayList<String>();
    		LinkedList<String> linkedList = new LinkedList<String>(array);
    4.常用的方法
    		增删改查 add();remove();set();get();size();		offer();poll();peek();
    		addAll();addFirst();addLast();clear();contains();
    		element();getFirst();getLast();indexOf();lastIndexOf();
    		.......
    5.插入删除的特性是否像想象的那样
    		对比ArrayList,LinkedList
    
  • Set

    Set
    	特点	无序无重复
    	无序:添加的顺序,获取的顺序不一致(不是集合本身是否有序,Tree自然有序)
    	无重复:添加的元素不能一致(如果出现重复元素,只存第一个,不再存入)
    
    	HashSet(HashMap--->数据存储结构 散列表)
    	TreeSet(TreeMap)--->数据存储结构 二叉树)
    
    	set集合家族的基本使用
    		增删改查
    		add(E e)	remove(E e)  没有修改  iterator迭代器(增强for) size();
    					    hasNext();
    					    E = next();
    	set集合的无重复特性
    		HashSet	无重复原则有两个方法同时起作用
    			equals()	hashCode()
    			默认比较的是两个对象的地址,若第二个对象地址与之前的一致,不再存入
    			如果想要改变其比较的规则,可以重写上述两个方法
    		TreeSet	无重复原则有一个方法起作用
    			compareTo
    			上述这个方法不是每一个对象都有的
    			若想要将某一个对象存入TreeSet集合中,需要让对象所属的类实现接口Comparable接口
    			实现接口后将compareTo方法重写,返回值int,负数靠前排布,正数排列靠后
    
  • Map

    Map
    				以key-value形式存储
    
    HashMap
    	1.java.util包
    	2.构造方法创建对象,无参数,带默认容量的,带Map参数的构造方法
    	3.特点(数组+链表)底层散列表形式存储,key无序无重复,value无序可重复
    		找寻某一个唯一元素的时候建议使用map,更适合于查找唯一元素
    	4.常用方法
    		增删改查
    		put(key,value);
    		remove(key);
    		replace(key);---->put()map集合第二次存储相同的key,则会覆盖之前的value
    		get(key);
    		keySet();获取全部的key,entrySet();获取全部的entry(Node);对象,Map$Entry
    		size();
    		-----------------------
    		clear,containsKey,containsValue,isEmpty,putAll
    		E value = getOfDefault(key,default);若key存在就返回value,若不存在就返回default
    		putIfAbsent(key,value);key若不存在就存入,若存在就放弃
    ======================================================================================
    TreeMap		自然有序,按照Unicode编码自然有序
    	1.java.util包
    	2.构造方法
    		无参数,带map参数
    	3.常用方法
    		put,get,remove,replace,size
    	4.底层数据结构的存储
    		红黑二叉树
    

9.错误与异常

Throwable
	|-Error
		|-StatckOverflowError:栈内存溢出异常
		|-OutOfMemoryError:堆内存异常
	|-Exception
		|-RuntimeException:运行时异常

(1)错误

通常是一些物理性的,JVM虚拟机本身出现的问题,程序指令是处理不了的

(2)异常

通常是一种认为规定的不正常现象,通常是给定的程序指令产生了一些不符合规范的事情
  • 异常的分支体系

    • 运行时异常(非检查异常)

      Error和RuntimeException都算作运行时异常
      		javac编译的时候,不会提示和发现
      		在程序编写时不要求必须做处理,如果我们愿意可以添加处理手段(try throws)
      		要求大家出现这样的异常的时候,知道怎么产生及如何修改
      	1.InputMismatchException		输入类型不匹配
      		int value = input.nextInt();//abc
      	2.NumberFormateException		数字格式化异常
      		Integer.parseInt("sfa");
      	3.ArrayIndexOfBoundsException	数组索引越界
      		int array[] = {1,2,3};
      		int i = array[array.length];
      	4.NegativeArraySizeException		数组长度负数
      		int[] array = new int[-2];	
      	5.NullPointerException		空指针异常;空对象调用方法
      		int[][] array = new int[3][];
      		array[0][0] = 10;
      		Person p = null;
      		p.getName();
      	6.ArithmeticExcetipn		算数异常		除以0
      		10/0			整数不允许除以0;Infinity小数除以0会产生无穷
      	7.ClassCastException		对象铸型异常	对象无继承关系情况转型
      		Person p = new Teacher();
      		Student t = (Student)p;
      	8.StringOutOfIndexException		字符串索引越界
      		String str = "sdfa";
      		char c = str.charAt(str.length);
      	9.IndexOutOfBoundsException	集合越界
      		List家族
      		ArrayList list = new ArrayList();
      		list.add();list.add();
      		list.get(list.size());
      	10.IllegalArgumentException		非法参数异常
      		ArrayList list = new ArrayList(-1);
      
    • 编译时异常(检查异常)

      除了Error和RuntimeException以外其他的异常
      		javac编译的时候,强制要求我们必须为这样的异常做处理(try或throws)
      		因为这样的异常在程序运行过程中极有可能产生问题
      		异常产生后后续的所有执行就停止了
      		1.InterruptException
      			try{
      				Thread.sleep(5000);
      			}catch(Exception e) {
      				
      			}
      		后续还会有更多的编译时异常
      
  • 异常的处理手段

    	添加处理异常的手段
    		try{}catch{}[finally{}]
    		1.try不能单独的出现
    		2.后面必须添加catch或finally
    		3.catch有一组括号(NullPointException)目的是为了捕获某一种异常
    		4.catch可以有很多个存在
    			捕获的异常之间没有任何的继承关系
    			捕获的异常需要从小到大进行捕捉
    		5.finally不是必须存在的
    			若存在finally结构,则必须执行
    			引申一个小问题:final,finally,finalize区别
    				final	特征修饰符  修饰变量,属性,方法,类
    					修饰变量:基本类型,值不能改变;引用类型,地址不能改变,如果没有初值,给一次赋值的机会。
    					修饰属性:特点与修饰变量类似(要求必须给属性赋初始值,否则编译报错)
    					修饰方法:不能被子类重写
    					修饰类:不能被其他的子类继承
    				finally	处理异常手段的一部分
    					try{}catch{}后面的一部分
    					这个部分可有可无,如果有只能含有一份,且必须执行
    				finalize	是Object类中的一个protected方法
    					对象没有任何引用指向的时候---会被GC回收
    					当对象回收得时候,默认调用finalize()方法
    					若想看到对象回收的效果,可以重写 public void finalize(){}
    		6.处理异常放在方法内部,可能还会有小问题
    			如果在方法内部含有返回值
    			不管返回值return在哪里,finally一定会执行完毕
    			返回值的具体结果,看情况
    
  • throws抛出异常

    throws抛出异常
    	1.异常只能在方法上产生的,属性是不能处理异常的
    	2.方法,构造
    	3.方法可以抛出不止一个异常,通过逗号","隔开
    	4.抛出的异常与多个catch类似,要么没关系,要么先抛出小异常
    

(3)小结

		Throwable
	Error			Exception	
	错误			异常
	通常是一些物理性错误	认为规定的不正常现象
	StackOverflowError			运行时RuntimeException
	OutOfMemoryError			编译时

	Error和RuntimeException这一类的异常,运行时,javac变异的时候不检测
	不需要主动添加处理异常的手段,当然我们愿意的话,也可以添加
	除了上述以外的其他的异常都需要做检测,要求我们必须添加处理异常的手段,编译不过去

	处理异常的手段
	try{}catch{}finally{}
		1.try不能单独出现,后面必须跟着其他的一个结构,catch或finally都可以
		2.catch可以出现很多个,要么多个catch捕获的异常没有继承关系,要么先捕获小,再捕获大
		3.finally可有可无,若添加了这个结构,则必须执行,即便是放在方法中,之前有return,也执行
		4.注意方法内部返回值问题
		5.finally可能会出现一个笔试题,final,finally,finalize区别
	throws
		1.之能在方法和构造方法结构上存在(抛出异常)
		2.谁调用此方法,谁处理异常
		3.抛出的异常也可以有多个,用,隔开,小到大

	自定义
		1.写一个类,继承Exception,RuntimeException
		2.类中可以写带String参数的构造方法,可以做细致的说明
		3.通过throw关键字,new一个异常的对象

10.输入输出流

			InputStream		OutputStream
			Reader			Writer
	文件流
		低级
			字节型	FileInputStream	FileOutputStream
			字符型	FileReader	FileWriter
		缓冲
			字节型	BufferedInputStream	BufferedOutputStream
			字符型	BufferedReader		BufferedWriter
	数组流
		byte数组		ByteArrayInputStream	ByteArrayOutputStream
		char数组		CharArrayReader		CharArrayWriter
	数据流
				DataInputStream		DataOutputStream
	字符串流
				StringInputStream		StringOutputStream
	对象流
				ObjectInputStream		ObjectOutputStream

(1)File

1.什么叫文件
		一种电脑的存储形式
		文件有不同的格式 	.txt  .doc  .ppt  .mp4  .jpg  .rar ...
		文件夹?
		File---->与电脑上的文件或文件夹产生一一对应的映射关系
File是一个类
	1.java.io包中
	2.文件或目录路径名的抽象表示形式
	3.File与真实硬盘中的文件或文件夹   不是一个东西
		   File是在内存中的一个对象<----映射---->硬盘上的文件或文件夹
	4.File类中常用的方法
			boolean = canExecute();	文件是否可执行
			boolean = canRead();	文件是否可读
			boolean = canWrite();	文件是否可写
			boolean = isHiddden();	文件是否隐藏
			boolean = isFile();		文件是否是文件
			boolean = isDirectory();	文件是否是文件夹
			long = length();		文件的字节长度
			long = lastModified();	文件的最后修改时间
			String = getAbsolutePath();	得到文件的绝对路径
				绝对路径<---->相对路径
				绝对路径可以通过完整的字符串,定位盘符,文件夹,文件
				相对路径没有盘符的写法,当前工程(项目所在的位置找寻)
			String = getName();		得到文件的名字
			boolean = createNewFile();		创建一个新文件
			boolean = mkdir();		创建一个新文件夹
			boolean = mkdirs();		创建新的文件夹,外层没有,可以自动创建
			String = getParent();	获取当前file的父亲的file名字
			Fine = getParentFile();	获取当前file的父亲的file对象
			String[] = list();		获取当前file的所有儿子名字
			File[] = listFiles();		获取当前file的所有儿子对象
			boolean = delete();		删除文件或空的文件夹,不能删除带元素的文件夹
	
		File file = new File(String path);
		file对象,不是真正的文件,是堆内存中,创建出来的一个对象空间
		路径是看创建的对象,是否能与硬盘中的一个真实文件产生对应的映射关系
		通过文件流去读文件的内容,硬盘上的文件名字是不区分大小写,内存中的File对象,变量名区分大小写
		文件本身的一些属性
	2.什么叫文件流?做什么?
		读取文件中的内容			向文件中写内容
		文件输入流			文件输出流
		字节型文件输入流			字节型文件输出流
		字符型文件输入流			字符型文件输出流

(2)字节型流

  • 字节型文件输入流:FileInputStream

    1.包  java.io
    2.了解一下继承关系,InputStream类,字节型输入流的父类
    3.创建对象
    		调用一个带File类型的构造方法
    		new FileInputStream(File);
    		调用一个带String类型的构造方法
    		new FileInputStream(String);	
    4.常用方法
    		int code = read();		每次从流管道中读取一个字节,返回字节的code码,若没有读到,返回-1
    		int count = read(byte[]);	每次从流管道中读取若干个字节,存入数组内,返回有效元素个数
    		int count = available();	返回流管道中还有多少个缓存的字节数
    		long = skip(long n);		跳过n个字节,再读取,返回n
    			多线程---->利用几个线程同时读取文件
    			10000字节,5个小人同时读取
    			1-2000,2001-4000,4001-6000,6001-8000,8001-10000
    			D当做服务器,E当做客户端
    		close();			将流通道关闭---必须要做,最好放在finally里,注意代码的健壮性,判断严谨性
    
  • 字节型文件输出流:FileOutputStream

    FileOutputStream
    1.java.io
    2.继承OutputStream,所有字节型输入流的父类
    3.创建对象
    调用一个带File参数(默认覆盖写入),还有File boolean重载(boolean参数设置是否追加写入)
    new FileOutputStream(File);/new FileOutputStream(File,true);
    调用一个带String参数(默认覆盖写入),还有String boolean重载(boolean参数设置是否追加写入)
    new FileOutputStream(String);/new FileOutputStream(String,true);
    4.常用方法
    write(int code); 将给定的code对应的字符写入文件
    write(byte[]); 将数组中的全部字节写入文件,String.getByte();
    flush(); 将管道内的字节推入(刷新)文件
    close(); 注意在finally中关闭流

(3)字符型流

只能操作纯文本文件(文件右键打开方式,记事本打开能看懂)

  • FileReader

    1.java.io包
    2.继承 InputStreamReader	Reader
    3.构造方法
    4.常用
    		read();
    		read(char[]);
    
  • FileWriter

    1.java.io包
    2.继承OutputStreamWriter	Writer
    3.构造方法
    		带file参数,带file,boolean
    		带String参数,带String,boolean
    4.常用方法
    		write(int);
    		write(char[]);
    		writer(String);
    		flush();
    		close();
    

(4)缓冲流

在流管道内增加缓存的数据
让我们使用流读取的文字更加的流畅
高级流-->创建通过低级流
  • BufferedInputStream/BufferOutputStream

    1.构建方式,使用低级流构建	
    	BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
    2.基本使用与低级流的方法完全一致
    	read();skip();available();close();
    3.构建方式,使用低级流构建	
    	BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));
    	//注意,缓冲流构建的时候没有boolean类型的参数
    4.基本使用与低级流的方法完全一致
    	write();flush();close();
    
  • BufferedReader/BufferWriter

    BufferedReader
    			String value = readLine();
    BufferedWriter
    			write(String);
    			newLine();
    

(5)其他流

			InputStream		OutputStream
			Reader			Writer
	文件流
		低级
			字节型	FileInputStream	FileOutputStream
			字符型	FileReader	FileWriter
		缓冲
			字节型	BufferedInputStream	BufferedOutputStream
			字符型	BufferedReader		BufferedWriter
	数组流
		byte数组		ByteArrayInputStream	ByteArrayOutputStream
		char数组		CharArrayReader		CharArrayWriter
	数据流
				DataInputStream		DataOutputStream
	字符串流
				StringInputStream		StringOutputStream
	对象流
				ObjectInputStream		ObjectOutputStream
  • 对象的序列化和反序列化

    1.为什么要有文件?
    		文件永久性的保存信息	将很多的数据直接存入文件---数据持久化
    2.如果按照以行为单位写信息
    		好处在于每一行记录的信息都是相关的
    		信息我们可以读取出来,直接看懂文件
    		不好在于第一不安全,直接看懂
    		不好在于第二只能记录String信息,不能记录一些动作(方法)
    3.读取出来的信息 String--->Person
    4.如果能将对象拆分成字节码,直接写入文件
    		将对象直接存入文件中----->对象流
    
    		对象的序列化/反序列化
    		对象的序列化指的是
    			将一个完整的对象,拆分成字节碎片,记录在文件中
    		对象的反序列化指的是
    			将文件中记录的对象碎片,反过来组合成一个完整的对象
    		如果想要将对象序列化到文件中
    			需要让对象实现Serializable接口
    			是一个示意型接口
    			同时为了让对象可以反序列化
    			需要让对象中多存在一个属性 private long serialVersionUID = 任意值;
    		如果想要将对象反序列化
    			需要给对象提供一个序列化的版本号 1.7---->String  1.8---->String
    

(6)小结

  • 字符集

    字符集
    	字符  文字和符号总称(Character)
    	不同国家的数字和符号是一样的,字母
    	不同国家的文字,中文, 日文,韩文
    	计算机最早产生是按照英语单词,单个字符设计的
    	字母,数字,符号---->1字节,8bit,256
    	如果计算机想要处理除了上述字母符号以外的其他字符---比如中文2字节
    	需要将中文进行字符编码---->拆分和组合
    	拆分和组合的规则---所谓的字符编码
    	常见的字符编码
    		ASCII	American Standard Code for Information Interchange
    		ISO-8859-1
    		GB2312	GB18030	GBK	BIG5
    		Unicode
    		UTF-8	UTF-16
    
    		平台(操作系统)默认字符集GBK	Linux(MacOS)默认字符集UTF-8
    		编程序使用的开发环境(IDE)	Idea-->UTF-8	Eclipse-->GBK
    		HTML--->浏览器解析文字使用的字符集
    		注意在用技术本存储文字,流操作纯文本形式的时候
    		字符的形式采用UTF-8
    		String s = "你我他";
    		byte[] = s.getBytes("UTF-8");
    		new String(byte[],"UTF-8");
    

11.线程

程序
	可以理解为是一组静态的代码
进程
	正在进行的程序,静态的代码,运行起来
线程
	正在执行程序中的小单元
1.主线程,系统线程
2.用户线程,main
3.守护线程(精灵线程)	  GC

线程-----操作系统级别  CPU
如何在Java中创建线程,让线程执行,多线程
掌握每一个线程的几种不同状态,及状态之间如何切换
new	     	start()	    CPU分配run()	wait()	     exception  over
创建线程-----就绪状态-----执行状态-----等待/挂起-----异常/消亡
				           notify/notifyAll

(1)线程基础

  • 实现线程的过程

    方式一:
    	1.自己描述一个类
    	2.继承父类Thread
    	3.重写run方法
    	4.new一个线程对象,调用start()方法,让线程进入就绪状态
    方式二:
    	1.自己描述一个类
    	2.实现一个父接口Runnable
    	3.重写run方法
    	4.new一个线程对象,需要创建Thread将自己的对象包起来,然后调用start()
    

(2)锁

  • synchronized

    特征修饰符
    		synchronized	同步	一个时间点只有一个线程访问
    		线程安全锁
    		两种形式写法
    		1.将synchronized关键字,放在方法的结构上
    			public synchronized void get(){}
    			锁定的是调用方法时的那个对象
    		2.将synchronized关键字,放在方法(构造方法,块)的内部(性能比第一种好)
    			public void get(){
    				好多代码;
    				synchronized(对象){
    					好多代码;
    				}
    				好多代码;
    				好多代码;
    			}
    		3.我们觉得return不是很好
    			应该让线程的不同状态来回切换
    			执行  等待   执行  等待
    			wait()	Object类中的方法
    			对象.wait();
    			对象.wait();不是当前的这个对象wait
    				访问当前这个对象的线程wait
    			notify()	notifyAll()	   Object类中的方法
    
    			sleep();
    			run();
    			start();
    		
    			notify();
    			notifyAll();
    			p.setPriority(10);		p.getPriority();
    
    			产生一个类似假死状态
    			所有的线程都进入等待状态,没有线程做事
    		4.通过上述的生产消费者模型
    			做一个非常完整而且安全的模型
    			1.利用线程安全锁,特征修饰符synchronized
    				两种不同的写法
    				不管怎么写,锁定的永远是对象
    			2.利用方法控制线程状态的来回切换
    				wait();
    				notify();	notifyAll();
    			3.Thread类中的方法
    				sleep方法,静态方法(参数long  毫秒值)
    				setPriority(10);	getPriority(10);
    				设置/获取线程的优先级 1-10
    				数字越高优先级越高,更加容易获取CPU分配的资源碎片
    			4.笔试题
    				程序  进程  线程  概念的区别
    				线程的创建方式
    				线程的几种状态,如何切换
    					sleep()方法	wait()方法的区别
    				1.类	Thread类		Object类
    				2.调用	静态 类名		对象
    				3.理解	那个位置调用	对象调用方法
    					那个线程等待	访问对象的其他线程等待
    				4.锁	不会释放锁	等待后会释放锁
    			5.join方法,Thread类中的方法
    				让多个线程同步执行,变成单个线程
    			6.死锁
    

(3)小结

1.生产消费者模型
		可能产生多线程并发带来的安全隐患----抢夺资源
2.如何解决线程安全的问题
    synchronized	特征修饰符,同步的
    线程锁,锁定的是对象
    1.放置在方法的结构上
    public synchronized void test(){
    	好多代码;
    	好多代码;
    	好多代码;
    }
    对象.test();  对象被某一个访问他的线程锁定
    2.放置在方法(构造,块)的内部(看起来是包含着一堆代码)
    public void test(){
    	好多代码;
    	synchronized(对象){
    		执行代码;
    	}
    	好多代码;
    }
3.线程相关的一些方法
    sleep();	run();	start();	setPriority();
    wait();	notify();	notifyAll();
    注意wait方法,notify方法,使用
    对象.wait();
    对象调用wait方法,不是对象等待
    访问此对象的线程进入等待状态
4.笔试中经常考察的关于线程的问题
    程序,进程,线程概念
    如何实现线程
    线程的几种状态
    如何切换几种状态
    wait();	sleep();方法的区别

12.反射

(1)概述

反射  reflect
	面向对象的编程思想
	类		从很多对象中抽取出来的公有的特征行为,抽象描述,用来描述一组对象
	对象		现实生活中,先存在了好多对象,很多相同特征,相同行为

	类是用来描述一组对象
	反射机制认为是用来描述一组类
	可以与之前学习File对比着学习

	Class		用来描述类本身
	Package		用来描述类所属的包
	Field		用来描述类中的属性
	Method		用来描述类中的方法
	Constructor	用来描述类中的构造方法
	Annotation	用来描述类中的注解@Override,注解可以放在(类上面,属性上面,方法上面,构造方法上,参数前)

(2)获取Class

如下三种方式
			Class clazz = Class.forName("包名.类名");
			Class clazz = 类名.class;
			Class clazz = 对象引用.getClass();	//Object类中的方法

(3)Class中的常用方法

1.int modifiers = getModifiers();		获取类的修饰符
			//每一个修饰符,用一个整数来进行表示 0 2 4 8 16 32 64 128 256 512
            //0默认不写,1public,2private,4protected,8static,16final,
           //32synchronized,64volatile,128transient,256native,512interface,1024abstract
2.String name = getName();		获取类全名,包名加类名
3.String simpleName = getSimpleName();	获取类名,简单名
4.Package p = getPackage();		获取包对象
	String packageName = p.getName();	获取包名
5.Class sclazz = getSuperClass();	获取超类(父类)
6.Class[] classes = getInterfaces();	获取类实现的所有的接口
---------------------------------------------------------------------------------------------------
7.Object obj = getConstructor().newInstance();		默认利用无参构造方法创建对象
		getConstructor(int.class).newInstance(6666);	利用带参数的构造方法创建对象
8.Field f = getField("属性名");		根据对象属性名获取对象的属性对象
	Field[] fields = getFields();		得到所有的属性对象
		   如上的两个方法只能获取公有的属性,但是包含继承过来的父类属性
9.getDeclaredField("属性");
	getDeclaredField();
		   如上的两个方法能获取公有和私有的属性,但是只能获取本类中的属性
10.Class[] = getClasses()		获取所有内部类
  • 操作类中的方法和构造方法

    Class类中的方法
    操作类中的方法
    	Method = getMethod("方法名"[,参数列表.class]);		获取一个方法(公有的,父类+自己类)
    	Method[] = getMethods();				获取全部的方法(公有的,父类+自己类)			
    	Method = getDeclaredMethod("方法名"[,参数列表.class]);	获取一个方法(公有的,私有的,自己类)
    	Method[] = getDeclaredMethods();			获取全部的方法(公有的,私有的,自己类)
    操作类中的构造方法
    	Constructor = getConstructor([参数列表.class]);		获取一个构造方法(公有的,父类+自己类)
    	Constructor[] = getConstructors();			获取全部的构造方法(公有的,父类+自己类)
    	Constructor = getDeclaredConstructor([参数列表.class]);	获取一个构造方法(公有的,私有的,自己类)
    	Constructor[] = getDeclaredConstructors();		获取全部的构造方法(公有的,私有的,自己类);
    

(4)Field类中常用的方法

1.int = getModifiers();	得到属性的的修饰符
2.Class = getType();		得到属性的类型
3.String = getType().getName();	得到属性的类型的名字
4.String = getName();		得到属性的名字
5.操作属性,向里面存值
	set(对象,值);
6.操作属性,从里面取值
	值 = get(对象);
7.field.setAccessible(true);	设置私有属性可修改

	对象 = new();	创建对象空间,当前对象空间里有自己的一套元素(属性,方法)
	对象.属性 = 值;

	属性 = 类.getField("属性名");

	对象.属性 = 值;
	属性.set(哪个对象,值);

	值 = 对象.属性
	值 = 属性.get(那个对象);

		String str = new String("abc");
		Class clazz = String.class;	得到String类
		Field field = clazz.getDeclaredField("value");得到String类中私有属性value
		field.setAccessible(true);	设置私有属性可修改
		byte[] temp = (byte[])field.get(str);得到私有属性对象,并转型
		temp[0] = (byte)'A';		重新赋值
		temp[1] = (byte)'B';
		temp[2] = (byte)'C';
		System.out.println(str);	打印新的值

(5)Method类中常用方法

int = getModifiers();		获取方法的修饰符(权限+特征)
Class = getReturnType();		获取返回值数据类型
String = getName();			获取方法的名字
Class[] = getParameterTypes();	获取方法参数列表的类型
Class[] = getExceptionTypes();		获取方法抛出异常的类型
如何操作方法,调用方法,让他执行一次
	Object = (造型)invoke(对象);		利用对象执行无参的方法,返回方法的返回值
	Object = (造型)invoke(对象,参数列表);	利用对象执行有参的方法,返回方法的返回值
若方法是私有的方法,不允许操作
	setAccessable(true);			设置方法使用权,准入

(6)Constructor类中的常用方法

int = getModifiers();		获取方法的修饰符(权限)
String = getName();			获取方法的名字
Class[] = getParameterTypes();	获取方法的参数列表的类型
Class[] = getExceptions();		获取方法抛出异常的类型
如何操作构造方法,执行一次,创建对象
	Object = newInstance([参数列表]);	创建对象
若构造方法是私有的,不允许操作
	setAccessable(true);			设置方法使用权,准入

13.注解

(1)概述

1.注解的写法
	@xxx[(一些信息)]
2.注解放置在哪里
	类的上面、属性上面、方法上面、构造方法上面、参数前面
3.注解的作用
	1.用来充当注释的作用(仅仅是一个文字的说明)	@Deprecated
	2.用来做代码的检测(验证)			@Override
	3.可以携带一些信息(内容)			文件.properties  .xml  注解
4.Java中有一些人家写好的注解供我们使用
	@Deprecated		用来说明方法是废弃的
	@Override		用来做代码检测,检测此方法是否是一个重写
	@SuppressWarnings(信息)	String[]	{"",""}	如果数组内的元素只有一个元素,可以省略大括号
		unused		变量定义后未被使用
		serial		类实现了序列化接口,不添加序列化UID号
		rawtypes		集合没有定义泛型
		deprecation	方法已经废弃过时
		unchecked	出现了泛型的问题,可以不检测
		all		 包含了以上所有(不推荐)
5.注解中可以携带信息,可以不携带
	信息不能随便写,信息的类型只能是如下的类型
	1.基本数据类型
	2.String类型
	3.枚举类型enum
	4.注解类型@
	5.数组类型[]  数组的内部需要是如上的四种类型

(2)定义注解

如何自己去描述一个注解类型
	1.通过@interface关键字定义一个新的注解类型
	2.发现写法与接口非常相似(可以利用接口的特点来记忆注解)
		公有的静态的常量属性  public static final的属性,比较少见
		可以描述公有的抽象的方法	方法要求返回值必须有,返回值是如上的那些
	3.我们自己定义的注解如果想要拿来使用
		光定义还不够,还需要做很多细致的说明(需要利用Java提供好的注解来说明)
		元注解(也是注解,不是拿来使用的,是用来说明注解的)
			@Target		用来描述当前的这个注解可以放置在哪里写的
			@Retention	描述当前的这个注解存在什么作用域中的
				源代码文件---->编译---->字节码文件---->加载---->内存执行
				SOURCE		        CLASS		RUNTIME
			@Inherited	描述当前这个注解是否能被子类对象继承
			@Document	描述当前这个注解是否能被文档所记录
	4.自己使用自己描述的注解
		问题1.在注解里面描述了一个方法,方法没有参数,方法是有返回值String[]
			使用注解的时候,让我们传递参数
			理解为,注解的方法做事,将我们传递给他的参数,搬运走了,给了别人
		问题2.使用别人写好的注解不用写方法名,我们自定义的方法需要写名字
			如果我们自己定义的注解,只有一个方法,方法的名字叫value
			在使用的时候就可以省略方法名
			如果传递的信息是一个数组,数组内只有一个元素,可以省略{}
			如果方法是两个以上,注解使用时,每一个方法必须写名字

(3)反射解析注解

	1.获取Class
	2.获取类中的成员,类,属性,方法,构造方法
	3.Annotation a = 成员.getAnnotation(注解类型.class);
	4.注解对象,执行方法获取返回结果
		Class clazz = Person.class;
		Field field = clazz.getDeclaredField("name");
		Annotation a = field.getAnnotation(MyAnnotation.class);
		Class aclazz = a.getClass();
		Method amethod = aclazz.getMethod("value");
		String[] values = amethod.invoke(a);
		System.out.println(values[0]);
		for(String value : values) {
			System.out.println(value);
		}

(4)解析Properties文件

Properties类的使用
		java.util包
		继承HashTable
		使用方式像是map集合	value = getProperty(key)方法
		读取的信息是文件
		文件的后缀名.properties
		文件里面key = value
2.使用方法
		Properties pro = new Properties();
		pro.load(new FileReader(new File("pro.properties")));
		System.out.println(pro.get("key1"));
		@SuppressWarnings("unchecked")
		Enumeration<String> en = (Enumeration<String>) properties.perpertyNames();
		while(en.haMoreElements()) {
			String key = en.nextElement();
			String value = (String) properties.get(key);
			System.out.println(key+"--"+value);
		}

(5)小结

1.注解写法
		@XXXX(信息)
2.注解放置在哪里写
	类 方法  属性  构造  变量  参数(前面)
3.Java中定义好的注解
	@Deprecated		废弃的
	@Override		检测方法是否重写
	@SuppressWarning		去掉程序中的警告(尽量不要用,尽量通过编写代码去掉警告)
		unused   serial   rawtypes   deprecation   unchecked   all
4.如何自己去定义注解
	描述一个自己的类	@interface
	类的上面通过元注解来描述
		@Target		作用域
		@Retention	生命周期
		@Inherited	是否可被继承
		@Document	描述当前这个注解是否能被文档所记录
	想要携带一些信息   自定义注解类型,添加方法
		方法要求必须有返回值,返回值类型,基本,String,枚举,注解,数组
		方法的作用将我们传递的信息,搬走了,交给别人
5.注解的作用
	充当注释	仅仅是一个文字说明
	代码检测	@Override
	*携带信息
6.如何访问到注解对象@XXX
	如何获取里面的信息(需要反射机制)
7.注解在开发中应用的场景

二、MySql

1、DDL数据定义语言

Data Definition Language
用来定义数据库中的对象
create创建,drop删除,alter修改

(1)创建数据库

Java英文字母区分大小写;
MySQL英文字母,不区分大小写(关键字,表格名字,列名字)

create database 数据库名;
create database 数据库名 [default character set = 'utf8'];
  • 查询数据库信息

    --可以通过如下语句来进行查询
    --select 列 from 表 where 数据库 = 名字;
    --查询数据库默认字符集:
    select schema_name,default_character_set_name from information_schema.schemata	where schema_name ='自己的数据库名';
    

(2)创建表

  • 数据库中的数据类型

    存储数据的方式来分类
    	分为三类
    		数值型
    			整数:tinyint、smallint、mediumint、*int 4、bigint
    			小数:*float 4、*double 8、decimal、numeric
    		字符串
    			char(4) 字符串(固定长度,长度不够补),a 4字节,ab 4字节
    			varchar(4) 可变字符串,a 1字节,ab 2字节
    			text正常字符大文本
    				数据库里面所有的字符串类型,使用'a','abc'
    			binary二进制
    			varbinary可变二进制
    			blob二进制大文本
    		日期/时间
    			*date日期,time时间,*datetime日期&时间,timestamp时间戳
    
  • 创建一个表格

create table 表格名字(
	'列名' 类型(长度),
    '列名' 类型(长度),
    '列名' 类型(长度),
    '列名' 类型(长度)
) [character set utf8] [collate utf8_general_ci]
--设置字符集和排序规则
--排序规则:utf8_general_ci;默认 性能比较高,可能不太精确,俄罗斯
--排序规则:utf8_unicode_ci;性能比较低,扩展型好
  • 查看表的信息

    show table status from 数据库名 like '表名';
    

(3)修改表

  • 修改表名字

    alter table 原表名 rename [to] 新表名;
    
  • 修改原有的列

    alter table 原表名 change 原列名 新列名 新类型 新长度;
    
  • 新增一个列

    alter table 原表名 add [column] 新列名 新类型 新长度;
    
  • 删除一个原有的列

    alter table 原表名 drop 原列名;
    

(4)删除

drop table 表格名字;
drop database 数据库名字;

2、DML数据操作语言

*DML数据操作语言
	操作的是表格中的数据信息
	写入信息(数据库中的信息发生了真实的改变)
		新增insert 删除delete 修改update
	读取信息(数据库中的信息没有发生改变,读取信息展示出来) DQL
		查询select

(1)新增记录

insert into 表名(列名,列名,列名) values(,,);

(2)查询记录

select 列名,列名,列名 from 表名;
select * from 表名;
select * from 表名 [where ...];

(3)删除记录

delete from 表名 [where ...]

(4)修改记录

update 表名 set='值'[,='值'] [where ...];

3、关键字

(1)where

条件筛选

1.除了insert以外的其他三个语句都可以做筛选
	where是一个关键字 拼接在除了insert语句以外的其他语句基本结构之后
	delete from 表 where.....;
	update 表 set 列=值 where...;
	select 列 from 表 where...;
2.筛选用来筛出符合条件的记录行数
	并不是控制显示的列
3.按照某一个列或者是某一些条件进行筛选
	列,满足一定条件
  • where后面可以连接什么

    1.比较运算符 > >= < <= != =
    2.算术运算符 + - * /
    3.逻辑运算符 and or not
    	如果and和or同时出现,and优先级别更高
    4.[not] between...and...
    	包含前后两端的值
    5.[not] in (v1,v2,v3);
    	如下的条件满足一个就可以
    6.[not] like 模糊查询
    	查询像什么一样,模糊查询
    	% 用来代替0-n个字符
    	_ 用来代替1个字符(有且只有一个)
    float(m,n);  总共可以存储m位数字,小数点之后有n位
    	m取值范围1-65	n取值范围是0-30
    	默认:m=10	n=0
    
  • 数据库底层做的事情

    select * from student where chinese>=95 and english>=95;
    
    1.解析SQL
    2.从表格中全部数据都读取出来,放在数据库缓存,集合List
    3.将list集合做一个循环遍历,每一次拿到一个元素(一行记录),条件
    	假设我们的表格有7条记录
    	如果只写了一个where条件
    	执行7次循环就可以比较出来啦
    	
    	如果有and连接不止一个条件
    	先按照第一个条件先筛选
    		7次循环,5条满足>95
    	再按照第二个条件在筛选
    		5次循环,2条满足
    4.如果以后在语句中使用了and
    	尽量将条件苛刻的写在前面,提高执行效率
    

(2)order by

连接在查询语句之后

order by 列
升序排列 asc 默认就是升序,可以省略不写
降序排列 desc
order by 列名 asc,列名 desc;

(3)函数

函数----数据库定义好的(Java API中的方法)
	1.可以理解为函数就是以前我们Java中定义的方法
	2.函数需要调用才能执行,没有对象,函数直接放置在语句中相当于调用
	3.函数可以放置在什么位置上
		查询中用来显示的部分----->select 函数(列) from 表格;
		条件筛选的后面	------>select 列 from 表格 where sal > 函数(值);
  • 比较函数

    isnull(值);	是空值返回1,不是空值返回0
    
  • 数学函数

    abs绝对值  
    floor向下取整  
    mod(5,2)取余数  
    pow求次方  
    round();四舍五入
    
  • 日期和时间

    now();	
    year(date);	
    month();  
    day();  
    week();
    
  • 控制流程函数

    if(条件,值1,值2);	如果条件满足,值1,否则为值2
    ifnull(值,v);	如果值为null,则值改为v
    
  • 字符串函数

    						String str = "abc";
    						str.length();
    length(str)				length();
    concat()				concat();
    substr()				substring();
    instr(str,'a')索引从1开始	str.indexOf("a");
    replace(str,'a','A')		replace();
    upper()					toUpperCase();
    lower()					toLowerCase();
    ltrim()  rtrim()			trim();
    lpad()  rpad()  
    lpad(str,10,'*');长度不够就在左边补*
    rpad(str,length(str)+4,'*');在str的右边加4个*
    reverse()
    
  • 分组函数+分组条件

    分组函数
    count()
    max()
    min()
    avg()
    sum()
    分组条件
    group by 列
    

(4)distinct

去重复 distinct
		distinct 列  如果有一样的列信息,将一样的信息合并
			行数会减少,查询的每一个列,行数个数需要一致
		distinct 列,列,如果有两个以上的列,将两个或多个列的组合当做整体
			如果整体有一样的信息,才会去重复,否则就全部显示

(5)group by

分组函数+分组条件
分组函数
	count()
	max()
	min()
	avg()
	sum()
分组条件
	group by 列
如果先进行条件筛选,后分组	where group by
如果先进行分组,后进行筛选	group by having
如果分析之后还需要进行排序	order by最后处理

(6)in,any,some,all

in(),not in():
	满足查询自己中的某一个即可	默认=比较
	in后面的子集内,可以是常量固定值
	也可以是通过另一条sql语句查询出来的结果
如下的三个使用起来与in类似,查询是否满足后面子集中的条件
关键字的后面不允许写固定值,只允许写sql语句(只能通过嵌套来获取子集)
	any:满足查询子集中的某一个即可
	>any <any =any(结果与in一致) !=any(有一个不满足即可)
	some		与any完全一致
	all		满足查询子集中
		>all <all =all !=all(结果和not in)

(7)union

结合,合并

有两张表格,学生信息,老师信息
我们的学校想要召开运动会
学校想要给所有的老师和同学都准备统一的服装
这时候就需要统计全学校的所有人的信息
	
select tid,tname,tsex from teacher union select sid,sname,ssex from student;
1.要求前后两个查询子集的列数是一致
2.类型没有要求
3.拼接后显示的列名是前一个子集默认的列名
4.注意union和union all的区别
	union合并后做去重复的处理,性能比较慢
		如果产生重复元素,记录的是第一次出现的那一行
	union all将两个查询的字节直接做合并
		不作任何处理,性能比较快
		建议以后尽量使用union all来进行合并处理

(8)limit

分页查询

limit a,b;
--注意:与函数使用区分 instr(ename,'A');	1第一个出现 0没有
--a为想要显示的起始行索引(第一行索引为0),包括此行,(偏移量)
--b为想要显示的行数

4、约束

(1)列的约束

a.主键约束

  • 设置主键约束

    --每一个表格内,只能有一个列被设置为主键约束
    --主键约束通常是用来标记表格中数据的唯一存在
    --主键约束要求当前的列,不能为null值
    --要求值是唯一存在的,不能重复
    --alter table 表名 add constraint 约束名字 约束类型 (列);
    alter table myclass add constraint pk_myclass primary key (classid);
    --也可以简写如下
    alter table 表名 add primary key (classid);
    
  • 查看约束

    --description 描述
    desc 表名;
    show keys from 表名;
    
  • 添加主键自增

    alter table myclass modify classid int(4) auto_increment;
    alter table myclass change classid classid int(4) auto_increment;
    
  • 取消主键自增

    alter table myclass modify classid int(4);
    
  • 设置自增起始值

    --默认为1
    alter table myclass auto_increment = 10;
    
  • 删除主键约束

    alter table myclass drop primary key;
    --删除后,不重复特性没了,但还需要删除非空约束
    alter table myclass modify classid int(4) null;
    alter table myclass change classid classid int(4) null;
    

b.唯一约束

  • 添加唯一约束

    --可以为表格中的某一个列添加唯一约束,约束与主键类似
    --唯一约束表示的列的值,不能重复,可以为null
    --唯一约束在表格中可以存在多个列
    --alter table 表名 add constraint 约束名 约束类型 (列);
    alter table myclass add constraint uk_myclass_cname unique [key] (loc);
    --简写如下
    alter table myclass add unique [key](loc);
    
  • 删除唯一约束

    alter table myclass drop index 约束名;
    

c.非空约束

  • 添加非空约束

    --在表格中的某一个列上添加非空约束
    --当前列的值不能为null
    --alter table 表名 modify 原列名 原列类型 not null;
    --alter table 表名 change 原列名 新列名 新列类型 not null;
    alter table myclass modify cname varchar(20) not null;
    alter table myclass change cname cname varchar(20) not null;
    
  • 删除非空约束

    --取消非空约束,即可以为null
    --alter table 表名 modify 原列名 原列类型 null;
    --alter table 表名 change 原列名 新列名 新列类型 null;
    alter table myclass modify cname varchar(20) null;
    alter table myclass change cname cname varchar(20) null;
    
  • 为非空约束添加默认值

    alter table myclass modify cname varchar(20) not null default 'xxx';
    alter table myclass change cname cname varchar(20) not null default 'xxx';
    

d.外键约束

  • 添加外键约束

    --表格中可以有多个列被设置为外键约束
    --当前列的值可以为空,可以重复
    --当前列的值不能随便的填写,值去另外一张表格内寻找
    --外键是当前列的值受到另外一张表格某一个列的影响
    --另外一张表格的列,是唯一约束(主键唯一)
    alter table 表名字 add constraint fk_当前表_关联表 foreign key() references 另一个表();
    		
    
  • 查看外键约束

    show keys from 表名;
    desc 表名;
    show create table 表名字;
    --PRI UNI MUL---->multiple(多样,并联)
    
  • 删除外键约束

    alter table 表名字 drop foreign key 约束名字;
    show create table 表名字;	查看创建表时的语句
    	--注意:通过上述语句其实已经将外键约束删掉了
    	--自动在当前表格内添加了一个新的key
    	--需要再次手动将这个生成的key删掉,外键约束才真的删除干净
    alter table 表名字 drop key 约束名字;
    
    alter table student add foreign key() references 另一个表();
    	--注意:如果是简写的效果添加外键,外键的名字不是默认列名,
    alter table student drop foreign key 外键名;
    alter table student drop key 约束名;
    

e.检查约束

--检查约束SQL(Check)(MySQL中不起作用)
--列在存值的时候做一个细致的检查,范围是否合理
alter table 表名字 add constraint 约束名 check(检查约束条件);

f.小结

--表格中列的约束
	--1.主键约束
	--2.外键约束
	--3.唯一约束
	--4.非空约束
	--5.检查约束

--添加
alter tableadd constraint 约束名字 约束类型 列 [references 表 列];
alter tablemodify 列 类型 长度 not null;
--删除
alter tabledrop 类型(primary key | index key | foreign key | key);
alter tablemodify 列 类型 长度 null;

5、DQL数据库操作语言

(1)表格之间的关系

0.列的约束
	主键	*外键	唯一	非空	检查
1.表格之间的关系
	一对多	一端保证一个主键	多端保证有一个晚间关联关系
	多对多	两个一对多合并在一起,中间表,中间表记录着两边的对应关系
	一对一	在一对多的基础上,将多端设置成唯一约束(多端外键-->唯一)(多端主键-->外键)

(2)联合查询

a.等值连接

--等值连接
	--广义笛卡尔积--->进行条件筛选--->等值连接
	--广义笛卡尔积将两张表格或多张表格,进行无条件的拼接
	--在拼接后的一张大表格的基础上进行了where的筛选
	--任何表格都能进行拼接
select * from A,B where 条件;
select * from A a,B b where 条件;	//给表格取别名

b.外连接

--外连接
select * from A left/right [outer] join B on 条件;
--1.两张表格A和B,取决于谁的数据在左边显示
	--A表格先出现,A左边显示
	--B表格后出现,B右边显示
--2.left和right来控制以哪一个表格的数据作为基准
	--作为基准的表格数据必须全部显示出来
	--非基准的表格按照on条件与之拼接
	--若找到条件拼接,则正常显示,若找不到满足条件的则 null
--3.外连接查询结果可能比等值连接的最终结果多一部分数据
--4.因为外连接是分为左外,右外,可以省略outer关键字
--5.外连接不写on关键字是不能进行拼接

c.内连接

--内连接(自连接)(建议用内连接替代等值连接)
select * from A inner join B on 条件;
--在当前表格中再次查询当前表格的信息
select e1.empno,e1.ename,e1.mgr,e2.empno,e2.ename from emp e1,emp e2 where e1.mar = e2.empno;
select e1.empno,e1.ename,e1.mgr,e2.empno,e2.ename from emp e1 inner emp e2 on e1.mgr = e2.empno;
--1.查询出的结果与等值连接的结果一致
--2.内连接不分左右,不能省略inner关键字
--3.A和B是可以不同的两张表格
--4.A和B也可以是相同的一张表格
	--必须给表格起别名
	--可能还需要当前表格有一定的设计

d.行列互换

	wname	winventory	wmonth
	仓库名称	仓库库存		月份
	A	100		一月份
	B	1000		一月份
	C	10		一月份
	A	200		二月份
	B	2000		二月份
	C	20		二月份
	A	300		三月份
	B	3000		三月份
	C	30		三月份
	
	要求变成如下效果
	仓库名称	一月份	二月份	三月份
	A		100		200		300			A组三个值,每一个月份对应一个库存
	B		1000	2000	3000		B组三个值,每一个月份对应一个库存
	C		10		20		30			C组三个值,每一个月份对应一个库存
--一旦使用group by分组条件
--可以select 显示的列,只有两种(分组条件,分组函数)
select 
	wname,
    max(if(wmonth='一月份',winventory,0)) as '一月份',
    max(if(wmonth='二月份',winventory,0)) as '二月份',
    max(if(wmonth='三月份',winventory,0)) as '三月份'
from warehouse
group by wname;

6、DCL数据库控制语言

(1)查询所有用户信息

--管理员可以操作其他普通用户的权限
--通过root账号查看mysql数据库中的user表格
--记录着所有用户信息
select user,host,authentication_string from user;

(2)创建一个新的用户

--database table user
--create user '用户名'@'IP' identified by '密码';
create user 'lwy'@'localhost' identified by '123456';
--用户被创建成功啦(只有一个默认的权限 Usage 只允许登录,不允许做其他事情)
--通过这个语句查看权限:
show grants for '用户名'@'IP';

(3)给新的用户赋予权限

--grant 权限 on 数据库名.表 to '用户名'@'IP';
grant all on *.* to 'lwy'@'localhost';
--赋予权限之后最好刷新一下
flush privileges;	

(4)注销root,用新用户登录

exit;
mysql -u lwy -p
123456

(5)回收用户权限

--Usage
--revoke 权限 on 数据库名.表名 from '用户名'@'IP';
revoke all on *.* from 'lwy'@'localhost';

(6)修改用户的密码

--update user set authentication_string = password('123') where user = 'lwy';
--alter user '用户名'@'IP' identified by '新密码';
alter user 'lwy'@'localhost' identified by '123';
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '123456';

(7)删除用户

--drop user '用户名'@'IP';
drop user 'lwy'@'localhost';

(8)常用权限

	数据库/数据表/数据列权限:
		Create			建立新的数据库或数据表
		Alter			修改已存在的数据表(例如增加/删除列)
		Drop			删除数据表或数据库
		Insert			增加表的记录
		Delete			删除表的记录
		Update			修改表中已存在的记录
		Select			显示/搜索表的记录
		----------------------------------------------------------------------------
		References		允许创建外键
		Index			建立或删除索引
		Create View		允许创建视图
		Create Routine		允许创建存储过程和包
		Execute			允许执行存储过程和包
		Trigger			允许操作触发器
		Create User		允许更改、创建、删除、重命名用户和收回所有权限
	全局管理MySql用户权限:
		Grant Option		允许向其他用户授予或移除权限
		Show View		允许执行SHOW CREATE VIEW语句
		Show Databases		允许账户执行SHOW DATABASES语句来查看数据库
		Lock Table		允许执行LOCK TABLE语句来锁定表
		File			在MySQL服务器上读写文件
		Process			显示或杀死属于其他用户的服务线程
		Reload			重载访问控制表,刷新日志
		ShutDown		关闭MySQL服务
	特别的权限:
		All			允许做任何事(和root一样)
		Usage			只允许登录,其他什么也不允许做

7、TPL事务处理语言

(1)范式

1NF
	数据的原子性
	每一个表格的每一个列都是不可分割的(行列交叉点的单元格内只存储一个数据)
	每一个表格必须有主键约束(快速查询某一行记录)
2NF
	在满足第一范式的前提下
	不允许出现部分依赖型
	(非主键列不能受到主键列或主键的一部分影响)
3NF
	在满足前两个范式的前提下
	不允许出现传递依赖
	(非主键列不能受到非主键列或非主键的一部分影响)

(2)事务

a.概念

SQL语句使我们给数据库发送了指令,让数据库帮我们做事情
	1.事务可以理解为是让数据库做的事情
	2.有些时候事情之内不止一条sql,存在多个组成单元
		比如:银行系统 转账 张三 100 ---->李四
			update atm set abalance = 原来-100 where aname = 张三;
			update atm set abalance = 原来+100 where anem = 李四;
			登录 查询余额 存款 取款 转账 开户 销户
			.txt文件 I/O
			缓存Map commit();	MVC分层思想 IO 缓存
	3.一件事情中的所有操作应该是统一的
		要么都成功,要么都失败
	4.事务的本质
		可以理解为
		多线程并发操作同一张表格可能带来的安全问题

b.特征

事务的四大特性(ACID)
A:Atomicity---->原子性
		一个事务中的所有操作是一个整体,不可再分
		事务中的所有操作要么都成功,要么都失败
C:Consistency---->一致性
		一个用户操作了数据,提交以后
		另一个用户看到的数据与之前的用户看到的效果是一致的
*I:Isolation---->隔离性----->(事务隔离级别)
		指的是多个用户并发访问数据库时
		一个用户操作数据库,另一个用户不能有所干扰
		多个用户之间的数据事务操作需要互相隔离
D:Durability---->持久性
		指的是一个用户操作数据的事务一旦被提交(缓存--->文件)
		他对数据库底层真实的改变是永久性的,不可返回

c.实现

	mysql数据库事务管理默认的效果可以更改
		autocommit变量 = on;
		show variables like '%commit%';
		show variables like 'autocommit';

		set autocommit = off;	设置自动提交关闭
	
	1.开启一个事务
		每一次执行的一条sql语句之前
		mysql数据库都会默认的开启
		begin;	start transaction;
	2.执行操作
		insert,update,delete
		select
		可能不止一条语句
	3.事务的处理
		提交/回滚/保存还原点
		commit;
		rollback;
		mysql数据库会默认的执行提交事务

d.隔离级别

	事务的隔离性可能会产生多线程并发操作同一个数据库表格的问题
		1.脏读
			一个人读到了另外一个人还没有提交的数据
			A B在操作同一张表格
			A修改了数据,还没有提交,B读取到了
			A不提交了,回滚回来,B刚刚读取到的那些数据就是无用的---脏数据
		2.不可重复读
			A B在操作同一个表格
			A先读取了一些数据,读完之后B此时将数据做了修改/删除
			A再按照之前的条件重新读一遍,与第一次读取的不一致
		3.幻读(虚读)
			A B在操作同一个表格
			A先读取一些数据,读完之后B此时将数据做了新增
			A再按照之前的条件重新读一遍,与第一次读取的不一致
	
	会带来数据的安全隐患
	需要考虑事务的隔离级别
		Serializable		最高 可以避免所有出现的问题,性能很慢
		Repeatable Read		可重复读		(可以避免脏读和不可重复读)
		Read Committed		读已提交		(避免脏读)
		Read UnCommitted	读取未提交	(所有的效果均无法保证)
	
	MySQL数据库提供的默认隔离级别	Repeatable Read
	Oracle数据库提供默认隔离级别		Read Committed

	可以修改数据库中的隔离级别
		set session transaction isolation level xxx;
	如果不放心可以查看
		select @@tx_isolation;

8、JDBC

(1)步骤

通过java利用JDBC的桥梁操作MySQL数据库
JDBC六部曲
	1.导包(将找到的这个jar文件包导入到Java工程里)
		在我们的工程里创建一个文件夹lib
		将mysql-connector-java.jar复制到当前工程lib文件夹内
		做一个设置
			File-->Project Structure--->Libraries
			点击中间的+,选择Java,选择jar文件路径
	2.加载驱动类  Driver,Class.forName("com.mysql.jdbc.Driver")
	3.获取连接----可以理解为以前的Socket,DriverManager
	4.创建状态参数(流)--可以理解为是以前socket.getInputStream socket.getOutputStream
	5.执行数据库操作
		写DML--->insert,delete,update	(对数据库进行更新)
		读DQL---->select			(数据库没有发生变化,我需要处理结果)
	6.关闭

(2)实现

//        1.导包(将找到的这个jar文件包导入到Java工程里)
//        2.加载驱动类  Driver
String className = "com.mysql.jdbc.Driver";
try {
    Class.forName(className);       //加载类,雷钟德静态元素就执行啦
    //        3.获取连接----可以理解为以前的Socket,DriverManager
    String url = "jdbc:mysql://localhost:3306/test";    //jdbc:mysql://ip:port/database名
    String user = "root";
    String password = "root";
    Connection connection = DriverManager.getConnection(url,user,password);
    //        4.创建状态参数(流)--可以理解为是以前socket.getInputStream socket.getOutputStream
    Statement statement = connection.createStatement();
    //        5.执行数据库操作
    //        写DML--->insert,delete,update	(对数据库进行更新)
    //        读DQL---->select			(数据库没有发生变化,我需要处理结果)
    //            String sql = "insert into emp(empno,ename) values(9999,'zzt')";
    //            String sql = "update emp set ename = 'lwy' where empno = 9999";
    String sql = "delete from emp where empno = 9999";
    statement.executeUpdate(sql);
    System.out.println("执行完毕!!");
    //        6.关闭
    statement.close();
    connection.close();
} catch(Exception e) {
    //异常处理
}

(3)查询操作

ResultSet rs = executeQuery(String sql);	Set<Map<String,Object>>
if(rs.next()) {
	int empno = rs.getInt("empno");
	String ename = rs.getString(2);
}
//rs.getString();	可以接受任何一个列的值,自动转化
//rs.getInt();	不能接受其他类型,比如String

(4)其他问题

a.版本问题

1.导包	8.x  5.x  版本不一致,有问题
2.加载驱动类的时候
	如果5.x版本	com.mysql.jdbc.Driver
	如果8.x版本	com.mysql.cj.jdbc.Driver
3.获取链接的时候
	8.x  5.x版本不一致,有问题
	如果5.x版本	url---->jdbc:mysql://ip:port/database名
			url---->jdbc:mysql://ip:port/database名?useSSL=true
	如果8.x版本	url---->jdbc:mysql://ip:port/database名?serverTimezone=CST
			String url = "jdbc:mysql://localhost:3306/test?serverTimezone=CST";

b.加载驱动问题

//1.通过反射机制
    Class.forName("类全名");---->类中的静态成员
    //static特征修饰符 属性 方法 块 内部类
//2.通过DriverManager静态方法注册驱动
    DriverManager.registerDriver(new Driver());
//3.通过直接创建驱动对象
    new Driver();
//4.通过System类中设置属性值来加载
    System.setProperty("jdbc.driver","com.mysql.cj.jdbc.Driver");

c.操作事务

//1.JDBC默认的开启事务,默认的自动提交事务
//2.可以自己设计手动提交事务
    conn.setAutoCommit(false);	false表示手动提交 true默认,表示自动提交
//3.可以设置事务的隔离级别
    conn.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);
//4.事务最终的处理操作
    conn.commit();
	conn.rollback();
//5.设置还原点
	Savepoint s = conn.setSavepoint("x");
	conn.rollback(s);

d.SQL注入

跟字符串拼接有关
1.SQL注入
	所谓的SQL注入
	意思就是通过SQL命令,拼接其他的字符串
	让其他的那些字符串来改变原有的SQL语句的执行
	最终达到欺骗服务器的效果
2.问题产生的原因
	1.判断不严谨导致的
	2.SQL语句问题,允许拼接字符串,认为用户很不安全
	3.可以利用PreparedStatement

	Statement	和	PreparedStatement
	普通的状态参数		预处理的状态参数
	创建时不需要SQL	创建时就需要预先加载SQL语句
	此时没有执行		此时没有执行,但底层预先处理SQL需要查询的结果,性能高
					可以利用动态化进行参数的处理,利用?代替,数据类型及值
					好处
						1.增强SQL可读性
						2.可以参数动态化
						3.防止SQL注入
						4.提高执行性能
PreparedStatement
		使用方式与之前的Statement类似
		通过连接获取	PreparedStatement pstat = conn.prepareStatement(sql);
		在创建对象时需要预先接在SQL,需要一个String参数
		SQL语句为了防止注入的问题,可以使用动态化参数处理,可以利用?代替 值和类型
		SQL语句的可读性就增强	并且提高了执行效率
		注意:sql语句上面的问号需要在执行操作之前赋值
		pstat.setXXX(parameterIndex.value);

e.模糊查询

模糊查询	like %_	
	方式一
		Sql语句正常写	select * from emp where ename like ?
		pstat.setString(1,"%"+letter+"%");
	方式二
		Sql语句稍微改变一下	select * from emp where ename like "%"?"%";
		sql语句对于Java程序来说就是一个字符串
		String sql = "select * from emp where ename like \"%\"?\"%\"";
		pstat.setString(1,letter);
		sql语句本身的双引号和String类型的双引号冲突
		可以利用转义字符来帮忙
分页查询	limit 起始行索引,每页几个

三、协议、网络

1.计算机

冯诺依曼式计算机–冯诺依曼(计算机之父)

  • 运算器:CPU,GPU(显卡)
  • 存储器:
    • 内存:断电数据清空,读写速度快
    • 硬盘:辅存,数据可以持久化,读写速度相对较慢
  • 控制器:主板上的一些器件
  • 输入设备:键盘,鼠标,麦克风,网口
  • 输出设备:显示器,耳机,网口

2.IP地址

(1)格式

IP地址分为四个段:xxx.xxx.xxx.xxx

每个段0-255,每个段都是由8个0或1组成的

(2)分类

一个IP地址分为两个部分:网络ID,主机ID。

A类:0.0.0.0—127.255.255.255
B类:128.0.0.0—191.255.255.255
C类:192.0.0.0—223.255.255.255
D类:多播地址
E类:

3.域名和DNS解析

www.baidu.com 域名

(1)解析

用域名和IP形成对应关系

首先,计算机是不知道域名对应的IP的。
问路由器,如果路由器认识这个域名,就返回一个IP,然后计算机访问这个IP;
如果路由器不认识,他就问上一层路由器;
如果问到了城市这个级别的路由器的时候,DNS服务器。
如果DNS服务器不认识这个域名,继续向上级DNS服务器查找。

互联网建立的时候,13台总的DNS服务器。

(2)URL解析

当向浏览器的地址栏中输⼊⼀个url按回⻋之后,⽹络中都会发⽣什么?例如:123.xyz

1.看浏览器的缓存。
	本机host找到文件:
	C:windows/system32/drivers/etc/host
   	寻找对应IP地址:
	127.0.0.1 localhost 
	0.0.0.0 
2.如果找不到,则从家⾥路由器里找
3.如果找不到,再向上级路由、城市的LDNS服务器
4.继续向上级的DNS服务器找。
gDNS服务器。

4.网络模型

由上到下:应用层、运输层、网络层、数据链路层、物理层

(1)应用层

HTTP协议、DNS协议

a.HTTP协议

请求:Request

响应:Response

请求方式:Post,Get

(2)运输层

TCP协议、UDP协议

a.TCP/IP协议

对方的IP,自己的IP,对方的端口

(3)网络层

IP地址—IP协议

(4)数据链路层

mac地址

(5)物理层

5.请求方式

Get和Post方式

1.没有前提的情况下,GET和POST几乎没什么区别,只有名字不一致。
2.语法相同,语义不同,GET是为了获取数据,POST是为了发送数据。
3.GET的数据在URL是可⻅的。POST请求不显示在URL中。
4.GET对⻓度是有限制的,POST⻓度是⽆限的。
5.GET请求的数据可以收藏为书签,post请求到的数据不可收藏为书签。
6.GET请求后,按后退按钮、刷新按钮⽆影响,post数据会被重新提交。
7.GET编码类型:application/x-www-form-url,post的编码类型:有很多种。
 encodeapplication/x-www-form-urlencoded 
 multipart/form-data
8.GET历史参数会被保留在浏览器⾥,psot不会保存在浏览器中的。
9.GET只允许ASCII.post没有编码限制,允许发⼆进制的。
10.GET与POST相⽐,GET安全性较差,因为所发的数据是URL的⼀部分。

6.Cookie和Session

  • Cookie

    1.存放在浏览器里,可以长期存储
    2.不安全,登录成功后,每次请求带着存有ID的Cookie,就能免登录。
    
    
  • Session

    1.存储在后端,比较安全
    2.用户多的时候,资源消耗大
    
    

7.结构

  • B/S结构

    Browser/Server——Browser只负责内容的展示,Server负责提供内容。
    
  • C/S结构

    Client/Server——Client只负责内容的展示,Server负责提供内容。
    

8.跨域

答案:
1. 即使跨域了(协议,域名,端⼝号有不⼀样的),请求也可以发出。
2. 服务器端也是可以接收的。
3. 服务器端也是可以正常处理的。
4. 服务器端也是可以正常返回数据。
5. 浏览器也能接收到这些数据。
6. 接收到之后,发现当前⻚⾯的域和请求的域不同,所以判定为跨域。
7. 我们的代码在这等着结果呢,但是因为浏览器判定跨域了,不会把结果传递给我们的代码。
虽然跨域了,但是我们依然需要这个数据,怎么办?
解决跨域问题:
1. 后端(别⼈家的)配合我们进⾏跨域。
 pan.baidu.com ——> zhidao.baidu.com
 (1)JSONP(正常的情况,返回的数据都是JSON格式。JSONP是⼀种特殊的格式。)
 (2)后端设置Access-Control-Allow-Origin属性以⽀持跨域。(聊天机器⼈课讲,因为需
要nodejs)
2. 后端不配合我们进⾏跨域。
 (3)iframe(只能显示,不能控制)
 (4)通过后端代理(⾃⼰的后端)(后⾯聊天机器⼈讲,因为需要nodejs)

四、J2EE

1.请求与响应

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5dJYOYbW-1616603856878)(C:\Users\Administrator\Desktop\MarkDown\渡一后端\我的程序员笔记.assets\1616589996186.png)]

2.Servlet

(1)Tomcat

  • 简介
web容器-----服务器(硬件 软件)

Tomcat	Apache组织开源免费容器
Jetty	
Resin	Caucho公司一个产品
JBoss    WebLogic    WebSphere

Tomcat是Apache组织的一个开源免费的容器
	用来管理web项目     Servlet   JSP   HTML+CSS+JavaScript
了解一下历史及各种版本
	Tomcat6  JDK5     Servlet2.x  JSP2.x   EL2.x
	Tomcat7  JDK6     Servlet3.x  JSP2.x   EL2.x
	Tomcat8  JDK7     Servlet3.x  JSP2.x   EL3.x
	Tomcat9  JDK8     Servlet4.0  JSP2.3   EL3.0
  • 安装和配置
1.下载一个Tomcat容器
	www.apache.org
	下载之后直接解压缩就可以使用啦
2.了解一下Tomcat容器的所有文件夹结构
	bin文件夹		服务器启动相关
	*conf文件夹	配置文件	web.xml(请求相关)    server.xml(容器自身的信息 比如端口)
	lib文件夹		jar形式的包
	logs文件夹	日志信息
	temp文件夹	临时文件
	*webapps文件夹	用来存放部署在容器内的项目资源的
	*work文件夹	用来存放解析JSP后形成的java文件
3.将Tomcat和IDEA集成在一起   便于开发调试
	Run---> Edit  Configurations
	左上角+号   Tomcat Server  Local
	若没有 证明IDEA中缺少相关的插件(File--Settings--Plugins--Installed)
	搭建一个集成环境完毕
	如果运行Tomcat后  IDEA控制台出现乱码的问题 解决一下
		1.修改一下IDEA安装目录bin文件夹中的配置文件
			D:\JetBrains\IntelliJ IDEA 2018.3\bin
				idea.exe.vmoptions
				idea64.exe.vmoptions
			记事本形式打开   添加一行    -Dfile.encoding=UTF-8
			如果不好用   另外再添加一行   -Dconsole.encoding=UTF-8
2.在配置Tomcat容器的时候做参数处理
		server选项卡
		VM options处添加   -Dfile.encoding=UTF-8
		如果还不好用
		Startup/Connection选项卡
		勾选 Pass  environment  variables
		手动添加
			JAVA_OPTS		-Dfile.encoding=UTF-8
			JAVA_TOOL_OPTIONS	-Dfile.encoding=UTF-8
4.创建web项目
5.访问web项目

(2)请求和响应

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-633jhqem-1616603856882)(C:\Users\Administrator\Desktop\MarkDown\渡一后端\我的程序员笔记.assets\1616590339953.png)]

  • 实现步骤

    *如何访问一个Servlet类对象
    1.自己写一个类   通常叫XXXController          (Servlet  Action)
    2.继承一个父类HttpServlet
    3.重写一个方法service		   (doPost  doGet)
    4.方法里有两个参数HttpServletRequest    HttpServletResponse
    5.方法还有两个异常ServletException         IOException
    6.方法是没有返回值    void类型
    7.需要告知Tomcat有一个自己定义类需要帮忙管理  web文件夹  WEB-INF文件夹
    		需要配置web.xml	请求名字----真实类全名   映射关系
    		<servlet>
    			<servlet-name>用来配对的名字</servlet-name>
    			<servlet-class>真实类全名</servlet-class>
    		</servlet>
    		<servlet-mapping>
    			<servlet-name>用来配对的名字</servlet-name>
    			<url-pattern>/请求名字</url-pattern>
    		</servlet-mapping>
    8.浏览器发送请求
    

(3)项目布署

第一个问题,WEB项目如何导入外部的.jar包
	深入理解项目的部署以及运行的过程
	在IDEA编辑器中写完的这个项目  存在硬盘上 C:用户/账号名/IdeaProject(存储真实的代码文件)
	创建的是一个web项目   执行需要Tomcat容器帮我们管理
	需要将web项目部署在Tomcat内部   (webapps文件夹内)  D:tomcat9/webapps/
	部署的过程本质上是I/O文件读写  必然会耗费很多时间
	(IDEA)编辑器觉得耗费时间  默认的效果没有将真实的文件写入Tomcat 而是写了一个映射关系
	项目修改了部署的路径  现在我们的项目存在了Tomcat内部的webapps内
	我们原来的真实文件代码有两个主要的部分   src web
	发现部署之后的文件只含有web文件夹的内容 src丢掉了
	src不是真的丢掉了  src中存储的.java文件进行编译 .class才能用
	web文件夹下  WEB-INF文件夹  classes文件夹(后来生成)

	项目部署之后
	HTML文件资源 直接读取内容 内容做响应
	Servlet类 可以通过参考web.xml文件 获取类全名 通过反射 从而执行最终方法
	JSP(HTML+Java)   解析---形成一个为了JSP解析而生成的Java类   Tomcat内部 (work文件夹内)
	解析形成的新文件默认也是存在IDEA内的  为了减少耗费的时间

(4)请求乱码处理

浏览器发送请求的时候 如果携带了中文的信息

控制层接受的时候产生了文字乱码的问题
		请求发送时的方式
		get	在浏览器输入URL点击回车    <a href="">     <form method="get">
		post	<form method="post">
		两种不同请求的区别
		get
		URL看起来很复杂  请求后面会有?拼接一些参数
		只有协议头   没有协议体  只能讲参数拼接在URL上面
		post
		URL看起来很简单  只有请求资源名  没有?拼接
		有协议头和协议体两部分  协议头传递资源名  协议体传递参数信息

		发送请求--->请求Tomcat--->Tomcat有一个默认处理字符集
			Tomcat的配置文件中存储	ISO-8859-1老版本
						UTF-8新版本(Tomcat8之后)
  • get请求

    get请求的处理方式
    	发送请求的时候  请求名字 携带的参数信息都在协议头中
    	浏览器解析的时候  <meta charset="UTF-8">
    		如果Tomcat是老版本 get请求需要如下处理
    		String aname = request.getParameter("aname");
    		byte[] value = aname.getBytes("ISO-8859-1");
    		String newString = new String(value,"UTF-8");
    		如果Tomcat是新版本 可以不处理
    
  • post请求

    post请求的处理方式
    	发送请求的时候  请求名字 协议头中
    	请求的参数信息是在协议体中(协议体只能传递字节)
    	浏览器解析的时候  <meta charset="UTF-8">
    	控制层接受的时候已经组合成一个String字符串
    		发送请求的时候按照UTF-8形式   拆开字节
    		接受的时候request对象直接给我组合(按照平台默认的字符集)成一个String
    	在request组合之前告知 按照哪一种字符集进行组合
    	request.setCharacterEncoding("UTF-8");
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ktocNYzu-1616603856884)(C:\Users\Administrator\Desktop\MarkDown\渡一后端\我的程序员笔记.assets\1616591294050.png)]

(5)管理机制

1.Servlet类的对象是单例设计模式(对象是唯一的)
	  采用生命周期托管的方式实现的
	  Tomcat底层有一个类似ServletController的类管理着我们的对象
2.单例对象的产生
	立即加载(Tomcat启动的时候 底层集合内就存在对象啦)
	延迟加载(Tomcat启动的时候没有对象产生 什么时候发送请求需要用到这个对象 才会创建)
	Tomcat启动的时候   web.xml文件如果写错了   服务器启动会报错
	证明Tomcat在启动的时候  就读取了我的web.xml配置文件
	web.xml文件配置的目的  存储请求名字---真实资源类名的对应关系
	Servlet对象的创建和销毁---->Servlet对象的生命周期问题
	Tomcat为了更好的管理对象的产生和销毁
	提供了三个方法---->标识Servlet对象的生命周期
	init();  service();  destroy();    重新部署项目
3.默认效果是一个延迟加载的机制
web.xml文件(如果配置错误 启动Tomcat时候就产生问题)
		说明Tomcat启动的时候读取了我们的配置文件---->请求  真实类名
		启动时候可能会有很多的Servlet对象   如果是立即加载的话  内存压力很大
4.如果想要改变对象的加载  从延迟的方式变成立即的方式(Tomcat启动的时候就创建对象)
		在web.xml文件中添加一个配置就可以啦
		<servlet>
			<servlet-name><>
			<servlet-class><>
			<load-on-startup>整数0</load-on-startup>
		</servlet>
		<servlet-mapping>
		</servlet-mapping>
5.如果对象是立即加载的 可能当前对象对于整个项目的执行非常重要
		有些时候通常会携带一些重要的信息
		<servlet>
			<servlet-name><>
			<servlet-class><>
			<init-param>
				<param-name>key1</param-name>
				<param-value>value1</param-value>
			</init-param>
			<load-on-startup>整数0</load-on-startup>
		</servlet>
		<servlet-mapping>
		</servlet-mapping>

		可以在init方法内使用带ServletConfig的参数读取
		String value = config.getInitParameter("key");//某一个key对应的value
		Enumeration en = config.getInitParameterNames();//获取全部的key
		String name = config.getServletName();//获取当前Servlet类名
		ServletContext application = config.getServletContext();//获取全局上下文对象
public class ServletController{

    //请求名字和真实类名字对应关系
    private static HashMap<String,String> controllerNameMap = new HashMap<>();			
    //请求名字和类对象的关系
    private static HashMap<String,HttpServlet> objMap = new HashMap<>();

    public void findController(request,response){
        String content = request.getContent();//请求的名字
        HttpServlet obj = objMap.get(content);//通过请求名字去第二个集合找真实对象
        if(obj==null){
            String realControllerName = 读取配置文件获取类全名(缓存)
                Class clazz = Class.forName(realControllerName);//找类
            HttpServlet obj = clazz.newInstance();
            objMap.put(content,obj);//
        }
        Class ControllerClazz = obj.getClass();
        Method method = clazz.getMethod("service",request,response);
        method.invoke(obj,request,response);
    }
}
  • Servlet类的继承关系
Servlet类的继承关系
	我们自己的类继承HttpServlet(抽象类)
	HttpServlet又继承了一个类GenericServlet(抽象类)
	GenericServlet又实现了三个接口
		Servlet接口    ServletConfig接口   Serializable接口
	ServletConfig接口里面只有四个方法(抽象的)
		String = getInitParameter(String var1);
		Enumeration<String> = getInitParameterNames();
		String = getServletName();
		ServletContext = getServletContext();
	Servlet接口里面有五个方法(抽象的)
		void init(ServletConfig var1) throws ServletException;
		void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
		void destroy();
		ServletConfig getServletConfig();
		String getServletInfo();
	GenericServlet抽象类为什么实现接口?????-----体现出来的是缺省适配器设计模式
		9个接口中的方法都添加过来
		将其中的8个方法都进行了方法重写----添加具体实现{}
		多添加了一个init()无参数的方法
		只留下了一个方法是没有具体实现的service方法(留给用户必须添加)
		多了一些自己独有的方法init()  log()
	HttpServlet抽象类的存在目的????-----具体化的说明和体现  肯定是跟HTTP协议有关
		添加了很多具体的属性   都与协议有关  get  post  。。。
		添加了很多具体的与请求方式对应的方法
			doGet
			doPost
		添加了几个自己独有的方法   getLastModifer   set   getAllDeclaredMethods
		保留了上面service方法 但将这个方法添加具体实现
			方法内部将两个没有协议的参数  强制类型转化成带HTTP协议的参数
		添加了一个独有的service方法   最终真正执行的那个
			方法内部先通过request.getMethod();获取请求的方式get/post
			找寻对应请求方式的方法执行  doPost   doGet
		
	我们自己的类继承 HttpServlet
	重写了service方法
	根据请求的方式找寻对应的doXXX方法
	请求发送过来  服务器底层通过反射就找service方法
	我们如果重写了service  正常执行我们的
	如果我们没有重写service 找HttpServlet类中的service方法
	HttpServlet类中的service方法 调用了doPost或doGet 其中的一个
	doPost或doGet方法不会做事 判断请求是正常的HTTP协议 返回405(没有方法执行)
	建议大家类中重写doPost或doGet其中的一个 更清晰的体现出请求的过程了

(6)小结

1.Servlet对象是单例的
	2.才用生命周期托管的方式实现的单例模式
	3.Servlet对象是延迟加载的方式
	4.Servlet对象是有一个生命周期	有三个方法可以看出生命周期
		对象创建时		init()	init(ServletConfig config)
		对象每次使用	service(HttpServletRequest,HttpServletResponse)
		对象被回收		destroy()		重新部署项目   关闭Tomcat
	5.可以通过修改web.xml配置文件  改变Servlet对象的加载方式   
		从默认延迟加载----->立即加载
		<servlet>
			<load-on-startup>0</load-on-startup>   0开始的整数  整数越小加载越早
		</servlet>
	6.在Servlet对象创建时,可以通过配置携带一些信息,就可以让Servlet对象读取到
		<servlet>
			<init-param>
				<param-name>key</param-name>
				<param-value>value</param-value>
			</init-param>
		</servlet>
		在Servlet对象的init方法中进行读取   通常利用带ServletConfig参数的方法
		String value = config.getInitParameter("key");
		Enumeration = config.getInitParameterNames();
		String = config.getServletName();
		ServletContext application = config.getServletContext();//获取全局上下文对象
	7.Servlet继承的关系????
		自己写一个类--->继承抽象类HttpServlet
		HttpServlet--->继承抽象类GenricServlet
		GenricServlet-->实现了三个接口  Servlet    ServletConfig   Serializable

		Servlet接口含有5个方法
			init(ServletConfig config);
			service(ServletRequest,ServletResponse);
			destroy();
			ServletConfig = getServletConfig();
			String = getServletInfo();
		ServletConfig接口含有4个方法
			String value = config.getInitParameter("key");
			Enumeration = config.getInitParameterNames();
			String = config.getServletName();
			ServletContext application = config.getServletContext();
		GenricServlet抽象类体现出了缺省适配器模式
			将上述两个接口中的8个方法全部添加了实现
			只留下一个service抽象方法    需要用户自己填写逻辑
			还添加了两个独有的方法   init(){} 无参数  log(){}
		HttpServlet体现了对于协议的具体化
			将父类service方法实现了
				目的是将两个跨协议的参数强制转化成HTTP协议
			自己添加了一个protected修饰的service方法(参数HttpServletRequest)
				独有service方法的目的是通过请求发送的方式get/post
				找寻对应具体的执行方法doGet   doPost
	8.从今以后如何使用???
		1.自己写一个类	类名字通常XXXController
		2.继承HttpServlet	当然我们也可以继承GenricServlet  当然也可以直接实现Servlet接口
		3.重写方法doPost/doGet/service	请求的方式更加的清晰
		4.方法参数HttpServletRequest    HttpServletResponse
		5.方法修饰符和返回值	   protected/public	返回值void
		6.方法异常ServletException	IOException
		7.工程内web文件夹中WEB-INF文件夹
			web.xml配置文件	目的   	请求---真实Controller类全名对应关系
		8.浏览器发送请求	访问操作资源
			404	没有找到资源	检查xml文件   检查Controller类
			405	没有找到执行方法	检查Controller类中的方法重写

3.JSP

(1)基本使用

	1.JSP----JS区别
		JS----JavaScript	基于对象和事件驱动的脚本语言
		JSP--Java Server Page	Java服务器页面   Java服务页
		原来我们是在Java中的Servlet类中   用out.write("<>");
		JSP为了服务Servlet的    拼接响应信息的部分   相当于换了一个拼接的位置
		JSP融合了    HTML  +  Java
	2.JSP从写法上看似是个文件
		.java     .html       .jsp
		JSP看似是个文件    因为文件中存有HTML+Java代码    最终浏览器展示的时候不认识
		JSP实际上应该是一个操作资源(JSP本质就是Servlet)
		所以底层想要执行看见JSP中的内容  需要Tomcat支持   浏览器访问
	3.如何创建一个JSP文件
		创建JSP以后  需要在第一行填写一个描述信息
		<%@page 属性=值%>
			contentType="text/html;charset=UTF-8";//告知浏览器
			language="java"//用来说明JSP中可以含有除了HTML形式的其他语言
			pageEncoding="UTF-8"//用来说明Tomcat在进行JSP编译的时候
		文件中的内容   如果是正常的HTML标签   正常写
			      如果想要在JSP中写Java    <%%>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FtqMkQGO-1616603856886)(C:\Users\Administrator\Desktop\MarkDown\渡一后端\我的程序员笔记.assets\1616592813188.png)]

(2)执行原理

	浏览器发送请求
	1.请求文件资源
		.html
		底层Tomcat参考自己的web.xml直接找到文件资源  
		文件中的内容(String <>)读取出来   直接响应回浏览器
	2.请求操作资源
		Servlet
		底层Tomcat参考我们工程内自己的web.xml配置文件  servlet  servlet-mappint
		通过反射找到我们自己写的XXXController类  反射找执行方法  service  doPost  doGet
		方法执行完毕   是自己out.write("<>");响应的   直接回浏览器
		有可能产生请求转发的 forward(req,resp);
		JSP      xxx.jsp
		底层Tomcat参考它自己的web.xml 找寻一个JSP解析引擎  JSPServlet
		解析引擎 负责读取JSP的内容 将内容重新拼接组合 将新的内容写入一个java文件
		java文件的名字叫    xxx_jsp.java   文件内容是out.write("");
		java文件还需要进行编译  形成一个   xxx_jsp.class
		class文件执行  回浏览器
		这两个生成的文件默认存储在IDEA自己的文件夹下
		C:\Users\Administrator\.IntelliJIdea2018.3\system\tomcat\Tomcat_9_0_19_TestJSP\work\Catalina\localhost\TestJSP\org\apache\jsp

	3.为什么JSP是一个Servlet
		从请求的配置文件可以看出
		从真正生成的java类   方法也能看出    _jspInit()    _jspDestroy()    _jspService();
	4.JSP中的内置对象    9个	
		_jspService(request response){方法内部
			session
			applcation
			out
			page
			pageContext
			config
		}

(3)JSP标签

<%@	%>	做说明  通常放在头部
<%!	%>	写Java代码	_jspService方法外部,作为成员存在,通常用来定义属性,方法
<%	%>	写Java代码	_jspService方法内部,方法内的局部,通常是写逻辑
<%=	%>	写Java代码	_jspService方法内部,通常用来赋值或者打印输出

a.指令标签

<%@ xxx %>	通常放置在JSP头部   做说明性质的描述
<%@ page %>
	contentType="text/html;charset=UTF-8"   告知浏览器解析时遵循的规则
	language="java"		告知JSP中含有的语言(默认)
	pageEncoding="UTF-8"	告知Tomcat解析JSP时遵循的字符规则
		Tomcat将JSP解析成Java文件---->   pageEncoding   charset   Tomcat默认
		浏览器解析class文件回写的消息-->    charset    pageEncoding  浏览器默认
	import=""	在JSP中导入的Java文件的包
	isErrorPage="true"	设置当前JSP作为一个异常页	exception
	errorPage="xxx.jsp"
<%@ taglib %>	Jsp   Standard   Tag  Library	JSTL
	uri="http://java.sun.com/jsp/jstl/core" prefix="c"
<%@ include%>	用来在当前JSP中引入已经写好的资源      .jsp    .html
	include标签引入一个JSP资源正常(不会出现中文乱码的问题 脚本也同时好用)
	include标签引入一个HTML资源(产生中文乱码 即便是设置了charset也不好用)
	解决上述HTML乱码问题需要配置一个文件 web.xml
	主要配置page-encoding就可以了
		<jsp-config>
			<jsp-property-group>
				<description>JSPConfiguration</description>
				<display-name>JSPConfiguration</display-name>
				<url-pattern>*.jsp</url-pattern>
				<el-ignored>false</el-ignored>
				<page-encoding>UTF-8</page-encoding>
				<scripting-invalid>false</scripting-invalid>
			</jsp-property-group>
 			<jsp-property-group>
				<description>HTMLConfiguration</description>
				<display-name>HTMLConfiguration</display-name>
				<url-pattern>*.html</url-pattern>
				<el-ignored>false</el-ignored>
				<page-encoding>UTF-8</page-encoding>
				<scripting-invalid>false</scripting-invalid>
			</jsp-property-group>
		</jsp-config>

b.动作标签

<jsp:xxx>
替代之前Java程序 创建对象 对象赋值取值  请求转发 携带参数
	<jsp:include page="">
	<jsp:useBean id="atm" class="domain.Atm" scope="request"></jsp:useBean>
	<jsp:setProperty name="atm" property="*"></jsp:setProperty>		//当atm属性名与表单参数名一致时使用
	<jsp:setProperty name="atm" property="aname" param="aname"></jsp:setProperty>	//设置单个atm属性值时使用
	<jsp:getProperty name="" property=""></jsp:getProperty>
	<jsp:forward page="">
		<jsp:param name="" value=""></jsp:param>
	</jsp:forward>

c.小结

1.技术最早是ModelOne模式
	只有Servlet	VC+M
	VC在一起的	拼接响应信息V  很麻烦
2.技术稍微革新了一下ModelTwo模式
	JSP+Servlet	V+C
	V  C分开   M
3.JSP技术出现以后   写法比较简单   更像是一个文件资源
	而且这个文件中还能直接写Java程序
	JSP--->V	     JSP--->Servlet
	运行性能就有问题   不安全   管理起来也不方便
	JSP2.0	动作标签    替代对象创建  赋值  请求转发
4.JSP展示时候会出现一些逻辑的问题
	所有JSP的标签风格不统一
	EL+JSTL
	Expression  Language
	Jsp  Standard  Tag  Library
5.新的模板语言产生

JSP三个指令标签	<%@page%>  <%@taglib%>  <%@include%>
JSP六个动作标签	<jsp:>   useBean  setProperty  getProperty  forward  param  include
JSP四个作用域	page(pageContext)   request    session     application
JSP九个内置对象	request  response  session  application  out  page  pageContext  config  exception

(4)内置对象

-HttpServletRequest		request
-HttpServletResponse	response
-HttpSession		session
-ServletContext		application
JSPWriter			out
Object			page
PageContext		pageContext
-ServletConfig		config
Exception			exception

a.HttpServletRequest

request

1.用来获取请求携带的参数信息
	String value = request.getParameter("key");
2.用来设置接受请求参数时的字符集(POST)
	request.setCharacterEncoding("UTF-8");
3.存储某一个自己产生的数据  业务逻辑方法的结果
	request.setAttribute("key",Object);
4.获取之前一次请求中request对象存储的数据
	Object = request.getAttribute("key");
5.用来设置转发的资源位置
	RequestDispatcher rd = request.getRequestDispatcher("path");
	rd.forward(request,response);//真正的转发
6.获取请求携带参数全部的key
	Enumeration = request.getParameterNames();
7.获取key一致的一组value值  通常用作复选框
	String[] = request.getParameterValues("key");
8.Uniform	Resource  Locator统一资源定位器
	StringBuffer = request.getRequestURL();
	//http://localhost:8080/JSPBuiltInObject/index.jsp
9.Uniform	Resource	Identifier统一资源标识符
	String = request.getRequestURI();
	/JSPBuiltInObject/index.jsp
10.获取协议头传递的信息	国际化
	request.getHeader("Accept-Language");
11.HttpSession = request.getSession();
12.Cokie[] = request.getCookies();
  • 协议头

    GET    /index.jsp     HTTP/1.1
    Host: localhost:9999
    Connection: keep-alive
    Upgrade-Insecure-Requests: 1
    User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
    Accept-Encoding: gzip, deflate, br
    Accept-Language: zh-CN,zh;q=0.9
    Cookie: Webstorm-2f8f75da=1b88d886-30e2-4089-abc9-af9030089775
    

b.HttpServletResponse

response

1.response.setCharacterEncoding("UTF-8");
2.PrintWriter pw = response.getWriter();
	pw.write();
3.获取状态响应码
	int statusNumber = response.getStatus();
4.设置响应码
	response.setStatus(int statusNumber);
6.response.addCookie();
	new Cookie("key","value");
7.用来做请求重定向
	response.sendRedirect("path");

转发和重定向

	forward						sendRedirect
1.类不一样
	RequestDispatcher类			HttpServletResponse类
2.调用方式不一样
	request.getRequestDispatcher("path");	response.sendRedirect("path");
	rd.forward(req,resp);	 
3.转发或重定向请求都是在服务器端产生的
		转发是在服务器内部发起的	重定向是在服务器内部发起的
		在服务器内部转发		   告知浏览器需要重新定位新的资源
		浏览器不知道				浏览器被动的发起一个新的请求   浏览器知道
		一次请求				 相当于产生了新请求
4.浏览器URL地址栏是否会发生改变???
	转发的时候浏览器URL不会改变		重定向的时候浏览器的URL会发生改变
5.请求时候是否传递参数??? req  resp
		传递了req resp		没有传递req resp
		可以获取之前请求携带的参数	不能获取之前请求携带的参数
6.转发只能在当前服务器的当前工程内部		重定向可以发送给新的服务器或新的工程
  • 转发

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Zkruvp5k-1616603856888)(我的程序员笔记.assets/1616596815977.png)]

  • 重定向

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ldAEsUVx-1616603856889)(我的程序员笔记.assets/1616596833468.png)]

c.HttpSession

session

session.setAttribute("key",Object);
Object = session.getAttribute("key");
session.removeAttribute("key");
Enumeration en = session.getAttributeNames();//获取全部的key
  • 作用域

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GnpT1NdZ-1616603856890)(我的程序员笔记.assets/1616597186090.png)]

d.ServletContext

application

1.application.setAttribute("key",Object);
2.Object = application.getAttribute("key");
3.application.removeAttributer("key");
4.Enumeration en = application.getAttributeNames();

5.String value = application.getInitParameter("key");
6.Enumeration en = application.getInitParameterNames();	
<context-param>
	<param-name>testParam</param-name>
	<param-value>testValue</param-value>
</context-param>

7.application.getRequestDispatcher("").forwar(req,resp);
8.String realPath = application.getRealPath("/");

e.JSPWriter

out

write();
println();

f.Object

page

当前页对象

g.PageContext

pageContext

页面对象上下文

pageContext.setAttribute();
pageContext.getAttribute();
pageContext.removeAttribute();

g.ServletConfig

config

String value = config.getInitParameter("key");
Enumeration en = config.getInitParameterNames();
String name = config.getServletName();
ServletContext application = config.getServletContext();

h.Exception

exception

可以写一个新的jsp	比如error.jsp
在error.jsp头信息上设置     isErrorPage="true"
在正常的jsp中设置头信息   errorPage="error.jsp"
404没有找到资源  不是异常

4.EL+JSTL

(1)EL

Expression Language

  • 简介
EL
	*1.代替原来Java程序取值的过程	request.getParameter();  request.getAttribute();
	2.能处理一些简单的计算(算数 逻辑 比较)
	3.调用方法(通常是有返回值)---->不常见
  • 用法
1.代替JSP中Java程序获取域对象中的信息
	page(pageContext)	request session  application
	setAttribute("key",objcet);
	(造型)getAttribute("key");
2.取值的不同类型
	基本数据类型+包装类类型+String类型
		${xxxScope.key}
	对象类型
		${xxxScope.key.属性}----->拥有对应的get方法
		${xxxScope.key.方法()}
	数组类型
	集合类型
3.EL有几个自己的作用域对象(EL内置隐式对象)
	*${param.xxx}
	${paramValues.xxx)
	*${requestScope.xxx}
	*${sessionScope.xxx}
	${applicationScope.xxx}
	${pageScope.xxx}
	${initParam.testParamName1}		web.xml配置文件  <context-param> 
	${cookie}
	${header["accept-language"]}
4.做简单的计算
	算数运算	+ - * /  % mod
	比较运算	>gt  >=ge  <lt  <=le  !=ne  ==eq
	逻辑运算	&&(and)  ||(or)  !(not)

(2)JSTL

JavaServerPage Standard Tag Library

  • 简介
JSTL
	*1.控制流程   if   for   switch   out
	2.处理字符串   String(方法)
	3.格式化(日期 时间)
需要下载两个外部的jar包
	jstl.jar	standard.jar

a.核心标签库

1.将两个.jar文件导入项目
	可以在工程内web文件夹的WEB-INF文件夹内创建自己的文件夹lib
	也可以直接将两个jar文件导入Tomcat中的lib文件夹
2.启动idea编辑器
	创建一个新的web工程
	设置新导入的jstl包关联
3.创建一个新的JSP
	JSP中描述一个头信息	目的是为了告知JSP有新的标签可以用
	<%@ taglib uri="http://java.sun.com/jsp/jstl/xxxx" prefix=""%>

	核心标签core   前缀c
	<c:out value=""></c:out>	可以写字符串   可以写表达式语言
	<c:if test=""></c:if>	表达式语言
	<c:choose>
		<c:when test=""></c:when>
		<c:otherwise></c:otherwise>
	</c:choose>
	<c:forEach begin="1" end="5" step="1" varStatus="i">
		${i}<br>
		${i.index}<br>
	</c:forEach>
	<c:forEach begin="0" end="${requestScope.userList.size()}" step="1" items="${requestScope.userList}" var="user" varStatus="i">
		${i.index}--${user}<br>
	</c:forEach>
	<c:forEach var="user" items="${requestScope.userList}">
		${user}<br>
	</c:forEach>
	只能遍历   数组  List集合  Set集合  Iterator  Enumeration
	<c:forEach var="xxx" items="${requestScope.Name}">
		${xxx}
	如果遍历map集合
	<c:forEach var="key" items="${requestScope.map.keySet()}">
		${requestScope.map.key}
	begin  end   step   varStatus(是一个对象  index属性索引)
	var    items
	<c:forTokens var="value" items="a-b-c"delims="-">

b.函数标签库

用来处理字符串
	可以理解为是以前Java中的String类常用方法
	1.需要在JSP上进行描述
		<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn"%>
	2.通常在业务层已经处理掉了字符的所有信息  通常不怎么用
	3.写法与核心标签不太一样
		${fn:xxx()}

c.格式化标签库

用来处理日期  实现格式化
	可以理解为是以前的Date类型      SimpleDateFormat
	1.在JSP进行描述
		<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
	2.写法与之前的核心标签一样
		<fmt:xxx>
		<fmt:formatDate value="${requestScope.date}" pattern="yyyy-MM-dd kk:mm:ss">

(3)自定义标签

a.自定义函数

1.自己描述一个类
2.类中描述自己的方法
	方法必须是静态的
	方法通常有返回值
	public class MyFunctions {
		public static int add(int a, int b) {
			return a + b;
		}
	}
3.配置一个"说明书"----->xxx.tld
	当前工程下web文件夹中的WEB-INF文件夹下创建一个新的xx.tld文件
	1.先描述两个重要的东西  uri   short-name
		<short-name>myFn</short-name>
		<uri>http://www.duyiedu.com</uri>
		<function>
			<name>add</name>
			<function-class>myfn.MyFunctions</function-class>
			<function-signature>int add(int,int)</function-signature>
		</function>
4.在JSP中声明头信息
			<%@ taglib uri="http://www.duyiedu.com" prefix="myFn"%>
				${myFn:add(99,900)}

b.自定义标签

每一个标签都是一个单独的类
1.创建一个类(用来描述一个标签)
	实现一个Tag接口	重写里面的方法
2.细致的看一下这些方法
	public void setPageContext(PageContext pageContext)、
	public void setParent(Tag parent)、
	两组对应的get/set	自己补全   并添加响应的私有属性
	还有一个单独的release方法   回收对象
	doStartTag
	doEndTag
3.在两个方法内添加自己的逻辑
4.描述一个"说明书"	tld
	先描述uri和short-name
	<short-name>myTag</short-name>
	<uri>http://www.duyiedu.com/myTag</uri>
	再描述标签及标签内部的属性
	<tag>
		<name>out</name>
		<tag-class>mytag.MyOut</tag-class>
		<body-content>JSP</body-content>
		<attribute>
			<name>value</name>
			<required>true</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
	</tag>
5.创建JSP  声明头信息

5.文件上传

(1)简介

文件上传
1.本质 : I/O读写
	客户端(浏览器)发送文件    HTTP协议    
		文件的内容写出去   客户端本地输入流  内容   网络输出流
	服务器(Web容器)接受文件    协议
		文件的内容读过来    网络输入流   内容    服务器本地输出流
2.可以使用别人写好的包来进行文件上传
	常用的是apache组织提供的一个包
	commons-fileupload.jar
	commons-io.jar
	去官方网站下载
		www.apache.org
	下拉至最下面  点击commons
		选择下载fileupload和io

(2)浏览端配置

1.写一个jsp/html做展示(选择某一个文件)
2.必须通过表单提交
3.必须使用post方式
	规定:ServletFileUpload类中一个属性  post
	字节数:
		get没有限制,肯定通过URL拼串儿
		每一个不同浏览器对于URL处理长度有所不同
			IE 2048+35  IE 4076
			Google  8182    FireFox 65535
			Safari   80000    Opera 190000
		post没有限制,需要web容器的支持,跟容器的处理性能有关
		比如Tomcat,没有限制,可以通过配置文件
		server.xml   <Connector port="8080" maxPostSize="0">
4.以前的表单只有两个属性  action  method="post"
	如果想要做文件上传  表单中必须再添加一个属性
	enctype="multipart/form-date"
5.必须使用<input type="file">通过这个组件让用户选择上传的文件
	不仅仅能得到文件名   将文件的内容读出来

(3)服务端配置

1.引入文件上传需要的jar包
	commons-fileupload-1.4.jar
	commons-io-2.6.jar
2.使用一个DiskFileItemFactory对象
	DiskFileItemFactory factory = new DiskFileItemFactory();
	使用一个ServletFileUpload对象   包含一个factory
	ServletFileUpload upload = new ServletFileUpload(factory);
	使用upload对象解析request   得到一个List<FileItem>
	List<FileItem> itemList = upload.parseRequest(request);
3.自己的业务逻辑
	通过遍历集合可以获取每一个item元素
	FileItem item 元素可能是一个普通组件   可能是一个文件
	item.isFormField();方法可以判断是否是一个普通文件
	如果item是一个普通的组件
		注意:不能用原生的方式获取参数request.getParameter();
			使用如下方式获取
			String = item.getFieldName();获取组件的name属性
			String = item.getString();获取组件的value属性
		注意:不能使用原生的方式处理中文request.setCharacterEncoding();
			使用如下方式处理
			String value = item.getString("UTF-8");
	如果item判断后是一个文件
		获取真实文件名
		item.getName();
		读取文件的内容
		item.getInputStream();	
		item.write(File file);
4.配置文件大小
	产生临时文件   为了防止丢包
	默认情况下存在tomcat的temp文件夹中
	factory.setSizeThreshold(1024000);	//设置缓冲区大小      默认10240
	factory.setRepository(new File("路径"));  //设置缓冲区位置
	还可以设置上传文件本身的大小
	upload.setFileSizeMax();		//单个上传文件的大小	1M
	upload.setSizeMax();		//上传文件的总大小		3M
  • 监督文件上传的进度

    upload.setProgressListener(new ProgressListener(){
        public void update(long l, long l1, int i) {
            //  第一个参数表示 已经上传的字节个数   4096个字节
            //  第二个参数表示 上传文件的总字节数
            //  第三个参数表示 正在上传第几个组件
            System.out.println("正在上传第"+i+"个组件,已经上传"+((((double)l/(double)l1)*100))+"%");
            try {
                Thread.sleep(300);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    });
    

(4)小结

小总结
	文件上传需要注意的事情
	1.浏览器端需要满足三个条件	form表单    post请求     enctype属性    file组件(多个)
	2.服务器端需要满足		factory工厂对象    upload对象    解析request方法   List<FileItem>
	3.上传文件保存的路径
		放在一个固定的位置D://test	可移植性不好
		放在当前工程的根目录下
			String path = this.getServletContext().getRealPath("/");根目录
	4.最好限制一下文件上传的大小	单个   总体   缓冲区
	5.如果文件上传出现文件名冲突的问题?
		原来名字+用户+时间.原来后缀
		1_zzt_date.jpg
		用一个随机产生的名字当做保存在服务器中的文件名
		1.jpg--->xxxxx.jpg		1   xxxxx    路径    用户   上传时间
		一个随机名字创建一个文件夹
		1.jpg放在文件夹里		用户   路径   文件夹名
	6.有些时候可能上传的文件需要控制类型
		自己设计一个方法

6.文件下载

(1)简介

5.文件下载
	浏览器端	发送请求的按钮
		<a href="download?fileName=xxxx"></a>
	服务器端
		1.接受需要下载的文件名
		2.找到文件并创建输入流读取内容
		3.处理一下响应时的中文字符
		4.设置响应内容类型和状态
		5.response创建输出流将内容响应回浏览器

(2)代码实现

//1.获取请求传递的文件名
req.setCharacterEncoding("UTF-8");
String fileName = req.getParameter("fileName");
//2.通过fileName找到一个服务器中的真实文件(固定位置,当前工程内部)
//找到文件需要一个输入流读取文件中的内容
InputStream inputStream = new FileInputStream("D://upfile/" + fileName);
//3.如果文件名还有中文,通过以下方式处理
fileName = URLEncoder.encode(fileName, "UTF-8");
//4.设置响应的contentType
//String atta = FileUploadBase.ATTACHMENT;  //静态常量
resp.setContentType("application/x-msdownload");
resp.setHeader("Content-disposition", "attachment;fileName=" + fileName);
//5.将内容响应回浏览器
OutputStream outputStream = resp.getOutputStream();
byte[] b = new byte[1024];
int length = inputStream.read(b);
while (length != -1) {
    outputStream.write(b, 0, length);
    outputStream.flush();
    length = inputStream.read(b);
}

7.Filter

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-z7UtzQ98-1616603856891)(我的程序员笔记.assets/1616602064733.png)]

(1)基本使用

Filter过滤器
	1.是Tomcat提供的一个组件
	2.他是一个特殊的Servlet
		特殊在可以放行   有一个多的参数FilterChain
	3.基本使用
		自己创建一个类
		继承HttpFilter(Tomcat9以后的)      Tomcat9之前 直接实现Filter接口
		重写方法doFilter		      init     doFilter     destroy
		doFilter方法中有三个参数    HttpServletRequest   HttpServletResponse   FilterChain
		可以抛出两个异常  ServletException   IOException
		配置web.xml    
	4.基本的使用
		用户认证
		事务的处理
		字符集处理

(2)管理机制

继承或实现的关系
	接口Serializable
		序列化接口
	接口FilterConfig
		getFilterName();
		getServletContext();
		String value = getInitParameter("key");
		Enumeration = getInitParameterNames();
	接口Filter
		default void init(FilterConfig filterConfig) throws ServletException {}
		void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException;
		default void destroy() {}
	抽象的父类GenericFilter
		目的是一个缺省适配器模式
		将大部分的抽象方法都添加了实现
		还增加了init方法重载
	抽象的父类HttpFilter
		做一个参数类型的转化  
		将无协议的参数强制转化成Http协议的参数
	我们自己写的类
		
	对象的创建    生命周期
	filter对象是一个单例的
	filter对象的单例模式   采用生命周期托管的方式实现的
	filter对象是一个立即加载的方式	不能通过配置load-on-startup来进行修改
	生命周期也可以通过init   doFilter   destroy方法重写看

(3)链的执行

1.Filter拦截请求
		处理请求     直接给予响应    转发    重定向    放行
		浏览器出发的请求会经过Filter
		服务器内部的请求转发  请求重定向   是否会经过Filter

		从浏览器发送出来的请求都会经过filter	前提是配置

		从服务器发送出来的请求转发forward   默认是不经过filter的
		从服务器发送出来的请求重定向sendRedirect   是经过filter的

		如果是同一次请求    默认是不经过filter
		如果是一次新请求    是经过filter

		如果想要让所有的请求都经过filter过滤
		做一个xml配置

		<filter>
			<filter-name>one</filter-name>
			<filter-class>filter.FilterOne</filter-class>
			<init-param>
				<param-name>key</param-name>
				<param-value>value</param-value>
			</init-param>
		</filter>
		<filter-mapping>
			<filter-name>one</filter-name>
			<url-pattern>/*</url-pattern>
			<dispatcher>REQUEST</dispatcher>
			<dispatcher>FORWARD</dispatcher>
		</filter-mapping>

2.Filter处理请求
		好多真实资源之前的一个操作	用户认证
		通常拦截pattern    /*      *.xxx
		多个filter都匹配同一个pattern	执行顺序?

		多个filter都会执行
		看起来是按照我们的web.xml的配置顺序来执行????

(4)责任链模式

  • 过滤器链

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NS1Oz2Fx-1616603856892)(我的程序员笔记.assets/1616602519099.png)]

  • 请求与转发和链的关系

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZVp2n25C-1616603856893)(我的程序员笔记.assets/1616602592414.png)]

  • 链表与责任链模式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A3wTrDi8-1616603856894)(我的程序员笔记.assets/1616602641944.png)]

	链表结构
		Node类(节点)   每一个对象 管理一个值
		0.属性    Node    prev   (找到上一个责任人在哪里)
		1.属性    Object  value  (存值)
		2.属性    Node    next   (找到下一个责任人在哪里)
	过滤器链(责任链设计模式)
		Chain of Responsbility Pattern
		Filter类	每一个filter对象  管理当前filter做的事情
		doFilter方法

(5)小结

	1.Filter	Tomcat提供的一个组件
	2.Filter是一个特殊的Servlet
	3.基本使用
		创建一个类    继承HttpFilter(Tomcat9之后)   实现Filter接口(Tomcat9之前)
		重写方法doFilter方法
		三个参数HttpServletRequest   HttpServletResponse   FilterChain
		配置xml文件
	4.管理机制
		继承或实现的关系
		filter对象是单例   生命周期托管的方式   立即加载的方式
		发送请求   从浏览器出发   会经过filter
			从服务器内部出发   转发默认是不经过filter(设置)   重定向经过filter
	5.过滤器链
		好多个filter对象    都处理相同的请求  /*
		我们经过filter不是目的   找到真实的资源
		经过的filter会在真实资源执行之前做些事情   之后也会做事情

8.Listener

Listener监听器	(观察者设计模式)
1.监听域对象产生和销毁的
2.监听域对象存值  修改  删除
	request   session   application
	setAttribute();   removeAttribute();

3.自定义类实现接口:
	ServletRequestListener
	ServletRequestAttributeListener
	HttpSessionListener
	HttpSessionAttributeListener
	ServletContextListener
	ServletContextAttributeListener
4.配置web.xml文件
	<listener>
		<listener-class>listener.TestRequestListener</listener-class>
    </listener>
    <listener>
        <listener-class>listener.TestSessionListener</listener-class>
    </listener>
5.什么场景用
在线人数  监听session对象产生 销毁

9.XML

(1)DTD规则

XML
		EXtensible  Markup  Language
		可扩展标记(标签)语言
		创建这个XML的宗旨不是为了HTML进行扩展  关注的非展示
		更多的是关注数据的存储和传输---->关注的是数据存储和传输

		1.写法
			创建一个文件   .xml
			建议在文件的第一行   头信息
			<?xml  version="1.0" encoding="UTF-8" >
		2.规则
			结构良好的	   有规则  标签对应 <xxx></xxx>
			结构有效的	   在结构良好的基础上遵循很多规则(写什么标签 名字叫什么 属性叫什么 几个 顺序)
				如果想要让写完的xml遵循结构有效的
				需要单独再写一个xml文件--->用来描述规则(类似元注解的作用)
				.tld   Tag  Library  Definition  用来描述标签的
				.dtd  Document  Type  Difinition 文档类型描述
				.xsd  Xml  Schema  Definition   用来描述xml文档内容
				.xml  eXtensible  Markup  Language   用来存储数据的文档
		3.基本xml文件写法
			为了让xml文件中的内容遵循某些规则
			自定义dtd
				第一可以写在当前的xml文件中
				第二可以写在一个外部的文件中  引入
			描述根标记
			<!DOCTYPE school [规则]>
			描述根标记中的其他标记<标签>
			<!ELEMENT 元素名 类别|(元素里面的内容) >
				类别  通常是EMPTY
				元素内容  (其他标签,其他标签)
				标签内部没有标签  是普通的文字    PCDATA
				PCDATA    Parsed  Character  DATA(通常用来描述标签中间的文字<>xxx<>)
				可以被解析的字符数据   支持实体  &xxx;  
					&gt;大于   &lt;小于   &amp;与符号   &quot;双引号   &apos;单引号
				正常情况下 描述标签内部的子标签时候  默认认为是一个
				还需要在子标签基础上增加一个  对于个数的说明
				*符号    0-n个    ?符号  0-1个   +符号  1-n个
				,符号  都有    |符号  a或b其中的一个
			每一个标记中还需要有属性
			<!ATTLIST>	attribute list
			<!ATTLIST 标签名 属性名 什么类型 值>
				通常类型的描述
					CDATA	Character DATA 原封不动 (通常用来描述属性名)
					(t1|t2|t3) 来描述
				通常值的描述
					默认值  "xxx"
					值的说明  (是否是必须 固定的。。)
					#REQUIRED必须   #IMPLIED非必需   #FIXED value固定的
			如果想要描述实体
			<!ENTITY 实体名字 "实体的值">
			<!ENTITY spring "this is spring">

			<div>&spring;</div>

<!--外部引入-->
<!DOCTYPE school SYSTEM "myxml.dtd">

<!--内部配置-->
<!--<!DOCTYPE school [-->
<!--        <!ELEMENT school (class*)>-->
<!--        <!ELEMENT class (teacher*,student*)>-->
<!--        <!ELEMENT teacher (sex*)>-->
<!--        <!ELEMENT student (sex*)>-->
<!--        <!ELEMENT sex (#PCDATA)>-->
<!--        <!ATTLIST school-->
<!--                id CDATA #IMPLIED-->
<!--                name CDATA #IMPLIED-->
<!--                loc CDATA #IMPLIED-->
<!--        >-->
<!--        <!ATTLIST class-->
<!--                id CDATA #IMPLIED-->
<!--                name CDATA #IMPLIED-->
<!--                loc CDATA #IMPLIED-->
<!--        >-->
<!--        <!ATTLIST teacher-->
<!--                id CDATA #IMPLIED-->
<!--                name CDATA #IMPLIED-->
<!--                age CDATA #IMPLIED-->
<!--        >-->
<!--        <!ATTLIST student-->
<!--                id CDATA #IMPLIED-->
<!--                name CDATA #IMPLIED-->
<!--                age CDATA #IMPLIED-->
<!--        >-->
<!--        <!ENTITY spring "this is spring">-->
<!--]>-->
	XML
		EXtensible  Markup  Language扩展标记语言
		<><>
		更多的关注数据的存储和传输	HTML(关注展示)
		结构良好的	   遵循标签的结构  成对出现  满足嵌套  标签名字随意
		结构有效的   在结构良好的基础上   遵循很多规则
			用来定义规则的也是一个xml形式的文件     dtd   xsd    tld(定义标签)
	描述一个dtd规则
		创建一个文件   普通的xml  想要记录数据
		数据基础上添加一个规则   写在xml文件的里面   写在另一个xml文件中 引入
		<!DOCTYPE 根标记 [规则]>
		<!DOCTYPE 根标记 SYSTEM/PUBLIC "文件">
		<!ELEMENT 标签名 类型>
		<!ELEMENT 标签名 (子标签*,子标签?,子标签+)>
			通配符不是必须	+(1-n)   ?(0-1)   *(0-n)
		<!ATTLIST 标签名 属性名 类型 值>
		<!ENTITY 实体名字 "值">	&实体名字;

(2)DOM解析XML文件

  • 简介
解析XML文件内容
		本质就是文件内容的读取Input

		解析XML文件两种方式
		DOM解析(Document Object Model)
			树结构处理方式
			将文档全部解析  形成一个树结构   节点---标签
			优点  编程容易  缺点 必须将整个文档全部处理完毕(慢)
		SAX解析(Simple Api for Xml)-----扩展
			类似流媒体方式
			基于事件的模式  解析时候触发一系列事件
			当某一个tag标签被解析的时候  激活后续的方法
			优点 快(不需要将所有文档都一次性处理完)
			缺点 编写很麻烦(复用性也不强)

		JDOM(Java-based Document Object Model)
			外部jar包  基于DOM方式 底层提升了性能
		DOM4J(Document Object Model for Java)
			外部jar包  基于JDOM方式 底层提升了性能
  • 代码实现
package testxml;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.File;
import java.io.InputStream;

public class Dom {

    public static void main(String[] args) {
        try {
            //采用DOM方式
            //1.需要一个工厂(建造工人)
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            //2.利用工厂创建工人
            DocumentBuilder builder = factory.newDocumentBuilder();
            //3.工人创建一个document对象(需要一张图纸 xml文件)
            File file = new File("src/testxml/school.xml");
            //InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("textxml/school.xml");
            Document document = builder.parse(file);
            //4.解析xml文件
            //获取根标签对象(school)
            //方式一
            Element school = document.getDocumentElement();
            //方式二
            //            Element school = document.getElementById("duyi"); //需要dtd规则
            //方式三
            //            NodeList rootList = document.getElementsByTagName("school");
            //            Element school = rootList.item(0);
            //school标签中的属性
            String schoolId = school.getAttribute("id");
            String schoolName = school.getAttribute("name");
            String schoolLoc = school.getAttribute("loc");
            System.out.println(schoolId + "--" + schoolName + "--" + schoolLoc);

            //school标签中的子标签
            //方式一
            NodeList classList = document.getElementsByTagName("class");
            //方式二
            //            NodeList classList = school.getElementsByTagName("class");
            //方式三
            //            NodeList classList = school.getChildNodes();
            for (int i = 0; i < classList.getLength(); i++) {
                Element classElement = (Element) classList.item(i);
                String classId = classElement.getAttribute("id");
                String className = classElement.getAttribute("name");
                String classLoc = classElement.getAttribute("loc");
                System.out.println("\t" + classId + "--" + className + "--" + classLoc);

                //class标签的子标签 teacher
                //方式一
                Element teacher = (Element) classElement.getElementsByTagName("teacher").item(0);

                //方式二
                //Element teacher = (Element) classElement.getFirstChild();//需要有dtd规则
                String teacherId = teacher.getAttribute("id");
                String teacherName = teacher.getAttribute("name");
                String teacherAge = teacher.getAttribute("age");
                Element sex = (Element) teacher.getElementsByTagName("sex").item(0);
                String teacherSex = sex.getTextContent();
                System.out.println("\t\t" + teacherId + "--" + teacherName + "--" + teacherAge + "--" + teacherSex);

                //class标签的子标签 student
                NodeList studentList = classElement.getElementsByTagName("student");
                for (int j = 0; j < studentList.getLength(); j++) {
                    Element student = (Element) studentList.item(j);
                    String studentId = student.getAttribute("id");
                    String studentName = student.getAttribute("name");
                    String studentAge = student.getAttribute("age");
                    sex = (Element) student.getElementsByTagName("sex").item(0);
                    String studentSex = sex.getTextContent();   //获取标签中的文本内容
                    System.out.println("\t\t" + studentId + "--" + studentName + "--" + studentAge + "--" + studentSex);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

(3)JDOM和DOM4解析XML文件

  • JDOM实现
public class JDOM {

    public static void main(String[] args){
        try {
            System.out.println("以JDOM形式进行解析 需要一个jdom.jar外部包");
            //获取builder对象   自己创建
            SAXBuilder builder = new SAXBuilder();
            File file = new File("src/testxml/school.xml");
            //工人创建document对象
            Document document = builder.build(file);

            //读取school.xml中的根标记  school
            Element school = document.getRootElement();
            //获取school标签中的属性
            String schoolID = school.getAttributeValue("id");
            String schoolName = school.getAttributeValue("name");
            String schoolLOC = school.getAttributeValue("loc");
            System.out.println(schoolID+"--"+schoolName+"--"+schoolLOC);
            //获取school标记的子元素 好几个class
            List<Element> classList = school.getChildren("class");
            for(Element classEle : classList){
                //获取classEle中的属性
                String classID = classEle.getAttributeValue("id");
                String className = classEle.getAttributeValue("name");
                String classLOC = classEle.getAttributeValue("loc");
                System.out.println("\t"+classID+"--"+className+"--"+classLOC);
                //获取class中的子元素 teacher
                Element teacher = classEle.getChild("teacher");
                String teacherID = teacher.getAttributeValue("id");
                String teacherName = teacher.getAttributeValue("name");
                String teacherAge = teacher.getAttributeValue("age");
                Element teacherSexEle = teacher.getChild("sex");
                String teacherSex = teacherSexEle.getText();
                System.out.println("\t\t"+teacherID+"--"+teacherName+"--"+teacherAge+"--"+teacherSex);
                //获取class中的子元素 好多student
                List<Element> studentList = classEle.getChildren("student");
                for(Element student : studentList){
                    String studentID = student.getAttributeValue("id");
                    String studentName = student.getAttributeValue("name");
                    String studentAge = student.getAttributeValue("age");
                    String studentSex = student.getChildText("sex");
                    System.out.println("\t\t"+studentID+"--"+studentName+"--"+studentAge+"--"+studentSex);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}
  • DOM4J解析
public class DOM4J {

    public static void main(String[] args){
        try {
            System.out.println("利用DOM4J形式解析 需要以来外部dom4j.jar");
            //创建一个解析对象
            SAXReader reader = new SAXReader();//理解为是之前的builder对象
            //提供一个文件
            File file = new File("src/testxml/school.xml");
            //让解析对象读取file并产生一个document对象
            Document document = reader.read(file);

            //获取根元素
            Element school = document.getRootElement();
            //获取school中的属性
            String schoolID = school.attributeValue("id");
            String schoolName = school.attributeValue("name");
            String schoolLOC = school.attributeValue("loc");
            System.out.println(schoolID+"--"+schoolName+"--"+schoolLOC);

            //获取school中的子元素 class
            List<Element> classList = school.elements("class");
            for(Element classEle : classList){
                //获取class中的属性
                String classID = classEle.attributeValue("id");
                String className = classEle.attributeValue("name");
                String classLOC = classEle.attributeValue("loc");
                System.out.println("\t"+classID+"--"+className+"--"+classLOC);
                //获取class中的子元素(一个teacher)
                Element teacher = classEle.element("teacher");
                String teacherID = teacher.attributeValue("id");
                String teacherName = teacher.attributeValue("name");
                String teacherAge = teacher.attributeValue("age");
                Element teacherSexEle = teacher.element("sex");
                String teacherSex = teacherSexEle.getText();
                System.out.println("\t\t"+teacherID+"--"+teacherName+"--"+teacherAge+"--"+teacherSex);
                //获取class中的子元素(好多student)
                List<Element> studentList = classEle.elements("student");
                for(Element student : studentList){
                    String studentID = student.attributeValue("id");
                    String studentName = student.attributeValue("name");
                    String studentAge = student.attributeValue("age");
                    String studentSex = student.elementText("sex");
                    System.out.println("\t\t"+studentID+"--"+studentName+"--"+studentAge+"--"+studentSex);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

(9)Session

(10)Cookie

(11)ThreadLocal

(12)WEB注解

(13)AJAX

(14)JSON

五、JQuery

六、算法

七、MyBatis

八、Spring

九、SpringMVC

十、Maven

十一、Git-SVN

十二、SpringBoot

十三、模板引擎

十四、数据库连接池

十五、Redis

十六、Linux

十七、Nginx

十八、Structs2

十九、Hibernate

二十、Netty

二十一、Dubbo

二十二、设计模式

一共有23种设计模式

1.创建型模式(5种)---->用于解决对象的创建的过程
单例模式,工厂方法模式,抽象工厂模式,建造者模式,原型模式

2.结构性模式(7种)---->把类或对象通过某种形式结合在一起,构成某种复杂或合理的结构
适配器模式,装饰者模式,代理模式,外观模式,桥接模式,组合模式,享元模式

3.行为性模式(11种)---->用来解决类或对象之间的交互,更合理的优化类或对象之间的关系
观察者模式,策略模式,模板模式,责任链模式,解析器模式,迭代子模式,
命令模式,状态模式,备忘录模式,访问者模式,中介者模式

  • 1
    点赞
  • 0
    评论
  • 0
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

表情包
插入表情
评论将由博主筛选后显示,对所有人可见 | 还能输入1000个字符
©️2022 CSDN 皮肤主题:深蓝海洋 设计师:CSDN官方博客 返回首页

打赏作者

狂神说Java的粉丝小迷弟

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

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

打赏作者

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

抵扣说明:

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

余额充值