目录
JAVA基础 1
编程习惯 1
变量与运算符 1
<<移位运算符 1
>>有符号运算符 2
a++和++a 2
位运算符 2
控制语句 2
If与Switch 语句 2
特殊流程控制语句break与continue 2
遍历 2
Java基本类型 3
数组 4
数组的定义 4
* 除声明和使用基本数组外,还可以声明和使用引用类型数组(即对象数组) 5
数组排序 5
冒泡排序 5
选择排序 5
筛选法求质数 6
字符串 6
字符串的拆分 6
正则表达式 6
Java正则表达式 7
数据库正则表达式 7
javascript正则表达式 7
声明和使用方法 7
方法重载pk方法重写 7
参数的值传递 7
面向对象 8
对象属性的初始化 8
JVM垃圾回收机制 8
面向对象的四个特性: 9
接口pk抽象 9
三大特性 9
封装 9
继承 10
多态 11
三大修饰符 12
Static 13
Final 13
Abstract 14
接口 15
C流程图 15
Final finally finalize 比较 16
嵌套类 16
成员内部类 16
局部内部类 17
静态嵌套类 17
匿名类 17
集合框架 17
Collection 18
---List 18
---Set 18
Map 18
equals 19
hashCode 19
异常处理 23
---Exception 24
-------RuntimeException 24
-------Exception 24
Try-catch-finally 24
Try-finally 24
重载*覆盖 26
I/O流 26
文件操作 26
流的三种分类 26
字节流 27
字符流 28
关闭流 28
多线程 28
同步机制 28
线程通信 29
网络编程 29
TCP/IP Socket网络通讯 29
寻址与套接字 30
网络的分层 30
传输层 30
客户端 30
服务器 30
反射机制 31
构造方法获取 31
方法获取 31
属性获取 32
反射作用 32
GoF设计模式 32
单例模式(创建型) 33
饿汉式 33
懒汉式 34
工厂模式(创建型) 34
适配器模式(结构型) 34
命令模式(行为型) 34
动态代理 35
Java DOM解析XML 36
Jdbc数据库 36
命名规范 37
键设计原则 37
Oracle (甲骨文) 37
表连接 37
数据模糊查询 38
集合运算符 38
约束 38
创建表语句 39
列一级建表 39
表一级建表 39
子查询建表 39
SQL结构 39
DML (数据管理语言) 39
DDL (数据定义语言) 39
DCL (数据控制语言) 40
事务控制Transaction 40
事务4大特性ACID 40
事务的隔离级别 40
并发访问时可能引发的问题 41
范式 41
主键生成策略 41
视图 41
索引 41
表关系 42
Jdbc发展的四个阶段 42
JDBC 加载6步 42
优化代码 42
JDBC2.0新特性 43
批处理 43
可滚动结果集 43
Blob 和Clob对象处理 44
JDBC事务控制策略 44
提高JDBC运行效率 44
O-RMapping 45
Servlet 45
Servlet作用域 45
配置Servlet & B/S/db模式 45
配置Tomact 46
请求响应 46
过滤器Filter 46
事件监听器 47
Servlet程序配置 47
编解码 47
Forward&sendRedirect 47
Servlet 生命周期 48
Cookie创建 48
JSP 48
脚本元素 48
表达式脚本 48
声明式脚本 48
普通脚本 48
指令元素 49
页面指令 49
标签指令 49
包含指令 49
动作元素 49
包含动作 49
请求转发 49
JSP隐含9大对象 49
PageContext 50
Request 50
Session 50
Application 50
Response 50
Out 50
Config 50
Exception 50
Page 51
EL表达式 51
隐含对象 51
JSTL标签库 52
SET标签 52
OUT标签 52
If标签 52
forEach标签 52
forTokens标签 53
catch标签 53
remove标签 53
import标签 53
url标签 53
redirect标签 54
parma标签 54
中文乱码问题 54
乱码产生的原因 54
处理乱码 54
Hibernate 55
One-TO-One 55
主键关联 55
外键关联 55
One-TO-Many 55
单向关系 55
双向关系 56
Many-To-One 56
Struts2 56
Struts流程图 56
Web.xml配置 56
拦截器 57
作用域 57
Struts方式 57
Servelet方式 57
Spring 57
IOC依赖注入 58
Setter注入 58
构造方式注入 58
接口注入 58
AOP切面编程 58
JAVA基础
Java 特性: 面向对象,分布式,简单化,多线程,安全,跨平台移植(.class)
JDK : 编译器 (解释器 JVM 类库 工具)JRE
环境变量:JAVA_HOME :主要是为了其他工具能找到Java虚拟机,例如Tomcat
Path :设置快捷方式,能迅速找到指令
Classpath :设置运行所需要的包,.class 的指定位置。
Date : yyyy 表示年 MM表示月份 dd 表示日 E 表示星期 HH表示24进制 小时 hh 表示12进制小时mm 表示分 ss 表示秒 MMM表示月+”月”
DateFormart df = SimpleDateFormat(“yyyy-MM-dd E HH:mm:ss”);
df.format(new Date()); 返回值类型为 String
编程习惯
- 缩进:每行一句代码 同级别代码块对齐,不同级别代码缩进
- 注释://单行注释 /* 多行注释 */ /** 文档注释 */
- Java代码大小写敏感。标识符命名规则:包名全部小写 ,类名每个单词首字母大写 ,方法名和变量名第一个单词小写后面单词首字母大写。 命名语法: 字母,数字 _和$组成,不能以数字开头,不能使用关键字 例如assert goto(保留字) synchronized instanceof transient strictfp
volatile const等。在JAVA中关键词均为小写!
变量与运算符
变量的作用—保存数组
声明变量:<数据类型> <变量名称>
变量赋值:<变量名称>=<值>
声明和赋值变量:例如:int variable = 10;
局部变量:在方法中声明的变量称为局部变量。
局部变量只在其所属语句块内有效,变量在其有效范围内可以被多次使用
在使用的时候必须先赋值
全局变量(成员变量):声明在类中方法外,位置可在任何地方,且成员变量使用的时候没有赋值也是没有语法错误的。允许和局部变量重名!
移位运算符可以分为三种: 分别为 <<(向右移动) || >>(有符号向左移动) || >>>(无符号向左移动)这种不常用,不做介绍了!
<<移位运算符
向右移动不超过32位的时候是该数值越来越大 ,对于负数来说,绝对值越 来越大
<< 例如 : a<<3 等价于 a * 23 ====== a*8 ;
>>有符号运算符
向左移动不超过32位的时候是该数值越来越小 ,对于负数来说,绝对值
来越小 例如 : a>>3 等价于 a/2P3P;
a++和++a
int a =5 ; int b=(a++)+(--a)+(++a)= ? // 5+5+6=16
位运算符
1 按位” 与 ”运算符 a & b a , b对应位置都为1 结果为1 否则为0
2 按位” 或 ”运算符 a | b a , b 对应位置都为0 结果为 0 否则为 1
3 按位” 非 ”运算符 ~ a a 对应位置为0 结果为1 否则为 0
4 按位” 异或 ”运算符 a ^ b a , b对应位相同 结果为 0 否则为 1
位运算符也可以操作逻辑型数据 原理同对应的逻辑运算符相同
逻辑运算符&& || 属于短路运算符 , a && b 如果a 为false 则b 不执行
a || b 如果a 为 true 则b 不执行
控制语句
If与Switch 语句
if语句是一种分支语句,或称为条件语句
switch是另一种分支语句,也称为枚举语句 ,是if-else if-else的一种替代形式
Switch(<expression>),<expression>)表达式可以是整型(byte short int )或字符型,枚举类型
jdk7之后支持String类型
<expression>)表达式不可以是:float、long、对象引用类型
特殊流程控制语句break与continue
break:结束当前循环,转到循环之后
continue:结束当前循环,直接继续下一次循环
遍历
下标遍历 : for(int i=0 ; i<n ; i++ )
迭代遍历 : while( iter.hasnext()){ } // Iterator iter
For---each : for(类型 循环变量名 : 遍历的对象 )
Map遍历 :
通过key值遍历 : Set set = map. keyset(); 转为set集合
通过 value 遍历 : Collection coll =map.values(); 转为 Collection集合
Hashtable Vector 遍历的另一种方法 (枚举遍历)
Enumeration emun = map.keys();
While(emun. hasMoreElements()){
Emun. nextElement(); //返回对应的对象类型
}
Java基本类型
在Java中,我们通常所说的基本类型包括8种,分别为整型,浮点型,字符型和布尔型。而整型根据取值范围不同分为4种,分别 byte(字节型8 bit) short(短整型16 bit) int(整型32 bit) long(长整型64 bit) 。
* 浮点型
* float——单精度32位
* double——双精度64位
* 字面值:d或D后缀表示双精度小数;f或F后缀表示单精度小数;
* 通常在遇到小数时使用double类型,字面值更简单
* 字符型
* char——2个字节,存储Unicode值——全世界统一的编码字符集
* 包括:a-z、A-Z、0-9
* 特殊字符(~`#$%^)
* 汉字或其他国家文字
汉字的取值范围 : ‘\u4E00’ ----- ‘\u9FA5’ 收录汉字 20902 个
|
byte |
short |
int |
long |
float |
double |
char |
boolean |
字节 |
1B |
2B |
4B |
8B |
4B |
8B |
2B |
--- |
取值范围 |
-128 127 |
-2P15 2P15 P-1 |
-2P31 2P31 -1 |
-2P63 2P63 P-1 |
--- |
--- |
--- |
true false |
* 数值的自动升级和强制转换:低到高
* 两个int以下类型的整数运算,结果为int整型
* 强制类型转换:高到底(强制类型转换可能产生意想不到的结果)
* 整型转换为char
使用基础API
1.java.lang与Object
Object是所有类的父类,也成为根类
finalize是垃圾回收机制在回收的时候调用
public static String valueOf(Object obj) {
return (obj == null)?“null”:obj.toString(); }
== 运算符与equals区别(Object类中的equals方法用于比较两个对象是否相同)
==运算符可用来执行相等的比较,但只适用于基本类型,如果试图比较两个对象是否相等时须使用equals方法
(==在java中是比较两个变量的地址是否相等;equals方法用来比较2个实例的逻辑是否相等 )
自定义类时,对象有等同性比较的需求时应重写equals方法(提供逻辑判断的标准 ,同时需覆盖HashCode方法)
int i;
int j;
i == j;
什么是包裹类?有什么作用?
基本数据类型int的初值是0;
引用类型(每次需要new一个实例)Integer的初值是null;
基本数据类型都对应一个包裹类(装箱)
包裹类的实例是以对象形式来表示对应基本类型的数据
常被用于集合等一些所需场合
包裹类-必须使用对象的场合
需要使用包裹类提供的一些方法
in的值是地址,引用Integer,用类将数据封装为一个属性
集
Ctrl+O查看类中的所有方法;
数组
数组的定义
数组用来保存批量数据,数组是对象,需要声明其引用变量和对象的创建
一维数组定义 : int[] a=new int[3] || int[] a={1,2,3,4,5} || int [] a ; a=new int[]{1,2,3,4,5} || int[] a ; a={1,2,3,4,5,6} 这种形式的定义错误
* 多维数组
* 除了声明和使用一维数组外,还可以声明和使用多维数组。二维数组最常见
* 二维数组可以看作是一个一维数组(行)的一维数组(列)。因此可以使用两重循环对其遍历
数组的访问
通过数组下标索引(从0开始)来访问指定元素,数组长度可以从数组的length常量中获得
引用类型数组
* 除声明和使用基本数组外,还可以声明和使用引用类型数组(即对象数组)
数组排序
冒泡排序
依次比较相邻的两个数,将最小数放在前面,大数放在后面。如此重复下去,直至最终完成排序。
两个相邻的元素进行比较 1 2 3 4 5 ,12 23 34 45 每次循环结束把一个值沉到数组尾部
具体代码如下:
for(int i= 1 ; i< a .length ; i++ ){
for(int j=0 ; j< a.length –i ; j++ ) {
if ( a[j]>a[j+1] ){
int t = a[i];
a[i] = a[i+1];
a[i+1] = t;
}
}
}
选择排序
每一趟从待排序的数据元素中选出最小的一个元素,顺序放在已排好序的数列的最后,直到全部待排序的数据元素排完。
拿出一个元素,和他后面的所有元素进行一一比较 如果比这个数小就进行交换
for( int i=0 ; i< a.length-1 ; i++ ){
for( int j=i+1 ; j< a.length ; j++ ){
if ( a[i] > a[j] ){
int t = a[i] ;
a[i] = a[j] ;
a[j] = t ;
}
}
}
筛选法求质数
public static void leap(int num){
Boolean[] b = new Boolean[num+1];
for(int i=0;i<b.length;i++){
b[i]=true;
}
for(int i=2;i<= Math.sqrt(num); i++){
if(b[i]){
for(int j=2; j<= num/i ; j++){
b[i*j]=false;
}
}
}
}
字符串
String str =new String (“abc”); //创建2个对象
字符串的拆分
字符串是一种特殊的数组 由多个字符组成的
Split(“分割标记”) 可以说子串 也可以是正则表达式
StringBuilder与StringBuffer 同样是处理字符串的类 reverse() 倒置字符串
正则表达式
TU\dUTH [0-9]数字
HTU\DUTH [^0-9] 非数字
HTU\wUTH 单词字符[A-Z0-9a-z]
HTU\WUTH [^\\w]
^x 以x开头
x$ 以x结尾
* 出现0次或多次
? 出现1次或0次
+ 出现1次或多次
\\p{Lower} 小写字母
\\p{Upper} 大写字母
HTU\sUTH 空白字符
X{3,}至少出现三次
X{3} 出现三次
X{1,3}出现至少1次,至多3次
. 代表任意字符
\\. 代表 .
Java正则表达式
在java中匹配正则表达式主要通过 Pattern 和Martch 两个类来实现 实例代码如下:
Pattern p = Pattern.complie(“正则表达式”) ; //双引号括起来
Matcher m = p.matcher(要匹配的字符串) ;
m.find()
数据库正则表达式
在模糊查询中可以使用 where regexp_like(字段名 ,’正则表达式’) //单引号括起来
JavaScript正则表达式
通过exec来使用 实例代码如下:
Var regex =/正则表达式/ //用 /…./
regex.exec(“要匹配的字符串”); // 返回boolean值
声明和使用方法
方法重载pk方法重写
重载方法——同一类中方法名相同而参数(类型或数量)不同的方法
重载方法的规则:
参数列表必须不同
返回类型可以不同
在调用重载方法时,JVM根据参数匹配对应方法
参数的值传递
方法调用的参数按值传递
在调用方法时,参数是以传递值得方式进行,也就是说如果在所调用方法内部对参数进行修改,不会对原值产生影响
面向对象
面向对象是一种程序设计方法,其基本思想是使用对象和类基本概念进行程序设计
类是对现实世界事物的抽象定义(类的成员包括属性和方法)
对象与现实世界的具体事物相对应(对象是类的实例)
对象属性的初始化
JVM创建对象的基本步骤
当执行new语句创建一个对象时,JVM执行以下基本步骤
1:为新对象分配一块适当大小的内存,以用来保存该对象的属性值,属性值也称为对象状态
2:在该内存中,将对象的所有属性进行缺省初始化赋值
3.对有显式初始化赋值的属性执行显示初始化赋值
* 对象属性(实例变量)的初始化
* 对象的属性,也称为字段,又称为实例变量
* 对象属性的初始化,即初始赋值,有以下两种方式:
* 缺省初始化赋值:对象被创建时,不同类型的属性首先被赋予不同的缺省值
* 显式初始化赋值:如果在类中声明属性时指定了初始值,那么在对象被创建时,相应的属性就被显式地赋予此初始值
* 对象属性的缺省初始化赋值
* boolean false
* byte 0
* char ‘\u0000‘
* short 0
* int 0
* long 0L
* float 0.0f
* double 0.0d
* 引用类型 null
JVM垃圾回收机制
* 垃圾对象——内存中不再被使用的对象
* 垃圾回收(GC)——JVM自动释放垃圾对象所占内存的机制
* 如果对象在没有被引用变量时,便称之为垃圾,其所占用的内存将很快被JVM回收
面向对象的四个特性:
1, 各司其职 ( 靠封装来实现! )
2, 可重用性 ( 靠封装来实现! )
3, 可扩展性 ( 靠继承来实现! )
4, 弱耦合性 ( 靠多态来实现! )
类: 人们对对象的认识,对象的模板
成员变量: 1,有默认值 2,至少在内部范围内有效 3,允许和局部变量重名,局部变量优先 调用成员变量使用关键词 this
含有父类的类的对象创建过程:
1, 分配空间
创建父类对象 (1,父类属性赋值 (2, 调用父类构造方法
2, 类成员赋值
3, 调用构造方法
接口pk抽象
接口中的方法默认为 public abstract 方法,所以在实现接口方法时候必须给出方法体,并且一定要用public 来修饰,而且接口中的常量默认值是public static final 常量
抽象类: |
接口 |
属性无要求 |
属性为 public static final |
不一定有abstract方法 |
所有的方法都为public abstract |
有构造方法 |
没有构造方法 |
单继承 |
多继承,一个类在继承一个类的同时可以实现多个接口 |
三大特性
UML全称统一建模语言,用图形符号来表示面向对象元素的图形化语言。
类用方框表示。方框三部分:
-类名框
-属性框
-操作(方法)框
属性和方法均可用符号表示其访问控制修饰符:
- +:public
- #:protected
- ~或空:default
- -:private
封装
对象明显的边界,体现可重用性,提升一应用系统的可维护性
封装 很大程度上保护内部数据的安全
Private 私有 属性值设置为私有
Public 公有 方法设置为公有
局部变量不允许使用修饰符
继承
继承关系:一般到特殊的关系
父类:存放共性(抽取子类的共性)子类:存放个性,特性
子类继承的父类属性只是继承了访问权,而不是所有权,所以继承的属性并不是子类的属性。
一个类可以有多个父类,但只能有一个直接父类。
单继承 类之间会形成树状结构 (JAVA)
多继承 类之间会形成网状结构 ( C++ )
Class Son extends Father 内存情况
Son (this ) |
在构造Son类对象的时候必须先构造Father?
super : 调用父类中的属性或者方法 (一般为方法,属性一般设置为私有的)
super() 调用父类中的相对应的参构造方法
this : 调用本类中的成员变量或者方法
this() 调用本类中其他的构造方法
当在一个类中没有this() || super()默认为super()调用父类的无参构造方法
继承定义:
从现有类创建子类(现有类称为父类,超类或基类)
(1)子类继承父类中的所有成员(构造器除外)
(2)子类继承父类的私有成员,子类无法直接访问继承来的父类的私有成员,需通过继承来的public的get/set方法来访问私有成员;
单继承:Java语言规定,一个类只能继承一个父类,这是一种限制。
继承优点:
可以创建更为特殊的类型;
可以消除重复代码;
利于可维护性。(例:初始值:一改都改;单独抽出来的一层进行修改不应成其他功能,例如登录的过滤器;AOP)
方法覆盖:子类继承父类的方法
(1)要求方法签名必须一致(方法名和参数列表)
(2)子类方法的访问修饰符范围必须大于或等于父类被覆盖方法;
(3)被覆盖父类方法不能为private私有方法。
子类方法返回值类型必须和父类保持一致,或为父类返回值的子类
(子类覆盖方法可抛出异常,但所抛出衣长范围不能大于其所覆盖方法;父类方法未抛出异常,子类不能抛出异常)
super关键字:调用(本类中 )被覆盖的 (父类 )方法。(即super.方法)
this关键字:调用本类中的方法或属性。(即this.属性或this.方法)
调用父类构造器
子类构造器
(1)当一个类没有声明任何构造器时,编译器为该类默认提供无参构造器(即隐含super(),在编译时被自动添加);
隐含super()说明:
a.调用父类无参数构造器
b.借用父类构造器初始化本类继承的属性
c.当一个构造器的第一行既不是this(),也不是super()时,编译器为该构造器添加一个super()语句,隐含调用父类的无参构造器。
(2)子类继承父类的所有属性(构造器除外)
子类无法直接访问继承来的私有的属性,子类可通过调用父类对应参数的构造器初始化继承的私有属性(调用方法为super(...) ,显式super());
super()&super(...)只能出现在构造器中,并且只能在第一行。也可是this(...)用来调用本类其他重载构造器。
在本类的有参构造器中调用无参构造器时用this()调用。
例如Service中调用DAO,默认构造器初始化DAO,在增删该查中直接调用。
a.确保继承性;有可能子类没有调用父类的构造器,不管如何都会调用构造器,即必须有一个构造器。
b.确保子类在实例化时,其继承的父类的属性得到初始化。开辟空间,new时在内存中开辟空间。
访问权限
|
Public |
Proptected |
友好类 |
Private |
权限
|
在任何地方都可访问
|
同包之间可以访问 非同包子类可以访问 |
同包可以访问
|
本类可以访问
|
多态
子类的对象赋值给父类对象的引用
1、 对象类型不会发生改变
2、 引用只能调用引用类型中的定义方法
3、 运行时根据对象类型调用子类覆盖之后的方法
子类引用可以直接赋值给父类引用
父类引用必须通过强制转换才能赋值给子类引用
(引用 instanceof 类名) 判断引用中的对象是不是 与类名兼容
多态的作用:将不同的子类对象统一看成父类对象,屏蔽子类的差异
做 参数 父类做形参 实参可以是任何形式的子类对象
做 返回值类型 父类为返回值类型 方法中可以返回各种子类对象
1.使用多态:
(1)a.多态与多态引用:
多态:同一个对象的多种形态(本态:对象的原始形态;多态:对象的父类形态)
b.多态引用(本态引用:使用对象原始类型的引用变量来引用对象)
声明了一个父类类型的引用,指明了(引用了)子类类型的实例
(多态引用只能访问子类继承的父类的成员,不能访问子类特有的成员!否则编译出错 )
(2)虚拟方法调用 -多态引用调用的是子类重写后的父类的方法
(3)多态的实用性-多态数组(多态的用途之一):在引用类型的数组中,使用多态形式存放对象
2.对象引用类型的转换
(1)多态参数:方法参数列表中的引用类型参数。
父类的对象作为参数:本台和多态都可用。优点:增加了程序的灵活性;
(2)instanceof运算符-判断一个对象是否为指定类型(形态)
如果是该类或该类的子类,判断返回true;
(3)强制类型转换-将对象从一种引用形态转换为另一种引用形态
引用类型的强制类型转换((Employee)o).子类中的方法
(char )9989 UNICODE65536期2的16次方
对象关联与Object类
1.对象的关联
一个对象中使用另一个对象-对象的关联。例:教师对象使用电脑对象。
2.使用Object类
(1)Object类:所有类的根类。
如果生命类时未使用extends,则该类缺省继承Object类。使用反编译工具javap。
(2)Object类的toString方法
a.toString方法返回对象的字符串表示
b.子类覆盖toString方法,返回自己需要的String内容
System.out.println(<对象>);等同于System.out.println(<对象>.toString());
三大修饰符
Static
可修饰:方法 , 成员变量(属性) 内部类
静态属性全类共有,由类名调用
静态方法中只能访问静态的成员(属性+方法);
静态方法可以被覆盖 , 但是没有多态
静态初始化代码块 在类加载的时候,执行一次
类加载: 1 . 需要的话 , 先加载父类(可能父类已加载过 ,这时候就可不用加载父类了)
2 . 为静态属性分配空间并初始化
3 . 按顺序执行静态初始化代码块
(1)static修饰符:
用来将类中的成员修饰为静态成员
被static修饰的属性称为静态变量或类变量(相对于实例变量而言),静态变量的初始化赋值在类加载时完成;
被static修饰的方法称为静态方法或类方法(相对于实例方法而言),静态成员通过<类名>.<成员>的方式访问;
static允许不创建实例即可访问相关成员
静态变量的生命周期是从类加载的时候开始到程序结束时为止(例服务器内存不足)
过度地使用静态变量,会占据大量系统资源,影响系统性能;通常将一些频繁使用且无需创建新数据的方法写成静态的(例如常用的工具类中的方法)
将一些唯一性的不会因创建实例而受到影响的变量
(2)与实例成员互访
静态成员只是类的"准成员",为类的其他成员提供了快捷的访问方式;
静态成员不能直接访问实例成员,必须通过实例来访问(因为有可能实例并不存在,一次该实例成员也不存在) ;
实例成员可以直接访问静态成员(如果存在类的实例,则该类的静态成员一定已被初始化)。
(3)静态初始化器
在类中,可以存在与其他成员平级静态语句块-静态初始化器
静态语句块在类加载的时候被执行,因此只执行一次。(一般用来初始化类的静态成员,只在类被第一次加载的时候执行一次)先执行静态代码块再执行构造器
Final
可修饰: 变量(局部变量和成员变量): 赋值后不能再发生改变
方法:final 修饰后的方法不能被覆盖 ,但可以继承
类: final类不能被继承
Final修饰属性时,属性此时没有默认值. 此时可以初始化属性值,或者构造方法中赋值
一般情况下常量为 public static,常量名全部大写
(1)final修饰符:用来修饰类或类中的成员
被final修饰的类为最终类,不能再被子类所继承;
被final修饰的方法为最终方法,不能再被子类的方法所覆盖;
被final修饰的属性为常量,其值一旦赋予,便不可修改(常量声明通常使用大写)。
(2)声明静态常量
多数情况下,static与final一起使用修饰一个公用常量。该常量可在程序的任何位置直接被访问。
(3)空final变量
在声明常量时可暂时不为其指定初始值-空final变量
空final变量的初始值必须在构造器中指定。
空final变量不能用static来修饰。
String为什么是final修饰的?
系统的功能性与稳定性将会受影响。常用类。
final修饰的引用类型的变量不能够进行重新指向,也就是说final规定引用类型变量引用的地址不能被改变,所引用对象的属性可以被修改。
Abstract
如果一个类中有抽象方法,那么这个类必须是抽象类 ,抽象类中未必有抽象方法
抽象类 抽象方法 抽象类中可以有抽象方法,也可以有实例方法 抽象方法只能声明,不能实现 后面用 ; 结尾
抽象类的子类 如果不希望成为抽象类,那么它就必须去实现父类中所有的抽象方法
抽象类允许定义构造方法
抽象类 只能声明引用 , 不能 创建对象
抽象方法不能与static 一起使用 , abstract 类中的方法必须在子类中重写 ,并实现多态
Static 只能继承并重写父类中方法 , 但是不能实现多态 .
抽象方法不能与 final 一起使用 , final 修饰的方法不能够在子类中覆盖,而抽象方法是必须要求要在子类中覆盖的.
抽象方法不能与 private 一起使用 , private 修饰的方法不能够被子类覆盖,而抽象类的抽象方法必须要求被子类继承 , 重写覆盖的
抽象类、接口和枚举
1.抽象类
(1)抽象类(抽象出一类事物共同的行为,但不提供一个实现。代码体现:包含了抽象方法的类( abstract) )OOP角度如下:
抽象类与具体类:对现实世界一种实体的抽象定义-具体类(例如Bird);对现实世界一种类型的多种实体的统一抽象定义-抽象类(例如Pet)。
抽象类中可声明抽象方法。抽象类中可包含的成员:属性;构造器;具体方法;抽象方法。
(2)具体类继承抽象类(必须提供抽象类中定义的抽象方法的实现 )
抽象类不能被实例化(抽象类不能new自己)
子类(具体类)可继承抽象父类,实现抽象方法
具体子类使用抽象父类的多态(多态数组、多态参数、虚拟方法调用)抽象类只能访问具体类中对抽象类可见的部分,具体类中继承抽抽象类的部分
抽象类继承和实体类继承间的区别
抽象类不能new自己
抽象类的子类必须提供抽象类中定义的抽象方法的实现
2.接口
(1)接口(接口的用途:定义现实世界不同类型事物的共同行为的特征)
接口的成员:属性和方法,所有属性都是静态常量,所有的方法均是抽象方法。
(2)具体类实现接口
接口不能被实例化(接口不能new自己)
具体类(子类)可以实现接口(父类),并实现接口中的抽象方法(实现类实现一个接口必须提供接口中定义的抽象方法的实现)
具体类适用父接口的多态
一个类可以同时实现多个接口,但只能继承一个父类;子类必须提供所有父接口中所有方法的实现
继承更多的是用来消除在属性和实体方法上(get/set)的代码重复
接口更多的是定义行为规范-方法签名
一个类可以同时继承父类并实现接口
(3)具体类-抽象类-接口
抽象类实现接口,并可实现接口中的部分方法;
具体类继承抽象类,并实现所有抽象方法;
3.枚举
(1)枚举(一种特殊的Java类 ,用来定义有限数量的可穷举数据集)
必须使用<枚举类名>类型的变量引用枚举值。
接口
接口是一种特殊的抽象类 Interface
属性: 都是public static final(公开静态常量) 可以省略不写
方法: 都是public abstract 方法 可以省略不写
接口: 没有构造方法 implements (实现)
接口之间的继承可以为多继承
接口是一个标准, 标准就是为了实现弱耦合 接口就是一种解耦合工具
C流程图
Final finally finalize 比较
final , finally , finalize 在使用的时候没有任何关系,只是长的相似而已
final |
可以修饰 : 类 表示不可继承的 方法 表示不可覆盖的 属性 表示 常量 不可改变的,一般变量名为大写 |
finally |
异常处理语句的一部分,和 try catch 配合使用 总是被执行 |
finalize |
垃圾回收 JVM 在对象0引用时成为垃圾 且内存耗尽后 一次性释放 是Object类中的一个方法 可以重写该方法实现关闭文件等功能(不推荐重写) |
嵌套类
嵌套类语法:类中声明类。类中成员,四大修饰符及static都可用。
相对于嵌套类而言,其外层的类称为顶级类。
顶级类规则:
只能用public或default访问控制修饰符,且不能被static修饰。
编译后,套嵌类生成独立的.class文件。文件名<外部类>$<内部类>。
嵌套类可对外部类的所有字段和方法(以及其他嵌套类)完全访问。嵌套用于实现辅助类,高度依赖于外部类。
嵌套类特点:
新级别的封装
提高代码的可读性和可维护性
组织类层次的更多层
嵌套类类型:
非静态嵌套类,称之为内部类
静态嵌套类(使用static修饰)
区别:对实例的创建要求
成员内部类
内部类实例创建:
在外部类中创建内部类实例
在外部类以外的地方创建内部类实例
访问外部类属性 : 外部类名. This. XXX
不允许在内部类中定义静态属性
创建内部类对象 : 创建成员外部类对象,依靠外部类对象.new 内部类();
局部内部类
作用范围:定义在方法内部,从定义开始到定义结束,只能在方法内部使用
可以直接访问外部类成员 可以访问局部常量final修饰
静态嵌套类
与内部类区别:static修饰,是外部类的静态成员
静态嵌套类与其他静态成员(静态变量和静态方法)一样,并不是外部类的真实成员。在级别上与外部类级别相同,只是代码位置位于外部类内部而已。
创建内部类对象:<外部类>.<内部类> 引用 = new 外部类.内部类();
只能访问外部类的静态成员
匿名类
嵌套在方法内的特殊类(特殊的局部内部类):
new <已存在类名>() {
// class code here
public String toString() {
return “This is a anonymous class”;
}
}
匿名类声明示例:
Object obj1 = new Object() {};
含义:
声明一个Object类的子类,该子类无名称,因此是匿名类
创建该匿名类的实例,并将其引用赋予obj1变量,这是一个多态引用
在声明匿名类时,也可以覆盖父类的方法
创建内部类须具备以下条件:
1.继承,或者实现接口
2.只能出现一次new
内部类的用途:
当声明类和使用类代码邻近时
当类代码较短时
匿名类的特征:
一定是内部类并且隐含final
不能是抽象和静态
集合框架
容器 : 用来存储 管理 对象的
常见数据结构的java 实现有:
链表 : LinkedList (靠结点来实现链表……..)
栈 : Stack (sun公司用的是Vector实现的,所以不再推荐使用,建议用LinkedList实现)
树集 : TreeSet
树映射: TreeMap
散列集: HashSet (哈希算法, 元素内容不同,底层用hashMap实现的)
散列表: Hashtable (不能存放空值 , 线程安全)
向量 : Vector (线程安全 慢)
小结 : 设计到对集合排序的时候基本都要考虑实现Comparable 接口中的
compareTo(Object o)方法
Collection
Collection 集合中存放的都是 元素对象
---List
元素是有顺序的 , 元素是可以重复的
实现类 : ArrayList : 数组遍历方便 增删 难 (线程不安全)
LinkedList : 链表遍历困难 增删 快
Vector : (线程安全) -------- 已经淘汰 查询慢
排序 : Collections.sort( List<T> list ); 泛型必须实现Comparable 接口
Collections Java提供的工具类 里面封装了大量的static 方法 可以用类名直接调用
---Set
元素是无顺序的,没有下标来控制 , 元素的内容是不可以重复的
Add(Object o) 如果o 存在 那么 添加不成功
实现类 : HashSet 两个对象向同一位置插入的时候才调用equals()
不允许元素(对象)内容相同 必须满足两个条件:
1, 覆hashCode()确保相同对象的内容相同哈希码 必须相同尽量最大化的确保不同对象的内容不同
2, 覆盖 equals() 保证相同内容返回true
优点 : 增删改查都比较快
缺点 : 浪费内存
TreeSet 自动排序 , 排序对象要求必须实现 Comparare 接口
Map
接口特点: 元素是键值对 键是不重复的 值 是可以重复的 键无顺序
主要作用: 通过键查找对应的值
Put(key , value) 如果键值存在 , 新值替换原来的value
Get(Key) 通过键值获取 value值
实现类 : HashMap允许空指针作为键或者值 线程不安全 快 Hashtable 不允许空指针 线程安全 慢
TreeMap 自动对键排序 (按照key值排序) 不允许空指针 ,key为Object对象的时候 , 必须实现 Comparable 接口 才能使用
Map 遍历(遍历键值对)
Set<Map.Entry<String, String>> set =m.entrySet();
Properties : Hashtable的子类 特点: 键值均为String
setProperty(key,value) getProperty(key) load(inputStream)加载配置文件
equals
Object类是所有类的父类 ,在 Object类中 有一个Equals方法 主要是来比较来个对象的内容 但是对象是不确定的,所以 Object中的equals只是简单的比较两个对象的地址,要实现比较两个对象的内容 ,必须在类中实现重写 equals方法
重写的步骤如下:
public boolean equals(Object o){
//第一步 判断 o是否为null
If(null==o) return false;
//第二步 判断 对象是否是同一个对象
If(this==o) return true ;
//第三步 判断 两个对象 是否是同一类型的
If(this.getClass()!=o.getClass()) return false ;
//此时两个对象类型都是同种类型 逐一比较属性
把 o 强制转换为 this 对象后在比较属性
}
hashCode
在Object中 由于无法确定具体一个对象的内容 所以 Object类中的hashCode只是确保了同一个地址的两个对象的hashCode相同
相同的内容确保哈希码必须相同 , 尽量最大化做到不同的内容哈希码不同
极端做法 public int hashCode(){ return 0; }
HashSet HashMap 在存放对象数据时候为了保证 每一个对象的内容相同 对象所在的类必须重写 hashCode() 来保证相同内容对象的hashCode相同 内部属性包含引用对象的时候 该引用所在的类同样必须重写hashCode()方法
集合与泛型
一.Collection系列集合(java.util包)
集合的主要用途是保存批量对象(可变长度数组 );数组的主要用途是保存批量数据
Collection:表示不按添加顺序存放对象的集合,集合内元素可以重复,即“无序可重复”集合;
有序和无序是相对于元素的添加顺序来说的
Set集合内部不能保障按照元素的添加顺序去保存元素(无序不可重复)
List集合内部可以保障按照元素的添加顺序去保存元素(有序可重复)
二.使用泛型
集合类中的元素使用Object类型,以允许不同的添加和获取类型。当获取集合中所需对象时必须进行强制类型转型(可能产生异常)
1.泛型的作用
泛型机制为编写代码提供了便利,同时提供了编译时的类型安全检查。
使用集合编程是,应结合使用泛型。泛型以<>形式呈现,<>中的类型约束了集合所能存储的对象类型。这样在获取集合中对象时,不必再进行强制类型转型。<>中的类称为泛型的类型参数。
泛型集合API
三.泛型的通配符类型参数
1.泛型类型参数的精确匹配
泛型的类型参数必须精确匹配,不可将一种泛型类型的集合被另一种泛型类型的集合变量所引用,即使第二种类型是第一种类型的子类。(泛型的类型参数没有多态)
2.通配符类型参数
同泛型集合一起使用时,通配符(?)提供了一定程度的灵活性。
? extends Father 引用赋值合法,仅限于只读访问
如果在类型参数中只使用统配符(例如:List<?>,则表示它支持任意类型(包括接口等类型))
集合高级应用
* 1.常用的遍历集合的方式有哪些?
* 2.forEach和迭代器遍历集合的区别是什么?
* 3.Iterator和ListIterator的区别?
一.集合算法与数据结构
常用的Set集合实现类包括:
HashSet:基于哈希(Hash)算法来存放和管理集合中的数据(集合中保存的是对象的引用)
HashSet集合实现无序不可重复的机制:(哈希算法)在HashSet集合中,有一个用来存放数据对象的内部数组。
* 当向HashSet中添加元素时,系统先调用该元素的hashCode()方法,获取hashCode值(任何对象都有自己的哈希值,该值可通过调用对象的hashCode()方法(继承自Object类)来获得)
* 之后使用hashCode值对数组长度取余,根据结果确定一个index
* 若数组对应的index位置无元素,则直接将该元素添加至index位置
* 若数组该index位置已有元素,则调用该元素的equals方法进行判断
* 如果该方法返回true,则认为两个元素相等,重复不再添加
* 如果该方法返回false,则认为两个元素不等,扩大数组的长度,重新散列一个位置进行添加
思考:如果2个实例,调用equals方法返回true,但是调用hashCode方法返回的hashCode值不同,上面的机制能否确保以上机制?
* 内容相同,但是通过上述算法,两个实例的位置不同,所以不能保障元素不重复
*
* 如何避免:调用equals方法返回true的两个实例,调用hashCode方法,返回的结果相同
* 对象相等即equals值为true则hashCode值也需相等(保证两种方法的返回值相同)
TreeSet:使用排序二叉树数据结构来存放和管理数据,集合中的数据按其顺序自然排序存放
让TreeSet按照我们的逻辑进行排序,有两种方式:
* 1.让实体类实现Comparable接口,提供compareTo方法的实现
* 其中,逻辑大返回正数,逻辑小返回负数,逻辑相等返回0
* 2.创建一个Comparator接口的实现类,提供compare方法的实现
* 其中,逻辑大返回正数,逻辑小返回负数,逻辑相等返回0
* 3.同等情况下,自定义比较器的比较逻辑会覆盖实体类提供的比较逻辑
什么时候用?
* 实体类定义的compareTo方法,使用方便,但是只有一种逻辑
* 现实中往往不止需要一种排列的逻辑。其他的这些排序逻辑,可通过自定义比较器来实现
* 比如:按学生姓名排序,按学生生日排序,按学生年纪排序,按某次成绩排序
使用TreeSet保存的自定义类需要实现Comparable接口或者使用Comparator的实现类,穿入TreeSet的构造器
常见的List集合实现类包括:
ArrayList:以数组数据结构来存放和管理数据
所有数据都是在一个连续的内存中存放,新添加的数据被放在数组最末端
适用场景:
* 适用于不需要进行首尾端频繁插入或删除操作的场景
* 适用于频繁查询的场景 尤其是需要使用下标查询的场景
* 适用于大概知道要保存元素数量的场景
LinkedList:以双向链表数据结构来存放和管理数据(因为内存的不连续性,更适合大批量数据的存放和管理)
* 适用于需要在非首尾端频繁插入或删除操作的场景
* 不适用于需要使用下标查找元素的场景或需要频繁遍历
LinkedList底层没有下标的概念,当使用下标查找一个元素时需从链表的第一个元素开始向后遍历
二.使用迭代器遍历集合
遍历集合的三种方式:* 1.forEach循环 * 2.迭代器* 3.使用索引去遍历(List集合)
hasNext()判断当前指针下方是否有元素
next()让指针向下移动,并返回越过一个位置的元素
remove()必须在next()方法后调用且只能调用一次* 用途:删除最近一个被迭代器返回的元素
forEach循环和迭代器的区别:
* 1.forEach循环写法比较简单,适用于单纯的遍历集合
* 2.forEach和迭代器都可以更改集合中元素的属性(i是一个局部变量,和set集合中对应位置的元素的值相等,改变i的值,并不会影响集合中对应元素的值)
* 3.forEach不能对集合中的元素进行添加、删除、重定向集合
* 4.迭代器和可以对集合中的元素进行删除操作
* 5.ListItertor
ListIterator<Integer> lit = list.listIterator(0); // 指针指向开始
ListIterator<Integer> lit2 = list.listIterator(list.size()); // 指针指向结束
lit.add(30); // 将元素插入到调用.next返回的元素之前,不强制与.next方法配合使用。可以反复调用,执行多次添加操作
lit.set(31); // 异常,必须在返回一个元素后调用,并可调用多次
while (lit.hasPrevious()){
lit.previous();
}
三.Map系列映射集合
1.Map集合是否属于Collection结合API?为什么不是?
* 从OOP角度来讲,接口是对不同事物共同行为的抽象
* Map集合中元素是以键值对的形式保存的
* Map集合使用Set集合的形式保存所有键
* Map集合使用Collection集合的形式保存所有的值
* 因此,Map集合与Collection接口的行为不同,不适合存在继承关系
向Map集合中添加一个重复的Key,会用新值替换旧值并将旧值作为方法的返回值返回。如果key无重复,添加方法返回null
* HashMap-使用HashSet管理Map集合的key
* TreeMap-使用TreeSet管理map集合的key(不可重复如何实现?)
异常处理
Throwable类是 Java 语言中所有错误(Error)或异常(Exception)的超类。
Throwable ||
|| Exception
|| Error
---Exception
-------RuntimeException
UnCheckedException : (常常用来定义自定义异常类)
未检查异常 可以避免 可处理可不处理
处理方法 try---catch---finally
-------Exception
CheckedException : 除 RuntimeException 外其他的Exception
已检查异常 不可以避免 必须进行处理
处理方法 throws XXXException || try ----catch ----finally
Try-catch-finally
Try中的语句可能会不执行所以在使用局部变量的时候一定要注意赋值问题
Try{//代码块1} catch(//代码块2) finally(//代码块3)
代码块1中产生异常后try语句结束 进入catch代码块 处理结束后今日代码块3
代码块1 没有异常 执行完后进入finally代码块
Finally 常用的作用是进行 释放资源 并且finally中的代码一定执行(该部分可省略)
Try-finally
Try{……}finally{…….} 并不是进行处理异常的 而往往 是利用finally代码块必须执 行的性质来实现一些特殊的功能
1.异常的原理
(1)异常定义:异常是一种通信机制:是对程序运行过程中发生错误的一种通知的机制。(不同的异常对象封装了相应的错误信息 )
异常以对象出现,当出现异常,系统会将异常封装成一个对象,将异常抛给该方法调用者。
(2)异常的信息内容:1.异常类型(所有的异常都在java.lang包下);2.导致异常的原因;3.异常出现的位置;
(3)异常的堆栈式抛出机制:main方法最终将异常抛给OS(系统)。 (为了保证程序正常执行,代码必须对可能出现的异常进行处理 )
(出异常,先分析,从逻辑上找问题;锁定异常三部曲。)
a.空指针异常ArrayIndexOutOfBoundsException(在RuntimeException )
Father f = null;f.method();
当尝试通过一个引用变量访问实例的成员,而该引用变量咩有引用任何实例的情况下。
b.数组下标越界异常:int[] arry = new int[10];
array[-1] = 0;
(4)异常分类:受检异常与非受检异常:
受检异常指程序中必须接受检查和处理的异常,由Exception表示;
非受检异常指程序中可以不接受检查和处理,或致命性异常错误。Error或Exception中的RuntimeException(程序员的锅,可规避该异常)表示。
2.捕获并处理异常
(1)异常的处理:(所有的异常均在java.lang包下)
Trowable(所有异常的父类)包括Error与Exception
(在编写异常处理程序时不应使用Trowable类 ,应使用其不同的子类异常以表示特定的异常错误)
Trowable类中的getMessage()与printStackTrace()公有方法可应用与对其子类异常的处理上。
异常对象的printStackTrace()用于打印输出方法调用的栈踪迹
异常的三种处理方式:(适用于Exception类型受检异常与RuntimeException类型的非受检异常)受检异常必须有程序显示处理
a.捕获
捕获处理异常 (try-catch-finally 语句),避免程序不正常终止。可使用多个catch字句铺货多个异常。 catch中return一个值与finally中return一个值;
b.直接抛出(方法声明)
声明和抛出异常
主动抛出异常:throw与throws分别作用于方法体和方法上;
throw语句主动抛出RuntimeException及其子类的异常对象;throw语句执行后方法返回(相当于执行了return语句)
throws方法抛出受检异常可在方法声明中显示指明:若抛出多个异常,用逗号分隔,也可声明抛出涵盖这些异常的父类异常。
c.捕获再抛出{自定义异常:继承Exception提供构造器,(String messge );(String message,Throwable cause )}
捕获并抛出异常:先捕获再将该异常包装为自定义异常抛给调用者。
思考catch 中return;
Java面试题:
try { }里有一个return语句,那么紧跟在这个try后的finally {}里的code会不会被执行,什么时候被执行,在return前还是后?(如果try后面有个catch块,里面有return语句,那么finally语句会不会执行?)
finally语句块的作用就是为了保证无论出现什么情况,一定要执行的,那么finally里的code肯定会执行,并且是在return前执行。(只要语句执行了,肯定是在return前执行的。 finally中也可以有return,并且会覆盖其他的return)
根据java规范:在try-catch-finally中,如果try-finally或者catch-finally中都有return,则两个return语句都执行并且最终返回到调用者那里的是finally中return的值;而如果finally中没有return,则理所当然的返回的是try或者catch中return的值,但是finally中的代码是必须要执行的,方法在return的时候并不是把它所拥有的那个值给返回了,而是复制一份返回!因此,对于基本类型的数据,在finally中改变return的值对返回值没有任何影响,而对于引用类型的数据,就有影响。
重载*覆盖
方法覆盖 :修饰符相同或者更宽 返回值类型,方法名,参数列表相同 异常抛出相同或者更窄
方法重载 : 方法名相同 参数列表不同
I/O流
文件操作
File file = new File(“file name”)
File 代表了磁盘中的一个文件或者文件夹 不能对文件进行读写
常用方法 :exists() isFile() isDirectory() getName() lastModified()
流的三种分类
流的方向 : 输入流 输出流
数据单位 : 字节流 字符流 (只有文本以字符为单位)
流的功能 : 节点流 过滤流
I/O流数据访问
字节流(类结尾一般为OutputStream InputStream)
例如:ab中 (读取4次)
FileOutputStream (写 write() )
FileInputStream (读取 read())
BufferedOutputStream
BufferedInputStream
中间桥梁(字节流Stream->字符流的过渡)
OutputStreamWriter
InputStreamReader
字符流(Reader Writer)
例如:ab中123
FileWriter
FileReader
BufferedReader
BufferedWriter
1.I/O流与文件操作
从传输数据的角度,I/O流又可分为字节流和字符流
InputStream和OutputStream是字节流的基类,Reader和Writer是字符流的基类。
I/O流在文件读写、网络通讯、内存数据交换等方面被广泛应用。
包装流:
通常很少使用单个流对象,而是
字节流
字节流的父类 为 InputStream / OutputStream
主要的字节流 --à 节点流 : FileInputStream / FileOutputStream
主要的字节流 --à 过滤流 : DataInputStream / DataOutputStream
--à 过滤流 : BufferedInputStream
--à 过滤流 : ObjectInputStream / ObjectOutputStream
对象流能处理 8种基本类型 自带缓冲 处理实现序列化的对象
Serializable 对象序列化 一个类实现Serializable 接口
transient 修饰属性不参与序列化
RandomAccessFile 随机访问文件流 seek(long pos) 文件指针
处理缓冲输出字节流 的另一个类 PrintStream
PrintStream : 可以作为节点流使用 也可以作为过滤流使用
字符流
编码和解码不同的时候就会产生乱码 GBK GB2312 Big5 UTF-8 ASCII
字符流的父类 为 Reader / Writer
桥转换 : 字节流-à字符流 指定编解码方式
主要的字符流 --à 节点流 : FileReader / FileWriter
--à 桥转换 : InputStreamReader / OutputStreamWriter
--à 过滤流 : BufferedReader / BufferedWriter
处理缓冲输出字符流 的另一个类 PrintWriter (过滤流)
PrintWriter : 可以作为节点流使用 可以作为桥转换使用可以作为过滤流使用
关闭流
流的关闭属于释放资源 , 所以 我们尽量可以把关闭流的语句写在finally语句块中 ! 同时在关闭流的同时我们一定要注意对象是否指向 null 尽最大程度上来避免空指针异常 在关闭流的动作完成后 将流对象指向null 释放内存 ,以便java垃圾回收机制进行垃圾回收
关闭流 关闭最外层的流对象就可以了 例如 关闭 过滤流 创建的对象
规范写法 例如关闭Connection conn
Finally { if(conn!=null){try{conn.close();conn=null}
catch(Exceptione){e.printStackTrace();}}}
多线程
同步机制
进程 : OS 并发的多个任务 (堆空间独立)
OS采用分时间片 交替执行 宏观并行 微观串行
线程 : 进程中并发的多个任务
线程组成 : CPU 数据( 堆空间共享 , 栈空间独立 ) 代码(任务)
堆空间存放对象 栈空间存放局部变量
多线程并发访问引发的安全问题 :多个线程共同访问同一资源(临界资源)
由于线程交替访问破坏临界资源的原子结构 产生数据不一致的问题
任何一个对象都有一个互斥锁标记 用来分配给线程 ( synchronized )
Synchronized(obj){ } // obj 为临界资源 {//为原子操作}
对obj加锁的同步代码块只有拿到obj的锁标记才能进入obj加锁的同步代码块
线程在离开obj加锁的同步代码块时 ,必须释放obj 所标记
方法修饰符 synchronized 对this 加锁的同步代码块 this 指的是当前线程对象
·在多线程中 线程访问 同一对象 中的成员变量数据共享 局部变量数据独立
线程通信
线程的等待和唤醒过程
T 线程: Thread t --à synchronized (o) --à o .wait() ---à o. notify();
M 线程:Thread m --àsynchronized(o)--à o .wait() ----à o. notify() ;
synchronized (o) : 线程 t 获得o 的锁旗标
Wait() : 线程t自动释放o 的锁旗标
Notify() : 当另外的一个线程m执行了o. notify() 后 线程t可能从o的等待线程池中释放出来 并且移动到等待线程池中o的锁旗标线程池中 , t 获得o 的锁旗标就会执行下去
网络编程
TCP/IP Socket网络通讯
在联网环境(包括内部网环境和互联网环境)下,两台主机可以实现通讯,进行数据交换。
TCP/IP: transport controller protocal传输控制协议
internet protocal 互联网协议
TCP/IP网络通讯模型:基于客户端-服务端架构的网络通讯模型。
客户端主机——(TCP/IP)——服务器主机
作为服务器的主机,通常处于伺服状态,等待来自客户端的连接请求。一次完整通讯步骤:
客户端想服务器发出TCP/IP连接请求
服务器端接受请求后,与客户端建立Socket连接
双方进行数据通讯(客户端与服务端相互发送接受数据)
双方关闭连接
IP地址 : 主机在网络中的逻辑地址
物理地址 : 和设备相关
端口 :网络间的通信本质上是进程间的通信 监听进程的编号 范围 0~65535
协议 : 双方之间通信的标准和约定
寻址与套接字
连接寻址:客户端寻找服务器以向其发送连接请求。进行连接寻址是服务器需对外提供:
服务器主机的IP地址或主机名称
服务器端标识连接目的的端口号:0至65535,1024以内系统保留
Socket(套接字)通道:建立连接后,服务器与客户端形成的虚拟网络通道,数据在这个通道中进行传输。
网络的分层
TCP-IP四层结构 网络接口 网络层 传输层 应用层
传输层
在CoreJava中我们用到的网络编程技术主要是解决传输层中的问题
TCP 传输控制协议 面向连接 可靠
UDP 用户数据包 非连接 不可靠
客户端
Socket : s = new Socket(“IP地址” , 端口号);
s.getInputStream()
s.getOutputStream()
服务器
ServerSocket : ss = new ServerSocket(端口号);
Socket s= ss.accept();
为每一个s开启一个线程
new Thread(new Runnable(){
Public void run(){
……. s.getInputStream();
…….. s.getOutputStream();
}
}).start();
或者写一个实现Runnalbe的类 在构造方法中传入Socket对象----同等效果
无论是在服务器还是在客户端 在关闭流的时候我们都需要关闭 s 使用缓冲流写入数据的时候必须使用 out.flush() || out.close() 刷新||关闭 流
反射机制
反射(Reflection)是一种机制,它允许程序动态的发现和捆绑某个类、方法、字段,以及由语言组成的所有其他元素。
类加载:JVM第一次使用一个类的时候,会根据classpath给定的路径找到类的对应的.class
将文件读入内存,封装成类对象保存下来的过程
类对象:类加载的产物;java.lang.class这个类的对象,称为类对象
类对象的三种获取形式:类名.class 对象.getClass() Class.forName(“String”)
类对象创建对象: c.newInstance()无参构造 || c.newInstance( Object[] args )对应参数构造
反射的概念:主要是指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。
反射是java中一种强大的工具,能够使我们很方便的创建灵活的代码,这些代码可以再运行时装配,无需在组件之间进行源代码链接。但是反射使用不当会成本很高!
构造方法获取
假设c 为类对象
Constructor[]cons=c.getConstructors()||c.getDeclaredConstructors()
Constructor con =c.getConstructor( Class[] parameterTypes )
con =c.getDeclaredConstructor( Class[] parameterTypes )
newInstance( Object[] args ) 通过Constructor对象来调用创建一个对象
方法获取
假设c 为类对象
Method[] methods =c.getMethods() || c.getDecaledMethods()
Method method = c.getMethod(String s ,Class[] parameterTypes) 方法名和参数列表
c.getDeclaredMethod(String s , Class[] parameterTypes)
invoke(Object o , Object[] args) // 调用o对象的参数列表为args的方法
getReturnType() Method对象来调用 返回方法的返回值类型
isPrimitive() 类对象来调用 判断是否为8种基本类型
属性获取
假设 c 为类对象
Field[] field = c.getFields() // 获取类中包括父类中所有的公开属性
c.getDeclaredFields() //获取当前类中的所有属性包括私有的
Field field =c.getField( String s ) || getDeclaredField(String s)
set(Object o , Object value )o为对象value 为修改的值 Field对象调用set
get(Object o) 获取对象的属性值 Field对象调用get
反射作用
反射是一种底层技术 , 适合工具软件和框架的开发 滥用反射是一种不好的编程习惯
GoF设计模式
软件模式:在软件开发环境中通用问题的通用解决方案(为了使应用程序具有更好的可读性、可扩展性、可维护性、灵活性、可移植性等等)
软件模式分为以下三类:
设计模式—设计阶段使用,解决设计问题。
常见:单例模式、迭代器模式等。通常使用UML类图表示。
架构模式—架构阶段使用,解决系统或子系统的架构问题。
常见:MVC模式、发行-订阅模式等15种。。通常使用UML组件图或部署图表示。
Java EE模式—在Java EE企业项目架构阶段使用,构造良好的设计模式。
常见:FC模式、DAO模式等。通常使用UML组件图表示。
GoF设计模式:GoF(Gang of Four,四人组)模式是最流行的设计模式。
GoF设计模式是通用的面向对象设计问题的解决方案。共23种模式,分为三组:
行为型模式-描述对象间如何交互及分担职责。
创建型模式-提供更健壮的方式来创建对象。
结构型模式-讨论如何将各对象联系到一起。
单例模式(创建型)
单例分为2种写法:饿汉式和懒汉式
饿汉式 : 在类加载的时候对象就存在 相对来说 浪费空间
懒汉式 : 在调用get方法是产生对象 但是为了保证单例 必须实现同步 这样会造成 时间的浪费
用途:将类限制为可全局访问的单一实例。
优点:方便引用对象
类加载或需要时创建
缺点:替代全局变量,误用
饿汉式
在创建对象时需考虑线程问题
public class HungrySingleton {
private static HungrySingleton hs;
private HungrySingleton() {};
public static HungrySingleton getInstance() {
if (hs == null) {
synchronized (HungrySingleton.class) { // 同步唯一标识,类的字节码
if (hs == null) {
hs = new HungrySingleton();
}
}
}
return hs;
}
}
懒汉式
public class LazySingleton {
private static LazySingleton ls = new LazySingleton(); // 唯一实例私有静态引用
private LazySingleton(){}; // 私有构造器
/** 单个实例公有静态方法* @return ls LazySingleton */
public static LazySingleton getInstance() {
return ls;
}
}
工厂模式(创建型)
工厂方法模式通过一个方法调用来创建类或其子类的对象,将复杂的对象创建过程封装在方法中,这样客户端只需调用该方法,便可获得所需对象,而无需关心对象的创建细节。
优点:由工厂控制产品对象的创建
客户端无需知道知道子类的名称与创建细节
缺点:为创建新的产品类型,需创建工厂接口的子类型,编码较多
适配器模式(结构型)
适配器模式通过客户端程序与不兼容接口之间增加一个转换组件(即适配器类),有效地解决了组件调用的兼容性问题。这样客户端类可以以统一的方式调用标准接口与不兼容接口类,而无需编写两套不同的代码。
优点:编程简单,不会因调用不同接口而使编程复杂
不必修改被适配类
客户端可以使用带有或不带有适配器的被适配类
缺点:增加了适配器类
被适配类请求需转发,增加开销
命令模式(行为型)
命令模式将命令(操作)与命令的执行逻辑进行了分离,将命令逻辑封装在指定的Command对象中,同时提供命令执行器(Invoker)。
当客户端类需要执行某种操作是,只需创建相应的命令对象,并调用命令执行器执行该命令即可。
命令模式不但消除了大量的if-else语句,而且使用程序具有良好的可维护性与可扩展性。
该模式的设计结构,使得当命令逻辑发生变化时,只需要修改相应的命令对象;当增加新的操作时,只需再实现一个Command类就可以了。其他组件均没有任何变化。
优点:降低了决策逻辑的复杂性
提供了可扩展能力
能够在不同的线程
缺点:在对象的创建、销毁及使用的过程中可能会增加开销
使应用程序的结构更加复杂
动态代理
代理对象和目标对象实现同一个接口 屏蔽两者之间的差异
代理和目标的区别 : 代理自己完成自己的功能后 在去做目标要做的事情
创建动态代理可以用反射来实现,具体代码如下:
/*创建一个代理工厂 来产生代理对象*/
Class ProxyFactory {
/*target 为目标对象 调用getProxy()产生一个代理对象*/
public static Object getProxy( final Object target ){
//定义一个proxy作为返回的代理对象
Objcect proxy = Proxy.newProxyInstance(target.getClass().getClassLoader ,
target.getClass().getIntefaces() ,
// 具体代理实现的功能
new InvocationHandler(){
//返回 一个目标对象 返回的对象
// method 当前调用的方法 args 方法参数表 proxy 代理对象
public Object invoke(Object proxy , Method method , Object[] args) throws Throwable {
//具体实现写日志的功能 /*
获取方法名用 method.getName();
*/
//返回目标对象调用方法的返回值
return method.invoke(target , args);
}
}
) ;
return proxy ;
}
}
Java DOM解析XML
DOM 解析 一次将 .xml文件加载到内存 封装成为1个document 对象
具体解析代码如下: 将 XML标签中的内容存放到内存中或者封装到对象中
//获取 Document对象
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document document = db.parse(“xml文件路径”)
//获取根标记 root
Element root = document.getDocumentElement();
//根据标签名获取同类型标签集合
NodeList nlist = document.getElementsByTagName(“标签名”); //NodeList 为集合
//遍历 Node 可以理解为 Element 和TextNode 的父类
For(int i=0 ; i< nlist.getLength() ; i++ ){
Element node = (Element) nlist.item(i); parseElement( node)
}
Public void parseElement(Element e){ // 分析标签
NodeList nlist = e.getChildNodes();
if(nlist.getLength()==1){ // 说明该标签下为文本
String text = e.getTextContext();
String tagName =e.getTagName();
Switch(tagName){
case “标签名” :…… //可以保存到一个对象中
}
}
else{
for(int i=0 ; i< nlist.getLength() ; i++ ){
if(nlist.item(i) instanceof Element){
parseElement((Element)nlist.item(i));
}
}
}
}
Jdbc数据库
类型 |
驱动Driver |
URL |
Access |
sun.jdbc.odbc.JdbcOdbcDriver |
jdbc:odbc:数据库名 |
Mysql |
com.mysql.jdbc.Driver |
jdbc:mysql://localhost:3306/数据库名 |
Oracle |
oracle.jdbc.driver.OracleDriver |
jdbc:oracle:thin:@localhost:1521 |
SQL Server |
com.microsoft.sqlserver. dbc.SQLServerDriver |
"jdbc:sqlserver://localhost:1433; DatabaseName= 数据库名 |
命名规范
表的建立首先要确定是使用单数还是负数,
别名 :命名规范 如果一个单词 取前4个字母 ,两个单词 每个取前2个组成
3个单词,前两个每个取一个,最后的取两个组成4个
字段定义 :命名规范 如果是数字类型 尽量在字段后加_N 如果是字符类型 在后加_C
如果是日期类型,最后以D_开头
键设计原则
所有的键必须唯一 关键字段创建外键 避免使用复合键 外键总是关联唯一主键
Oracle (甲骨文)
Oracle 版本从7开始 前面版本为内测版本
sql 查询语句 基本结构
select from where group by having order by 六大结构 循序不能乱
单行函数 :
substr() length() to_char() to_date() round() trunc() mod() 等
聚合函数 :
sum() max() min() count() avg()
查询表 : select table_name from user_tables ;
字符串连接 : mysql: concat(str1 , str2) Oracle : ||
字符串截取:MySQL : substring(int index, int len) Oracle : substr(int index, int len)
表连接
内连接: 表之间的连接 inner join (inner 可以省略) 表连接条件用 on 尽量避免使用笛卡尔连接 其他查询条件仍旧使用where
外连接:
左外: 关键字 left outer join (outer可以省略)
右外: 关键字 right outer join (outer可以省略)
全外: 关键字 full outer join (outer可以省略)
自连接:
一个表起2个表名 模拟一张虚表 和外连接语法相同
非等值连接:
和内连接相反 没有关键字 只能使用 笛卡尔(表,表 where)结构 效率慢
数据模糊查询
模糊查询 1 where 字段 like ‘%_’ %代表零个或多个 _ 代表 一个字符
2 where regexp_like (字段 , ‘正则表达式’)
集合运算符
Union ( 求∪,相同保留一个)
Select * from employees where department_id in(100,60)
Union select * from employees where department_id in(100,80) //100,60,80
Union all (合并在一起,相同保留全部)
Select * from employees where department_id in(100,60)
Union all select * from employees where department_id in(100,80) //100,60,100,80
Minus (减 , 第一个查询结果减去第二个查询结果中相同的部分)
Select * from employees where department_id in(100,60)
Minus select * from employees where department_id in(100,80) //60
Intersect (求∩)
Select * from employees where department_id in(100,60)
Intersect select * from employees where department_id in(100,80) //100
约束
主键约束
关键字 : primary key 。。。。。。。pk
非空约束
关键字 : not null 。。。。。。。nn
唯一约束
关键字 : unique 。。。。。。。uk
自定义约束
关键字 : check 。。。。。。。ck
外键约束
关键字 : ( foreign key ) references 。。。。。。。fk
联合主键
在建表语句的最后 例如写 primary key(字段1 ,字段2) , not null 不能用联合主键
创建表语句
列一级建表
create table 表明( 字段 类型 默认值 约束 )
约束在一行字段后面进行
not null 必须用列一级
表一级建表
create table 表名(
字段 类型 是否非空 ,
约束(字段),
) 字段一个约束是一个语句 ,不能一个字段在一个语句中定义多个约束
联合主键 必须用表一级
子查询建表
只拷贝表中数据 创建字段时候不能指定数据类型 数据类型和子句查询的结果有关
create table 表名(
(字段1 约束 , 字段2 约束 , …….)
Select 字段1 ,字段2,……..from 表名
)
只拷贝表中字段
create table 表名(Select 字段1 ,字段2,……..from 表名 where 1=2 )
拷贝表中字段和数据 create table 表名( Select * from 表名)
SQL结构
DML (数据管理语言)
增加记录 :
1,添加一条完整的记录 insert into 表名 values (v1,v2,v3……vn) ;
2,添加自定义字段记录 insert into 表名(字段1,字段2)values(对应字段值)
3,子查询增加记录 insert into 表名[字段] select 语句 增加多条记录
修改记录 :
update 表名 set 字段1 = v1 ,字段2=v2 ….where 条件
删除记录 :
delete from 表名 where 条件
DDL (数据定义语言)
create table / user 等
drop table / user drop table 表 [ cascade constraint ]
alter table 表
添加列: add( //和建表内部写法一样 )
删除列: drop (列1 ,列2 ,…….)
修改列名: rename column oldname to newname
修改列属性: modify (列名 ,[类型],[默认值],[约束] )
删除约束: drop constraint 约束名
添加约束: add constraint 约束(列名1 , [列名2] ,……..)
生效约束: enable constraint 约束名
失效约束: disable constraint 约束名 [ casecade constraint ]
truncate (截取) truncate table 表 [ casecade constraint ]
DCL (数据控制语言)
grant (授权) revoke (撤销权限)
事务控制Transaction
当想要回滚指定位置时 ,可以用savepoint 在指定位置处指定个s
然后 rollback to s 这样就能回滚到指定的位置(不常用)
事务 : 一组不可分割的sql命令集合 ,是对操作数据库的最小单位
sql 的结果 会暂时被存储在回滚段里面 ,
事务结束时候成功commit , 失败用 rollback
当前客户端进行insert , update delete 操作 而没有进行commit || rollback时候,相当于对数据表加了一个行级锁 ,其他客户端访问只能够进行查询
手动加行级锁 select * from 表 for update 加锁不成功,一直在等待
select * from 表 for update nowait 加锁不成功,不等待
select * from 表 for update wait 10 加锁不成功,等10秒
事务4大特性ACID
A 原子性 Atomic : 操作事务确保同一个事务数据不可分割
C 一致性 Consistent : 数据保持一致
I 隔离性 Isolated : 不同事务之间不能发生交集
D 持久性 Durable : 数据永 久性保存到数据库 或 永久性丢失
事务的隔离级别
1 read-uncommited 提交前读 事务并发时访问数据库,可能产生 脏读 现象
2 read-commited 提交后读
3 repeatable-read 可重复读 自动对查询记录加 行级锁
4 serializable 序列化读 自动对表加锁 级别最高 ,但访问最慢
并发访问时可能引发的问题
1 脏读 :B事务读到了A事务没有提交的数据
2 不可重复读 : B事务在操作数据过程中,发现数据前后查询结果不一致
3 幻影读 : B事务在在操作数据过程中,发现数据凭空产生了一些数据
在开发中,我们最主要解决的问题为 脏读 所以Oracle默认的隔离级别为 read-commited
范式
一范式 :表中属性单值
二范式 :表里的所有属性必须完全的依赖主属性
三范式 :表中的属性都必须直接依赖主属性 不能间接依赖主属性
主键生成策略
1 max(id)+1 来确定表中最大值后加1
2 系统提供的sys_guid() 函数来生成唯一值
3 采用单行单列表 ,存放键值 (拿取后修改值)作为一个事物
4 序列squence 生成唯一的主键值
创建一个序列 : create sequence seq [start with ] [increment by] [maxvalue] [minvalue]
[nocycle | cycle ] [ nocache | cache ];
Start with 100 //从100开始生成
Increment by 1 步长为 1
Maxvalue 100000 //最大生成主键值为100000
Minvalue 1 //最小生成值为1
Nocycle | cycle // 是否可以循环生成
Nocache | cache // 是否缓存 cache 10 // 缓存10个数据
NextVal 从序列里获取唯一一个值 select seq.nextval from dual ;
视图
给 查询语句 结果 起的名字 语法 : create view 名字 as 子查询
作用 : 1 简化查询,减少查询嵌套 视图里不保存数据 只保存查询语句 不能提高查询效率
2 对 表 进行权限管理
索引
1 加快查询效率,数据库服务器会为主键和唯一键自动建立索引
2 经常查询的表 经常出现在where条件里的列,查询数量少的时候适合添加索引
3 创建索引 create index 名 on 表(字段)
4 删除索引 drop index 名
表关系
一对一 :
fk+uk (关系松散) pk + fk (共享主键) (关系紧密)
一对多 :
数据库最擅长做的 在多的一边建 外键
多对多 :
建立一张新表 将两个表中的主键 做联合主键
Jdbc发展的四个阶段
Jdbc 是java连接数据库的桥梁
1 java ---- jdbc ---- odbc ----- db
2 java ----jdbc ----- dbClient -----db
3 java ----jdbc ---- db
4 java ----server ---jdbc -----db
JDBC 加载6步
JDBC的加载过程 是一个工厂链
1 注册Driver Class.forName(“oracle.jdbc.driver.OracleDriver”)
2 连接 url = “jdbc:oracle:thin:@localhost:1521:xe”
Connection DriverManager.getConnection(url , username , password );
3 创建Statement对象 conn.createStatement() | conn.prepareStatement(sql)
4 处理sql命令 ps.execute(sql) ps.executeQuary(sql) ps.executeUpdate(sql);
5 处理ResultSet rs.next() 1,指针向下移动一行 2,判断下一条记录是否为null
6 释放资源 依次关闭 rs ps conn
优化代码
1 将代码中重复出现的,冗余的代码封装到一个函数中 为了方便其他用户使用,我们需要建立一个工具包 里面创建多个工具类 满足 内部方法为static
2 代码中经常变化的量写入配置文件中 并通过Properties类读取 ,由于读取的信息可以供以后多次使用 所以将该段代码放入静态语句块中
3 类对象.getResourceAsStream(虚拟路径) 获取JVM读.class文件的输入流,这个流只会到classpath 下面找.class文件
虚拟路径“/”开头,代表本机的 classpath
JDBC2.0新特性
批处理
通过浪费客户端空间来获取时间的做法
Statement 缓存的是完整的sql命令
AddBatch(sql) //添加到缓存中 sql 只能为 增加 修改 删除
ExecuteBatch() //批发送 返回一个整形数组 代表每行sql语句返回的更新情况
PreparedStatement 缓存的是数据
addBatch()
executeBatch()
事务处理的大小一般要大于缓存批处理数量的大小
处理100020条同构sql 插入到数据库 要求控制事务 ,伪代码如下:
//手动控制事务
Conn.setAutoCommit(false);
//同构sql用PreparedStatement 来处理
String sql =”insert into 表 values (?,?,?,?)”;
PreparedStatement ps = conn.prepareStatement(sql);
//循环插入100020条记录
for(int i =1 ; i <100020 ; i++){
ps.setXXX(1, xxx);
ps.setXXX(2, xxx);
ps.setXXX(3, xxx);
ps.setXXX(4, xxx);
//准备好一组数据后添加到缓存
ps.addBatch() ;
//每200条记录进行批处理
if(i%200==0) ps.executeBatch() ;
//每2000条sql做为一个事务进行处理
if(i%2000==0) conn.commit();
}
//将剩余的记录一次性进行批处理
ps.executeBatch();
//将剩余的记录作为一个事务进行提交
Conn.commit();
可滚动结果集
JDBC1.0 中结果集只有next()方法 指针只能往下移动 ,while()结束后结果集也就没有用途了 无法在定义指针
JDBC2.0 中定义了可滚动结果集
ResultSet = ps.executeQuery ( int v1 , int v2 );
V1代表是否可以滚动 可选值为 ResultSet. TYPE_SCROLL_INSENSITIVE
V2代表是否可以更新结果集(影响数据库中数据的永久性更改)一般我们不需要更改,因此常用值为CONCUR_READ_ONLY
常用移动指针的方法 详细可见API文档
Next()---- previous() first()---last() absolute(int pos)----relative(int pos)
Blob 和Clob对象处理
提供了一系列的getBlob方法 getClob方法
JDBC事务控制策略
O-RMapping 实体关系数据库映射
在java中 Jdbc 的事务控制策略默认为 一条sql语句为一个事务
Sql执行成功失败是通过异常来判断的
手动控制事务
1 con.setAutoCommit(false) //设置事务提交方式为手动提交
2 通过con放送的所有数据都需要手动提交,设置永久生效
3 控制一个事务的方法 在try语句中提交事务 con.commit()
在catch中回滚事务 con.rollback() 业务逻辑层
1 从上一层接受数据 (一般分为零散状态)
2 对数据进行业务逻辑判断
3 将数据封装成对象(entity)
4 利用entity对象调用dao的方法
5 控制事务
Dao数据访问层
1 接收业务层传入的数据(对象)
2 将对象存放进数据库表中
3 查询方法时候 ,将ResultSet 封装成一个对象 Rà O
4 将对象返回给业务逻辑层
Dao数据访问层的作用
1 对业务层屏蔽底层数据库的差异
2 完成O-RMapping
提高JDBC运行效率
1 对事务进行控制
2 使用PreparedStatement 命令
3 使用 批处理
4 删除表中的约束 (数据在进入的时候不用check)
5 删除表中的索引(一张表只做插入时候 ,可以删除表中索引 增加效率)
6 降低表隔离级别 (不长操作的表可以把表的级别调整到uncommited)
7 将大对象拆分成小对象
O-RMapping
映射规则 类---表 对象---row(行) 属性---column(列) 关系----fk
JAVA中的关系
一对一关系 : 保留对方的一个引用 (单向[双向]一对一)
一对多关系 : 在多的一方保留一的一方的一个引用 [在一的一方保留多的一个集合]
多对对关系 : JDBC在处理多对多的时候往往将两个多对多拆分为两个一对多处理
关系在代码中的维护 :
一般来说 哪个实体保存对方的引用(这个实体对应的表为子表) 这个实体负责在增加 更新 插入中维护数据关系 而删除在父表对应的实体中进行关系的维护
实体 : 客观存在的对象 一个项目的主体
表 : 每一个实体都有一张对应的表结构,内部封装实体的属性
DAO /Impl : 对数据库的增删改查 (接口 / 实现类 )
Servlet
Servlet作用域
作用域就是能够保存命名属性的内存空间 主要包括 生命周期 和 共享范围
Session 工作原理:Session为懒汉式 当客户端发出获取session请求后,服务器会到浏览器cookie中查找jsessionid 如果浏览器中没有 ,则服务器会创建一个新session返还给用户 并将新的jsessionid 写入浏览器中
特点 作用域 |
生命周期 |
共享范围 |
Request |
一次请求和响应 |
forword方式的跳转 |
Session |
创建开始 时间结束消亡 |
同一用户间的资源可以共享 |
ServletContext |
应用启动---应用关闭 |
被整个应用所有程序共享 |
配置Servlet & B/S/db模式
客户端----------------------------------- 浏览器
服务器Service ---------------------- 开源Tomcat
DB -----------------------------------------Oracle MySQL
配置Tomact
1 必须配置jdk环境 JAVA_HOME
2 整合Tomcat 和开发工具MyEclipse
3 数据库为Oracle 默认端口号8080 修改Tomcat默认端口号8080 (否则无法启动)
4 修改端口号 tomcat/conf/service.xml
5 配置数据库连接池 (可选)
a) 打开 tomcat/conf/context.xml
b) 新建标签<Resource /> 注意 该标签为空白标签
c) 标签包含属性driverClassName=”oracle.jdbc.driver.OracleDriver” //大小写敏感
url=”jdbc:oracle:thin:@127.0.0.1:1521:xe”
username=”数据库用户名”
password=”数据库用户密码”
name=”jdbc/oracle” // 固定格式 oracle可以替换成对应的数据库
type=”javax.sql.DataSource” //固定不变
maxActive=”100” //创建的连接个数
auto=”Container” //固定写法 (可以省略不写)
d) 在程序中获取连接方法 :
a) Context context = new InitialContext() //获取根
b) DataSource ds =( DataSource)context.lookup(“java:comp/env/jdbc/oracle”);
c) Connection conn =ds.getConnection();
请求响应
1.客户端发送请求到服务器
2.服务器获取URL中的URI(/ContextPath/ServletPath)
3.根据URI中的应用名获取ServletContext对象
4.通过ServletContext对象来匹配ServletPath和url-pattern
5.根据匹配的结果获取相应的 类全名
6.一次性加载类封装成ServletConfig对象
7.对象根据多态调用Service()方法
8.将返回结返回给用户
过滤器Filter
Filter ----对程序起到保护作用 具体实现方式:
实现Filter接口 ,在接口中实现接口中的doFilter()方法 例如过滤编解码
Public void doFilter(ServletRequest req, ServletResponse res,FilterChain fc)throws …..{
HttpServletRequest request =( HttpServletRequest)req;
HttpServletResponse response =(HttpServletResponse)res;
fc.doFilter(request,response);
}
Filter 在web.xml中的配置
<filter>
<filter-name>xxx</filter-name>
<filter-class>类全名<filter-class>
<filter>
<filter-mapping>
<filter-name>xxx</filter-name>
<url-pattern >/servlet的url-pattern<url-pattern>
<filter-mapping>
事件监听器
ServletContext 对象在服务器启动的时候创建 在服务器关闭的时候消亡 是磁盘web.xml在内存中的表现形式 可以再ServletContext中创建事件监听器
事件监听器 ServletContextListener || ServletContextAttributeListener
监听器 实现上面的接口 重写接口中的方法
配置 事件监听器 : web.xml 中 配置
<listener><listener-class>自定义类全名</listener-class></listener>
Servlet程序配置
Servlet程序 有关协议的 需要继承 HttpServlet
无关协议的 需要实现Servlet接口或者继承GenericServlet
其中GenericSevlet 为适配器
Servlet程序在web.xml中的配置
< servlet >
<servlet-name>xxx</ servlet -name>
< servlet -class>类全名< servlet -class>
< servlet >
< servlet -mapping>
< servlet -name>xxx</ servlet -name>
<url-pattern >/servlet的url-pattern<url-pattern>
< servlet -mapping>
编解码
采用post提交的数据 可以通过filter来过滤请求和响应编码
采用get 提交的数据 在Tmocat/Server.xml修改端口标签中添加 URIEncoding=”GBK”
Forward&sendRedirect
程序内部 配合方式 include 和 forward
Include 共同完成一件工作
Forward 工作方式为 流水线 式 各司其职
Forward |
请求转发 在同一个请求中实现页面的跳转 发生在服务器内部程序之间 在客户端用户往往会看到地址栏和响应的信息不匹配, 由request 调用 |
sendRedirect |
请求重定向 跨越多次请求 第一次请求为用户发出,后续请求为客户端根据服务器发回的特殊响应自动的发出的请求 并更改地址栏url内容 由response调用 |
Servlet 生命周期
初始化: public void init(ServletConfig config ) throws ServletException
活动期: public void service(ServletRequest request ,ServletResponse response )
throws ServletException , IOException
消亡期: public void destroy()
Cookie创建
Cookie c = new Cookie(name ,value ) // name 和 value 均为 String
response.addCookie(c) //在Http协议中添加Cookie
Cookie[] cookies =request.getCookies(); //获取浏览器中所有的Cookie
JSP
脚本元素
表达式脚本
<%=表达式 %>
声明式脚本
<%! 变量 或者 函数%>
变量为成员变量
普通脚本
<% java代码 %> 内部定义的变量为局部变量 内部不能定义 函数
指令元素
页面指令
<%@page 属性名=属性值 %>
常见的属性名 :
ContentType 设置响应的格式和编码方式 面向 浏览器
Import 导入引用的包
Session 值为true|false true 为饿汉式 false 懒汉式 默认true
pageEncoding 设置编码方式 面向 服务器
errorPage 值为跳转指定的页面 采用 uri (forward跳转方式)
isErrorPage 值为true/false 指定该jsp页面是否为处理错误页面
不常用属性 language isThreadSafe isELIgnored(是否忽略EL技术)
标签指令
<%@taglib uri =’’ prefix=’’ %>
包含指令
<%@include file=’’ %>
动作元素
包含动作
<jsp:include page=”url-pattern” />
<jsp:include page=”url-pattern”><jsp:prama name =”” value =”” /> </jsp:include>
请求转发
<jsp:forward page=”url-pattern” />
<jsp:forward page=”url-pattern”><jsp:prama name =”” value =”” /></jsp:forward>
JSP隐含9大对象
PageContext
jsp特有的作用域 生命周期1个网页 主要作用 给标签间传数值
特有方法 : findAttribute(“name”) //依次从作用域的小到大查找
Request
作用和Servlet中的HttpServletRequest一样
Session
在page标签中可以声明session的创建方式 饿汉式(true) 懒汉式(false)
饿汉式 :在用户访问量比较大的网站建设中往往不采用这样会造成大量的垃圾Session
相对来说浪费空间 牺牲空间 换取时间
懒汉式 :通过浪费创建时间的方法来节约空间
Servlet中的Session 采用懒汉式 Jsp中的Session默认采用 饿汉式
Application
作用同Servlet中的ServletContext 对象相同
Response
作用同Servlet中的HttpServletResponse 对象相同
Out
作用同Servlet中的 PrintWriter 对象相同
Config
可以通过在配置文件web.xml中Servlet标签<init-param>
<param-name>name</param-name><param-value>value</param-value>
</init-param>下获取数据
此时的jsp页面必须配置servlet 并通过servlet中的url-pattern才能获取到值
Exception
只有jsp页面 中设置页面标签<%@page isErrorPage=”true” %> 该页面才包含隐含对象Exception 该页面主要是用来处理异常信息的 该页面的页面标签不能出现
<%@page ErrorPage=”url-pattern” %> 这个标签 出现此标签的页面是抛出异常的页面才具有的。实际开发中 不用该隐含属性
Page
相当于 jsp页面的 this 基本不用
EL表达式
语法结构为${……}
获取作用域中的属性value ${name} ===== pageContext.getAttribute(“name”);
获取具体作用域的属性value ${requestScope.name} =====request.getAttribute(“name”);
同理 ${sessionScope.name} ${applicationScope.name}
获取cookie
${cookie.name} //通过cookie名称找到对应的cookie 对象
${cookie.name.maxAge} //获取cookie的最大生命周期
接受客户端参数
${param.name} =========== request.getParameter(“name”);
${!empty param.name} ======= if(request.getParameter(“name”)!=null)
隐含对象
作用域有关的隐含对象
pageScope sessionScope requestScope applicationScope 分别对应jsp中的四大作用域
pageContext session request application
参数有关的隐含对象(输入相关)
param paramValues
其他隐含对象
cookie header headerValues initParam pageContext
header 储存用户浏览器 和 服务器用来沟通的数据
获取浏览器版本用 ${header.User-Agent}或者${header[“User-Agent”]}
initParam 获取web站点的环境参数Context
例如 String userid= (String)application.getInitParameter(“userid”); 等价于
${initParam.userid}
pageContext 用来获取其他相关用户要求或页面的详细信息
${pageContext.request.queryString} //获取请求的参数字符串
${pageContext.request.requestURL}//获取请求的url 不包括请求所带的参数
${pageContext.request.contextPath}//获取web应用名
${pageContext.request.method}//获取HTTP请求的方法 get||post
${pageContext.request.romoteAddr}//获取用户的IP地址 romoteUser 获取用户名称
${pageContext.session.new}//判断session是否是新的
${pageContext.session.id} //获取session的Id
JSTL标签库
导入标签库所需要的jar包 jstl.jar 和standard.jar
在需要标签库的网页中添加标签动作
<%@taglib uri=”http://java.sum.com/jsp/jstl/core” prefix=”c” %>
<%@taglib uri=”http://java.sun.com/jsp/jstl/sql” prefix=”sql” %>
等一系列标准库
SET标签
<c:set value =”${1+1} ” var=”name” /> 访问 ${name} 结果为2
默认name属性被存放在pageContext中
<c:set var=”name” value=”${1+1}” scope=”session” /> 存放在session中
<c:set var=”name”>
//中间部分为value值
</c:set>
OUT标签
<c:out value=” ${name}”> 对name中value值包含的html原样子处理 不做网页格式化
<c:out value=”${name}” escapeXml=”false”/> 对html 做格式化输出
<c:out value=”${name}” default=”abc” /> 当name为null时候显示 abc
If标签
<c:if test=”${布尔表达式}”>
输出内容
</c:if>
If标签没有和else嵌套的功能 如果判断另外一部分 则需要再写一个if标签
Choose标签
<c:choose>
<c:when test=”${表达式}”>XXXXXX</c:when>
<c:otherwise>YYYYYYY</otherwise> //其他情况
</c:choose>
同switch的区别是 该标签中的功能有一定的逻辑关系, 不需要再使用break跳出
forEach标签
<c:forEach begin=”n1” end =”n2” step=”s” varStatus=”st” >
//内部循环体
</c:forEach>
st 是一个对象 包含两个属性 index count 分别表示 下标 和 计数器
//object表示当前迭代的对象 items里面的值必须来自作用域中
<c:forEach var=” object” items=”${作用域中的集合属性}” varStatus=”st”></forEach>
forTokens标签
浏览字符串中的所有成员 通过制定的符号进行分割字符串
<c:forTokens items=”${被分析的字符串}” delims=”${指定分割字符}” [var =” ”] [varStatus =””] [begin=””] [end=””] [step=””] </c:forTokens>
catch标签
<c:catch var =”exception” >相当于try语句块中内容</c:catch>
只有一个var属性 来标记获取异常的对象名称
异常可以用 ${exception.message} 显示出来 var后不能跟EL表达式
remove标签
<c:remove var=”” [scope=”page|request|session|application”]>
import标签
同jsp:inclue相似 但是<c:import>标签不限制访问本地文件
<c:import url=”url” [context=””] [var=””] [scope=””] [charEncoding=””]></c:import>
url : 要导入的资源 支持EL表达式
context 指定上下文资源 支持EL表达式
charEncoding 支持EL表达式 专门解决包含进来的资源乱码问题
url标签
<c:url value=”url” [context=””] [var=””] [scope=””] [charEncoding=””]></c:url>
通常和set标签搭配使用 来传递参数 例如:
<c:set var =”url” >
<c:url value=”uri”> //value值可以为url 也可以为uri
<c:param name=”name” value=”huo” />
<c:param name=”age” value=”18” />
</c:url>
</c:set>
${url} ============ uri ?name=huo&age=18 但是在地址栏我们看不到?后面的内容 表现形式和post相同
redirect标签
服务器向浏览器发送Http重定向响应 和SendRedirect()功能相当的标签
<c:redirect url=”${…}” [context=””] />
<c:redirect url=”” [context=””] >
<c:param name=”xxx” > XXX </c:param>
<c:param name=”xxx” value=”xxx”/>
</c:redirect>
parma标签
作用:为一个Url添加请求参数
<c:param name=”” value=””/> 支持EL
<c:param name-“”> value值 </c:param>
中文乱码问题
乱码产生的原因
1 在JSP编译成class文件的时候,如果没有指定字符集,默认采用ISO8859-1的编码方式
这样会出现中文乱码
2 使用表单提交如果设定的提交方式为post 而没有设置提交的编码格式,则会以
ISO8859-1方式进行提交,而接受的jsp却通过UTF-8来接受 导致乱码
3 表单使用时如果设置提交方式为get 而没有设置提交的编码格式 ,则会通过
ISO8859-1方式对汉字进行编码 编码后追加到URL 导致接收页面得到的是乱码
处理乱码
1)JSP编译
<%@page pageEncoding=”GBK”%> 解决本页面的静态文本
2)JSP输出
<%@page contentType=”text/html;charset=GBK” %>解决本页面动态生成的文本
等价于Servlet中的 response.setCharacterEncoding(“GBK”);
3) META设置
指定网页使用的编码 尤其对于静态页面
<META http-equiv=”Content-Type” content=”text/html;charset=GBK” />
4) form设置
浏览器提交表单时后 可以指定相对应的编码
<form accept-charset=”GBK” >
一般不需要进行设置 ,浏览器会直接使用页面的编码
5) 数据库连接
String url =”jdbc:oracle:thin:@localhost:1521:xe?
user=xxx&password=xxxx&useUnicode=true&characterEncoding=UTF-8”
6) 中文做参数
例如: HTTP://localhost:8080/test?name=”中国” 传递参数要进行处理 ,处理方式
String url =”HTTP://localhost:8080/test?name=”+ java.net.URLEncoder.encode(“中国”,”GBK”)
7) Struts处理乱码
在 Struts.xml文件中配置常量
<constant name=”struts2.i18n.Encoding” value=”UTF-8||GBK”/>
Hibernate
One-TO-One
主键关联
在关联一方属性中添加 @OnetoOne @PrimaryKeyJoinColumn
在关联另一方属性上添加 @OneToOne(mappedBy=”对方关联属性名”)
外键关联
在关联一方属性中添加 @OnetoOne @JoinColumn(name=”保存表中对方字段名”)
在关联另一方属性上添加 @OneToOne(mappedBy=”对方关联属性名”)
在一方配置中添加<many-to-one name=”对方属性” unique=”true” column=””/>
One-TO-Many
在一的一方保留多的集合
<set name=”set集合的属性名”cascade=”all||save-update”
inverse=”true||false” lazy=”false”>
<key column=”本类对应表的id” ></key>
<one-to-many class=”对方类” column=”对方表id” />
</set>
多方保留一方的一个引用
<many-to-one class=”对方类” column=”外键在表中对应的字段”
cascade=”all||save-update” inverse=”true||false” lazy=”false” />
单向关系
一的一方维护关系 : @OneToMany(cascade=CascadeTtype.All , fetch=FetchType.EAGER)
@JoinColumn(name=”引用外键名”)
双向关系
一的一方不维护关系 : @OneToMany(mappedBy=”对方关联属性”)
多的一方维护关系 : @ManyToOne @JoinColumn(name=”对方属性在表
Many-To-One
单向Many-TO-One
<many-to-one class=”一方的类” column=”保留一方引用对应数据库字段” />
@ManyToOne( cascade = {CascadeType.PERSIST, CascadeType.MERGE} )
@JoinColumn(name=”引用所对应的表中字段”)
Struts2
将请求和视图分离 基于理念 :MVC
配置标签 : struts.xml
<package name=”xxx” extends=”struts-default” namespace=”/”>
<action name=”*_*” class=”{1}Action” method=”{2}”>
<result>${xxx}</result>
</action>
<package>
Struts流程图
Web.xml配置
<filter>
<filter-name>struts</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
拦截器
自定义拦截器 需要实现 Interceptor 接口 调用invocation.invoke();
将程序交给ActionInvation继承执行
配置 :
<interceptors>
<interceptor name=”myInterceptor” class=”interceptor.MyInterceptor”>
<interceptor-stack name=”myInter” >
<interceptor-ref=”defalutStack”/>
<interceptor-ref=” myInterceptor”/>
</interceptor-stack>
</interceptors>
在aciton标签中配置 <interceptor-ref=”myInter”/>
作用域
Struts方式
Map request = ActionContext.getContext().getContextMap();
Map session =ActionContext.getContext().getSession();
Map application =ActionContext.getContext().getApplication();
Servelet方式
HttpServletRequest request = ServletActionContext.getRequest();
HttpSession session = request.getSession();
ServletContext application = session.getServletContext();
Spring
统一管理资源的容器 基于理念 : AOP IOC
IOC依赖注入
Setter注入
通过对应的setXxx方法将属性注入 配置标签如下:
<property name=”xxx” ref=”要注入的id”/>
构造方式注入
<constructor-arg ref =”xxx” index =” ” value =”” type=”” />
<constructor-arg ref =”yyy” index =” ” value =”” type=”” />
接口注入
静态工厂:
<bean id =”xxx” class=”xxxxxxxx” factory-method=”xxxxx” />
实例工厂:
<bean id=”xxx” class=”xxxxxxx”/>
<bean id=”yyy” factory-bean=”xxx” factory-method=”xxxxx”/>
AOP切面编程
Filter interceptor 都是用了AOP的思想