java学习笔记

来源:互联网 发布:java身份证识别 编辑:程序博客网 时间:2024/04/27 23:05

一、 java开发工具Editplus:Editplus与jdk的连接配置,如:javac(编译)、java(运行)、javap(查看字节码)
a) 配置内容:
i. javac(编译):参数为 -d .  $(FileName);初始目录 $(FileDir)
ii. java(运行):参数为 $(CurSel).$(FileNameNoExt);初始目录:$(FileDir)
iii. javap(查看字节码):参数为 $(FileNameNoExt);初始目录:$(FileDir)
二、 java初始:
a) 通过HelloWorld类讲解了关键字、命名规范、修饰符;
pubic class HelloWorld{
    public static void main(String[] args){
       System.out.println("Hello World!");
    }
}
b) jdk与jre的区别;内容、范围///开发、运行//里面包含了各种类库和工具、java程序的运行环境JVM
           jar;java下的压缩文件
           javac;编译
           javadoc;可形成帮助文档
     共有:java;运行
           native2ascii;本地码改成ASCII码
           javap;查看字节码文件
c) 字节码;是java跨平台的一个机制,是一段二进制代码,是一种包含执行程序、
由一序列 op 代码(操作码)/数据对组成的二进制文件。字节码是一种中间码,它比机器码更抽象,是包含一个执行程序的二进制文件(.class)
数据单位的进制;K是千 M是兆 G是吉咖 T是太拉 8bit(位)=1Byte(字节) 
              1024Byte(字节)=1KB 1024KB=1MB 1024MB=1GB 1024GB=1TB
  java中,字节码是CPU构架(JVM)的具有可移植性的机器语言。
d) 四个目标;
   1、java简介;历史和地位---跨平台纯面向对象的语言--第三代语言:继承、封装、多态:方法同名,体不同
                      C++  ---  类函数
                      .NET---跨语言的平台
                      SQL--结构化查询语言--第四代语言
                      Lisp、Prolog人工智能语言---第五代语言
      自身发展:95年后变成javaSE
      java体系:javase、javaee、javame
      特点:面向对象、平台无关、健壮性:无指针、内存的申请与释放(内存分配)
   2、工作原理
        I java虚拟机
Java虚拟机(JVM)是以 字节码 为机器指令的系统,编译虚拟机的指令集与编译微处理器的指令集非常类似。
Java虚拟机包括一套字节码指令集、一组寄存器、一个栈、一个垃圾回收堆和一个存储方法域。------堆,栈,本地方法栈,方法区,pc寄存器
    .java---.class
        Ii 垃圾回收机制(GC);不再使用的内存空间应该回收起来
    java 的垃圾回收机制:Java的垃圾回收机制是Java虚拟机提供的能力,用于在空闲时间以不定时的方式动态回收无任何引用的对象占据的内存空间。需要注意的是:垃圾回收回收的是无任何引用的对象占据的内存空间而不是对象本身 
         1.垃圾回收是由虚拟机自动执行,不能人为地干预。
         2.系统比较空闲(垃圾回收线程)执行
         3.对象不在被引用.对象处于引用的隔离岛状态(隔离引用),对象具备了回收的条件
         4.gc()方法,可以建议虚拟机执行垃圾回收,但是不能确定是否会执行回收。
   iii、开发环境搭建
tools:JCreator\Eclipse\MyEclipse\Jbuilder\NetBeans
   
iv、第一个java程序
        java源文件;xx.java
基本组成是class,只能有一个public类,命名与其一致
java运行(JVM): 类装载器、字节码校验、解释器
java中只有值传递
三、 数据类型与转换(标示符和关键字、常量与变量、基本数据类型,自动转换,强制转换、转义字符、表达式)
a) 标示符:标示符的格式要求:
i. 定义:java对各种变量、方法和类等要素的命名时使用的字符序列,均须遵守标示符的规则
ii. 规则:
1. 由字母、下划线_、美元符$、数字组成
2. 开头不能是数字
3. 大小写敏感,长度无限制(区别C)
4. 类名首字母一般要大写,方法名一般要小写,并且遵循骆驼命名规则,如:ActiveDemo
b) 关键字
i. 定义:java中一些赋以特定的含义,用作专门用途的字符串
ii. 所有关键字都必须小写
iii. 常用的关键字用
1. 用于数据类型的:int、long、short、String、byte、char、float、double、boolean
2. 用于流程控制的:if、else、for、switch、case、do、while、break、continue
3. 访问控制符:public、protected、default、private
4. 用于异常的:try、catch、finally、throw、throws
5. 返回类型的:native、super、null、void、return、synchronized(同步)
6. 实例:instanceof、this、new
7. 面向对象:class、extends、interface、abstract、final、implements、import、package、static
8. goto和const用来破坏程序入口,也是关键字
c) 常量与变量
i. 常量:(public static final 常量名;)
1. 定义:始终不变的值,可以是数值、字符、字符串
2. 规则:习惯上命名时要大写
ii. 变量:(type varName  [=value];)
1. 注意:局部变量使用前必须先初始化不然编译失败!
iii. 调用格式:
1. 调用同文件中的其他类的变/常量格式为:对象.变量
2. 同类中调用其它函数的实例变/常量格式为:new 对象().变量名
3. 同类中调用其它函数的类变/常量格式为: 类名.变量名
d) 数据类型
i. 基本数据类型:byte、short、int、long、char、float、double、boolean
1. 默认值(范围是-2^(n-1)∽2^(n-1)-1)
a) Byte//1、short//2、int//4、long//8------默认值为0
b) char //2--------字符0-----范围是0~65535---unicode编码
c) float//4、double//8--------0.0
d) Boolean//2---------------false
ii. 引用数据类型:数组、类、接口
e) 自动转换(隐式转换)(由小转大)
i. 定义:自动类型转换,也称隐式类型转换,是指不需要书写代码,由系统自动完成的类型转换
ii. 转换规则:byteshort(char)intlongfloatdouble
iii. 示例代码:
1. int i = 4;
2. float n = i;
f) 强制转换(由大转小)
i. 转换规则:double→float→long→int→short(char)→byte
ii. 格式:(转换到的类型)需要转换的数值
iii. 示例代码:
1. double d = 3.10;
2. int n = (int)d;
iv. 注意:强制转换通常都会导致精度的损失
g) 转义字符
i. \b退格
ii. \n换行
iii. \r回车
iv. \’单引号
v. \”双引号
vi. \\反斜杠
h) 运算符------表达式
i. 定义:表达式是由数字、算符、数字分组符号(括号)、自由变量和约束变量等以能求得数值的有意义排列方法所得的组合。约束变量在表达式中已被指定数值,而自由变量则可以在表达式之外另行指定数值
ii. 算术运算符:
1. 单目: ++(自加1)、--(自减1)、+(取正)、-(取负)
2. 双目: + 、- 、* 、/、 %
3. 三目:   ?:     如:a>b?a:b
iii. 关系运算符:-------返回结果true/false
1. 等于符号:==
2. 不等于符号:!= 
3. 大于符号:> 
4. 小于符号:<
5. 大于等于符号:>= 
6. 小于等于符号:<=
iv. 逻辑运算符:------返回结果true/false
1. 与(&&):假短路
2. 或(||):真短路
3. 非(!):
v. 位运算符:-----将原数转化为二进制计算
1. 与(&):     如  1100&1010=1000
2. 或(|):     如  1100|1010=1110
3. 非(!): 如  !1100=0011
4. 异或(^): 如  1100^1010=0110
5. << 带符号左移 ------相当于乘以2
6. >>带符号右移 -------相当于除以2
7. >>> 无号右移
8. 异或的规律:
a) a ^ a = 0
b) a ^ b = b ^ a
c) a ^ b ^ c = a ^ (b ^ c) = (a ^ b) ^ c;
d) d = a ^ b ^ c 可以推出 a = d ^ b ^ c.
e) a ^ b ^ a = b
vi. 赋值运算符:
1. =、+=、-=、*=、/=、%=、&=、^=、|=、<<=、>>=
vii. Intanceof:----归属
1. 定义:为双目运算符,左边操作元是一个对象,右边是一个类。当左边的对象是右边类的对象时,返回true 
2. 格式:result = object instanceof class 如:a = b instaceof B;//true
viii. 优先级:(从高到低、从左到右)
1. () [] 
2. ! +(正) -(负) ~ ++ --
3. * / %
4. +(加) -(减)
5. << >> >>>
6. < <= > >= instanceof
7. == !=
8. &(按位与)
9. ^(位异或)
10. |(位非)
11. &&
12. ||
13. ?:
14. = += -= *= /= %= &= |= ^= ~= <<= >>=>>>=
四、 流程控制语句(分支、循环)
a) If…else:    例1.1:
i. If(a>b){
ii.   System.out.println(a);
iii. }else if(b>c){
iv.   System.out.println(b);
v. }else{
vi.   System.out.println(b);
vii. }
b) 分支:(switch)
i. 格式:switch(条件语句){
case :
case :
…..
default :
}
ii. 例1.2:switch(month){
case 1:System.out.println(“spring”);break;
case 1:System.out.println(“spring”);break;
case 1:System.out.println(“spring”);break;
case 1:System.out.println(“spring”);break;
default: System.out.println(“spring”);break;//一定会执行的语句
}
c) For循环  
i. 格式:For(初始化语句;条件语句;控制语句){
循环体;
}
ii. 例1.3:for(int i=1;i<101;i++){
   int sum = 0;
   sum += i;
}
d) while
i. 格式:while(条件语句){
//初始化语句;
循环体;
//控制语句;
}
ii. 例1.4:int i=1;
while(i<101){
  int sum=0;
  sum += i;
}
e) Do….while()
i. 格式: do{
循环体;
}while(条件语句);
ii. 例1.5:int i =1;
do{
int sum = 0;
 sum += i;
}while(i>101);
f) 增强型for循环----------主要用于打印数组元素
i. 格式:for(e:数组名){
循环体
}
ii. 例1.6:int[] a = new int[10];
                for(e:a){
  System.out.println(e);
}
五、 方法与递归
a) 方法---函数 
i. 定义:一段用来完成特定功能的代码片段
ii. 声明格式:【修饰符】返回类型 方法名(形参列表){
方法体;
}
iii. 语法解释:
1. 形式参数:在方法被调用时用于接收外界输入的数据
2. 实参:调用方法时实际传给方法的数据
3. 返回值:方法在执行完毕后返回给调用它的环境的数据
4. 返回值类型:事先约定的返回值的数据类型,无返回值,必须给出返回类型void
5. return语句中止方法的运行并指定要返回的数据
iv. 调用格式:
1. 静态方法(又称类方法)的调用:类名.方法名(实际参数)
2. 实例方法的调用:对象名.方法名(实际参数)
3. 调用中传递参数时,遵循的规则是:基本数据类型是该数据本身,引用数据类型传递的是对象的引用(地址),不是对象本身----基本数据类型:值传递;引用数据类型:地址传递。
v. 例1:
public class DemoMethod{
public static void main(String[] args){//静态方法(又称类方法)的调用:类名.方法名(实际参数)
        show("i am a girl");
//实例方法的调用:对象名.方法名(实际参数)//如何产生对象(Object),格式:new 构造方法()
        //和类同名的方法称为构造方法
//什么是构造方法(Constructor)?每个类都有一个和类名相同的构造方法,且自动产生
      // new DemoMethod().display();
 new DemoMethod().visiable(12,"aaa",3.0f);
}
    //静态方法的定义【有关键字static修饰的方法】
public static void show(String s){//自定义方法
       System.out.println(s);
}
    //实例方法的定义【没有关键字static修饰的方法】
public int display(){System.out.println("welcome to jiangxi");return (85);//返回结果,可以用括弧,也可以不用}
    //多个参数的实例方法
public void visiable(int x,String y,float f){System.out.println("=======================");}
}
b) 递归----------必须要有出口
i. 定义:递归用于让一个函数从其内部调用其自身
ii. 特点:
1. 程序代码简练,易于理解但浪费内存
2. 一定要有返回类型
3. 一定有if…….else……且if中有终止条件
六、 类(面向对象技术基础、类的声明与使用、对象的声明与使用、构造方法)
a) 面向对象技术基础
i. 面向对象设计的方法论【OOA(分析)OOD(设计)OOP(编程)Test(测试)部署】
ii. 面向对象(Object Oriented,OO)特点: 
1. 对象唯一性:每个对象都有自身唯一的标识,通过这种标识,可以找到相应的对象。在对象的整个生命期中,它的标志都是不改变的,不同的对象不能有相同的标识(地址)。
2. 封装性(抽象性):把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。
3. 继承性:继承性是子类自动共享父类数据结构和方法的机制,这是类之间的一种关系,java中的类只支持单继承,接口支持多继承
4. 多态性(多形性):多态性是指相同的操作或方法、过程可作用于多种类型的对象上并获得不同的结果。不同的对象,收到同一消息可以产生不同的结果,这种现象称为多态性
5. 总结作用:封装可以隐藏实现细节,使得代码模块化;继承可以扩展已存在的代码模块(类);它们的目的都是为了——代码重用。而多态则是为了实现另一个目的——接口重用!多态的作用,就是为了类在继承和派生的时候,保证使用“家谱”中任一类的实例的某一属性时的正确调用。
iii. 面向对象(OO)基本特征
1. 封装(package)
2. 继承(inheritance)------关联关系
a) 继承(泛化generalize)
i. 实现继承
ii. 可视继承
b) 组合(聚合)
i. 接口继承
3. 多态(Polymorphism)
a) 重写(override)
i. 方法
ii. 接口(interface)
b) 重载(overload)
i. 同名函数
b) 类的声明和使用
i. 声明格式:
【修饰符】class【类名】{
方法体;
}
ii. 例1:
public static class Demo{
System.out.println();
}
c) 对象的声明与使用
i. 格式:类名 对象的引用变量 = new 类名();
ii. 例2:Demo d = new Demo();
d) 类与对象的比较
i. 类就是对象的模板,对象是类的实例
e) 构造方法
i. 定义:定义在类中,用来初始化对象的成员变量的方法,返回的是内存地址
ii. 格式:
1. 【修饰符】方法名(){}
2. 例3:public Demo(){}
iii. 要求:
1. 与类同名;2、没有返回值(无void 的修饰);必须要先创建对象,在对象上进行调用(new)
七、 UML
a) UML定义:(Unified Modeling Language)统一建模语言,一种用于面向对象的软件工程的分析与设计阶段的一种可视化建模语言
b) UML关系(类与类之间的关系):关联对属性,依赖对方法
i. 关联关系:菱形指向整体   has a
1. 关联关系------若在逻辑上A是B的“一部分”(a part of),则不允许B从A派生,而是要用A和其它东西组合出B
2. 聚合(aggregation)---实线空心菱形
3. 组合---整体与部分不可分开,实线实心菱形
ii. 泛化(Generalization)关系(继承):用实线空心三角形指向父类    is a
1. 若在逻辑上B是A的“一种”,并且A的所有功能和属性对B而言都有意义,则允许B继承A的功能和属性
iii. 实现关系(接口):虚线
iv. 依赖(Dependency)关系:  A”————>”B(A依赖于B)    use a  虚线箭头
c) 修饰符图形
i. +  public -   private #   protected ~  默认访问
d) 建模图形(9种):
i. 用例图(Use Case Diagram):展示系统外部的各类执行者与系统提供的各种用例之间的关系
ii. 类图(Class Diagram):展示系统中类的静态结构(类是指具有相同属性和行为的对象),类图用来描述系统中各种类之间的静态结构
iii. 对象图(Object Diagram):是类图中的一种实例化图(是对类图的实例化)
iv. 顺序图(时序图)序列图(Sequence Diagram):展示对象之间的一种动态协作关系(一组对象组成,随时间推移对象之间交换消息的过程,突出时间关系)
v. 协作图(合作图)(Collaboration Diagram):从另一个角度展示对象之间的动态协作关系(对象间动态协作关系,突出信息收发关系)
vi. 状态图(Statechart Diagram):描述一类对象具有的所有可能的状态及其转移关系(展示对象所具有的所有可能的状态以及特定事件发生时状态的转移情况)
vii. 活动图(Activity Diagram):展示系统中各种活动的执行流程(各种活动的执行顺序、执行流程)
viii. 构件图(Component Diagram):展示程序代码的物理结构(描述程序代码的组织结构,各种构件之间的依赖关系)
ix. 部署图(Deployment Diagram):展示软件在硬件环境中(特别是在分布式及网络环境中)的配置关系(系统中硬件和软件的物理配置情况和系统体系结构)
八、 自定义类
a) 类的定义:类是具有相同属性和相同操作的对象集合,类是对象的模板,一个类可以产生对个对象,产生单个对象的话就是单例模式,类是对现实世界中实体的抽象,对象是对现实世界中实体的实例
b) 类的组成:字段(成员变量)+方法+初始化块(静态初始化块+对象初始化块)
c) 命名规则:类名的首字母大写;变量名和方法名(构造方法除外)的首字母小写,采用骆驼名命名标识
d) 字段(实例变量+类变量(静态变量))的定义格式:
【修饰符(4p、static、final)】 数据类型 属性名【=默认值】;
e) 方法的定义格式:【修饰符(4p、static、final、abstract)】 返回值 方法名(【参数列表】){ 代码块;}
f) 初始化顺序:静态初始化块类变量,实例变量初始化对象初始化块和成员变量初始化(在程序代码中的先后顺序来定)构造方法
g) JavaBean规范:
i. 必须是公共类,并将其访问属性设置为public,如:public class Stu{}
ii. 必须有一个空的构造方法(public、无参):必须有一个不带参数的公共构造器
iii. 字段(实例变量)要私有化,首字母要小写,用private修饰 如:private int id;
iv. 字段应该通过一组存取方法(getter和setter)来访问,一般是用Eclipse、JBuilder、IDE等工具生成getter和setter方法
v. setter和getter规范:字段首字母小写------如:
1. public class Demo{
a) private String name;
b) public Demo(){}
c) public Demo(){
System.out.println(“不错”);
d) }
e) public void setName(String name){
this.name = name;
f) }
g) public String getName(){
return name;
h) }
}
九、 数组(一维数组、二维数组、排序、Arrays.sort)
a) 一维数组
i. 定义:数组就是相同类型元素的集合
ii. 数组变量是引用类型,栈stack(FILO,自动回收)引用堆heap(new出来的,树形结构,JVM回收)中的数据;
iii. 格式:int[] a = new int[3];
int[] a = {1,2,4};
iv. 使用for循环遍历输出,获得数组长度length,访问元素
For…each: 增强型for循环
for(String i:a){//增强型for循环System.out.println(i);}
//冒泡排序
public class SortTest {
 public void sort(int[] args){
    System.out.println("排序前 ");
for(int m : args){System.out.print(args[m]+",");}
  int time1 = 0,time2 = 0;
for(int i = 0 ; i < args.length-1 ; i++){for(int j = i+1 ; j < args.length ; j++){int temp ;if(args[i] > args[j]){temp = args[j];args[j] = args[i];args[i] = temp;}}}System.out.println();System.out.println("排序后 ");for(int n : args){System.out.print(n+",");}}public static void main(String[] args) {int[] arg = new int[]{2,1,4,5,8,7,6,3,9,0};new SortTest().sort(arg);}
}
b) 二维数组-----实质是一维数组引用另一维数组
i. 声明:Int[][] arr;//4个字节
ii. 创建时必须创建行,初始化就是对每个元素进行初始化,使用增强型for循环
十、 Object类
a) Object类是所有类的超类;
b) 常用方法:HashCode()----哈希值,如:
i. IntegertoHexString(p1.hashCode());//把哈希码的无符号十六进制转换成十进制
c) getClass()//获取运行时的类
d) toString()//返回字符,相当于getClass().getName()+”@”+Integer.toHexString(HashCode());
e) clone()//创建一个与源对象完全相同的对象,但新对相象与源对象不相等
i. 子类重写clone()要求:1、创建一个类A实现cloneable接口;2、重写Object的clone(),调用super.clone()
ii. 代码实现:如
public class Person implements Cloneable{
int as ;
protected Object clone() throws CloneNotSupportedException{Person p = (Person)super.clone();
}
}
public class PersonDemo{public static void main()throws CloneNotSupportedException{Person p = new Person();p.as=11;System.out.println(“Before clone”+p.as);Person p1 = (Person)p1.clone();p1.as=22;System.out.println(“After clone”+p.as);}}
十一、 包装类(Integer)
a) 常用方法:
i. Integer.MAX_VALUE();//获取int的最大值
ii. Integer.MIN_VALUE();//获取int的最小值
iii. toBinaryString()//转二进制
iv. toHexStrng()//转十六进制
十二、 抽象类
a) 抽象类的特点:
i. 抽象方法一定在抽象类中;
ii. 抽象方法和抽象类都必须被abstract关键字修饰;
iii. 抽象类不可以用new创建对象,因为调用抽象方法没意义;
iv. 抽象类中的方法要被使用,必须由子类复写起所有的抽象方法后,建立子类对象调用;
v. 如果子类只覆盖了部分抽象方法,那么子类还是一个抽象类
b) 格式:【访问控制符】class 类名{
属性;
访问控制符 返回类型 方法名(形参列表){
//方法体;【return 返回值】
}
访问控制符 abstract 返回类型 方法名(形参列表);
}
例:package b;
public class  AbstractDemo{
public static void main(String[] args){Chinese c = new Chinese();}
}
abstract class Chinese{
public abstract void show();
}
abstract class D{
public void show(){System.out.println("213");} 
}
十三、 接口(interface)--------不能实例对象,也就是不能new接口
a) 定义:当抽象类中的方法都是抽象的,那么该类可以通过接口的形式来表示
b) 格式:
1、 接口中常见定义:常量、抽象方法
2、 接口中的成员都有固定修饰符
常量:public static final
方法:public abstract
  接口中的成员都是public的
c) 接口不可以建立对象,需要被子类实现时,子类对接口中的抽象方法都覆盖后,才可以实例化,否则子类就是一个抽象类
接口支持多实现implements,但接口不能实现接口,可以继承(多继承)接口
d) 例子
public class InterfaceDemo{
public static void main(String[] args){SubInter si = new SubInter();System.out.println(si.NUM);System.out.println(SubInter.NUM);System.out.println(Inter.NUM);}
}
interface Inter{
public static final int NUM = 3;public abstract void show();
}
class SubInter implements Inter{//实现接口
public void show(){}
}
十四、 单例设计模式
a) 定义:是对同一种问题的固定解决方式,单例就是只创建一个对象
b) 想要保证对象唯一:1、为了避免其他程序过多建立该类对象,先控制其他程序建立该类对象;2、为了让其他程序可以访问,在本类中自定义该对象;3、为方便访问,提供访问方式
c) 使用场景:仅需要创建一个对象时
d) 定义步骤:
1、private 的构造方法
2、private static 的实例对象
3、public static外界访问方法
i. 代码实现:
1. 第一种:饿汉式-----先初始化
private int a;
private A(){};
private static A a = new A();
public static get(){
Return a;
}
2. 第二种:懒汉式----调用时初始化—延时加载
private int a;
private A(){};
private static A a = new A();
public static get(){
if(a==null){a == new A();
}
return a;
}
e) 好处:
i. 控制资源的使用
ii. 控制实例的产生数量
iii. 让多个不相关的两个线程或进程之间实现通信
十五、 package
a) 定义:就是把字段和方法包裹起来,并用一定的修饰符加以修饰从而达到对外信息隐藏,并暴露可以暴露的方法
b) Java.lang.*;--------基础包,默认导入
c) 要求:1、必须放在非注释的第一行;2、包名通常是域名的倒置,包名必须小写,不含关键字,不能以java、javax开头
d) 作用:1、便于管理;封装的需要;防止类名冲突
e) 包的导入用import关键字;
f) 常用包有; java.lang.annotation\java.net\java.nio\java.sql\java.util\javax.sql\
javax.xml\javax.swing
十六、 继承(extends)-----类与类之间是属于关系-----关联关系
a) 实现方式:继承(inheritance)和组合(composition)
i. 继承的实现方式有:实现继承、可视继承----------类与类之间是继承(泛化)关系
1. 实现继承是指使用基类的属性和方法而无需额外编码的能力;
2. 可视继承是指子窗口(类)使用基窗口(类)的外观和实现代码的能力;
ii. 组合(聚合关系):接口继承和纯虚类继承
1. 接口继承是指仅使用属性和方法的名称、但是子类必须提供实现的能力。
b) 初始化顺序:先父类静态初始化块--》子类静态初始化块---》父类的对象初始化块---》父类的构造方法--》子类的对象初始化块---》子类的构造方法,如:
package a;
public class  B extends A{
static{System.out.println("-------------4------------");}{System.out.println("-------------5------------");}public B(){System.out.println("-------------6------------");}public static void main(String[] args){B b = new B();new B();}
}
class A{
static{System.out.println("-------------1------------");}{System.out.println("-------------2------------");}public A(){System.out.println("-------------3------------");}
}
十七、 多态(向上转型)
a) 多态的坏处
i. 向上转型后,会丢掉子类的新方法
ii. 向上转型是安全的,但向下转型却是不安全的
iii. 例:
package a;
//向上转型------------打印的类型看右边
//缺点:损失掉了子类新增的方法、属性
public class A extends Super{
public void f(Super s){System.out.println(s);}public static void main(String[] args) {//Super a = new A();//a.A@82764b-----打印出A型变量//System.out.println(a);/*A a = new A();a.f(a);//a.A@82764b-------向上转型*///Super[] s = new Super[](new A(),new Super());//System.out.println(a.length);Super[] s = new Super[]{new A(),new Super()};System.out.println(s.length);Object o = new int[3];int[] b = (int[])o;System.out.println(b.length);//编译出错,损失掉了子类新增的方法、属性}
}
class Super{}
b) 后期绑定
i. 将一个方法调用同一个方法主体关联起来被称为绑定。若在程序执行前绑定,叫前期绑定,java中除了static和final方法,其他所有的方法都是后期
ii. Overload-----前期绑定--------静态绑定------编译阶段
Override-----后期绑定--------动态绑定------运行阶段
例:Super a = new subclass();//向上转型-------overload看左边,override看右边
c) 实现多态的方式
i. 重写override:指子类重新定义父类的方法的做法
ii. 重载(overload):是指允许存在多个同名函数,而这些函数的参数表不同(或许参数个数不同,或许参数类型不同,顺序或许两者都不同)
iii. 协变重写:子类方法可以比父类方法的返回类型更具体(子类的返回类型是父类方法返回类型的子类)
d) 只有普通方法具有多态,final、static、private方法不具备多态性
Field(域成员==字段)不具备多态性-----它们都是前期绑定----同变量的声明类型绑定
c) 设计原则:
1、开闭原则---对扩展开放,对修改封闭,实现关键在于抽象化
2、里氏代换原则---面向基类原则---任何基类可以出现的地方,子类一定可以出现
十八、 String(声明,创建,初始化,操作(比较equals/==,转换,查找,截取,分割,拆分,替换,连接))
a) 在java中使用的是unicode码;字符串的内存空间大小跟它的属性有关,String创建初始化时在JVM中数据流动,
b) 声明创建初始化
i. 格式:String 变量名 = 初始值;
ii. String 变量名 = new String(初始值);
c) 操作:
i. 比较(equals与==)
1. equals比的是内容,==比的是地址,equalsIgnoreCase()---忽略大小写
2. 例1:String d = “123”;
  String d1 = new String(“123”);
  System.out.println(d.equals(d1)); //true
System.out.println(d==d1);//false
ii. charAt(int index)------返回指定索引处的char值
iii. length()--------返回字符串的长度
iv. 转换
1. toString()------返回本身
2. toLowerCase()---将所有字符串转换为小写
3. toUpperCase()---将所有字符串转换为大写
v. 查找
1. indexOf(String key)------从前查找返回的第一个key的索引
2. indexOf(String key,int formindex)----返回从指定位置开始查找到的第一个key的索引
3. lastIndexOf()---------从后查找返回最后一个key的索引
vi. 截取
1. substring(int bindex,int eindex)----截取源字符串(begin,end)并返回一个新String
vii. 拆分
1. split(String regex)-----根据regex将源字符串进行分割成若干个新字符串
viii. 替换
1. replace(char oldchar,char newchar);
ix. 连接
1. + 或concat连接---在源字符串尾部连接新字符串,返回新字符串
2. “a“+”b”;
x. 创建对象
1. String str1 = "abc"; 
  System.out.println(str1 == "abc");
步骤: 
1) 栈中开辟一块空间存放引用str1, 
2) String池中开辟一块空间,存放String常量"abc", 
3) 引用str1指向池中String常量"abc", 
4) str1所指代的地址即常量"abc"所在地址,输出为true
2. String str2 = new String("abc"); 
  System.out.println(str2 == "abc");
步骤: 
1) 栈中开辟一块空间存放引用str2, 
2) 堆中开辟一块空间存放一个新建的String对象"abc", 
3) 引用str2指向堆中的新建的String对象"abc", 
4) str2所指代的对象地址为堆中地址,而常量"abc"地址在池中,输出为false
3. String str3 = new String("abc"); 
  System.out.println(str3 == str2);
步骤: 
1) 栈中开辟一块空间存放引用str3, 
2) 堆中开辟一块新空间存放另外一个(不同于str2所指)新建的String对象, 
3) 引用str3指向另外新建的那个String对象 
4) str3和str2指向堆中不同的String对象,地址也不相同,输出为false
4. String str4 = "a" + "b"; 
  System.out.println(str4 == "ab");
步骤: 
1) 栈中开辟一块空间存放引用str4, 
2) 根据编译器合并已知量的优化功能,池中开辟一块空间,存放合并后的String常量"ab", 
3) 引用str4指向池中常量"ab", 
4) str4所指即池中常量"ab",输出为true
5. final String s = "a"; 
  String str5 = s + "b"; 
  System.out.println(str5 == "ab");
步骤: 
同4
6. String s1 = "a"; 
  String s2 = "b"; 
  String str6 = s1 + s2; 
  System.out.println(str6 == "ab");
步骤: 
1) 栈中开辟一块中间存放引用s1,s1指向池中String常量"a", 
2) 栈中开辟一块中间存放引用s2,s2指向池中String常量"b", 
3) 栈中开辟一块中间存放引用str5, 
4) s1 + s2通过StringBuilder的最后一步toString()方法还原一个新的String对象"ab",因此堆中开辟一块空间存放此对象, 
5) 引用str6指向堆中(s1 + s2)所还原的新String对象, 
6) str6指向的对象在堆中,而常量"ab"在池中,输出为false
7. String str7 = "abc".substring(0, 2); 
  
步骤: 
1) 栈中开辟一块空间存放引用str7, 
2) substring()方法还原一个新的String对象"ab"(不同于str6所指),堆中开辟一块空间存放此对象, 
3) 引用str7指向堆中的新String对象,
8. String str8 = "abc".toUpperCase(); 
  步骤: 
1) 栈中开辟一块空间存放引用str6, 
2) toUpperCase()方法还原一个新的String对象"ABC",池中并未开辟新的空间存放String常量"ABC", 
3) 引用str8指向堆中的新String对象
十九、 this
a) this是只指向当前对象的指针;
b) 使用:
i. 如果用在构造方法中,表示当前构造方法正在初始化的对象,如:
1. Person p = new Person();
2. public Person(int id){
this.id = id;//相当于是p.id = id;
3. }
ii. 如果用在方法中,表示当前正在调用该方法的对象,如:
1. public show(int id){
this.id = id;//相当于是p.id = id;
2. }
------------p.show();
二十、 Static------数据共享
a) Static修饰符可以用于修饰类的成员变量和方法-----只在类加载时加载一次
i. 修饰成员变量时,该变量成为类变量或静态变量,隶属于类,类的所有对象共享同一个静态变量(生命周期长,类加载时确立,保存在方法区中)
ii. 修饰方法时,该方法成为类方法或静态方法,可以直接用类名.方法名()调用,也可以使用创建对象后通过对象引用名.方法()调用
iii. 静态方法不能访问非静态方法:
1. 静态方法也称类方法,它在调用时直接使用类名.方法来调用;非静态方法在调用时必须先创建对象,在对象上调用,格式为:对象名.方法名();
2. 在静态方法被调用时可能没有实例对象,也就无法调用非静态方法
二十一、 区别与联系:
a) break与continue与return
i. continue和break都可以结束本轮循环,但continue结束本轮后继续下一轮循环,break则直接跳出循环
ii. break可以用在多重循环中用来跳出离它最近的循环,也可以用在多分支语句swtich中用来跳出循环
iii. continue只能用在循环语句中,用于结束本轮循环,执行下一次循环;
iv. continue与break之后的语句都不执行
v. return是终止方法并返回数据,在方法体内return后的语句都不执行
b) 类变量(static)、实例变量、局部变量
i. 定义:类变量和实例变量定义在类中方法外,局部变量定义在方法内、形参、代码块中
ii. 修饰符:类变量必须要用static修饰,实例变量不用static修饰,类变量和实例变量可以不赋值,局部变量必须要先初始化
iii. 使用:类变量调用格式为:类名.变量名;实例变量调用时必须要先创建实例对象,在该对象上调用(对象.变量名);局部变量可以直接使用
iv. 加载:类变量(栈中)在类加载时加载,类结束时结束;实例变量(堆中)在对象调用时加载,调用结束时结束;局部变量(栈中)在方法开始调用时开始,方法结束时结束
c) this与super
i. 操作属性--------this.属性:表示调用本类中的属性,如果本类中的属性不存在,则从父类开始查找;super.属性:表示调用父类中的属性
ii. 操作方法--------this.方法():表示调用本类中的方法,如果本类中的方法不存在,则从父类开始查找;super.方法():表示调用父类中的方法;
iii. 调用构造方法----this();调用本类中的其他构造方法,super():表示调用父类的构造方法
iv. 查找范围---------this先从子类查找,如果没有从父类查找,super不查子类直接查父类;
v. 特殊:this可以表示当前对象
d) String与StringBuffer、StringBuilder
i. String是不可变的对象,每次对String类型进行改变都相当于产生了一个新的对象,StringBuffer是可变长度的字符序列,修改后不会产生新对象
ii. StringBuffer的实质是它有容量这个属性,默认容量为16,当初始化长度大于16时,其容量为初始化长度的2倍。
iii. String操作字符的方法有”+”、concat;StringBuffer操作字符的方法有insert、append、delete(开始int,endint)
iv. 初始化格式:
1. String st = “234”; String s = new String();
2. StringBuffer sb = new StringBuffer();
v. StringBuffer与StringBuilder都是可变长度的字符序列,在多线程中,前者是安全的,后者是不安全的
e) equals与==
i. 如果是基本类型比较,那么只能用==来比较,不能用equals;

ii. 对于基本类型的包装类型,比如Boolean、Character、Byte、Short、Integer、Long、Float、Double等的引用变量,==是比较地址的,而equals是比较内容的;

iii. 在String或重写equals方法的类中:equals是比内容,==是比地址
iv. 在其他类中没有重写equals方法时,equals与==用法相同,都是比地址
f) 重载与重写
i. 重载与重写都是类的多态表现形式,重载是一个类的多态表现形式,重写是子类继承父类的多态表现形式,重载与重写都是针对方法;
ii. 重载要求同名不同参数列表(类型、个数、顺序),与返回类型无关,重写要求同名同参数列表(类型、个数、顺序),同返回类型(协同----引用数据类型,是其子类或相同,基本数据类型是相同),访问修饰符大于或等于父类,抛出异常要小于或等于父类(当抛出的异常是RuntimeException时,则都可以编译通过)
iii. 重载可以用在构造方法和普通方法中,重写只能用在普通方法中
g) Integer与int
i. 类型:int是基本数据类型,Integer是引用数据类型;
ii. Integer是对int的包装,属于包装类;
iii. 默认值:int的默认值是0,Integer的默认值是null.
h) 类、抽象类、interface
1、抽象类需要有abstract修饰,类则不需要
2、抽象类中可以有普通方法和抽象方法,但普通类中只能有普通方法
3、 抽象类和普通类都可以继承,但抽象类的子类必须重写其父类的所有抽象方法,而普通类则不要求
4、抽象类不能被实例化,普通类可以被实例化
5、接口是抽象类的抽象,接口中只能有抽象方法和常量,接口支持多继承,不含有构造方法和初始化块
i) final、finally与finalize
i. final用于声明属性方法和类,分别表示:属性不可变,方法不可覆盖,类不可继承
ii. finally是异常处理语句的一部分,表示总是执行
iii. finalize是Object的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法。
二十二、 不能共存的
a) super()与this():都必须放在方法的非注释第一行
b) final与abstract:一个最终的,一个是抽象的
c) abstract与private
 

 一、内部类(局部内部类、成员内部类、匿名内部类)

1、定义:内部类就是在类的内部定义一个类,它的分类有成员内部类、局部内部类、匿名内部类,
它可以定义在类中方法外,也可以定义在类中方法内,内部类的好处是可以访问外部类的私有成员,但外部类无法访问内部类的私有成员
通过使用内部类可以确保程序的结构清晰和代码精炼

编译后的内部类名称:InnerTest$A.class

2、分类:成员内部类(静态成员内部类)、局部内部类、匿名内部类
a、成员内部类(非静态内部类):与外部类的属性和方法并列,成员内部类可以看作是外部类的实例变量
在内部类中访问实例变量:this.字段;
在内部类中访问外部类的实例变量:外部类名.this.字段
成员内部类中不能有静态字段或方法(final修饰的常量除外),因为Static在加载时就创建,此时内部类可能还没被实例化
在外部类的外部实例化对象:
Foo foo = new Foo();
Koo koo = foo.new Koo();
Foo.Koo koo = new Foo().new Koo();

b、静态内部类
静态内部类可以直接访问外部类的静态成员,不能访问外部类的实例成员,但可以通过外部类的实例(new 对象)来访问
静态内部类里面可以定义静态成员(其他内部类不可以)
静态内部类不可以使用private修饰
静态内部类的对象可以直接生成
Foo.Koo koo = new Foo().new Koo();
c、局部内部类
在方法中定义的内部类称为局部内部类,类似局部变量,不可以加修饰符public、protected、private,其范围为定义它的代码块
可以访问外部类的所有成员,还可以访问所在方法中的final修饰的参数和变量,但不能访问方法体中的局部变量
d、匿名内部类
匿名内部类没有类名,它必须继承一个类或者实现一个接口,并且不能显示的extends或implements关键字
匿名内部类不能有构造方法,因为它没有类名。可以通过new<父类名>的方法创建实例对象,匿名类的创建与定义同时进行
匿名内部类只能一次性的创建其对象
匿名内部类既可以在方法体中,也可以在参数列表中
注意:匿名内部类一定是在new的后面隐含实现一个接口或继承一个类,匿名内部类不是抽象类
      匿名内部类必须实现他的父类抽象接口或接口里的所有的抽象方法
new 父类的构造器(实参列表)|实现接口(){
//类体
}
new Object(){
}

3、内部类的访问规则:内部类可以直接访问外部类中的成员,包括私有
                    最近的外部类要访问内部类必须建立内部类对象new Inner().fumction()来访问内部类中的成员
               如: Outer.Inner in = new Outer().new Inner();
                    in.function();

4、使用:当描述事物时,事物的内部还有事物,该事物用内部类来描述,因为内部事物在使用外部事物的内容。
内部类定义在局部时,不能使用成员修饰符、static修饰,使用时需要new—
可以直接访问外部类中的成员,但不可访问它所在的局部中的变量,只能访问被final修饰的局部变量

5、代码分析:例1:----分类
public class Demo2 {
class B{//成员内部类------Demo2$B.class
}
static class A{//静态成员内部类------Demo2$A.class
}
void show(){
class C{//局部内部类-------Demo2$1C.class
}
}
public static void main(String[] args) {
class C{//局部内部类----Demo2$2C.class
}
System.out.println();
}
}

 

例2:-----匿名内部类

1、  匿名内部类其实就是内部类的简写格式
2、  定义前题必须继承一个类或实现一个接口
3、  匿名内部类的格式: new 父类或接口(){定义子类的内容}
4、  匿名内部类定义的方法最好不要超过三个

public class Test{
       public static void main(String[] agrs){
              Test t=new Test();   //new了 一个Test对象
              t.te(new A(){                //调用实例方法并且声明一个匿名内部类类作为一个参数传入
                            public void as(){
                                   System.out.println("我是实现了接口A的匿名类");
                            }
                     }
              );
      }         
      void te(A a){    //实例方法
              a.as();
      }
}
interface A{    //声明了一个接口类
       void as();    //抽象方法
}

 

例3:
class A{
       void as(){
              System.out.println("我是内部类A");
       }
}
class B{
       void bs(){
              System.out.println("我是内部类B");
       }
}
public class MultipleExtends {
       private class C extends A{}
       private class D extends B{}
       public static void main(String[] args) {
              MultipleExtends m=new MultipleExtends(); //声明一个外部类的对象
              MultipleExtends.C c=m.new C(); //让外部类对象持有一个
              MultipleExtends.D d=m.new D();//内部类对象的引用
              c.as();                                                                                                                          
              d.bs();                                                                                                                          
       }
}


例4:-----内部类是可以被私有的
public class MemberClass {
   private int i=10;  //定义一个私有字段
    private static int j=20;      
    public static void main(String[] args) {
MemberClass mc=new MemberClass();//new 一个外部类的对象
A a=mc.new A();//A a=new MemberClass().new A();//new 一个内部类的对象
a.as();//调用内部类的实例方法
    }
private class A{
//static int j=6;
//int i=5;              //定义一个内部类的实例字段    
void as(){     //定义一个内部类的实例方法
System.out.println("这里是内部类A");   
System.out.println("调用外部类私有实例字段i:"+i);
System.out.print("调用外部类私有静态字段j:"+j);
}
}
}

//---------- java ----------
//这里是内部类A
//调用外部类私有实例字段i:10
//调用外部类私有静态字段j:20

 


例5:----静态内部类
public class StaticClass {         
       private static int i=10; //定义一个私有静态字段
       //private int j=7;
       public static void main(String[] args) {
              StaticClass sc=new StaticClass();//new 一个外部类的对象
              A a=new StaticClass.A(); //new 一个静态内部类
              a.as();            //调用静态内部类的实例方法
              A.at        //调用静态内部类的静态方法
       }
       static class A{       
              int i=5;
              static at(){   //定义静态内部类的静态方法
                     System.out.println("这里是静态内部类的静态方法");
              }
              void as(){                 //定义静态内部类的实例方法
                     System.out.println("这里是内部类A");
                     System.out.print("调用外部类私有静态字段i:"+i);
              }
       }
}

 
例6:------局部内部类
public class InteriorClass {
         private int i=5;
         public static void main(String[] args) {
                   InteriorClass ic=new InteriorClass();   //new 一个对象
                   ic.as();             //调用实例方法
                   //      B b=ic.new B();
         }
         void as(){
                   final int y=5;        //常量       
                   int u=1;            //局部变量
                   class B{
                            void bs(){
                                     System.out.println("这里是内部类B");        
                                     System.out.println("调用i"+i);
                                     System.out.println("常量"+y);
                            }                          
                   }
                   new B().bs();
         }
}

----------------------------------------------------------------------|----------------------------------------------------------------------|
----------------------------------------------------------------------|----------------------------------------------------------------------|
----------------------------------------------------------------------|----------------------------------------------------------------------|

二、异常(try\catch\fainlly\throw\throws)
i、 异常的含义和分类
  a)含义:异常是对问题的描述,将问题进行问题的封装
  b)分类:java.lang.Object-----Throwable(java中所有错误和异常的超类)-----Error(无法通过代码来处理的错误)        
                                            |---------------Exception(可处理的异常,并能恢复运行)
     |---RuntimeException(运行时异常)---可以不捕获也可以不处理
     |----CheckedException(已检查时异常)----必须捕获或处理不然编译失败---IOException\SQLException
 标签(Marker)接口:既无字段又无方法---Cloneable/Serializable/EventListener

 Error----如:JVM硬件错误----OutOfMemoryError—内存不足、不断的创建实例、StackOverflowError---递归导致的堆异常
 
 2、异常分类(Throwable)
  1、编译时被检测的异常
     throws 需要处理
  2、编译时不被检测的异常---运行时异常(RuntimeException或其子类)
    函数内throw,函数外不需要声明,--------无法处理,需要修改代码

ii、 异常处理
a)RuntimeEception及其子类异常,不需要程序员处理,其后语句不编译
b)非运行时异常必须处理
c)Exeception中有一个特殊的子类异常RuntimeException,如果在方法内抛出该异常,方法上可以不用声明,编译可以通过;如果在方法上声明了该异常,调用者可以不用处理,编译可以通过。之所以不在函数声明,是因为不希望让使用者处理,当异常发生时,希望程序停止,程序员修正程序代码

异常的捕获和处理

第一种格式:
try{
         //可能抛出异常的语句
}catch(异常类型 e){
         //处理语句1
} catch(异常类型 e){
         //处理语句2
}finally{
         //一定执行的语句
}

finally只要用于异常处理,修饰异常块,无论异常是否处理都会执行
finally在return、throw前输出,不管return是在try还是catch中
finally定义一定执行的代码,通常用于关闭资源------如:数据库关闭连接

finally块在以下情况将不会被执行:
(1)finally块中发生了异常;
(2)程序所在线程死亡;
(3)在前面的代码中用了System.exit(0);
(4)关闭CPU。

第二种格式:
try{

}finally{

}

第三种格式:
try{

}catch(){

}

 
iii.在多个catch时只执行一个,自上而下遇到的第一个异常所对应的catch,如果没有对应的catch,则先执
行finally后在抛出,没有finally则直接抛出,定义多个catch可精确地定位异常。如果为子类的异常定
义了特殊的catch块,而父类的异常则放在另外一个catch块中,此时,必须满足以下规则:子类异常的处
理块必须在父类异常处理块的前面,否则会发生编译错误。所以,越特殊的异常越在前面处理,越普遍的
异常越在后面处理。这类似于制订防火墙的规则次序:较特殊的规则在前,较普通的规则在后。

throws--------声明方法抛出异常
1、说明:当不知道在当前代码中如何处理的时候,可以选择用throws将异常交给上层调用者处理
2、基本格式:
类型 方法名(形参列表)throws 异常列表(逗号隔开){
          //代码
}

例:
//手工抛出异常实例
public class JavaThrow1{
         public static void main(String[] args){
                   System.out.print(" Now");
                   try{
                            System.out.print(" is");
                            throw new NullPointerException();//直接抛出异常转到catch进行处理
                            //System.out.println("This will not excute!");//有throw这句执行不到
                   }catch (NullPointerException e){
                            System.out.print(" the");
                   }
                   System.out.print(" time.\n");
         }
}

//自动抛异常
public class ExTest {
public static void main(String[] args){
String s=null;
try{
System.out.println("0");
int i=s.length();//自动抛异常--空指针异常
System.out.println("2");
}finally{
System.out.println("1");
}
}
}

例:--------throws
public class ExceptionTest4{
public static void p() throws ArithmeticException{
//间接抛出异常,自己并未处理,让方法的调用者来处理
int i;
i=4/0;//可能发生异常
System.out.println("8");
}
  public static void main(String[] args){    
try{ 
try{
                p();//方法的直接调用调用者捕获异常处理
}catch(ArithmeticException e){
System.out.println("Divider is zero !");
}
}catch(RuntimeException  e){
              System.out.println("4");
}
  }
}

v.java异常处理机制

答:程序出现想数组角标越界,空指针等错误时,JAVA就会用异常Throwable 
来描述这些错误,Throwable继承了Object类,同时实现了Serializable接口,
根据出现的问题是否可以通过程序来解决。把Throwable分为Error错误和Exception异常,Exception根据编译时是否会被检
测分为运行时异常RuntimeException和已检测异常CheckedException。异常的处理方
式有两种,在发生异常的地方直接使用catch处理,或者将异常抛出给调用者,让调用者来处理。

 1、检查性异常------程序正确,但因为外在的环境条件不满足引发。例如:用
户错误及I/O问题----程序试图打开一个并不存在的远程Socket端口。这不是程序
本身的逻辑错误,而很可能是远程机器名字错误(用户拼写错误)。对商用软件系统,
程序开发者必须考虑并处理这个问题。JAVA编译器强制要求处理这类异常,如果不
捕获这类异常,程序将不能被编译。
  2、运行期异常------这意味着程序存在bug,如数组越界,0被除,入参不满足规
范.....这类异常需要更改程序来避免,JAVA编译器强制要求处理这类异常。
  3、错误------一般很少见,也很难通过程序解决。它可能源于程序的bug,但一般
更可能源于环境问题,如内存耗尽。错误在程序中无须处理,而有运行环境处理。


三、 自定义异常
当jdk内置异常类型不能满足系统需求时,我们需要自定义异常,如:
public class MyExceptionTest {
         public static void main(String[] args) {
                  MyExceptionTest mt = new MyExceptionTest();
                  mt.manager();
         }

         public void registe(int num) throws MyException{
                  if(num<0){
                           throw new MyException("人数为负数",3);
                  }
                  System.out.println(" 登记人数为:"+num);
         }

         public void manager(){
                  try{
                           registe(-100);
                  }catch (MyException e){
                           System.out.println("登记类型出错:"+e.getId());
                           e.printStackTrace();
                  }       
                  System.out.println(" 操作结束!");
         }
}
class MyException extends Exception{
         private int id;
         public MyException(){}
         public MyException(String message,int id){
                  super(message);//调用父类的getMessage()
                  //父类中已经定义了getMessage()可以直接使用-----------该方法为Exception继承Throwable的
                  this.id=id;
         }
         public int getId(){
                  return id;
         }
}

自定义异常类必须要继承Exception/RuntimeException,如果该异常的发生无法再继续进行运算,就让它继承RuntimeException 
继承的原因是为了让该类自定义类具备可抛型,让该类具备操作异常的共性方法
自定义异常:按照JAVA的OO思想,将程序中出现的特有问题进行封装

四、常见异常
IOException--------------------输入输出异常
ClassNotFoundException-------找不到类异常
NumberFormatException---------字符串到数字格式的异常
FileNotfoundException-----------文件找不到异常
NoSuchMethodException---------------请求方法异常

运行时异常:RuntimeException
SecurityException-----------试图违反安全性异常
NullPointerException----没有实例化却调用其属性和方法--------------空指针异常
ArrayIndexOfBoundsException---------数组越界异常
StringIndexOfBoundsException---------字符串越界异常
ArithmeticException--------------算数异常/除数为零异常
NullPointerException-------试图查找null异常


Main方法通常情况下不能把异常抛给JVM

Super a = new subclass();//向上转型----
---overload看左边,override看右边
-----------------------------------多态针对的是方法
 

异常的好处:1、将问题进行封装
            2、将正常流程代码和问题代码进行分离,方便阅读

处理原则:
1、处理方式有:try或者throws
2、调用到抛出异常的功能时,抛出几个处理几个(一个try对应多个catch)
3、多个catch,父类的catch放到最后
4、Catch内,需要定义针对性的处理方式,不要简单的定义printStackTrace输出语句,也不要不写
5、当铺获到的异常,本功能处理不了时,可以继续在catch中抛出

6、  例:
try{
throw new AException();
}catch(AException e){
throw e;
}

7、如果异常在内部被处理(catch),外部则不需要抛出

基本格式:catch用来处理异常,如果该异常为检测时异常时,必须要处理或者抛出
异常继承时,子类只能抛出父类的异常或者该异常的子类/子集异常,也可以不抛出异常

异常的注意事项
1、在子父类覆盖时,
a)子类抛出的异常必须是父类异常的子类或子集
b)如果父类或接口没有异常抛出时,子类覆盖出现异常,只能try不能抛
c)如果父类中是RuntimeException时,子类可以不用抛出异常,反之,子类为RuntimeException异常,父类为其异常的子类或自己都可以编译通过

1、throw 与throws
throw 后跟异常对象(只能有一个),throws后跟异常类(多个时用逗号隔开);
位置:throw用在方法体中,代表手工抛异常,throws用在方法声明上,代表该方法可能发生异常

2、RuntimeException和CheckedException的区别
前者可以不在方法上声明也可以不处理,后者必须要处理或者抛出

----------------------------------------------------------------------|----------------------------------------------------------------------|
----------------------------------------------------------------------|----------------------------------------------------------------------|
----------------------------------------------------------------------|----------------------------------------------------------------------|
                                                                                                                                                                                                                                                                                                                                                                                                                     
三、集合(collection、set、list、map)

一、定义:
集合是Java里面最常用的,也是最重要的一部分。能够用好集合和理解好集合对于做Java程序的开发拥有无比的好处。
容器:用来存储数据,不同的容器集合以不同的格式保存对象,它能够自动的改变这个容器的所能存放的数据数量的大小。这一点上,如果使用数组来存储的话,就显得十分的笨拙。
对于对象集合,必须执行的操作主要以下三种:
?       添加新的对象
?       删除对象
?       查找对象
Java容器类类库的用途是“保存对象”,并将其划分为两个不同的概念:
1)  Collection 。 一组对立的元素,通常这些元素都服从某种规则。List必须保持元素特定的顺序,而Set 不能有重复元素。
2)  Map 。 一组 成对的“键值对”对象。

? Collection – 对象之间没有指定的顺序,允许重复元素。
? Set –  对象之间没有指定的顺序,不允许重复元素
? List–  对象之间有指定的顺序,允许重复元素,并引入位置下标。 
? Map –  接口用于保存关键字(Key)和数值(Value)的集合,集合中的每个对象加入时都提供数值和关键字。Map 接口既不继承 Set 也不继承 Collection。 
List、Set、Map共同的实现基础是Object数组


Collection
1.2.1常用方法
Collection 接口用于表示任何对象或元素组。想要尽可能以常规方式处理一组元素时,就使用这一接口。Collection 在前面的大图也可以看出,它是List和Set 的父类。并且它本身也是一个接口。它定义了作为集合所应该拥有的一些方法。如下:
注意:
集合必须只有对象,集合中的元素不能是基本数据类型。
Collection接口支持如添加和除去等基本操作。设法除去一个元素时,如果这个元素存在,除去的仅仅是集合中此元素的一个实例。
?     boolean add(Object element) 
?     boolean remove(Object element) 
Collection 接口还支持查询操作:
?     int size() 
?     boolean isEmpty() 
?     boolean contains(Object element) 
?     Iterator iterator() 
组操作 :Collection 接口支持的其它操作,要么是作用于元素组的任务,要么是同时作用于整个集合的任务。
?     boolean containsAll(Collection collection) 
?     boolean addAll(Collection collection) 
?     void clear() 
?     void removeAll(Collection collection) 
?     void retainAll(Collection collection) 
containsAll() 方法允许您查找当前集合是否包含了另一个集合的所有元素,即另一个集合是否是当前集合的子集。其余方法是可选的,因为特定的集合可能不支持集合更改。 addAll() 方法确保另一个集合中的所有元素都被添加到当前的集合中,通常称为并。 clear() 方法从当前集合中除去所有元素。 removeAll() 方法类似于 clear() ,但只除去了元素的一个子集。 retainAll() 方法类似于 removeAll() 方法,不过可能感到它所做的与前面正好相反:它从当前集合中除去不属于另一个集合的元素,即交。
 
集合类的基本方法的使用:
import java.util.*;
public class CollectionToArray {
public static void main(String[] args) {
Collection collection1=new ArrayList();//创建一个集合对象
collection1.add("000");//添加对象到Collection集合中
collection1.add("111");
collection1.add("222");
System.out.println("集合collection1的大小:"+collection1.size());
System.out.println("集合collection1的内容:"+collection1);
collection1.remove("000");//从集合collection1中移除掉 "000" 这个对象
System.out.println("集合collection1移除 000 后的内容:"+collection1);
System.out.println("集合collection1中是否包含000 :"+collection1.contains("000"));
System.out.println("集合collection1中是否包含111 :"+collection1.contains("111"));
Collection collection2=new ArrayList();
collection2.addAll(collection1);//将collection1 集合中的元素全部都加到collection2中
System.out.println("集合collection2的内容:"+collection2);
collection2.clear();//清空集合 collection1 中的元素
System.out.println("集合collection2是否为空 :"+collection2.isEmpty());
//将集合collection1转化为数组
Object s[]= collection1.toArray();
for(int i=0;i<s.length;i++){
System.out.println(s[i]);
}
}
}
运行结果为:
集合collection1的大小:3
集合collection1的内容:[000, 111, 222]
集合collection1移除 000 后的内容:[111, 222]
集合collection1中是否包含000 :false
集合collection1中是否包含111 :true
集合collection2的内容:[111, 222]
集合collection2是否为空 :true
111
222
这里需要注意的是,Collection 它仅仅只是一个接口,而真正使用的时候,却是创建该接口的一个实现类。作为集合的接口,它定义了所有属于集合的类所都应该具有的一些方法。
而ArrayList (列表)类是集合类的一种实现方式。
 
Collection的实现基础是数组,所以有转换为Object数组的方法: 
?     Object[] toArray() 
?     Object[] toArray(Object[] a)
其中第二个方法Object[] toArray(Object[] a) 的参数 a 应该是集合中所有存放的对象的类的父类

1.2.2  迭代器(Iterator)
迭代器(Iterator)本身就是一个对象,它的工作就是遍历并选择集合序列中的对象,而客户端的程序员不必知道或关心该序列底层的结构。此外,迭代器通常被称为“轻量级”对象,创建它的代价小。但是,它也有一些限制,例如,某些迭代器只能单向移动。
Collection 接口的 iterator() 方法返回一个 Iterator。Iterator 和Enumeration 接口类似。使用 Iterator 接口方法,可以从头至尾遍历集合,并安全的从底层 Collection 中除去元素。
迭代器的使用:
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
 
public class IteratorDemo {
public static void main(String[] args) {
Collection collection = new ArrayList();
collection.add("s1");
collection.add("s2");
collection.add("s3");
Iterator iterator = collection.iterator();//得到一个迭代器
while (iterator.hasNext()) {//遍历
Object element = iterator.next();
System.out.println("iterator = " + element);
}
if(collection.isEmpty())
System.out.println("collection is Empty!");
else
System.out.println("collection is not Empty! size="+collection.size());
Iterator iterator2 = collection.iterator();
while (iterator2.hasNext()) {//移除元素
Object element = iterator2.next();
System.out.println("remove: "+element);
iterator2.remove();
}
Iterator iterator3 = collection.iterator();
if (!iterator3.hasNext()) {//察看是否还有元素
System.out.println("还有元素");
}
if(collection.isEmpty())
System.out.println("collection is Empty!");
//使用collection.isEmpty()方法来判断
}
}
程序的运行结果为:
iterator = s1
iterator = s2
iterator = s3
collection is not Empty! size=3
remove: s1
remove: s2
remove: s3
还有元素
collection is Empty!
可以看到,Java的Collection的Iterator 能够用来,:
1)使用方法 iterator() 要求容器返回一个Iterator .第一次调用Iterator 的next() 方法时,它返回集合序列的第一个元素。
2)使用next() 获得集合序列的中的下一个元素。
3)使用hasNext()检查序列中是否元素。
4)使用remove()将迭代器新返回的元素删除。
需要注意的是:方法删除由next方法返回的最后一个元素,在每次调用next时,remove方法只能被调用一次 。

1.3 List
1.3.1概述
Collection接口实际上并没有直接的实现类。而List是容器的一种,表示列表的意思。当我们不知道存储的数据有多少的情况,
我们就可以使用List 来完成存储数据的工作。例如保存一个应用系统当前的在线用户的信息。List的最大的特点就是能够自动
的根据插入的数据量来动态改变容器的大小。

1.3.2  常用方法
List 就是列表的意思,它是Collection 的一种,即继承了 Collection 接口,又定义一个允许重复项的有序集合。该接口不但
能够对列表的一部分进行处理,还添加了面向位置的操作。List 是按对象的进入顺序进行保存对象,而不做排序或编辑操作。它
除了拥有Collection接口的所有的方法外还拥有一些其他的方法。面向位置的操作包括插入某个元素或 Collection 的功能,还
包括获取、除去或更改元素的功能。在 List 中搜索元素可以从列表的头部或尾部开始,如果找到元素,还将报告元素所在的位置。

1、 void add(int index, Object element):添加对象element到位置index上
2、 boolean addAll(int index, Collection collection):在index位置后添加容器collection中所有的元素
3、 Object get(int index) :取出下标为index的位置的元素
4、 int indexOf(Object element) :查找对象element 在List中第一次出现的位置
5、 int lastIndexOf(Object element) :查找对象element 在List中最后出现的位置
6、 Object remove(int index) :删除index位置上的元素
7、 Object set(int index, Object element) :将index位置上的对象替换为element 并返回老的元素。

List(提供基于索引的对成员的随机访问)------ArrayList-----提供快速的基于索引的成员访问,对尾部成员的增加和删除支持较好
  成员可为任意Object子类的对象
----------LinkedList-----对列表中任何位置的成员的增加和删除支持较好,但对基于索引的成员访问支持性能较差
  成员可为任意Object子类的对象 
         
在“集合框架”中有两种常规的 List 实现:ArrayList 和 LinkedList。使用两种 List 实现的哪一种取决于您特定的需要。如果要
支持随机访问,而不必在除尾部的任何位置插入或除去元素,那么,ArrayList 提供了可选的集合。但如果,您要频繁的从列表的中间
位置添加和除去元素,而只要顺序的访问列表元素,那么,LinkedList 实现更好。

LinkedList 来实现一个简单的队列的例子:
import java.util.*;
 
public class ListExample {
  public static void main(String args[]) {
    LinkedList queue = new LinkedList();
    queue.addFirst("Bernadine");
    queue.addFirst("Elizabeth");
    queue.addFirst("Gene");
    queue.addFirst("Elizabeth");
    queue.addFirst("Clara");
    System.out.println(queue);
    queue.removeLast();
    queue.removeLast();
    System.out.println(queue);
  }
}
运行程序产生了以下输出。请注意,与 Set 不同的是 List 允许重复。
[Clara, Elizabeth, Gene, Elizabeth, Bernadine]
[Clara, Elizabeth, Gene]
该的程序演示了具体 List 类的使用。第一部分,创建一个由 ArrayList 支持的 List。填充完列表以后,特定条目就得到了。示例
的 LinkedList 部分把 LinkedList 当作一个队列,从队列头部添加东西,从尾部除去。

List 接口不但以位置友好的方式遍历整个列表,还能处理集合的子集:
ListIterator listIterator() :返回一个ListIterator 跌代器,默认开始位置为0
ListIterator listIterator(int startIndex) :返回一个ListIterator 跌代器,开始位置为startIndex 
List subList(int fromIndex, int toIndex) :返回一个子列表List ,元素存放为从 fromIndex 到toIndex之前的一个元素。
处理 subList() 时,位于 fromIndex 的元素在子列表中,而位于 toIndex 的元素则不是,提醒这一点很重要。

for-loop :
for (int i=fromIndex; i<toIndex; i++) {
  // process element at position i
}

对子列表的更改(如 add()、remove() 和 set() 调用)对底层 List 也有影响。


我们看一个List的例子:
import java.util.*;
 
public class ListIteratorTest {
public static void main(String[] args) {
List list = new ArrayList();
list.add("aaa");
list.add("bbb");
list.add("ccc");
list.add("ddd");
System.out.println("下标0开始:"+list.listIterator(0).next());//next()
System.out.println("下标1开始:"+list.listIterator(1).next());
System.out.println("子List 1-3:"+list.subList(1,3));//子列表
ListIterator it = list.listIterator();//默认从下标0开始
//隐式光标属性add操作 ,插入到当前的下标的前面
it.add("sss");
while(it.hasNext()){
System.out.println("next Index="+it.nextIndex()+",Object="+it.next());
}
//set属性
ListIterator it1 = list.listIterator();
it1.next();
it1.set("ooo");
ListIterator it2 = list.listIterator(list.size());//下标
while(it2.hasPrevious()){
System.out.println("previous Index="+it2.previousIndex()+",Object="+it2.previous());
}
}
}
程序的执行结果为:
下标0开始:aaa
下标1开始:bbb
子List 1-3:[bbb, ccc]
next Index=1,Object=aaa
next Index=2,Object=bbb
next Index=3,Object=ccc
next Index=4,Object=ddd
previous Index=4,Object=ddd
previous Index=3,Object=ccc
previous Index=2,Object=bbb
previous Index=1,Object=aaa
previous Index=0,Object=ooo
我们还需要稍微再解释一下 add() 操作。添加一个元素会导致新元素立刻被添加到隐式光标的前面。因此,添加元素后调用 
previous() 会返回新元素,而调用 next() 则不起作用,返回添加操作之前的下一个元素。下标的显示方式,如下图所示:

1.3.3实现原理
ArrayList中主要包含2个属性:
private transient Object elementData[];
private int size;
其中数组::elementData[] 是列表的实现核心属性:数组。 我们使用该数组来进行存放集合中的数据。而我们的初始化参数就
是该数组构建时候的长度,即该数组的length属性就是initialCapacity 参数。

Keys:transient 表示被修饰的属性不是对象持久状态的一部分,不会自动的序列化。

如果要判断一个类的一个实例对象是否等于另外一个对象,那么我们就需要自己覆写Object类的public boolean equals(Object obj)
 方法。如果不覆写该方法的话,那么就会调用Object的equals()方法来进行判断。这就相当于比较两个对象的内存应用地址是否相等了。
在集合框架中,不仅仅是List,所有的集合类,如果需要判断里面是否存放了的某个对象,都是调用该对象的equals()方法来进行处理的。

集合的个数用size();数组用length;String用length();

Collection<E> extends Iterable

方法:
增          add();addAll()---------boolean
删          remove();removeAll();------------boolean
                 clear()-------void
查          Iterator<E>()--------Iterator
改          toArray()-----Object   数组
元素数      size()--------------int

List<E>  extends Collection<E>----------有序的Collection,可重复

新增方法:
add(int index, E element)//在指定位置添加---------添加顺序要是连续的
get(int index)//返回指定位置
listIterator(int index)//从指定位置开始迭代

AbstractList<E> extends AbstractCollection<E> implements List<E>

Set<E>
无序的不可重复的Collection

Map<K,V>
键K不可以重复,值V可以重复

ArrayList------------在查询时快,增删改时慢

例:
import java.util.*;
//注解
//@SuperessWarnings("unchecked")---------

public class Demo{
public static void main(String[] args) {
List<Object> alist = new ArrayList<Object>();//List是接口,不能被实例化

//增加
alist.add("123");
alist.add(new StringBuffer("1s1"));
alist.add(3.4f);
alist.add(3.01d);
alist.add(1,222);//[123, 222, 323]

alist.add("123");//[123, 222, 323, 123]----------可重复
System.out.println(alist);//相当于toString()
System.out.println("长度为:"+alist.size());
System.out.println("------------------------------");
//删除
alist.remove(2);//角标
System.out.println(alist);
//alist.clear();
alist.remove("123");//移除的是第一次出现的
System.out.println(alist);
System.out.println(alist.isEmpty());
System.out.println("------------------------------");
//遍历
//第一种:
for(int i=0;i<alist.size();i++){
Object e = alist.get(i);
if(e instanceof String){//Object inteanceof 类型----判断类型是否是Object的实例
System.out.println(((String)e).length());
}else if(e instanceof Double){
System.out.println(((Double)e).intValue());
}
}

//第二种:
for(Object e:alist){
System.out.println(e);
}
System.out.println("------------------------------");
//List<Integer> alist1 = new ArrayList<Integer>();
int size = alist.size();
System.out.println(" size="+size);
boolean flag = alist.isEmpty();//判断是否为空
System.out.println(" flag="+flag);
System.out.println("------------------------------");
//第三种:Iterable-----迭代器输出
//Iterable Iterator<T>iterator();
Iterator<Object> it = alist.iterator();//Iterator与Iterable无关,是两个接口
while(it.hasNext()){
Object i = it.next();
System.out.println(i);
}
//System.out.println(alist.iterator());
System.out.println("--------------------------------");
//第一种:
for(int i=0;i<alist.size();i++){//注意:size()是动态变化的
System.out.print(alist.get(i)+",");//按照下标获取
}
System.out.println(" ");
System.out.println("--------------------------------");
//第四种:
for(Iterator it2 = alist.iterator();it2.hasNext();){
System.out.println(it2.next());
}
//转换
//alist.toArray();
//System.out.println(alist);

}
}


LinkedList-----------增删改快,查询慢
例:
import java.util.*;
public class  Demo1{
public static void main(String[] args) {
Queue<Integer> link = new LinkedList<Integer>();
//Queue是单端队列----------单链表
link.add(21);
link.offer(111);//队尾添加========>add
link.poll();//队头删除
System.out.println(link.remove());
link.poll();//为空时返回null==========>remove
System.out.println(link.poll());
link.peek();//访问=========>get
//link.remove();为空时异常
System.out.println(link.size());
System.out.println("-------------------------------------");

Deque<Object> dl = new LinkedList<Object>();
//Deque是双端队列--------双向链表
-------------------------------------------------------------------------------
第一个元素(头部)             最后一个元素(尾部)

               抛出异常     特殊值          抛出异常       特殊值

插入 addFirst(e)   offerFirst(e)   addLast(e)     offerLast(e) 
移除 removeFirst() pollFirst()     removeLast()   pollLast() 
检查 getFirst()    peekFirst()     getLast()      peekLast() 
-------------------------------------------------------------------------------
//add、offer默认在尾部增加 
//remove、poll默认从第一个开始删除

dl.add(123);//默认在尾部增加
dl.addFirst("sss");
dl.offerFirst(231);
dl.addLast(2212);
dl.offerLast(654);
System.out.println(dl);

System.out.println("-------------------1---------------");
//dl.removeFirst();
//System.out.println(dl);
//System.out.println("------------------2----------------");
dl.pollLast();
System.out.println(dl);
System.out.println("-----------------3-----------------");

        System.out.println(dl.getFirst());

System.out.println("-----------------4-----------------");
dl.peek();
System.out.println(dl);
}
}


注意:所有的集合框架都位于java.util包中,使用前必须导入该包中的类
熟悉并记忆以下接口之间的关系和相关方法
Iterable--------->接口(java.lang)
        常见方法1:Iterator<T> iterator()
 Iterator--------->接口
        常见方法1:boolean hasNext()
        常见方法2:E   next()
 Collection------->Iterable-------------->接口 
         常见方法1:int size()
         常见方法2:boolean isEmpty()
 常见方法3:void clear()
         常见方法4:boolean  add(E e)
 常见方法5:remove()
 List(线性表)----->Collection------->Iterable-------------->接口
         常见方法1:add(int index,E e)
 常见方法2:remove(int index,E e)
   常见方法3:E get(int index)
 Queue(队列)----->Collection------->Iterable-------------->接口
         常见方法1:offer(E e)  
 常见方法2:poll()
   常见方法3:E peek()
 Deque(双端队列)----->Queue----->Collection------->Iterable-------------->接口
         常见方法1:offerFirst(E e)和offerLast(E e)
 常见方法2:pollFirst()和pollLast
   常见方法3:E peekFirst()和peekLast
ArrayList-->AbstractList-->List--->Collection--->Iterator--------->类
LinkedList--->AbstractList-->List--->Collection--->Iterator--------->类
                    --->Deque---->Queue----->
Vector--->AbstractList-->List--->Collection--->Iterator--------->类
Stack-->Vector--->AbstractList-->List--->Collection--->Iterator--------->类
         常见方法1:E pop()
 常见方法2:E push(E e)
 常见方法3:E peek()
   常见方法4:boolean empty()
stack-----------后进先出---一端


无序的不可重复的(判断重复的标准是hashCode()+equals()),如果重复定义则会覆盖
LinkedSet---------------重复时保留第一个
TreeSet-------------(String)按照ASCll码进行排序

加载因子:加载因子 是哈希表在其容量自动增加之前可以达到多满的一种尺度。当哈希
表中的条目数超出了加载因子与当前容量的乘积时,通过调用 rehash 方法将容量翻倍。
通常,默认加载因子 (.75) 在时间和空间成本上寻 求一种折衷。加载因子过高虽然减少
了空间开销,但同时也增加了查询成本(在大多数 Hashtable类的操作中,包括 get 和 
put 操作,都反映了这一点)。在设置初始容量时应该考虑到映射中所需的条目数及其加
载因子,以便最大限度地降低 rehash 操作次数。如果初始容量大于最大条目数除以加载
因子,则不会发生 rehash 操作

List默认容量10,HashSet默认容量16,加载因子0.75;

HashMap 的实例有两个参数影响其性能:初始容量 和加载因子。容量是哈希表中桶的数量,
初始容量只是哈希表在创建时的容量。加载因子 是哈希表在其容量自动增加之前可以达到
多满的一种尺度。当哈希表中的条目数超出了加载因子与当前容量的乘积时,则要对该哈希
表进行 rehash 操作(即重建内部数据结构),从而哈希表将具有大约两倍的桶数。

在比较时可以自定义一个比较方式,此类必须要继承Comparable<T>接口,并实现compareTo( T t){ ----重写toString()输出
   
 return -1|0|1;      //  <|=|>
}

import java.util.*;
public class HashSetTest{
public static void main(String[] args) {
/*Set<String> set1 = new LinkedHashSet<String>();
set1.add("sds");
set1.add("2sa");
set1.add("213");
set1.add("213");
System.out.println(set1);//无序
System.out.println("--------------------------------------");
Set<String> set2 = new HashSet<String>();
set2.add("sds");
set2.add("213");
set2.add("2sa");
set2.add("213");
System.out.println(set2);//按插入顺序输出
System.out.println("--------------------------------------");

Set<String> set3 = new TreeSet<String>();
set3.add("sds");
set3.add("213");
set3.add("2sa");
set3.add("213");
System.out.println(set3); //排序
System.out.println("--------------------------------------");
*/
Set<Cat> set=new TreeSet<Cat>();
Cat c1=new Cat(2,"red");
Cat c2=new Cat(1,"black");
Cat c3=new Cat(3,"white");
set.add(c1);
set.add(c2);
set.add(c3);
System.out.println(set.toString());
}
}

class Cat implements Comparable<Cat>{
private int age;
private String color;
public Cat(int age,String color){
this.age=age;
this.color=color;
}
public String toString(){
return "{age="+age+" , color="+color+"}";
}
    public int compareTo(Cat o){
  if(this.age>o.age){
            return 1;
  }else{
    return -1;
  }
   }
}
//---------- java ----------
//[{age=1 , color=black}, {age=2 , color=red}, {age=3 , color=white}]

LinkedHashSet--->HashSet----->AbstractSet----->Set--->Collection------>Iterable
                                TreeSet------>AbstractSet----->Set--->Collection------>Iterable
                                TreeSet------>SortedSet------>Set---->Collection------>Iterable

 

Map

 泛型擦除----------类型擦除
     类型擦除指的是通过类型参数合并,将泛型类型实例关联到同一份字节码上。编译器只为泛型类型生成一份字
节码,并将其实例关联到这份字节码上。类型擦除的关键在于从泛型类型中清除类型参数的相关信息,并且再
必要的时候添加类型检查和类型转换的方法。
     类型擦除可以简单的理解为将泛型java代码转换为普通java代码,只不过编译器更直接点,将泛型java
代码直接转换成普通java字节码。
     
   类型擦除的主要过程如下:
     1.将所有的泛型参数用其最左边界(最顶级的父类型)类型替换。
     2.移除所有的类型参数,如:
interface Comparable <A> { 
  public int compareTo( A that); 

final class NumericValue implements Comparable <NumericValue> { 
  priva te byte value;  
  public  NumericValue (byte value) { this.value = value; }  
  public  byte getValue() { return value; }  
  public  int compareTo( NumericValue t hat) { return this.value - that.value; } 

-----------------
class Collections {  
  public static <A extends Comparable<A>>A max(Collection <A> xs) { 
    Iterator <A> xi = xs.iterator(); 
    A w = xi.next(); 
    while (xi.hasNext()) { 
      A x = xi.next(); 
      if (w.compareTo(x) < 0) w = x; 
    } 
    return w; 
  } 

final class Test { 
  public static void main (String[ ] args) { 
    LinkedList <NumericValue> numberList = new LinkedList <NumericValue> (); 
    numberList .add(new NumericValue((byte)0));  
    numberList .add(new NumericValue((byte)1));  
    NumericValue y = Collections.max( numberList );  
  } 
}
经过类型擦除后的类型为
 interface Comparable { 
  public int compareTo( Object that); 

final class NumericValue implements Comparable { 
  priva te byte value;  
  public  NumericValue (byte value) { this.value = value; }  
  public  byte getValue() { return value; }  
  public  int compareTo( NumericValue t hat)   { return this.value - that.value; } 
  public  int compareTo(Object that) { return this.compareTo((NumericValue)that);  } 

-------------
class Collections {  
  public static Comparable max(Collection xs) { 
    Iterator xi = xs.iterator(); 
    Comparable w = (Comparable) xi.next(); 
    while (xi.hasNext()) { 
      Comparable x = (Comparable) xi.next(); 
      if (w.compareTo(x) < 0) w = x; 
    } 
    return w; 
  } 

final class Test { 
  public static void main (String[ ] args) { 
    LinkedList numberList = new LinkedList(); 
    numberList .add(new NumericValue((byte)0));  ,
    numberList .add(new NumericValue((byte)1));  
    NumericValue y = (NumericValue) Collections.max( numberList );  
  } 
}
第一个泛型类Comparable <A>擦除后 A被替换为最左边界Object。Comparable<NumericValue>的类
型参数NumericValue被擦除掉,但是这直 接导致NumericValue没有实现接口Comparable的compareTo(Object that)
方法,于是编译器充当好人,添加了一个桥接方法。
第二个示例中限定了类型参数的边界<A extends Comparable<A>>A,A必须为Comparable<A>的子类
,按照类型擦除的过程,先讲所有的类型参数 ti换为最左边界Comparable<A>,然后去掉参数类型A,
得到最终的擦除后结果。

 

Collection 和 Collections的区别。

Collection是个java.util下的接口,它是各种集合结构的父接口。继承与他的接口主要有Set 和List.
Collections是个java.util下的专用静态类,它包含有各种有关集合操作的静态方法。提供一系列静态
方法实现对各种集合的搜索、排序、线程安全化等操作。

Array与Arrays的区别。

1.数组类Array,是Java中最基本的一个存储结构。提供了动态创建和访问 Java 数组的方法。其中的
元素的类型必须相同。效率高,但容量固定且无法动态改变。 它无法判断其中实际存有多少元素,
length只是告诉我们array的容量。
2、Arrays类,此静态类专门用来操作array ,提供搜索、排序、复制等静态方法。equals():比较两个
array是否相等。array拥有相同元素个数,且所有对应元素两两相等。 sort():用来对array进行排序。
 binarySearch():在排好序的array中寻找元素。

collections
例:
import java.util.*;
public class CollectionsDemo {
public static void main(String[] args) {
List<String> sl = new ArrayList<String>();
sl.add("jhn");
sl.add("ncgcxs");
sl.add("rgd");
sl.add("ceaz");
sl.add("vfe");
sl.add("byt");
sl.add("fe");
Collections.sort(sl);
System.out.println(sl);
//Collections.binarySearch(1);
//Collections.copy(sl);
System.out.println(Collections.max(sl));//max
System.out.println(Collections.min(sl));//min
Collections.reverse(sl);//反转
System.out.println(sl);
Collections.shuffle(sl);//打散
System.out.println(sl);
}


HashMap遍历的两种方式

第一种: 
Map map = new HashMap(); 
Iterator iter = map.entrySet().iterator(); 
while (iter.hasNext()) { 
    Map.Entry entry = (Map.Entry) iter.next(); 
    Object key = entry.getKey(); 
    Object val = entry.getValue(); 

效率高,以后一定要使用此种方式! 
第二种: 
Map map = new HashMap(); 
Iterator iter = map.keySet().iterator(); 
while (iter.hasNext()) { 
    Object key = iter.next(); 
    Object val = map.get(key); 

效率低,以后尽量少使用!

HashMap 与 TreeMap的区别
    集合框架”提供两种常规的Map实现:HashMap和TreeMap (TreeMap实现SortedMap接口)。在Map 
中插入、删除和定位元素,HashMap 是最好的选择。但如果您要按自然顺序或自定义顺序遍历键,那
么TreeMap会更好。使用HashMap要求添加的键类明确定义了hashCode()和equals()的实现。这个TreeMap
没有调优选项,因为该树总处于平衡状态。

TreeMap
(http://www.cnblogs.com/hzmark/archive/2013/01/02/TreeMap-Base.html)
Java 集合系列目录(Category)
(http://www.cnblogs.com/skywang12345/p/3323085.html)

----------------------------------------------------------------------|----------------------------------------------------------------------|
----------------------------------------------------------------------|----------------------------------------------------------------------|
----------------------------------------------------------------------|----------------------------------------------------------------------|
                                                                                                                                                 

四、I/O流、File

File--------java.io.File--------文件和目录路径名的抽象表示形式

常用方法:
createNewFile(" ")---------创建文件
delete(" ")
exists()-----------测试是否存在
getName()---------获得文件名

例:
String path = File.separator;//与系统有关的默认名称分隔符
File f = new File("c:"+path+"c.txt");
ystem.out.println(f.createNewFile());

 

例:import java.io.*;
public class FileDemo {
public static void main(String[] args) throws IOException{
/*
File f = new File("c:\\Users\\Rainlate\\Desktop\\123.txt");//注意\的转义字符
//构建实例不代表创建文件
boolean b =f.createNewFile();//创建文件
f.mkdirs();//创建前不必有父目录
//f.createTempFile(sd,jsp);//使用给定前缀和后缀生成其名称创建空文件
//f.createTempFile(23,txt, null);//使用给定前缀和后缀生成其名称
//boolean d1 = f.delete();//删除此抽象路径名表示的文件或目录。如果此路径名表示一个目录,则该目录必须为空才能删除
System.out.println(f.exists());//是否存在文件
System.out.println(f.getName());//123.txt
String path = File.separator;
File f = new File("c:"+path+"c.txt");
System.out.println(f.createNewFile());
String a = File.separator;
String path="c:"+a+"Users"+a+"Rainlate"+a+"Desktop"+a+"1";
File f = new File(path);
File[] files = new listFiles(f);
for(String file:files){
System.out.println(file);
}
*/
File x= new File("c:\\Users\\Rainlate\\Desktop\\1");
show(x);
}

public static void show(File f){//递归输出源目录下的所有文件
if(f.isDirectory()){//判断是否为目录
File[] files =f.listFiles();
for(int i=0;i<files.length;i++){
show(files[i]);
}
}else{
System.out.println(f.getPath());
}
}
}


IO流:
第一,确定方向-----------输入输出是以程序为中心
第二,确定是字节还是字符【若是字符型文本使用字符流,其他使用字节流】
第三,确定是否需要缓冲【autoFlush、Flush】----------缓冲流是用空间换时间
第四,所有操作必须关闭【在finally关闭】

例1;
import java.io.*;
public class  FileInputStreamDemo{//文本复制
public static void main(String[] args) {
String a = File.separator;//与系统有关的默认名称分隔符
FileInputStream fin = null;
//FileOutputStream fo = null;
BufferedOutputStream fo = null;
try{
fin = new FileInputStream("C:"+a+"Users"+a+"Rainlate"+a+"Desktop"+a+"123.docx");
byte[] b = new byte[512];//存储读取数据的缓冲区
long start = System.currentTimeMillis();
int size = fin.read(b,0,b.length);
//fo = new FileOutputStream("C:"+a+"Users"+a+"Rainlate"+a+"Desktop"+a+"12.java");
fo = new BufferedOutputStream (new FileOutputStream("C:"+a+"Users"+a+"Rainlate"+a+"Desktop"+a+"12.docx"));
while(size != -1){
fo.write(b,0,size);//文件的实际大小
fo.flush();
size = fin.read(b,0,b.length);
}
long late = System.currentTimeMillis();
System.out.println(late-start);
}catch (FileNotFoundException e){
System.out.println(e.getMessage());
}catch(IOException e){
System.out.println(e.getMessage());
}finally{
try{
fin.close();//关闭输入流
        fo.close();//关闭输出流
}catch (IOException e){
System.exit(1);//异常退出
}
}
}
}

例2:
import java.io.*;
public class ObjectSerializable {
public static void main(String[] args) {
Person p = new Person(32,"huhu");
String a = File.separator;
ObjectOutputStream ou =null;//序列化
ObjectInputStream oin = null;//反序列化
try{
ou = new ObjectOutputStream(new FileOutputStream("C:"+a+"Users"+a+"Rainlate"+a+"Desktop"+a+"1.txt"));
ou.writeObject(p);//对象序列化
ou.flush();

//反序列化
oin = new ObjectInputStream(new FileInputStream("C:"+a+"Users"+a+"Rainlate"+a+"Desktop"+a+"1.txt"));
Object obj = oin.readObject();
Person as = (Person)obj;
System.out.println(as);
out.flush();
}catch (FileNotFoundException e){
System.out.println(e.getMessage());
}catch(IOException e){
System.out.println(e.getMessage());
}catch(ClassNotFoundException e){
System.out.println(e.getMessage());
}finally{
try{
out.close();
}catch (IOException e){
System.exit(1);
}
}
}
}

class Person implements Serializable {
private int age;
private String name;
public Person(int age,String name){
this.age=age;
this.name=name;
}
public String toString(){
return "name="+this.name+",age="+this.age;
}
}


序列化的版本号(serialVersionUID=1L)?
作用:就是确保了不同版本之间的兼容性,不仅能够向前兼容,还能够向后兼容,即在版本升级时反序列化仍保持对象的唯一性。
它有两种生成方式:       
       一个是默认的1L,比如:private static final long serialVersionUID = 1L;
       一个是根据类名、接口名、成员方法及属性等来生成一个64位的哈希字段,比如:  private static final long serialVersionUID = xxxxL 


类图结构
  ┌BufferedReader
  ├InputStream──FileReader
  ├StringReader
┌Reader─┤
│   ├PipedReader
│   ├ByteArrayReader
│   └FileReader──PushbackReader
字符流─┤
│   ┌BufferedWriter
│   ├OutputStreamWriter──FileWriter
│   ├PrinterWriter
└Writer─┼StringWriter
  ├PipedWriter
  ├CharArrayWriter
  └FileWriter


┌FileInputStream
│ ┌BufferedInputStream
├FilterInputStream ──┼DataInputStream
│ └PushbackInputStream
┌InputStream ─┼ObjectInputStream
│ ├PipedInputStream
│ ├SequenceInputStream
│ ├StringBufferInputStream
│ └ByteArrayInoutStream
字节流─┤

│  ┌FileOutputStream
│  │   ┌BufferedOutputStream
│  ├FilterOutputStream ──┼DataOutputStream
└OutputStream ─┤   └PrintStream
 ├ObjectOutputStream
 ├PipedOutputStream

 

IO流------(http://developer.51cto.com/art/201309/410913.htm)

----------------------------------------------------------------------|----------------------------------------------------------------------|
----------------------------------------------------------------------|----------------------------------------------------------------------|
----------------------------------------------------------------------|----------------------------------------------------------------------|
                                                                                                                                                 

五、html

<!DOCTYPE>  定义文档类型。
<html> 定义 HTML 文档。
<body> 定义文档的主体。
<h1> to <h6> 定义 HTML 标题。
<p> 定义段落。
<br> 定义简单的折行。
<hr> 定义水平线。
<!--...--> 定义注释。

<b> 定义粗体文本。
<font> 不赞成使用。定义文本的字体、尺寸和颜色
<i> 定义斜体文本。
<em> 定义强调文本。
<big> 定义大号文本。
<strong> 定义语气更为强烈的强调文本。
<small> 定义小号文本。
<sup> 定义上标文本。
<sub> 定义下标文本。
<bdo> 定义文本的方向。
<u> 不赞成使用。定义下划线文本。

<pre> 定义预格式文本
<code> 定义计算机代码文本。
<tt> 定义打字机文本。
<kbd> 定义键盘文本。
<var> 定义文本的变量部分。
<dfn> 定义定义项目。
<samp> 定义计算机代码样本。
<xmp> 不赞成使用。定义预格式文本。 

<acronym> 定义只取首字母的缩写。
<abbr> 定义缩写。
<address> 定义文档作者或拥有者的联系信息。
<blockquote> 定义块引用。
<center> 不赞成使用。定义居中文本。
<q> 定义短的引用。
<cite> 定义引用(citation)。
<ins> 定义被插入文本。
<del> 定义被删除文本。
<s> 不赞成使用。定义加删除线的文本。
<strike> 不赞成使用。定义加删除线的文本。

<a> 定义锚。
<link> 定义文档与外部资源的关系。

<frame> 定义框架集的窗口或框架。
<frameset> 定义框架集。
<noframes> 定义针对不支持框架的用户的替代内容。
<iframe> 定义内联框架。

<form> 定义供用户输入的 HTML 表单。
<input> 定义输入控件。
<textarea> 定义多行的文本输入控件。
<button> 定义按钮。
<select> 定义选择列表(下拉列表)。
<optgroup> 定义选择列表中相关选项的组合。
<option> 定义选择列表中的选项。
<label> 定义 input 元素的标注。
<fieldset> 定义围绕表单中元素的边框。
<legend> 定义 fieldset 元素的标题。
<isindex> 不赞成使用。定义与文档相关的可搜索索引。

<ul> 定义无序列表。
<ol> 定义有序列表。
<li> 定义列表的项目。
<dir> 不赞成使用。定义目录列表。
<dl> 定义定义列表。
<dt> 定义定义列表中的项目。
<dd> 定义定义列表中项目的描述。
<menu> 不赞成使用。定义菜单列表。

<img> 定义图像。
<map> 定义图像映射。
<area> 定义图像地图内部的区域。

<table> 定义表格
<caption> 定义表格标题。
<th> 定义表格中的表头单元格。
<tr> 定义表格中的行。
<td> 定义表格中的单元。
<thead> 定义表格中的表头内容。
<tbody> 定义表格中的主体内容。
<tfoot> 定义表格中的表注内容(脚注)。
<col> 定义表格中一个或多个列的属性值。
<colgroup> 定义表格中供格式化的列组。

<style> 定义文档的样式信息。
<div> 定义文档中的节。
<span> 定义文档中的节。

<head> 定义关于文档的信息。
<title> 定义文档的标题。
<meta> 定义关于 HTML 文档的元信息。
<base> 定义页面中所有链接的默认地址或默认目标。
<basefont> 不赞成使用。定义页面中文本的默认字体、颜色或尺寸。

<script> 定义客户端脚本。
<noscript> 定义针对不支持客户端脚本的用户的替代内容。
<applet> 不赞成使用。定义嵌入的 applet。
<object> 定义嵌入的对象。
<param> 定义对象的参数。


----------------------------------------------------------------------|----------------------------------------------------------------------|
----------------------------------------------------------------------|----------------------------------------------------------------------|
----------------------------------------------------------------------|----------------------------------------------------------------------|
                                                                                                                                                  
六、CSS

CSS 背景属性(Background)
属性 描述 CSS
background 在一个声明中设置所有的背景属性。 1
background-attachment 设置背景图像是否固定或者随着页面的其余部分滚动。 1
background-color 设置元素的背景颜色。 1
background-image 设置元素的背景图像。 1
background-position 设置背景图像的开始位置。 1
background-repeat 设置是否及如何重复背景图像。 1

CSS 边框属性(Border 和 Outline)
属性 描述 CSS
border 在一个声明中设置所有的边框属性。 1
border-bottom 在一个声明中设置所有的下边框属性。 1
border-bottom-color 设置下边框的颜色。 2
border-bottom-style 设置下边框的样式。 2
border-bottom-width 设置下边框的宽度。 1
border-color 设置四条边框的颜色。 1
border-left 在一个声明中设置所有的左边框属性。 1
border-left-color 设置左边框的颜色。 2
border-left-style 设置左边框的样式。 2
border-left-width 设置左边框的宽度。 1
border-right 在一个声明中设置所有的右边框属性。 1
border-right-color 设置右边框的颜色。 2
border-right-style 设置右边框的样式。 2
border-right-width 设置右边框的宽度。 1
border-style 设置四条边框的样式。 1
border-top 在一个声明中设置所有的上边框属性。 1
border-top-color 设置上边框的颜色。 2
border-top-style 设置上边框的样式。 2
border-top-width 设置上边框的宽度。 1
border-width 设置四条边框的宽度。 1
outline 在一个声明中设置所有的轮廓属性。 2
outline-color 设置轮廓的颜色。 2
outline-style 设置轮廓的样式。 2
outline-width 设置轮廓的宽度。 2

CSS 文本属性(Text)
属性 描述 CSS
color 设置文本的颜色。 1
direction 规定文本的方向 / 书写方向。 2
letter-spacing 设置字符间距。 1
line-height 设置行高。 1
text-align 规定文本的水平对齐方式。 1
text-decoration 规定添加到文本的装饰效果。 1
text-indent 规定文本块首行的缩进。 1
text-shadow 规定添加到文本的阴影效果。 2
text-transform 控制文本的大小写。 1
unicode-bidi 设置文本方向。 2
white-space 规定如何处理元素中的空白。 1
word-spacing 设置单词间距。 1

CSS 字体属性(Font)
属性 描述 CSS
font 在一个声明中设置所有字体属性。 1
font-family 规定文本的字体系列。 1
font-size 规定文本的字体尺寸。 1
font-size-adjust 为元素规定 aspect 值。 2
font-stretch 收缩或拉伸当前的字体系列。 2
font-style 规定文本的字体样式。 1
font-variant 规定是否以小型大写字母的字体显示文本。 1
font-weight 规定字体的粗细。 1

CSS 外边距属性(Margin)
属性 描述 CSS
margin 在一个声明中设置所有外边距属性。 1
margin-bottom 设置元素的下外边距。 1
margin-left 设置元素的左外边距。 1
margin-right 设置元素的右外边距。 1
margin-top 设置元素的上外边距。 1

CSS 内边距属性(Padding)
属性 描述 CSS
padding 在一个声明中设置所有内边距属性。 1
padding-bottom 设置元素的下内边距。 1
padding-left 设置元素的左内边距。 1
padding-right 设置元素的右内边距。 1
padding-top 设置元素的上内边距。 1

CSS 列表属性(List)
属性 描述 CSS
list-style 在一个声明中设置所有的列表属性。 1
list-style-image 将图象设置为列表项标记。 1
list-style-position 设置列表项标记的放置位置。 1
list-style-type 设置列表项标记的类型。 1
marker-offset   2

内容生成(Generated Content)
属性 描述 CSS
content 与 :before 以及 :after 伪元素配合使用,来插入生成内容。 2
counter-increment 递增或递减一个或多个计数器。 2
counter-reset 创建或重置一个或多个计数器。 2
quotes 设置嵌套引用的引号类型。 2
CSS 尺寸属性(Dimension)

属性 描述 CSS
height 设置元素高度。 1
max-height 设置元素的最大高度。 2
max-width 设置元素的最大宽度。 2
min-height 设置元素的最小高度。 2
min-width 设置元素的最小宽度。 2
width 设置元素的宽度。 1

CSS 定位属性(Positioning)
属性 描述 CSS
bottom 设置定位元素下外边距边界与其包含块下边界之间的偏移。 2
clear 规定元素的哪一侧不允许其他浮动元素。 1
clip 剪裁绝对定位元素。 2
cursor 规定要显示的光标的类型(形状)。 2
display 规定元素应该生成的框的类型。 1
float 规定框是否应该浮动。 1
left 设置定位元素左外边距边界与其包含块左边界之间的偏移。 2
overflow 规定当内容溢出元素框时发生的事情。 2
position 规定元素的定位类型。 2
right 设置定位元素右外边距边界与其包含块右边界之间的偏移。 2
top 设置定位元素的上外边距边界与其包含块上边界之间的偏移。 2
vertical-align 设置元素的垂直对齐方式。 1
visibility 规定元素是否可见。 2
z-index 设置元素的堆叠顺序。 2

CSS 打印属性(Print)
属性 描述 CSS
orphans 设置当元素内部发生分页时必须在页面底部保留的最少行数。 2
page-break-after 设置元素后的分页行为。 2
page-break-before 设置元素前的分页行为。 2
page-break-inside 设置元素内部的分页行为。 2
widows 设置当元素内部发生分页时必须在页面顶部保留的最少行数。 2

CSS 表格属性(Table)
属性 描述 CSS
border-collapse 规定是否合并表格边框。 2
border-spacing 规定相邻单元格边框之间的距离。 2
caption-side 规定表格标题的位置。 2
empty-cells 规定是否显示表格中的空单元格上的边框和背景。 2
table-layout 设置用于表格的布局算法。 2

CSS 伪类(Pseudo-classes)
属性 描述 CSS
:active 向被激活的元素添加样式。 1
:focus 向拥有键盘输入焦点的元素添加样式。 2
:hover 当鼠标悬浮在元素上方时,向元素添加样式。 1
:link 向未被访问的链接添加样式。 1
:visited 向已被访问的链接添加样式。 1
:first-child 向元素的第一个子元素添加样式。 2
:lang 向带有指定 lang 属性的元素添加样式。 2

CSS 伪元素(Pseudo elements)
属性 描述 CSS
:first-letter 向文本的第一个字母添加特殊样式。 1
:first-line 向文本的首行添加特殊样式。 1
:before 在元素之前添加内容。 2
:after 在元素之后添加内容。 2


----------------------------------------------------------------------|----------------------------------------------------------------------|
----------------------------------------------------------------------|----------------------------------------------------------------------|
----------------------------------------------------------------------|----------------------------------------------------------------------|
                                                                                                                                                 

JDK1.5新特性:

七、枚举
枚举是一个类类型,是JDK1.5的新特性

枚举的关键字是enum

Java中所有的枚举类都是java.lang.Enum的子类

注意:枚举类中可以包含成员有【字段(常量)、方法(构造方法、普通方法)】

枚举中不能有number;不能赋值------------类

 只有顺序可以比较-----------

语法:

enum 枚举名{

         枚举体

}

例:

enum Direction{//枚举体

         EAST,SOUTH,WEST,NORTH//后面可以有分号也可以没有

}

调用:枚举名.成员

枚举名 name =枚举名.成员;

Direction dir = Direction.EAST;

 

Enum的方法使用:

Javap---------------查看字节码文件


代码:

enum Direction{

EAST('e'),SOUTH('s'),NORTH('n'),WEST('w');

    protected char a;

private Direction(char a){

this.a = a;

}

public String toString(){

return a+"";

}

}

字节码:


---------- javap ----------

Compiled from "Direction.java"

final class Direction extends java.lang.Enum<Direction> {//不能被实例化

  public static final Direction EAST;

  public static final Direction SOUTH;

  public static final Direction NORTH;

  public static final Direction WEST;

  protected char a;//默认是private,但可以使用4P

  public static Direction[] values();//默认方法,用来遍历打印枚举成员

  public static Direction valueOf(java.lang.String);

  public java.lang.String toString();

  static {};//静态初始化块

}

由上面可以知道枚举继承java.lang.Enum类,参数的默认修饰符public static final,在枚举中可以使用4p

 

public enum A{BLUE,RED,BLACK};//声明并定义一个枚举,初始化为。。。

在一个类中定义一个enum成员,enum默认是静态的-------------相当于类变量

 

枚举的用法

一、常量-----------枚举出来之前都是通过接口

在JDK1.5 之前,我们定义常量都是: public static fianl,现在可以把相关的常量分组到一个枚举类型里,例:

public enum Color {

  RED, GREEN, BLANK, YELLOW

}

二、Switch

JDK1.5之后的switch语句支持Byte,short,int,char,enum类型,使用枚举,能让我们的代码可读性更强,JDK1.7之后开始支持String类型,例:

enum Signal {

         GREEN, YELLOW, RED

}

public class TrafficLight {

         Signal color = Signal.RED;

         public void change() {

                   switch (color) {

                   case RED:

                            color = Signal.GREEN;

                            break;

                   case YELLOW:

                            color = Signal.RED;

                            break;

                   case GREEN:

                            color = Signal.YELLOW;

                            break;

                   }

         }

}

三、向枚举中添加新方法

要自定义方法,必须在enum实例序列的最后添加一个分号。而且 Java 要求必须先定义 enum实例,例:

public enum Color {

         RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4);

         // 成员变量

         private String name;

         private int index;

         // 构造方法

         private Color(String name, int index) {

                   this.name = name;

                   this.index = index;

         }

         // 普通方法

         public static String getName(int index) {

                   for (Color c : Color.values()) {

                            if (c.getIndex() == index) {

                                     return c.name;

                            }

                   }

                   return null;

         }

         // get set 方法

         public String getName() {

                   return name;

         }

         public void setName(String name) {

                   this.name = name;

         }

         public int getIndex() {

                   return index;

         }

         public void setIndex(int index) {

                   this.index = index;

         }

}

四、覆盖枚举的方法

例如覆盖toString()

public enum Color {

         RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4);

         // 成员变量

         private String name;

         private int index;

         // 构造方法

         private Color(String name, int index) {

                   this.name = name;

                   this.index = index;

         }

         //覆盖方法

         @Override

         public String toString() {

                   return this.index+"_"+this.name;

         }

}

五、实现接口------所有的枚举都继承自java.lang.Enum类。由于Java 不支持多继承,所以枚举对象不能再继承其他类,例:

public interface Behaviour {

         void print();

         String getInfo();

}

public enum Color implements Behaviour{

         RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4);

         // 成员变量

         private String name;

         private int index;

         // 构造方法

         private Color(String name, int index) {

                   this.name = name;

                   this.index = index;

         }

//接口方法

         @Override

         public String getInfo() {

                   return this.name;

         }

         //接口方法

         @Override

         public void print() {

                   System.out.println(this.index+":"+this.name);

         }

}

六、使用接口组织枚举

public interface Food {

         enum Coffee implements Food{

                   BLACK_COFFEE,DECAF_COFFEE,LATTE,CAPPUCCINO

         }

         enum Dessert implements Food{

                   FRUIT, CAKE, GELATO

         }

}

七、枚举集合

java.util.EnumSet和java.util.EnumMap是两个枚举集合。EnumSet保证集合中的元素不重复;EnumMap中的key是enum类型,而value则可以是任意类型。

 

枚举和普通类的区别与联系;

1、枚举与类都可以实现多接口;访问控制符都可以使用(4p),但枚举中默认的是private,类中默认的是package;

2、枚举直接继承java.lang.Enum类,普通类是继承java.lang.Object;其中java.long.Enum类实现了java.long.Serializable和java.long.Comparable两个接口。

3、使用enum定义、非抽象的枚举默认修饰符为public final,因此枚举不能派生子类。
4、枚举的构造器只能使用private访问控制符,如果省略了枚举的访问修饰符其默认为private修饰;因为枚举的字段不能初始化,对象类型的必须调用构造方法,所有有多少个成员构造方法就会运行多少次;
5、枚举的所有实例必须在枚举的第一行显示列出,否则这个枚举永远都不能生产实例,列出这些实例时系统会自动添加public static final修饰,无需程序员显式添加

6、所有的枚举类都提供了一个values方法,该方法可以很方便的遍历所有的枚举值

7、关键字:枚举是enum,类是class

8、枚举是类类型,类是引用类型


instanceof关键字:
public class FX {
public static void main(String[] args) {
boolean b = ("1" instanceof String);//判断某个对象是不是某个类的实例    Result = Object instanceof Class/interface
//Result:布尔类型。
   //Object:必选项。任意对象表达式。
//Class:必选项。任意已定义的对象类。
System.out.println(b);
}
}


注解---JDK1.5的新特性
使用位置:类上、方法上、语句上

----------------------------------------------------------------------|----------------------------------------------------------------------|
----------------------------------------------------------------------|----------------------------------------------------------------------|
----------------------------------------------------------------------|----------------------------------------------------------------------|


八、协变与泛型
协变-------可以用在数组、重写,不可以用在枚举中

可变参数:

int… a-------------代表一个没有长度限制的数组----------JDK1.5之后有的

输入的必须是数组

Java1.5增加了新特性:可变参数:适用于参数个数不确定,类型确定的情况,java把可变参数当做数组处理。注意:可变参数必须位于最后一项。只支持有一个可变参数。因为参数个数不定,所以当其后边还有相同类型参数时,java无法区分传入的参数属于前一个可变参数还是后边的参数,所以只能让可变参数位于最后一项。

可变参数的特点:

(1)、只能出现在参数列表的最后;

(2)、... 位于变量类型和变量名之间,前后有无空格都可以;

(3)、调用可变参数的方法时,编译器为该可变参数隐含创建一个数组,在方法体中以数组的形式访问可变参数。例:

public class Varable {
     public static void main(String [] args){
         System.out.println(add(2,3));
         System.out.println(add(2,3,5));
     }
     public static int add(int x,int ...args){
         int sum=x;
         for(int i=0;i<args.length;i++){
             sum+=args[i];
         }
         return sum;
     }
}

 协变的作用范围

1、数组:如果 A 是 B 的超类,则 A[] 也是 B[] 的超类,所有需要 A[] 的地方都可以用 B[] 代替,例:

public class Test2 {

    public static void main(String[] args){

        Integer[] ints=new Integer[1];

        ints[0]=99;

        show(ints);

    }

    static void show(Number[] ns){

        System.out.println(Arrays.toString(ns));

    }

}

 

2、重写

public class Test2 {

    public static void main(String[] args){

        P p=new C();

        System.out.println(p.get());

    }

}

class P{

    public Number get(){

        return new Integer(0);

    }

}

class C extends P{

    public Integer get(){

        return new Integer(1);

    }

}

3、泛型不能协变:如果 A 是 B 的超类,则 List<A> 和 List<B> 无关,需要 List<A> 的地方不可以用 List<B> 代替,例:

public class Test2 {

    public static void main(String[] args) {

        List<Integer> ints = new ArrayList<Integer>();

        //incompatible type--类型不兼容

        show(ints);

    }

 

    static void show(List<Number> ns) {

        System.out.println(ns);

    }

}


泛型(Generic)的本质是类型参数化

-------------是JDK1.5提供的新技术,它的本质是类型参数化,类似C++中的模板,它根据应用主要分为泛型方法,泛型接口,泛型类,协变不适用于泛型

 

泛型-------------泛型类class Demo<T>{},泛型接口interface Inter<T>{},泛型方法public<T> T show(T a) {}

泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,提高代码的重用率

 

例1:

public class  GenericDemo{

       public static void main(String[] args) {

              C c1 = new C(new A("aaa"));

              C c2 = new C(new B(3.4));//包装成double---自动装箱

              Object obj = c1.getObj();

              A obj = (A)(c1.getObj());//强制转换

              System.out.println(obj);

       }

}

class A{

       private String x;

       public A(String x){

              this.x=x;

       }

       public String getX(){

              return x;

       }

}

class B{

       private Double d;

       public B(Double d){

              this.d=d ;

       }

       public Double getD(){

              return d;

       }

}

class C{

       private Object obj;

       public C(Object obj){

              this.obj=obj ;

       }

       public Object  getObj(){

              return obj;

       }

}

 

泛型的使用:

一、泛型类:

public class Demo1 {

       public static void main(String[] args) {

              Generic<String> c = new Generic<String>("asad");

              System.out.println(c.getA());

 

              //Generic<int> c1 = new Generic<int>(12);必须要是包装类

       }

}

class Generic<T>{//泛型类

       private T a;

       public Generic(T a){

              this.a = a;

       }

       public T getA(){

              return a;

       }

}

 

二、泛型方法

       public static <T> T getX(T t){//泛型方法----------<  >--表声明

              return t;

       }

     

public static <T,K> T getX(K t){//泛型方法

              return t;

       }

 

三、泛型接口

public class GenericDemo3{

public static void main(String[] args) {

D<int[][]> d = new D<int[][]>();

d.show(new int[][]{{1,4},{2,3}});

}

}

interface IA<T>{

void show(T t);

}

 

class D<T> implements IA<T>{

public void show(T t){

System.out.println(t.getClass().getName());

}

}

 

 

有界类型:

上界:extends 默认上界为Object

Class G <T extends Number,K extends Object,H super Integer>{}

下界:super----------只有通配符有下限

extends关键字声明了类型的上界,表示参数化的类型可能是所指定的类型,或者是此类型的子类

super关键字声明了类型的下界,表示参数化的类型可能是所指定的类型,或者是此类型的父类型,直至Object

 

规则和限制

1、泛型的类型参数只能是类类型(包括自定义类),不能是简单类型。

2、同一种泛型可以对应多个版本(因为参数类型是不确定的),不同版本的泛型类实例是不兼容的。

3、泛型的类型参数可以有多个。<T,K>

4、泛型的参数类型可以使用extends关键字,例如<T extends superclass>。习惯上称为“有界类型”。

5、泛型的参数类型还可以是通配符类型。例如Class<?> classType = Class.forName("java.lang.String")

6、如果只指定了<?>,而没有extends,则默认是允许Object及其下的任何Java类了。也就是任意类。

7、通配符泛型不但可以向下限制,如<? extends Collection>,还可以向上限制,如<? super Double>,表示类型只能接受Double及其上层父类类型,如Number、Object类型的实例。

8、泛型类定义可以有多个泛型参数,中间用逗号隔开,还可以定义泛型接口,泛型方法。这些都与泛型类中泛型的使用规则类似。

一个普通static方法,无法访问泛型类的类型参数,所以,若普通static方法需要使用泛型参数,必须使其成为泛型方法。

 

 

java 泛型详解

普通泛型

Java代码

1.  class Point<T>{       // 此处可以随便写标识符号 

2.      private T var ; // var的类型由T指定,即:由外部指定 

3.      public T getVar(){  // 返回值的类型由外部决定 

4.          return var ; 

5.      } 

6.      public void setVar(T var){  // 设置的类型也由外部决定 

7.          this.var = var ; 

8.      } 

9.  } 

10. public class GenericsDemo06{ 

11.     public static void main(String[] args){

12.         Point<String> p = new Point<String>() ; // 里面的var类型为String类型  --------指定数据类型—必须是引用数据类型

13.         p.setVar("it") ;        // 设置字符串 

14.         System.out.println(p.getVar().length()) ;   // 取得字符串的长度 

15.     } 

16. }

17. //2

18. ---------------------------------------------------------- 

19. class Notepad<K,V>{       // 此处指定了两个泛型类型-----再类上进行声明泛型类型 

20.     private K key ;     // 此变量的类型由外部决定 

21.     private V value ;   // 此变量的类型由外部决定 

22.     public K getKey(){ 

23.         return this.key ; 

24.     } 

25.     public V getValue(){ 

26.         return this.value ; 

27.     } 

28.     public void setKey(K key){ 

29.         this.key = key ; 

30.     } 

31.     public void setValue(V value){ 

32.         this.value = value ; 

33.     } 

34. } 

35. public class GenericsDemo09{ 

36.     public static void main(String args[]){ 

37.         Notepad<String,Integer> t = null ;        // 定义两个泛型类型的对象 

38.         t = new Notepad<String,Integer>() ;       // 里面的key为String,value为Integer 

39.         t.setKey("汤姆") ;        // 设置第一个内容 

40.         t.setValue(20) ;            // 设置第二个内容 

41.         System.out.print("姓名;" + t.getKey()) ;      // 取得信息 

42.         System.out.print(",年龄;" + t.getValue()) ;       // 取得信息 

43.       } 

44. }  //汤姆

45.       20

 通配符

Java代码

1.  class Info<T>{ 

2.      private T var ;     // 定义泛型变量 

3.      public void setVar(T var){ 

4.          this.var = var ; 

5.      } 

6.      public T getVar(){ 

7.          return this.var ; 

8.      } 

9.      public String toString(){   // 直接打印 

10.         return this.var.toString() ; 

11.     } 

12. }

13. public class GenericsDemo14{ 

14.     public static void main(String args[]){ 

15.         Info<String> i = new Info<String>() ;       // 使用String为泛型类型 

16.         i.setVar("it") ;                            // 设置内容 

17.         fun(i) ; 

18.     } 

19.     public static void fun(Info<?> temp){     // 可以接收任意的泛型对象 

20.         System.out.println("内容:" + temp) ; 

21.     } 

22. }//  内容:it

 受限泛型

Java代码

1.  class Info<T>{ 

2.      private T var ;     // 定义泛型变量 

3.      public void setVar(T var){ 

4.          this.var = var ; 

5.      } 

6.      public T getVar(){ 

7.          return this.var ; 

8.      } 

9.      public String toString(){   // 直接打印 

10.         return this.var.toString() ; 

11.     } 

12. } 

13. public class GenericsDemo17{ 

14.     public static void main(String args[]){ 

15.         Info<Integer> i1 = new Info<Integer>() ;   // 声明Integer的泛型对象 

16.         Info<Float> i2 = new Info<Float>() ;         // 声明Float的泛型对象 

17.         i1.setVar(30) ;                              // 设置整数,自动装箱 

18.         i2.setVar(30.1f) ;                           // 设置小数,自动装箱 

19.         fun(i1) ; 

20.         fun(i2) ; 

21.     } 

22.     public static void fun(Info<? extends Number> temp){ // 只能接收Number及其Number的子类 

23.         System.out.print(temp + "、") ; 

24.     } 

25. }//  30、30.1、

26. ---------------------------------------------------------- 

27. class Info<T>{ 

28.     private T var ;     // 定义泛型变量 

29.     public void setVar(T var){ 

30.         this.var = var ; 

31.     } 

32.     public T getVar(){ 

33.         return this.var ; 

34.     } 

35.     public String toString(){   // 直接打印 

36.         return this.var.toString() ; 

37.     } 

38. } 

39. public class GenericsDemo21{ 

40.     public static void main(String args[]){ 

41.         Info<String> i1 = new Info<String>() ;      // 声明String的泛型对象 

42.         Info<Object> i2 = new Info<Object>() ;      // 声明Object的泛型对象 

43.         i1.setVar("hello") ; 

44.         i2.setVar(new Object()) ; 

45.         fun(i1) ; 

46.         fun(i2) ; 

47.     } 

48.     public static void fun(Info<? super String> temp){   // 只能接收String或Object类型的泛型  ----上限为String

49.         System.out.print(temp + "、") ; 

50.     } 

51. }//  hello、java.lang.Object@1ffc686、

 泛型无法向上转型

Java代码

1.  class Info<T>{ 

2.      private T var ;     // 定义泛型变量 

3.      public void setVar(T var){ 

4.          this.var = var ; 

5.      } 

6.      public T getVar(){ 

7.          return this.var ; 

8.      } 

9.      public String toString(){   // 直接打印 

10.         return this.var.toString() ; 

11.     } 

12. } 

13. public class GenericsDemo23{ 

14.     public static void main(String args[]){ 

15.         Info<String> i1 = new Info<String>() ;      // 泛型类型为String 

16.         Info<Object> i2 = null ; 

17.         i2 = i1 ;                           //这句会出错 incompatible types 

18.     } 

19. }//  编译失败

 泛型接口

Java代码

1.  interface Info<T>{        // 在接口上定义泛型 

2.      public T getVar() ; // 定义抽象方法,抽象方法的返回值就是泛型类型 

3.  } 

4.  class InfoImpl<T> implements Info<T>{   // 定义泛型接口的子类 

5.      private T var ;             // 定义属性 

6.      public InfoImpl(T var){     // 通过构造方法设置属性内容 

7.          this.setVar(var) ;   

8.      } 

9.      public void setVar(T var){ 

10.         this.var = var ; 

11.     } 

12.     public T getVar(){ 

13.         return this.var ; 

14.     } 

15. } 

16. public class GenericsDemo24{ 

17.     public static void main(String arsg[]){ 

18.         Info<String> i = null;        // 声明接口对象 

19.         i = new InfoImpl<String>("汤姆") ;  // 通过子类实例化对象 

20.         System.out.println("内容:" + i.getVar()) ; 

21.     } 

22. }//  内容:汤姆

 泛型方法

Java代码

1.  class Demo{ 

2.      public <T> T fun(T t){            // 可以接收任意类型的数据 

3.          return t ;                  // 直接把参数返回 

4.      } 

5.  } 

6.  public class GenericsDemo26{ 

7.      public static void main(String args[]){ 

8.          Demo d = new Demo() ;   // 实例化Demo对象 

9.          String str = d.fun("汤姆") ; //   传递字符串 

10.         int i = d.fun(30) ;     // 传递数字,自动装箱 

11.         System.out.println(str) ;   // 输出内容 

12.         System.out.println(i) ;     // 输出内容 

13.     } 

14. }//  汤姆  30

 通过泛型方法返回泛型类型实例

Java代码

1.  class Info<T extends Number>{ // 指定上限,只能是数字类型 

2.      private T var ;     // 此类型由外部决定 

3.      public T getVar(){ 

4.          return this.var ;    

5.      } 

6.      public void setVar(T var){ 

7.          this.var = var ; 

8.      } 

9.      public String toString(){       // 覆写Object类中的toString()方法 

10.         return this.var.toString() ;     

11.     } 

12. } 

13. public class GenericsDemo27{ 

14.     public static void main(String args[]){ 

15.         Info<Integer> i = fun(30) ; 

16.         System.out.println(i.getVar()) ; 

17.     } 

18.     public static <T extends Number> Info<T> fun(T param){//方法中传入或返回的泛型类型由调用方法时所设置的参数类型决定 

19.         Info<T> temp = new Info<T>() ;      // 根据传入的数据类型实例化Info 

20.         temp.setVar(param) ;     // 将传递的内容设置到Info对象的var属性之中 

21.         return temp ;   // 返回实例化对象 

22.     } 

23. }//  30

 使用泛型统一传入的参数类型

Java代码

1.  class Info<T>{    // 指定上限,只能是数字类型 

2.      private T var ;     // 此类型由外部决定 

3.      public T getVar(){ 

4.          return this.var ;    

5.      } 

6.      public void setVar(T var){ 

7.          this.var = var ; 

8.      } 

9.      public String toString(){       // 覆写Object类中的toString()方法 

10.         return this.var.toString() ;     

11.     } 

12. }

13. public class GenericsDemo28{ 

14.     public static void main(String args[]){ 

15.         Info<String> i1 = new Info<String>() ; 

16.         Info<String> i2 = new Info<String>() ; 

17.         i1.setVar("HELLO") ;        // 设置内容 

18.         i2.setVar("汤姆") ;       // 设置内容 

19.         add(i1,i2) ; 

20.     } 

21.     public static <T> void add(Info<T> i1,Info<T> i2){ 

22.         System.out.println(i1.getVar() + " " + i2.getVar()) ; 

23.     } 

24. }// HELLO 汤姆

 泛型数组

Java代码

1.  public class GenericsDemo30{ 

2.      public static void main(String args[]){ 

3.          Integer i[] = fun1(1,2,3,4,5,6) ;   // 返回泛型数组 

4.          fun2(i) ; 

5.      } 

6.      public static <T> T[] fun1(T...arg){  // 接收可变参数 

7.          return arg ;            // 返回泛型数组 

8.      } 

9.      public static <T> void fun2(T param[]){   // 输出 

10.         System.out.print("接收泛型数组:") ; 

11.         for(T t:param){ 

12.             System.out.print(t + "、") ; 

13.         } 

14.     } 

15. }//  接收泛型数组:1、2、3、4、5、6、

 泛型的嵌套设置

Java代码

1.  class Info<T,V>{      // 接收两个泛型类型 

2.      private T var ; 

3.      private V value ; 

4.      public Info(T var,V value){ 

5.          this.setVar(var) ; 

6.          this.setValue(value) ; 

7.      } 

8.      public void setVar(T var){ 

9.          this.var = var ; 

10.     } 

11.     public void setValue(V value){ 

12.         this.value = value ; 

13.     } 

14.     public T getVar(){ 

15.         return this.var ; 

16.     } 

17.     public V getValue(){ 

18.         return this.value ; 

19.     } 

20. } 

21. class Demo<S>{ 

22.     private S info ; 

23.     public Demo(S info){ 

24.         this.setInfo(info) ; 

25.     } 

26.     public void setInfo(S info){ 

27.         this.info = info ; 

28.     } 

29.     public S getInfo(){ 

30.         return this.info ; 

31.     } 

32. }

33. public class GenericsDemo31{ 

34.     public static void main(String args[]){ 

35.         Demo<Info<String,Integer>> d = null ;  // 将Info作为Demo的泛型类型 

36.         Info<String,Integer> i = null ;   // Info指定两个泛型类型 

37.         i = new Info<String,Integer>("汤姆",30) ;    // 实例化Info对象 

38.         d = new Demo<Info<String,Integer>>(i);//在Demo类中设置Info类的对象 

39.         System.out.println("内容一:" + d.getInfo().getVar()) ; 

40.         System.out.println("内容二:" + d.getInfo().getValue()) ; 

41.     } 

42. } // 内容一:汤姆 内容二:30

  泛型方法不一定要通过参数来确定泛型准确类型,可以只通过返回值,比如:

 public static <E> ArrayList<E> newArrayList() {
         return new ArrayList<E>();
 }

 public List<PrepaidHistory> queryHistories(Long skyid,PrepaidHistoryType type, Date from, Date end) { 

         return Lists.newArrayList();

}

 这样Lists.newArrayList();
智能的知道返回类型为PrepaidHistory

一、内部类(局部内部类、成员内部类、匿名内部类)

1、定义:内部类就是在类的内部定义一个类,它的分类有成员内部类、局部内部类、匿名内部类,
它可以定义在类中方法外,也可以定义在类中方法内,内部类的好处是可以访问外部类的私有成员,但外部类无法访问内部类的私有成员
通过使用内部类可以确保程序的结构清晰和代码精炼

编译后的内部类名称:InnerTest$A.class

2、分类:成员内部类(静态成员内部类)、局部内部类、匿名内部类
a、成员内部类(非静态内部类):与外部类的属性和方法并列,成员内部类可以看作是外部类的实例变量
在内部类中访问实例变量:this.字段;
在内部类中访问外部类的实例变量:外部类名.this.字段
成员内部类中不能有静态字段或方法(final修饰的常量除外),因为Static在加载时就创建,此时内部类可能还没被实例化
在外部类的外部实例化对象:
Foo foo = new Foo();
Koo koo = foo.new Koo();
Foo.Koo koo = new Foo().new Koo();

b、静态内部类
静态内部类可以直接访问外部类的静态成员,不能访问外部类的实例成员,但可以通过外部类的实例(new 对象)来访问
静态内部类里面可以定义静态成员(其他内部类不可以)
静态内部类不可以使用private修饰
静态内部类的对象可以直接生成
Foo.Koo koo = new Foo().new Koo();
c、局部内部类
在方法中定义的内部类称为局部内部类,类似局部变量,不可以加修饰符public、protected、private,其范围为定义它的代码块
可以访问外部类的所有成员,还可以访问所在方法中的final修饰的参数和变量,但不能访问方法体中的局部变量
d、匿名内部类
匿名内部类没有类名,它必须继承一个类或者实现一个接口,并且不能显示的extends或implements关键字
匿名内部类不能有构造方法,因为它没有类名。可以通过new<父类名>的方法创建实例对象,匿名类的创建与定义同时进行
匿名内部类只能一次性的创建其对象
匿名内部类既可以在方法体中,也可以在参数列表中
注意:匿名内部类一定是在new的后面隐含实现一个接口或继承一个类,匿名内部类不是抽象类
      匿名内部类必须实现他的父类抽象接口或接口里的所有的抽象方法
new 父类的构造器(实参列表)|实现接口(){
//类体
}
new Object(){
}

3、内部类的访问规则:内部类可以直接访问外部类中的成员,包括私有
                    最近的外部类要访问内部类必须建立内部类对象new Inner().fumction()来访问内部类中的成员
               如: Outer.Inner in = new Outer().new Inner();
                    in.function();

4、使用:当描述事物时,事物的内部还有事物,该事物用内部类来描述,因为内部事物在使用外部事物的内容。
内部类定义在局部时,不能使用成员修饰符、static修饰,使用时需要new—
可以直接访问外部类中的成员,但不可访问它所在的局部中的变量,只能访问被final修饰的局部变量

5、代码分析:例1:----分类
public class Demo2 {
class B{//成员内部类------Demo2$B.class
}
static class A{//静态成员内部类------Demo2$A.class
}
void show(){
class C{//局部内部类-------Demo2$1C.class
}
}
public static void main(String[] args) {
class C{//局部内部类----Demo2$2C.class
}
System.out.println();
}
}

 

例2:-----匿名内部类

1、  匿名内部类其实就是内部类的简写格式
2、  定义前题必须继承一个类或实现一个接口
3、  匿名内部类的格式: new 父类或接口(){定义子类的内容}
4、  匿名内部类定义的方法最好不要超过三个

public class Test{
       public static void main(String[] agrs){
              Test t=new Test();   //new了 一个Test对象
              t.te(new A(){                //调用实例方法并且声明一个匿名内部类类作为一个参数传入
                            public void as(){
                                   System.out.println("我是实现了接口A的匿名类");
                            }
                     }
              );
      }         
      void te(A a){    //实例方法
              a.as();
      }
}
interface A{    //声明了一个接口类
       void as();    //抽象方法
}

 

例3:
class A{
       void as(){
              System.out.println("我是内部类A");
       }
}
class B{
       void bs(){
              System.out.println("我是内部类B");
       }
}
public class MultipleExtends {
       private class C extends A{}
       private class D extends B{}
       public static void main(String[] args) {
              MultipleExtends m=new MultipleExtends(); //声明一个外部类的对象
              MultipleExtends.C c=m.new C(); //让外部类对象持有一个
              MultipleExtends.D d=m.new D();//内部类对象的引用
              c.as();                                                                                                                          
              d.bs();                                                                                                                          
       }
}


例4:-----内部类是可以被私有的
public class MemberClass {
   private int i=10;  //定义一个私有字段
    private static int j=20;      
    public static void main(String[] args) {
MemberClass mc=new MemberClass();//new 一个外部类的对象
A a=mc.new A();//A a=new MemberClass().new A();//new 一个内部类的对象
a.as();//调用内部类的实例方法
    }
private class A{
//static int j=6;
//int i=5;              //定义一个内部类的实例字段    
void as(){     //定义一个内部类的实例方法
System.out.println("这里是内部类A");   
System.out.println("调用外部类私有实例字段i:"+i);
System.out.print("调用外部类私有静态字段j:"+j);
}
}
}

//---------- java ----------
//这里是内部类A
//调用外部类私有实例字段i:10
//调用外部类私有静态字段j:20

 


例5:----静态内部类
public class StaticClass {         
       private static int i=10; //定义一个私有静态字段
       //private int j=7;
       public static void main(String[] args) {
              StaticClass sc=new StaticClass();//new 一个外部类的对象
              A a=new StaticClass.A(); //new 一个静态内部类
              a.as();            //调用静态内部类的实例方法
              A.at        //调用静态内部类的静态方法
       }
       static class A{       
              int i=5;
              static at(){   //定义静态内部类的静态方法
                     System.out.println("这里是静态内部类的静态方法");
              }
              void as(){                 //定义静态内部类的实例方法
                     System.out.println("这里是内部类A");
                     System.out.print("调用外部类私有静态字段i:"+i);
              }
       }
}

 
例6:------局部内部类
public class InteriorClass {
         private int i=5;
         public static void main(String[] args) {
                   InteriorClass ic=new InteriorClass();   //new 一个对象
                   ic.as();             //调用实例方法
                   //      B b=ic.new B();
         }
         void as(){
                   final int y=5;        //常量       
                   int u=1;            //局部变量
                   class B{
                            void bs(){
                                     System.out.println("这里是内部类B");        
                                     System.out.println("调用i"+i);
                                     System.out.println("常量"+y);
                            }                          
                   }
                   new B().bs();
         }
}

----------------------------------------------------------------------|----------------------------------------------------------------------|
----------------------------------------------------------------------|----------------------------------------------------------------------|
----------------------------------------------------------------------|----------------------------------------------------------------------|

二、异常(try\catch\fainlly\throw\throws)
i、 异常的含义和分类
  a)含义:异常是对问题的描述,将问题进行问题的封装
  b)分类:java.lang.Object-----Throwable(java中所有错误和异常的超类)-----Error(无法通过代码来处理的错误)        
                                            |---------------Exception(可处理的异常,并能恢复运行)
     |---RuntimeException(运行时异常)---可以不捕获也可以不处理
     |----CheckedException(已检查时异常)----必须捕获或处理不然编译失败---IOException\SQLException
 标签(Marker)接口:既无字段又无方法---Cloneable/Serializable/EventListener

 Error----如:JVM硬件错误----OutOfMemoryError—内存不足、不断的创建实例、StackOverflowError---递归导致的堆异常
 
 2、异常分类(Throwable)
  1、编译时被检测的异常
     throws 需要处理
  2、编译时不被检测的异常---运行时异常(RuntimeException或其子类)
    函数内throw,函数外不需要声明,--------无法处理,需要修改代码

ii、 异常处理
a)RuntimeEception及其子类异常,不需要程序员处理,其后语句不编译
b)非运行时异常必须处理
c)Exeception中有一个特殊的子类异常RuntimeException,如果在方法内抛出该异常,方法上可以不用声明,编译可以通过;如果在方法上声明了该异常,调用者可以不用处理,编译可以通过。之所以不在函数声明,是因为不希望让使用者处理,当异常发生时,希望程序停止,程序员修正程序代码

异常的捕获和处理

第一种格式:
try{
         //可能抛出异常的语句
}catch(异常类型 e){
         //处理语句1
} catch(异常类型 e){
         //处理语句2
}finally{
         //一定执行的语句
}

finally只要用于异常处理,修饰异常块,无论异常是否处理都会执行
finally在return、throw前输出,不管return是在try还是catch中
finally定义一定执行的代码,通常用于关闭资源------如:数据库关闭连接

finally块在以下情况将不会被执行:
(1)finally块中发生了异常;
(2)程序所在线程死亡;
(3)在前面的代码中用了System.exit(0);
(4)关闭CPU。

第二种格式:
try{

}finally{

}

第三种格式:
try{

}catch(){

}

 
iii.在多个catch时只执行一个,自上而下遇到的第一个异常所对应的catch,如果没有对应的catch,则先执
行finally后在抛出,没有finally则直接抛出,定义多个catch可精确地定位异常。如果为子类的异常定
义了特殊的catch块,而父类的异常则放在另外一个catch块中,此时,必须满足以下规则:子类异常的处
理块必须在父类异常处理块的前面,否则会发生编译错误。所以,越特殊的异常越在前面处理,越普遍的
异常越在后面处理。这类似于制订防火墙的规则次序:较特殊的规则在前,较普通的规则在后。

throws--------声明方法抛出异常
1、说明:当不知道在当前代码中如何处理的时候,可以选择用throws将异常交给上层调用者处理
2、基本格式:
类型 方法名(形参列表)throws 异常列表(逗号隔开){
          //代码
}

例:
//手工抛出异常实例
public class JavaThrow1{
         public static void main(String[] args){
                   System.out.print(" Now");
                   try{
                            System.out.print(" is");
                            throw new NullPointerException();//直接抛出异常转到catch进行处理
                            //System.out.println("This will not excute!");//有throw这句执行不到
                   }catch (NullPointerException e){
                            System.out.print(" the");
                   }
                   System.out.print(" time.\n");
         }
}

//自动抛异常
public class ExTest {
public static void main(String[] args){
String s=null;
try{
System.out.println("0");
int i=s.length();//自动抛异常--空指针异常
System.out.println("2");
}finally{
System.out.println("1");
}
}
}

例:--------throws
public class ExceptionTest4{
public static void p() throws ArithmeticException{
//间接抛出异常,自己并未处理,让方法的调用者来处理
int i;
i=4/0;//可能发生异常
System.out.println("8");
}
  public static void main(String[] args){    
try{ 
try{
                p();//方法的直接调用调用者捕获异常处理
}catch(ArithmeticException e){
System.out.println("Divider is zero !");
}
}catch(RuntimeException  e){
              System.out.println("4");
}
  }
}

v.java异常处理机制

答:程序出现想数组角标越界,空指针等错误时,JAVA就会用异常Throwable
来描述这些错误,Throwable继承了Object类,同时实现了Serializable接口,
根据出现的问题是否可以通过程序来解决。把Throwable分为Error错误和Exception异常,Exception根据编译时是否会被检
测分为运行时异常RuntimeException和已检测异常CheckedException。异常的处理方
式有两种,在发生异常的地方直接使用catch处理,或者将异常抛出给调用者,让调用者来处理。

 1、检查性异常------程序正确,但因为外在的环境条件不满足引发。例如:用
户错误及I/O问题----程序试图打开一个并不存在的远程Socket端口。这不是程序
本身的逻辑错误,而很可能是远程机器名字错误(用户拼写错误)。对商用软件系统,
程序开发者必须考虑并处理这个问题。JAVA编译器强制要求处理这类异常,如果不
捕获这类异常,程序将不能被编译。
  2、运行期异常------这意味着程序存在bug,如数组越界,0被除,入参不满足规
范.....这类异常需要更改程序来避免,JAVA编译器强制要求处理这类异常。
  3、错误------一般很少见,也很难通过程序解决。它可能源于程序的bug,但一般
更可能源于环境问题,如内存耗尽。错误在程序中无须处理,而有运行环境处理。


三、 自定义异常
当jdk内置异常类型不能满足系统需求时,我们需要自定义异常,如:
public class MyExceptionTest {
         public static void main(String[] args) {
                  MyExceptionTest mt = new MyExceptionTest();
                  mt.manager();
         }

         public void registe(int num) throws MyException{
                  if(num<0){
                           throw new MyException("人数为负数",3);
                  }
                  System.out.println(" 登记人数为:"+num);
         }

         public void manager(){
                  try{
                           registe(-100);
                  }catch (MyException e){
                           System.out.println("登记类型出错:"+e.getId());
                           e.printStackTrace();
                  }       
                  System.out.println(" 操作结束!");
         }
}
class MyException extends Exception{
         private int id;
         public MyException(){}
         public MyException(String message,int id){
                  super(message);//调用父类的getMessage()
                  //父类中已经定义了getMessage()可以直接使用-----------该方法为Exception继承Throwable的
                  this.id=id;
         }
         public int getId(){
                  return id;
         }
}

自定义异常类必须要继承Exception/RuntimeException,如果该异常的发生无法再继续进行运算,就让它继承RuntimeException 
继承的原因是为了让该类自定义类具备可抛型,让该类具备操作异常的共性方法
自定义异常:按照JAVA的OO思想,将程序中出现的特有问题进行封装

四、常见异常
IOException--------------------输入输出异常
ClassNotFoundException-------找不到类异常
NumberFormatException---------字符串到数字格式的异常
FileNotfoundException-----------文件找不到异常
NoSuchMethodException---------------请求方法异常

运行时异常:RuntimeException
SecurityException-----------试图违反安全性异常
NullPointerException----没有实例化却调用其属性和方法--------------空指针异常
ArrayIndexOfBoundsException---------数组越界异常
StringIndexOfBoundsException---------字符串越界异常
ArithmeticException--------------算数异常/除数为零异常
NullPointerException-------试图查找null异常


Main方法通常情况下不能把异常抛给JVM

Super a = new subclass();//向上转型----
---overload看左边,override看右边
-----------------------------------多态针对的是方法
 

异常的好处:1、将问题进行封装
            2、将正常流程代码和问题代码进行分离,方便阅读

处理原则:
1、处理方式有:try或者throws
2、调用到抛出异常的功能时,抛出几个处理几个(一个try对应多个catch)
3、多个catch,父类的catch放到最后
4、Catch内,需要定义针对性的处理方式,不要简单的定义printStackTrace输出语句,也不要不写
5、当铺获到的异常,本功能处理不了时,可以继续在catch中抛出

6、  例:
try{
throw new AException();
}catch(AException e){
throw e;
}

7、如果异常在内部被处理(catch),外部则不需要抛出

基本格式:catch用来处理异常,如果该异常为检测时异常时,必须要处理或者抛出
异常继承时,子类只能抛出父类的异常或者该异常的子类/子集异常,也可以不抛出异常

异常的注意事项
1、在子父类覆盖时,
a)子类抛出的异常必须是父类异常的子类或子集
b)如果父类或接口没有异常抛出时,子类覆盖出现异常,只能try不能抛
c)如果父类中是RuntimeException时,子类可以不用抛出异常,反之,子类为RuntimeException异常,父类为其异常的子类或自己都可以编译通过

1、throw 与throws
throw 后跟异常对象(只能有一个),throws后跟异常类(多个时用逗号隔开);
位置:throw用在方法体中,代表手工抛异常,throws用在方法声明上,代表该方法可能发生异常

2、RuntimeException和CheckedException的区别
前者可以不在方法上声明也可以不处理,后者必须要处理或者抛出

----------------------------------------------------------------------|----------------------------------------------------------------------|
----------------------------------------------------------------------|----------------------------------------------------------------------|
----------------------------------------------------------------------|----------------------------------------------------------------------|
                                                                                                                                                                                                                                                                                                                                                                                                                     
三、集合(collection、set、list、map)

一、定义:
集合是Java里面最常用的,也是最重要的一部分。能够用好集合和理解好集合对于做Java程序的开发拥有无比的好处。
容器:用来存储数据,不同的容器集合以不同的格式保存对象,它能够自动的改变这个容器的所能存放的数据数量的大小。这一点上,如果使用数组来存储的话,就显得十分的笨拙。
对于对象集合,必须执行的操作主要以下三种:
?       添加新的对象
?       删除对象
?       查找对象
Java容器类类库的用途是“保存对象”,并将其划分为两个不同的概念:
1)  Collection 。 一组对立的元素,通常这些元素都服从某种规则。List必须保持元素特定的顺序,而Set 不能有重复元素。
2)  Map 。 一组 成对的“键值对”对象。

? Collection – 对象之间没有指定的顺序,允许重复元素。
? Set –  对象之间没有指定的顺序,不允许重复元素
? List–  对象之间有指定的顺序,允许重复元素,并引入位置下标。 
? Map –  接口用于保存关键字(Key)和数值(Value)的集合,集合中的每个对象加入时都提供数值和关键字。Map 接口既不继承 Set 也不继承 Collection。 
List、Set、Map共同的实现基础是Object数组


Collection
1.2.1常用方法
Collection 接口用于表示任何对象或元素组。想要尽可能以常规方式处理一组元素时,就使用这一接口。Collection 在前面的大图也可以看出,它是List和Set 的父类。并且它本身也是一个接口。它定义了作为集合所应该拥有的一些方法。如下:
注意:
集合必须只有对象,集合中的元素不能是基本数据类型。
Collection接口支持如添加和除去等基本操作。设法除去一个元素时,如果这个元素存在,除去的仅仅是集合中此元素的一个实例。
?     boolean add(Object element) 
?     boolean remove(Object element) 
Collection 接口还支持查询操作:
?     int size() 
?     boolean isEmpty() 
?     boolean contains(Object element) 
?     Iterator iterator() 
组操作 :Collection 接口支持的其它操作,要么是作用于元素组的任务,要么是同时作用于整个集合的任务。
?     boolean containsAll(Collection collection) 
?     boolean addAll(Collection collection) 
?     void clear() 
?     void removeAll(Collection collection) 
?     void retainAll(Collection collection) 
containsAll() 方法允许您查找当前集合是否包含了另一个集合的所有元素,即另一个集合是否是当前集合的子集。其余方法是可选的,因为特定的集合可能不支持集合更改。 addAll() 方法确保另一个集合中的所有元素都被添加到当前的集合中,通常称为并。 clear() 方法从当前集合中除去所有元素。 removeAll() 方法类似于 clear() ,但只除去了元素的一个子集。 retainAll() 方法类似于 removeAll() 方法,不过可能感到它所做的与前面正好相反:它从当前集合中除去不属于另一个集合的元素,即交。
 
集合类的基本方法的使用:
import java.util.*;
public class CollectionToArray {
public static void main(String[] args) {
Collection collection1=new ArrayList();//创建一个集合对象
collection1.add("000");//添加对象到Collection集合中
collection1.add("111");
collection1.add("222");
System.out.println("集合collection1的大小:"+collection1.size());
System.out.println("集合collection1的内容:"+collection1);
collection1.remove("000");//从集合collection1中移除掉 "000" 这个对象
System.out.println("集合collection1移除 000 后的内容:"+collection1);
System.out.println("集合collection1中是否包含000 :"+collection1.contains("000"));
System.out.println("集合collection1中是否包含111 :"+collection1.contains("111"));
Collection collection2=new ArrayList();
collection2.addAll(collection1);//将collection1 集合中的元素全部都加到collection2中
System.out.println("集合collection2的内容:"+collection2);
collection2.clear();//清空集合 collection1 中的元素
System.out.println("集合collection2是否为空 :"+collection2.isEmpty());
//将集合collection1转化为数组
Object s[]= collection1.toArray();
for(int i=0;i<s.length;i++){
System.out.println(s[i]);
}
}
}
运行结果为:
集合collection1的大小:3
集合collection1的内容:[000, 111, 222]
集合collection1移除 000 后的内容:[111, 222]
集合collection1中是否包含000 :false
集合collection1中是否包含111 :true
集合collection2的内容:[111, 222]
集合collection2是否为空 :true
111
222
这里需要注意的是,Collection 它仅仅只是一个接口,而真正使用的时候,却是创建该接口的一个实现类。作为集合的接口,它定义了所有属于集合的类所都应该具有的一些方法。
而ArrayList (列表)类是集合类的一种实现方式。
 
Collection的实现基础是数组,所以有转换为Object数组的方法: 
?     Object[] toArray() 
?     Object[] toArray(Object[] a)
其中第二个方法Object[] toArray(Object[] a) 的参数 a 应该是集合中所有存放的对象的类的父类

1.2.2  迭代器(Iterator)
迭代器(Iterator)本身就是一个对象,它的工作就是遍历并选择集合序列中的对象,而客户端的程序员不必知道或关心该序列底层的结构。此外,迭代器通常被称为“轻量级”对象,创建它的代价小。但是,它也有一些限制,例如,某些迭代器只能单向移动。
Collection 接口的 iterator() 方法返回一个 Iterator。Iterator 和Enumeration 接口类似。使用 Iterator 接口方法,可以从头至尾遍历集合,并安全的从底层 Collection 中除去元素。
迭代器的使用:
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
 
public class IteratorDemo {
public static void main(String[] args) {
Collection collection = new ArrayList();
collection.add("s1");
collection.add("s2");
collection.add("s3");
Iterator iterator = collection.iterator();//得到一个迭代器
while (iterator.hasNext()) {//遍历
Object element = iterator.next();
System.out.println("iterator = " + element);
}
if(collection.isEmpty())
System.out.println("collection is Empty!");
else
System.out.println("collection is not Empty! size="+collection.size());
Iterator iterator2 = collection.iterator();
while (iterator2.hasNext()) {//移除元素
Object element = iterator2.next();
System.out.println("remove: "+element);
iterator2.remove();
}
Iterator iterator3 = collection.iterator();
if (!iterator3.hasNext()) {//察看是否还有元素
System.out.println("还有元素");
}
if(collection.isEmpty())
System.out.println("collection is Empty!");
//使用collection.isEmpty()方法来判断
}
}
程序的运行结果为:
iterator = s1
iterator = s2
iterator = s3
collection is not Empty! size=3
remove: s1
remove: s2
remove: s3
还有元素
collection is Empty!
可以看到,Java的Collection的Iterator 能够用来,:
1)使用方法 iterator() 要求容器返回一个Iterator .第一次调用Iterator 的next() 方法时,它返回集合序列的第一个元素。
2)使用next() 获得集合序列的中的下一个元素。
3)使用hasNext()检查序列中是否元素。
4)使用remove()将迭代器新返回的元素删除。
需要注意的是:方法删除由next方法返回的最后一个元素,在每次调用next时,remove方法只能被调用一次 。

1.3 List
1.3.1概述
Collection接口实际上并没有直接的实现类。而List是容器的一种,表示列表的意思。当我们不知道存储的数据有多少的情况,
我们就可以使用List 来完成存储数据的工作。例如保存一个应用系统当前的在线用户的信息。List的最大的特点就是能够自动
的根据插入的数据量来动态改变容器的大小。

1.3.2  常用方法
List 就是列表的意思,它是Collection 的一种,即继承了 Collection 接口,又定义一个允许重复项的有序集合。该接口不但
能够对列表的一部分进行处理,还添加了面向位置的操作。List 是按对象的进入顺序进行保存对象,而不做排序或编辑操作。它
除了拥有Collection接口的所有的方法外还拥有一些其他的方法。面向位置的操作包括插入某个元素或 Collection 的功能,还
包括获取、除去或更改元素的功能。在 List 中搜索元素可以从列表的头部或尾部开始,如果找到元素,还将报告元素所在的位置。

1、 void add(int index, Object element):添加对象element到位置index上
2、 boolean addAll(int index, Collection collection):在index位置后添加容器collection中所有的元素
3、 Object get(int index) :取出下标为index的位置的元素
4、 int indexOf(Object element) :查找对象element 在List中第一次出现的位置
5、 int lastIndexOf(Object element) :查找对象element 在List中最后出现的位置
6、 Object remove(int index) :删除index位置上的元素
7、 Object set(int index, Object element) :将index位置上的对象替换为element 并返回老的元素。

List(提供基于索引的对成员的随机访问)------ArrayList-----提供快速的基于索引的成员访问,对尾部成员的增加和删除支持较好
  成员可为任意Object子类的对象
----------LinkedList-----对列表中任何位置的成员的增加和删除支持较好,但对基于索引的成员访问支持性能较差
  成员可为任意Object子类的对象 
         
在“集合框架”中有两种常规的 List 实现:ArrayList 和 LinkedList。使用两种 List 实现的哪一种取决于您特定的需要。如果要
支持随机访问,而不必在除尾部的任何位置插入或除去元素,那么,ArrayList 提供了可选的集合。但如果,您要频繁的从列表的中间
位置添加和除去元素,而只要顺序的访问列表元素,那么,LinkedList 实现更好。

LinkedList 来实现一个简单的队列的例子:
import java.util.*;
 
public class ListExample {
  public static void main(String args[]) {
    LinkedList queue = new LinkedList();
    queue.addFirst("Bernadine");
    queue.addFirst("Elizabeth");
    queue.addFirst("Gene");
    queue.addFirst("Elizabeth");
    queue.addFirst("Clara");
    System.out.println(queue);
    queue.removeLast();
    queue.removeLast();
    System.out.println(queue);
  }
}
运行程序产生了以下输出。请注意,与 Set 不同的是 List 允许重复。
[Clara, Elizabeth, Gene, Elizabeth, Bernadine]
[Clara, Elizabeth, Gene]
该的程序演示了具体 List 类的使用。第一部分,创建一个由 ArrayList 支持的 List。填充完列表以后,特定条目就得到了。示例
的 LinkedList 部分把 LinkedList 当作一个队列,从队列头部添加东西,从尾部除去。

List 接口不但以位置友好的方式遍历整个列表,还能处理集合的子集:
ListIterator listIterator() :返回一个ListIterator 跌代器,默认开始位置为0
ListIterator listIterator(int startIndex) :返回一个ListIterator 跌代器,开始位置为startIndex 
List subList(int fromIndex, int toIndex) :返回一个子列表List ,元素存放为从 fromIndex 到toIndex之前的一个元素。
处理 subList() 时,位于 fromIndex 的元素在子列表中,而位于 toIndex 的元素则不是,提醒这一点很重要。

for-loop :
for (int i=fromIndex; i<toIndex; i++) {
  // process element at position i
}

对子列表的更改(如 add()、remove() 和 set() 调用)对底层 List 也有影响。


我们看一个List的例子:
import java.util.*;
 
public class ListIteratorTest {
public static void main(String[] args) {
List list = new ArrayList();
list.add("aaa");
list.add("bbb");
list.add("ccc");
list.add("ddd");
System.out.println("下标0开始:"+list.listIterator(0).next());//next()
System.out.println("下标1开始:"+list.listIterator(1).next());
System.out.println("子List 1-3:"+list.subList(1,3));//子列表
ListIterator it = list.listIterator();//默认从下标0开始
//隐式光标属性add操作 ,插入到当前的下标的前面
it.add("sss");
while(it.hasNext()){
System.out.println("next Index="+it.nextIndex()+",Object="+it.next());
}
//set属性
ListIterator it1 = list.listIterator();
it1.next();
it1.set("ooo");
ListIterator it2 = list.listIterator(list.size());//下标
while(it2.hasPrevious()){
System.out.println("previous Index="+it2.previousIndex()+",Object="+it2.previous());
}
}
}
程序的执行结果为:
下标0开始:aaa
下标1开始:bbb
子List 1-3:[bbb, ccc]
next Index=1,Object=aaa
next Index=2,Object=bbb
next Index=3,Object=ccc
next Index=4,Object=ddd
previous Index=4,Object=ddd
previous Index=3,Object=ccc
previous Index=2,Object=bbb
previous Index=1,Object=aaa
previous Index=0,Object=ooo
我们还需要稍微再解释一下 add() 操作。添加一个元素会导致新元素立刻被添加到隐式光标的前面。因此,添加元素后调用 
previous() 会返回新元素,而调用 next() 则不起作用,返回添加操作之前的下一个元素。下标的显示方式,如下图所示:

1.3.3实现原理
ArrayList中主要包含2个属性:
private transient Object elementData[];
private int size;
其中数组::elementData[] 是列表的实现核心属性:数组。 我们使用该数组来进行存放集合中的数据。而我们的初始化参数就
是该数组构建时候的长度,即该数组的length属性就是initialCapacity 参数。

Keys:transient 表示被修饰的属性不是对象持久状态的一部分,不会自动的序列化。

如果要判断一个类的一个实例对象是否等于另外一个对象,那么我们就需要自己覆写Object类的public boolean equals(Object obj)
 方法。如果不覆写该方法的话,那么就会调用Object的equals()方法来进行判断。这就相当于比较两个对象的内存应用地址是否相等了。
在集合框架中,不仅仅是List,所有的集合类,如果需要判断里面是否存放了的某个对象,都是调用该对象的equals()方法来进行处理的。

集合的个数用size();数组用length;String用length();

Collection<E> extends Iterable

方法:
增          add();addAll()---------boolean
删          remove();removeAll();------------boolean
                 clear()-------void
查          Iterator<E>()--------Iterator
改          toArray()-----Object   数组
元素数      size()--------------int

List<E>  extends Collection<E>----------有序的Collection,可重复

新增方法:
add(int index, E element)//在指定位置添加---------添加顺序要是连续的
get(int index)//返回指定位置
listIterator(int index)//从指定位置开始迭代

AbstractList<E> extends AbstractCollection<E> implements List<E>

Set<E>
无序的不可重复的Collection

Map<K,V>
键K不可以重复,值V可以重复

ArrayList------------在查询时快,增删改时慢

例:
import java.util.*;
//注解
//@SuperessWarnings("unchecked")---------

public class Demo{
public static void main(String[] args) {
List<Object> alist = new ArrayList<Object>();//List是接口,不能被实例化

//增加
alist.add("123");
alist.add(new StringBuffer("1s1"));
alist.add(3.4f);
alist.add(3.01d);
alist.add(1,222);//[123, 222, 323]

alist.add("123");//[123, 222, 323, 123]----------可重复
System.out.println(alist);//相当于toString()
System.out.println("长度为:"+alist.size());
System.out.println("------------------------------");
//删除
alist.remove(2);//角标
System.out.println(alist);
//alist.clear();
alist.remove("123");//移除的是第一次出现的
System.out.println(alist);
System.out.println(alist.isEmpty());
System.out.println("------------------------------");
//遍历
//第一种:
for(int i=0;i<alist.size();i++){
Object e = alist.get(i);
if(e instanceof String){//Object inteanceof 类型----判断类型是否是Object的实例
System.out.println(((String)e).length());
}else if(e instanceof Double){
System.out.println(((Double)e).intValue());
}
}

//第二种:
for(Object e:alist){
System.out.println(e);
}
System.out.println("------------------------------");
//List<Integer> alist1 = new ArrayList<Integer>();
int size = alist.size();
System.out.println(" size="+size);
boolean flag = alist.isEmpty();//判断是否为空
System.out.println(" flag="+flag);
System.out.println("------------------------------");
//第三种:Iterable-----迭代器输出
//Iterable Iterator<T>iterator();
Iterator<Object> it = alist.iterator();//Iterator与Iterable无关,是两个接口
while(it.hasNext()){
Object i = it.next();
System.out.println(i);
}
//System.out.println(alist.iterator());
System.out.println("--------------------------------");
//第一种:
for(int i=0;i<alist.size();i++){//注意:size()是动态变化的
System.out.print(alist.get(i)+",");//按照下标获取
}
System.out.println(" ");
System.out.println("--------------------------------");
//第四种:
for(Iterator it2 = alist.iterator();it2.hasNext();){
System.out.println(it2.next());
}
//转换
//alist.toArray();
//System.out.println(alist);

}
}


LinkedList-----------增删改快,查询慢
例:
import java.util.*;
public class  Demo1{
public static void main(String[] args) {
Queue<Integer> link = new LinkedList<Integer>();
//Queue是单端队列----------单链表
link.add(21);
link.offer(111);//队尾添加========>add
link.poll();//队头删除
System.out.println(link.remove());
link.poll();//为空时返回null==========>remove
System.out.println(link.poll());
link.peek();//访问=========>get
//link.remove();为空时异常
System.out.println(link.size());
System.out.println("-------------------------------------");

Deque<Object> dl = new LinkedList<Object>();
//Deque是双端队列--------双向链表
-------------------------------------------------------------------------------
第一个元素(头部)             最后一个元素(尾部)

               抛出异常     特殊值          抛出异常       特殊值

插入 addFirst(e)   offerFirst(e)   addLast(e)     offerLast(e) 
移除 removeFirst() pollFirst()     removeLast()   pollLast() 
检查 getFirst()    peekFirst()     getLast()      peekLast() 
-------------------------------------------------------------------------------
//add、offer默认在尾部增加 
//remove、poll默认从第一个开始删除

dl.add(123);//默认在尾部增加
dl.addFirst("sss");
dl.offerFirst(231);
dl.addLast(2212);
dl.offerLast(654);
System.out.println(dl);

System.out.println("-------------------1---------------");
//dl.removeFirst();
//System.out.println(dl);
//System.out.println("------------------2----------------");
dl.pollLast();
System.out.println(dl);
System.out.println("-----------------3-----------------");

        System.out.println(dl.getFirst());

System.out.println("-----------------4-----------------");
dl.peek();
System.out.println(dl);
}
}


注意:所有的集合框架都位于java.util包中,使用前必须导入该包中的类
熟悉并记忆以下接口之间的关系和相关方法
Iterable--------->接口(java.lang)
        常见方法1:Iterator<T> iterator()
 Iterator--------->接口
        常见方法1:boolean hasNext()
        常见方法2:E   next()
 Collection------->Iterable-------------->接口 
         常见方法1:int size()
         常见方法2:boolean isEmpty()
 常见方法3:void clear()
         常见方法4:boolean  add(E e)
 常见方法5:remove()
 List(线性表)----->Collection------->Iterable-------------->接口
         常见方法1:add(int index,E e)
 常见方法2:remove(int index,E e)
   常见方法3:E get(int index)
 Queue(队列)----->Collection------->Iterable-------------->接口
         常见方法1:offer(E e)  
 常见方法2:poll()
   常见方法3:E peek()
 Deque(双端队列)----->Queue----->Collection------->Iterable-------------->接口
         常见方法1:offerFirst(E e)和offerLast(E e)
 常见方法2:pollFirst()和pollLast
   常见方法3:E peekFirst()和peekLast
ArrayList-->AbstractList-->List--->Collection--->Iterator--------->类
LinkedList--->AbstractList-->List--->Collection--->Iterator--------->类
                    --->Deque---->Queue----->
Vector--->AbstractList-->List--->Collection--->Iterator--------->类
Stack-->Vector--->AbstractList-->List--->Collection--->Iterator--------->类
         常见方法1:E pop()
 常见方法2:E push(E e)
 常见方法3:E peek()
   常见方法4:boolean empty()
stack-----------后进先出---一端


无序的不可重复的(判断重复的标准是hashCode()+equals()),如果重复定义则会覆盖
LinkedSet---------------重复时保留第一个
TreeSet-------------(String)按照ASCll码进行排序

加载因子:加载因子 是哈希表在其容量自动增加之前可以达到多满的一种尺度。当哈希
表中的条目数超出了加载因子与当前容量的乘积时,通过调用 rehash 方法将容量翻倍。
通常,默认加载因子 (.75) 在时间和空间成本上寻 求一种折衷。加载因子过高虽然减少
了空间开销,但同时也增加了查询成本(在大多数 Hashtable类的操作中,包括 get 和 
put 操作,都反映了这一点)。在设置初始容量时应该考虑到映射中所需的条目数及其加
载因子,以便最大限度地降低 rehash 操作次数。如果初始容量大于最大条目数除以加载
因子,则不会发生 rehash 操作

List默认容量10,HashSet默认容量16,加载因子0.75;

HashMap 的实例有两个参数影响其性能:初始容量 和加载因子。容量是哈希表中桶的数量,
初始容量只是哈希表在创建时的容量。加载因子 是哈希表在其容量自动增加之前可以达到
多满的一种尺度。当哈希表中的条目数超出了加载因子与当前容量的乘积时,则要对该哈希
表进行 rehash 操作(即重建内部数据结构),从而哈希表将具有大约两倍的桶数。

在比较时可以自定义一个比较方式,此类必须要继承Comparable<T>接口,并实现compareTo( T t){ ----重写toString()输出
   
 return -1|0|1;      //  <|=|>
}

import java.util.*;
public class HashSetTest{
public static void main(String[] args) {
/*Set<String> set1 = new LinkedHashSet<String>();
set1.add("sds");
set1.add("2sa");
set1.add("213");
set1.add("213");
System.out.println(set1);//无序
System.out.println("--------------------------------------");
Set<String> set2 = new HashSet<String>();
set2.add("sds");
set2.add("213");
set2.add("2sa");
set2.add("213");
System.out.println(set2);//按插入顺序输出
System.out.println("--------------------------------------");

Set<String> set3 = new TreeSet<String>();
set3.add("sds");
set3.add("213");
set3.add("2sa");
set3.add("213");
System.out.println(set3); //排序
System.out.println("--------------------------------------");
*/
Set<Cat> set=new TreeSet<Cat>();
Cat c1=new Cat(2,"red");
Cat c2=new Cat(1,"black");
Cat c3=new Cat(3,"white");
set.add(c1);
set.add(c2);
set.add(c3);
System.out.println(set.toString());
}
}

class Cat implements Comparable<Cat>{
private int age;
private String color;
public Cat(int age,String color){
this.age=age;
this.color=color;
}
public String toString(){
return "{age="+age+" , color="+color+"}";
}
    public int compareTo(Cat o){
  if(this.age>o.age){
            return 1;
  }else{
    return -1;
  }
   }
}
//---------- java ----------
//[{age=1 , color=black}, {age=2 , color=red}, {age=3 , color=white}]

LinkedHashSet--->HashSet----->AbstractSet----->Set--->Collection------>Iterable
                                TreeSet------>AbstractSet----->Set--->Collection------>Iterable
                                TreeSet------>SortedSet------>Set---->Collection------>Iterable

 

Map

 泛型擦除----------类型擦除
     类型擦除指的是通过类型参数合并,将泛型类型实例关联到同一份字节码上。编译器只为泛型类型生成一份字
节码,并将其实例关联到这份字节码上。类型擦除的关键在于从泛型类型中清除类型参数的相关信息,并且再
必要的时候添加类型检查和类型转换的方法。
     类型擦除可以简单的理解为将泛型java代码转换为普通java代码,只不过编译器更直接点,将泛型java
代码直接转换成普通java字节码。
     
   类型擦除的主要过程如下:
     1.将所有的泛型参数用其最左边界(最顶级的父类型)类型替换。
     2.移除所有的类型参数,如:
interface Comparable <A> { 
  public int compareTo( A that); 

final class NumericValue implements Comparable <NumericValue> { 
  priva te byte value;  
  public  NumericValue (byte value) { this.value = value; }  
  public  byte getValue() { return value; }  
  public  int compareTo( NumericValue t hat) { return this.value - that.value; } 

-----------------
class Collections {  
  public static <A extends Comparable<A>>A max(Collection <A> xs) { 
    Iterator <A> xi = xs.iterator(); 
    A w = xi.next(); 
    while (xi.hasNext()) { 
      A x = xi.next(); 
      if (w.compareTo(x) < 0) w = x; 
    } 
    return w; 
  } 

final class Test { 
  public static void main (String[ ] args) { 
    LinkedList <NumericValue> numberList = new LinkedList <NumericValue> (); 
    numberList .add(new NumericValue((byte)0));  
    numberList .add(new NumericValue((byte)1));  
    NumericValue y = Collections.max( numberList );  
  } 
}
经过类型擦除后的类型为
 interface Comparable { 
  public int compareTo( Object that); 

final class NumericValue implements Comparable { 
  priva te byte value;  
  public  NumericValue (byte value) { this.value = value; }  
  public  byte getValue() { return value; }  
  public  int compareTo( NumericValue t hat)   { return this.value - that.value; } 
  public  int compareTo(Object that) { return this.compareTo((NumericValue)that);  } 

-------------
class Collections {  
  public static Comparable max(Collection xs) { 
    Iterator xi = xs.iterator(); 
    Comparable w = (Comparable) xi.next(); 
    while (xi.hasNext()) { 
      Comparable x = (Comparable) xi.next(); 
      if (w.compareTo(x) < 0) w = x; 
    } 
    return w; 
  } 

final class Test { 
  public static void main (String[ ] args) { 
    LinkedList numberList = new LinkedList(); 
    numberList .add(new NumericValue((byte)0));  ,
    numberList .add(new NumericValue((byte)1));  
    NumericValue y = (NumericValue) Collections.max( numberList );  
  } 
}
第一个泛型类Comparable <A>擦除后 A被替换为最左边界Object。Comparable<NumericValue>的类
型参数NumericValue被擦除掉,但是这直 接导致NumericValue没有实现接口Comparable的compareTo(Object that)
方法,于是编译器充当好人,添加了一个桥接方法。
第二个示例中限定了类型参数的边界<A extends Comparable<A>>A,A必须为Comparable<A>的子类
,按照类型擦除的过程,先讲所有的类型参数 ti换为最左边界Comparable<A>,然后去掉参数类型A,
得到最终的擦除后结果。

 

Collection 和 Collections的区别。

Collection是个java.util下的接口,它是各种集合结构的父接口。继承与他的接口主要有Set 和List.
Collections是个java.util下的专用静态类,它包含有各种有关集合操作的静态方法。提供一系列静态
方法实现对各种集合的搜索、排序、线程安全化等操作。

Array与Arrays的区别。

1.数组类Array,是Java中最基本的一个存储结构。提供了动态创建和访问 Java 数组的方法。其中的
元素的类型必须相同。效率高,但容量固定且无法动态改变。 它无法判断其中实际存有多少元素,
length只是告诉我们array的容量。
2、Arrays类,此静态类专门用来操作array ,提供搜索、排序、复制等静态方法。equals():比较两个
array是否相等。array拥有相同元素个数,且所有对应元素两两相等。 sort():用来对array进行排序。
 binarySearch():在排好序的array中寻找元素。

collections
例:
import java.util.*;
public class CollectionsDemo {
public static void main(String[] args) {
List<String> sl = new ArrayList<String>();
sl.add("jhn");
sl.add("ncgcxs");
sl.add("rgd");
sl.add("ceaz");
sl.add("vfe");
sl.add("byt");
sl.add("fe");
Collections.sort(sl);
System.out.println(sl);
//Collections.binarySearch(1);
//Collections.copy(sl);
System.out.println(Collections.max(sl));//max
System.out.println(Collections.min(sl));//min
Collections.reverse(sl);//反转
System.out.println(sl);
Collections.shuffle(sl);//打散
System.out.println(sl);
}


HashMap遍历的两种方式

第一种: 
Map map = new HashMap(); 
Iterator iter = map.entrySet().iterator(); 
while (iter.hasNext()) { 
    Map.Entry entry = (Map.Entry) iter.next(); 
    Object key = entry.getKey(); 
    Object val = entry.getValue(); 

效率高,以后一定要使用此种方式! 
第二种: 
Map map = new HashMap(); 
Iterator iter = map.keySet().iterator(); 
while (iter.hasNext()) { 
    Object key = iter.next(); 
    Object val = map.get(key); 

效率低,以后尽量少使用!

HashMap 与 TreeMap的区别
    集合框架”提供两种常规的Map实现:HashMap和TreeMap (TreeMap实现SortedMap接口)。在Map 
中插入、删除和定位元素,HashMap 是最好的选择。但如果您要按自然顺序或自定义顺序遍历键,那
么TreeMap会更好。使用HashMap要求添加的键类明确定义了hashCode()和equals()的实现。这个TreeMap
没有调优选项,因为该树总处于平衡状态。

TreeMap
(http://www.cnblogs.com/hzmark/archive/2013/01/02/TreeMap-Base.html)
Java 集合系列目录(Category)
(http://www.cnblogs.com/skywang12345/p/3323085.html)

----------------------------------------------------------------------|----------------------------------------------------------------------|
----------------------------------------------------------------------|----------------------------------------------------------------------|
----------------------------------------------------------------------|----------------------------------------------------------------------|
                                                                                                                                                 

四、I/O流、File

File--------java.io.File--------文件和目录路径名的抽象表示形式

常用方法:
createNewFile(" ")---------创建文件
delete(" ")
exists()-----------测试是否存在
getName()---------获得文件名

例:
String path = File.separator;//与系统有关的默认名称分隔符
File f = new File("c:"+path+"c.txt");
ystem.out.println(f.createNewFile());

 

例:import java.io.*;
public class FileDemo {
public static void main(String[] args) throws IOException{
/*
File f = new File("c:\\Users\\Rainlate\\Desktop\\123.txt");//注意\的转义字符
//构建实例不代表创建文件
boolean b =f.createNewFile();//创建文件
f.mkdirs();//创建前不必有父目录
//f.createTempFile(sd,jsp);//使用给定前缀和后缀生成其名称创建空文件
//f.createTempFile(23,txt, null);//使用给定前缀和后缀生成其名称
//boolean d1 = f.delete();//删除此抽象路径名表示的文件或目录。如果此路径名表示一个目录,则该目录必须为空才能删除
System.out.println(f.exists());//是否存在文件
System.out.println(f.getName());//123.txt
String path = File.separator;
File f = new File("c:"+path+"c.txt");
System.out.println(f.createNewFile());
String a = File.separator;
String path="c:"+a+"Users"+a+"Rainlate"+a+"Desktop"+a+"1";
File f = new File(path);
File[] files = new listFiles(f);
for(String file:files){
System.out.println(file);
}
*/
File x= new File("c:\\Users\\Rainlate\\Desktop\\1");
show(x);
}

public static void show(File f){//递归输出源目录下的所有文件
if(f.isDirectory()){//判断是否为目录
File[] files =f.listFiles();
for(int i=0;i<files.length;i++){
show(files[i]);
}
}else{
System.out.println(f.getPath());
}
}
}


IO流:
第一,确定方向-----------输入输出是以程序为中心
第二,确定是字节还是字符【若是字符型文本使用字符流,其他使用字节流】
第三,确定是否需要缓冲【autoFlush、Flush】----------缓冲流是用空间换时间
第四,所有操作必须关闭【在finally关闭】

例1;
import java.io.*;
public class  FileInputStreamDemo{//文本复制
public static void main(String[] args) {
String a = File.separator;//与系统有关的默认名称分隔符
FileInputStream fin = null;
//FileOutputStream fo = null;
BufferedOutputStream fo = null;
try{
fin = new FileInputStream("C:"+a+"Users"+a+"Rainlate"+a+"Desktop"+a+"123.docx");
byte[] b = new byte[512];//存储读取数据的缓冲区
long start = System.currentTimeMillis();
int size = fin.read(b,0,b.length);
//fo = new FileOutputStream("C:"+a+"Users"+a+"Rainlate"+a+"Desktop"+a+"12.java");
fo = new BufferedOutputStream (new FileOutputStream("C:"+a+"Users"+a+"Rainlate"+a+"Desktop"+a+"12.docx"));
while(size != -1){
fo.write(b,0,size);//文件的实际大小
fo.flush();
size = fin.read(b,0,b.length);
}
long late = System.currentTimeMillis();
System.out.println(late-start);
}catch (FileNotFoundException e){
System.out.println(e.getMessage());
}catch(IOException e){
System.out.println(e.getMessage());
}finally{
try{
fin.close();//关闭输入流
        fo.close();//关闭输出流
}catch (IOException e){
System.exit(1);//异常退出
}
}
}
}

例2:
import java.io.*;
public class ObjectSerializable {
public static void main(String[] args) {
Person p = new Person(32,"huhu");
String a = File.separator;
ObjectOutputStream ou =null;//序列化
ObjectInputStream oin = null;//反序列化
try{
ou = new ObjectOutputStream(new FileOutputStream("C:"+a+"Users"+a+"Rainlate"+a+"Desktop"+a+"1.txt"));
ou.writeObject(p);//对象序列化
ou.flush();

//反序列化
oin = new ObjectInputStream(new FileInputStream("C:"+a+"Users"+a+"Rainlate"+a+"Desktop"+a+"1.txt"));
Object obj = oin.readObject();
Person as = (Person)obj;
System.out.println(as);
out.flush();
}catch (FileNotFoundException e){
System.out.println(e.getMessage());
}catch(IOException e){
System.out.println(e.getMessage());
}catch(ClassNotFoundException e){
System.out.println(e.getMessage());
}finally{
try{
out.close();
}catch (IOException e){
System.exit(1);
}
}
}
}

class Person implements Serializable {
private int age;
private String name;
public Person(int age,String name){
this.age=age;
this.name=name;
}
public String toString(){
return "name="+this.name+",age="+this.age;
}
}


序列化的版本号(serialVersionUID=1L)?
作用:就是确保了不同版本之间的兼容性,不仅能够向前兼容,还能够向后兼容,即在版本升级时反序列化仍保持对象的唯一性。
它有两种生成方式:       
       一个是默认的1L,比如:private static final long serialVersionUID = 1L;
       一个是根据类名、接口名、成员方法及属性等来生成一个64位的哈希字段,比如:  private static final long serialVersionUID = xxxxL 


类图结构
  ┌BufferedReader
  ├InputStream──FileReader
  ├StringReader
┌Reader─┤
│   ├PipedReader
│   ├ByteArrayReader
│   └FileReader──PushbackReader
字符流─┤
│   ┌BufferedWriter
│   ├OutputStreamWriter──FileWriter
│   ├PrinterWriter
└Writer─┼StringWriter
  ├PipedWriter
  ├CharArrayWriter
  └FileWriter


┌FileInputStream
│ ┌BufferedInputStream
├FilterInputStream ──┼DataInputStream
│ └PushbackInputStream
┌InputStream ─┼ObjectInputStream
│ ├PipedInputStream
│ ├SequenceInputStream
│ ├StringBufferInputStream
│ └ByteArrayInoutStream
字节流─┤

│  ┌FileOutputStream
│  │   ┌BufferedOutputStream
│  ├FilterOutputStream ──┼DataOutputStream
└OutputStream ─┤   └PrintStream
 ├ObjectOutputStream
 ├PipedOutputStream

 

IO流------(http://developer.51cto.com/art/201309/410913.htm)

----------------------------------------------------------------------|----------------------------------------------------------------------|
----------------------------------------------------------------------|----------------------------------------------------------------------|
----------------------------------------------------------------------|----------------------------------------------------------------------|
                                                                                                                                                 

JDK1.5新特性:

七、枚举
枚举是一个类类型,是JDK1.5的新特性

枚举的关键字是enum

Java中所有的枚举类都是java.lang.Enum的子类

注意:枚举类中可以包含成员有【字段(常量)、方法(构造方法、普通方法)】

枚举中不能有number;不能赋值------------类

 只有顺序可以比较-----------

语法:

enum 枚举名{

         枚举体

}

例:

enum Direction{//枚举体

         EAST,SOUTH,WEST,NORTH//后面可以有分号也可以没有

}

调用:枚举名.成员

枚举名 name =枚举名.成员;

Direction dir = Direction.EAST;

 

Enum的方法使用:

Javap---------------查看字节码文件


代码:

enum Direction{

EAST('e'),SOUTH('s'),NORTH('n'),WEST('w');

    protected char a;

private Direction(char a){

this.a = a;

}

public String toString(){

return a+"";

}

}

字节码:


---------- javap ----------

Compiled from "Direction.java"

final class Direction extends java.lang.Enum<Direction> {//不能被实例化

  public static final Direction EAST;

  public static final Direction SOUTH;

  public static final Direction NORTH;

  public static final Direction WEST;

  protected char a;//默认是private,但可以使用4P

  public static Direction[] values();//默认方法,用来遍历打印枚举成员

  public static Direction valueOf(java.lang.String);

  public java.lang.String toString();

  static {};//静态初始化块

}

由上面可以知道枚举继承java.lang.Enum类,参数的默认修饰符public static final,在枚举中可以使用4p

 

public enum A{BLUE,RED,BLACK};//声明并定义一个枚举,初始化为。。。

在一个类中定义一个enum成员,enum默认是静态的-------------相当于类变量

 

枚举的用法

一、常量-----------枚举出来之前都是通过接口

在JDK1.5 之前,我们定义常量都是: public static fianl,现在可以把相关的常量分组到一个枚举类型里,例:

public enum Color {

  RED, GREEN, BLANK, YELLOW

}

二、Switch

JDK1.5之后的switch语句支持Byte,short,int,char,enum类型,使用枚举,能让我们的代码可读性更强,JDK1.7之后开始支持String类型,例:

enum Signal {

         GREEN, YELLOW, RED

}

public class TrafficLight {

         Signal color = Signal.RED;

         public void change() {

                   switch (color) {

                   case RED:

                            color = Signal.GREEN;

                            break;

                   case YELLOW:

                            color = Signal.RED;

                            break;

                   case GREEN:

                            color = Signal.YELLOW;

                            break;

                   }

         }

}

三、向枚举中添加新方法

要自定义方法,必须在enum实例序列的最后添加一个分号。而且 Java 要求必须先定义 enum实例,例:

public enum Color {

         RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4);

         // 成员变量

         private String name;

         private int index;

         // 构造方法

         private Color(String name, int index) {

                   this.name = name;

                   this.index = index;

         }

         // 普通方法

         public static String getName(int index) {

                   for (Color c : Color.values()) {

                            if (c.getIndex() == index) {

                                     return c.name;

                            }

                   }

                   return null;

         }

         // get set 方法

         public String getName() {

                   return name;

         }

         public void setName(String name) {

                   this.name = name;

         }

         public int getIndex() {

                   return index;

         }

         public void setIndex(int index) {

                   this.index = index;

         }

}

四、覆盖枚举的方法

例如覆盖toString()

public enum Color {

         RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4);

         // 成员变量

         private String name;

         private int index;

         // 构造方法

         private Color(String name, int index) {

                   this.name = name;

                   this.index = index;

         }

         //覆盖方法

         @Override

         public String toString() {

                   return this.index+"_"+this.name;

         }

}

五、实现接口------所有的枚举都继承自java.lang.Enum类。由于Java 不支持多继承,所以枚举对象不能再继承其他类,例:

public interface Behaviour {

         void print();

         String getInfo();

}

public enum Color implements Behaviour{

         RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4);

         // 成员变量

         private String name;

         private int index;

         // 构造方法

         private Color(String name, int index) {

                   this.name = name;

                   this.index = index;

         }

//接口方法

         @Override

         public String getInfo() {

                   return this.name;

         }

         //接口方法

         @Override

         public void print() {

                   System.out.println(this.index+":"+this.name);

         }

}

六、使用接口组织枚举

public interface Food {

         enum Coffee implements Food{

                   BLACK_COFFEE,DECAF_COFFEE,LATTE,CAPPUCCINO

         }

         enum Dessert implements Food{

                   FRUIT, CAKE, GELATO

         }

}

七、枚举集合

java.util.EnumSet和java.util.EnumMap是两个枚举集合。EnumSet保证集合中的元素不重复;EnumMap中的key是enum类型,而value则可以是任意类型。

 

枚举和普通类的区别与联系;

1、枚举与类都可以实现多接口;访问控制符都可以使用(4p),但枚举中默认的是private,类中默认的是package;

2、枚举直接继承java.lang.Enum类,普通类是继承java.lang.Object;其中java.long.Enum类实现了java.long.Serializable和java.long.Comparable两个接口。

3、使用enum定义、非抽象的枚举默认修饰符为public final,因此枚举不能派生子类。
4、枚举的构造器只能使用private访问控制符,如果省略了枚举的访问修饰符其默认为private修饰;因为枚举的字段不能初始化,对象类型的必须调用构造方法,所有有多少个成员构造方法就会运行多少次;
5、枚举的所有实例必须在枚举的第一行显示列出,否则这个枚举永远都不能生产实例,列出这些实例时系统会自动添加public static final修饰,无需程序员显式添加

6、所有的枚举类都提供了一个values方法,该方法可以很方便的遍历所有的枚举值

7、关键字:枚举是enum,类是class

8、枚举是类类型,类是引用类型


instanceof关键字:
public class FX {
public static void main(String[] args) {
boolean b = ("1" instanceof String);//判断某个对象是不是某个类的实例    Result = Object instanceof Class/interface
//Result:布尔类型。
   //Object:必选项。任意对象表达式。
//Class:必选项。任意已定义的对象类。
System.out.println(b);
}
}


注解---JDK1.5的新特性
使用位置:类上、方法上、语句上

----------------------------------------------------------------------|----------------------------------------------------------------------|
----------------------------------------------------------------------|----------------------------------------------------------------------|
----------------------------------------------------------------------|----------------------------------------------------------------------|


八、协变与泛型
协变-------可以用在数组、重写,不可以用在枚举中

可变参数:

int… a-------------代表一个没有长度限制的数组----------JDK1.5之后有的

输入的必须是数组

Java1.5增加了新特性:可变参数:适用于参数个数不确定,类型确定的情况,java把可变参数当做数组处理。注意:可变参数必须位于最后一项。只支持有一个可变参数。因为参数个数不定,所以当其后边还有相同类型参数时,java无法区分传入的参数属于前一个可变参数还是后边的参数,所以只能让可变参数位于最后一项。

可变参数的特点:

(1)、只能出现在参数列表的最后;

(2)、... 位于变量类型和变量名之间,前后有无空格都可以;

(3)、调用可变参数的方法时,编译器为该可变参数隐含创建一个数组,在方法体中以数组的形式访问可变参数。例:

public class Varable {
     public static void main(String [] args){
         System.out.println(add(2,3));
         System.out.println(add(2,3,5));
     }
     public static int add(int x,int ...args){
         int sum=x;
         for(int i=0;i<args.length;i++){
             sum+=args[i];
         }
         return sum;
     }
}

 协变的作用范围

1、数组:如果 A 是 B 的超类,则 A[] 也是 B[] 的超类,所有需要 A[] 的地方都可以用 B[] 代替,例:

public class Test2 {

    public static void main(String[] args){

        Integer[] ints=new Integer[1];

        ints[0]=99;

        show(ints);

    }

    static void show(Number[] ns){

        System.out.println(Arrays.toString(ns));

    }

}

 

2、重写

public class Test2 {

    public static void main(String[] args){

        P p=new C();

        System.out.println(p.get());

    }

}

class P{

    public Number get(){

        return new Integer(0);

    }

}

class C extends P{

    public Integer get(){

        return new Integer(1);

    }

}

3、泛型不能协变:如果 A 是 B 的超类,则 List<A> 和 List<B> 无关,需要 List<A> 的地方不可以用 List<B> 代替,例:

public class Test2 {

    public static void main(String[] args) {

        List<Integer> ints = new ArrayList<Integer>();

        //incompatible type--类型不兼容

        show(ints);

    }

 

    static void show(List<Number> ns) {

        System.out.println(ns);

    }

}


泛型(Generic)的本质是类型参数化

-------------是JDK1.5提供的新技术,它的本质是类型参数化,类似C++中的模板,它根据应用主要分为泛型方法,泛型接口,泛型类,协变不适用于泛型

 

泛型-------------泛型类class Demo<T>{},泛型接口interface Inter<T>{},泛型方法public<T> T show(T a) {}

泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,提高代码的重用率

 

例1:

public class  GenericDemo{

       public static void main(String[] args) {

              C c1 = new C(new A("aaa"));

              C c2 = new C(new B(3.4));//包装成double---自动装箱

              Object obj = c1.getObj();

              A obj = (A)(c1.getObj());//强制转换

              System.out.println(obj);

       }

}

class A{

       private String x;

       public A(String x){

              this.x=x;

       }

       public String getX(){

              return x;

       }

}

class B{

       private Double d;

       public B(Double d){

              this.d=d ;

       }

       public Double getD(){

              return d;

       }

}

class C{

       private Object obj;

       public C(Object obj){

              this.obj=obj ;

       }

       public Object  getObj(){

              return obj;

       }

}

 

泛型的使用:

一、泛型类:

public class Demo1 {

       public static void main(String[] args) {

              Generic<String> c = new Generic<String>("asad");

              System.out.println(c.getA());

 

              //Generic<int> c1 = new Generic<int>(12);必须要是包装类

       }

}

class Generic<T>{//泛型类

       private T a;

       public Generic(T a){

              this.a = a;

       }

       public T getA(){

              return a;

       }

}

 

二、泛型方法

       public static <T> T getX(T t){//泛型方法----------<  >--表声明

              return t;

       }

     

public static <T,K> T getX(K t){//泛型方法

              return t;

       }

 

三、泛型接口

public class GenericDemo3{

public static void main(String[] args) {

D<int[][]> d = new D<int[][]>();

d.show(new int[][]{{1,4},{2,3}});

}

}

interface IA<T>{

void show(T t);

}

 

class D<T> implements IA<T>{

public void show(T t){

System.out.println(t.getClass().getName());

}

}

 

 

有界类型:

上界:extends 默认上界为Object

Class G <T extends Number,K extends Object,H super Integer>{}

下界:super----------只有通配符有下限

extends关键字声明了类型的上界,表示参数化的类型可能是所指定的类型,或者是此类型的子类

super关键字声明了类型的下界,表示参数化的类型可能是所指定的类型,或者是此类型的父类型,直至Object

 

规则和限制

1、泛型的类型参数只能是类类型(包括自定义类),不能是简单类型。

2、同一种泛型可以对应多个版本(因为参数类型是不确定的),不同版本的泛型类实例是不兼容的。

3、泛型的类型参数可以有多个。<T,K>

4、泛型的参数类型可以使用extends关键字,例如<T extends superclass>。习惯上称为“有界类型”。

5、泛型的参数类型还可以是通配符类型。例如Class<?> classType = Class.forName("java.lang.String")

6、如果只指定了<?>,而没有extends,则默认是允许Object及其下的任何Java类了。也就是任意类。

7、通配符泛型不但可以向下限制,如<? extends Collection>,还可以向上限制,如<? super Double>,表示类型只能接受Double及其上层父类类型,如Number、Object类型的实例。

8、泛型类定义可以有多个泛型参数,中间用逗号隔开,还可以定义泛型接口,泛型方法。这些都与泛型类中泛型的使用规则类似。

一个普通static方法,无法访问泛型类的类型参数,所以,若普通static方法需要使用泛型参数,必须使其成为泛型方法。

 

 

java 泛型详解

普通泛型

Java代码

1.  class Point<T>{       // 此处可以随便写标识符号 

2.      private T var ; // var的类型由T指定,即:由外部指定 

3.      public T getVar(){  // 返回值的类型由外部决定 

4.          return var ; 

5.      } 

6.      public void setVar(T var){  // 设置的类型也由外部决定 

7.          this.var = var ; 

8.      } 

9.  } 

10. public class GenericsDemo06{ 

11.     public static void main(String[] args){

12.         Point<String> p = new Point<String>() ; // 里面的var类型为String类型  --------指定数据类型—必须是引用数据类型

13.         p.setVar("it") ;        // 设置字符串 

14.         System.out.println(p.getVar().length()) ;   // 取得字符串的长度 

15.     } 

16. }

17. //2

18. ---------------------------------------------------------- 

19. class Notepad<K,V>{       // 此处指定了两个泛型类型-----再类上进行声明泛型类型 

20.     private K key ;     // 此变量的类型由外部决定 

21.     private V value ;   // 此变量的类型由外部决定 

22.     public K getKey(){ 

23.         return this.key ; 

24.     } 

25.     public V getValue(){ 

26.         return this.value ; 

27.     } 

28.     public void setKey(K key){ 

29.         this.key = key ; 

30.     } 

31.     public void setValue(V value){ 

32.         this.value = value ; 

33.     } 

34. } 

35. public class GenericsDemo09{ 

36.     public static void main(String args[]){ 

37.         Notepad<String,Integer> t = null ;        // 定义两个泛型类型的对象 

38.         t = new Notepad<String,Integer>() ;       // 里面的key为String,value为Integer 

39.         t.setKey("汤姆") ;        // 设置第一个内容 

40.         t.setValue(20) ;            // 设置第二个内容 

41.         System.out.print("姓名;" + t.getKey()) ;      // 取得信息 

42.         System.out.print(",年龄;" + t.getValue()) ;       // 取得信息 

43.       } 

44. }  //汤姆

45.       20

 通配符

Java代码

1.  class Info<T>{ 

2.      private T var ;     // 定义泛型变量 

3.      public void setVar(T var){ 

4.          this.var = var ; 

5.      } 

6.      public T getVar(){ 

7.          return this.var ; 

8.      } 

9.      public String toString(){   // 直接打印 

10.         return this.var.toString() ; 

11.     } 

12. }

13. public class GenericsDemo14{ 

14.     public static void main(String args[]){ 

15.         Info<String> i = new Info<String>() ;       // 使用String为泛型类型 

16.         i.setVar("it") ;                            // 设置内容 

17.         fun(i) ; 

18.     } 

19.     public static void fun(Info<?> temp){     // 可以接收任意的泛型对象 

20.         System.out.println("内容:" + temp) ; 

21.     } 

22. }//  内容:it

 受限泛型

Java代码

1.  class Info<T>{ 

2.      private T var ;     // 定义泛型变量 

3.      public void setVar(T var){ 

4.          this.var = var ; 

5.      } 

6.      public T getVar(){ 

7.          return this.var ; 

8.      } 

9.      public String toString(){   // 直接打印 

10.         return this.var.toString() ; 

11.     } 

12. } 

13. public class GenericsDemo17{ 

14.     public static void main(String args[]){ 

15.         Info<Integer> i1 = new Info<Integer>() ;   // 声明Integer的泛型对象 

16.         Info<Float> i2 = new Info<Float>() ;         // 声明Float的泛型对象 

17.         i1.setVar(30) ;                              // 设置整数,自动装箱 

18.         i2.setVar(30.1f) ;                           // 设置小数,自动装箱 

19.         fun(i1) ; 

20.         fun(i2) ; 

21.     } 

22.     public static void fun(Info<? extends Number> temp){ // 只能接收Number及其Number的子类 

23.         System.out.print(temp + "、") ; 

24.     } 

25. }//  30、30.1、

26. ---------------------------------------------------------- 

27. class Info<T>{ 

28.     private T var ;     // 定义泛型变量 

29.     public void setVar(T var){ 

30.         this.var = var ; 

31.     } 

32.     public T getVar(){ 

33.         return this.var ; 

34.     } 

35.     public String toString(){   // 直接打印 

36.         return this.var.toString() ; 

37.     } 

38. } 

39. public class GenericsDemo21{ 

40.     public static void main(String args[]){ 

41.         Info<String> i1 = new Info<String>() ;      // 声明String的泛型对象 

42.         Info<Object> i2 = new Info<Object>() ;      // 声明Object的泛型对象 

43.         i1.setVar("hello") ; 

44.         i2.setVar(new Object()) ; 

45.         fun(i1) ; 

46.         fun(i2) ; 

47.     } 

48.     public static void fun(Info<? super String> temp){   // 只能接收String或Object类型的泛型  ----上限为String

49.         System.out.print(temp + "、") ; 

50.     } 

51. }//  hello、java.lang.Object@1ffc686、

 泛型无法向上转型

Java代码

1.  class Info<T>{ 

2.      private T var ;     // 定义泛型变量 

3.      public void setVar(T var){ 

4.          this.var = var ; 

5.      } 

6.      public T getVar(){ 

7.          return this.var ; 

8.      } 

9.      public String toString(){   // 直接打印 

10.         return this.var.toString() ; 

11.     } 

12. } 

13. public class GenericsDemo23{ 

14.     public static void main(String args[]){ 

15.         Info<String> i1 = new Info<String>() ;      // 泛型类型为String 

16.         Info<Object> i2 = null ; 

17.         i2 = i1 ;                           //这句会出错 incompatible types 

18.     } 

19. }//  编译失败

 泛型接口

Java代码

1.  interface Info<T>{        // 在接口上定义泛型 

2.      public T getVar() ; // 定义抽象方法,抽象方法的返回值就是泛型类型 

3.  } 

4.  class InfoImpl<T> implements Info<T>{   // 定义泛型接口的子类 

5.      private T var ;             // 定义属性 

6.      public InfoImpl(T var){     // 通过构造方法设置属性内容 

7.          this.setVar(var) ;   

8.      } 

9.      public void setVar(T var){ 

10.         this.var = var ; 

11.     } 

12.     public T getVar(){ 

13.         return this.var ; 

14.     } 

15. } 

16. public class GenericsDemo24{ 

17.     public static void main(String arsg[]){ 

18.         Info<String> i = null;        // 声明接口对象 

19.         i = new InfoImpl<String>("汤姆") ;  // 通过子类实例化对象 

20.         System.out.println("内容:" + i.getVar()) ; 

21.     } 

22. }//  内容:汤姆

 泛型方法

Java代码

1.  class Demo{ 

2.      public <T> T fun(T t){            // 可以接收任意类型的数据 

3.          return t ;                  // 直接把参数返回 

4.      } 

5.  } 

6.  public class GenericsDemo26{ 

7.      public static void main(String args[]){ 

8.          Demo d = new Demo() ;   // 实例化Demo对象 

9.          String str = d.fun("汤姆") ; //   传递字符串 

10.         int i = d.fun(30) ;     // 传递数字,自动装箱 

11.         System.out.println(str) ;   // 输出内容 

12.         System.out.println(i) ;     // 输出内容 

13.     } 

14. }//  汤姆  30

 通过泛型方法返回泛型类型实例

Java代码

1.  class Info<T extends Number>{ // 指定上限,只能是数字类型 

2.      private T var ;     // 此类型由外部决定 

3.      public T getVar(){ 

4.          return this.var ;    

5.      } 

6.      public void setVar(T var){ 

7.          this.var = var ; 

8.      } 

9.      public String toString(){       // 覆写Object类中的toString()方法 

10.         return this.var.toString() ;     

11.     } 

12. } 

13. public class GenericsDemo27{ 

14.     public static void main(String args[]){ 

15.         Info<Integer> i = fun(30) ; 

16.         System.out.println(i.getVar()) ; 

17.     } 

18.     public static <T extends Number> Info<T> fun(T param){//方法中传入或返回的泛型类型由调用方法时所设置的参数类型决定 

19.         Info<T> temp = new Info<T>() ;      // 根据传入的数据类型实例化Info 

20.         temp.setVar(param) ;     // 将传递的内容设置到Info对象的var属性之中 

21.         return temp ;   // 返回实例化对象 

22.     } 

23. }//  30

 使用泛型统一传入的参数类型

Java代码

1.  class Info<T>{    // 指定上限,只能是数字类型 

2.      private T var ;     // 此类型由外部决定 

3.      public T getVar(){ 

4.          return this.var ;    

5.      } 

6.      public void setVar(T var){ 

7.          this.var = var ; 

8.      } 

9.      public String toString(){       // 覆写Object类中的toString()方法 

10.         return this.var.toString() ;     

11.     } 

12. }

13. public class GenericsDemo28{ 

14.     public static void main(String args[]){ 

15.         Info<String> i1 = new Info<String>() ; 

16.         Info<String> i2 = new Info<String>() ; 

17.         i1.setVar("HELLO") ;        // 设置内容 

18.         i2.setVar("汤姆") ;       // 设置内容 

19.         add(i1,i2) ; 

20.     } 

21.     public static <T> void add(Info<T> i1,Info<T> i2){ 

22.         System.out.println(i1.getVar() + " " + i2.getVar()) ; 

23.     } 

24. }// HELLO 汤姆

 泛型数组

Java代码

1.  public class GenericsDemo30{ 

2.      public static void main(String args[]){ 

3.          Integer i[] = fun1(1,2,3,4,5,6) ;   // 返回泛型数组 

4.          fun2(i) ; 

5.      } 

6.      public static <T> T[] fun1(T...arg){  // 接收可变参数 

7.          return arg ;            // 返回泛型数组 

8.      } 

9.      public static <T> void fun2(T param[]){   // 输出 

10.         System.out.print("接收泛型数组:") ; 

11.         for(T t:param){ 

12.             System.out.print(t + "、") ; 

13.         } 

14.     } 

15. }//  接收泛型数组:1、2、3、4、5、6、

 泛型的嵌套设置

Java代码

1.  class Info<T,V>{      // 接收两个泛型类型 

2.      private T var ; 

3.      private V value ; 

4.      public Info(T var,V value){ 

5.          this.setVar(var) ; 

6.          this.setValue(value) ; 

7.      } 

8.      public void setVar(T var){ 

9.          this.var = var ; 

10.     } 

11.     public void setValue(V value){ 

12.         this.value = value ; 

13.     } 

14.     public T getVar(){ 

15.         return this.var ; 

16.     } 

17.     public V getValue(){ 

18.         return this.value ; 

19.     } 

20. } 

21. class Demo<S>{ 

22.     private S info ; 

23.     public Demo(S info){ 

24.         this.setInfo(info) ; 

25.     } 

26.     public void setInfo(S info){ 

27.         this.info = info ; 

28.     } 

29.     public S getInfo(){ 

30.         return this.info ; 

31.     } 

32. }

33. public class GenericsDemo31{ 

34.     public static void main(String args[]){ 

35.         Demo<Info<String,Integer>> d = null ;  // 将Info作为Demo的泛型类型 

36.         Info<String,Integer> i = null ;   // Info指定两个泛型类型 

37.         i = new Info<String,Integer>("汤姆",30) ;    // 实例化Info对象 

38.         d = new Demo<Info<String,Integer>>(i);//在Demo类中设置Info类的对象 

39.         System.out.println("内容一:" + d.getInfo().getVar()) ; 

40.         System.out.println("内容二:" + d.getInfo().getValue()) ; 

41.     } 

42. } // 内容一:汤姆 内容二:30

  泛型方法不一定要通过参数来确定泛型准确类型,可以只通过返回值,比如:

 public static <E> ArrayList<E> newArrayList() {
         return new ArrayList<E>();
 }

 public List<PrepaidHistory> queryHistories(Long skyid,PrepaidHistoryType type, Date from, Date end) { 

         return Lists.newArrayList();

}

 这样Lists.newArrayList();
智能的知道返回类型为PrepaidHistory

一、 Oracle的安装(windowXP、win7、Linux)和卸载
  1.1 Oracle的安装
    1.1.1 在WindowsXP、Win7下安装
      第一:解压win32_11gR2_database_1of2、win32_11gR2_database_2of2,生成detabase目录
      第二:安装oracle
           A、点击setup图标即可,注意:安装目录不要含有中文
           B、在弹出的第一个界面中取消更新选择项,点击下一步
           C、在弹出的警告框中选择是
           D、选择创建和配置数据库选项,下一步
           E、选择桌面类安装,点击下一步
           F、弹出的窗口中输入全局数据库名:orcl
                 输入管理口令:bluedot
                 默认的管理员是:sys和system
           G、点完成,开始安装数据库,出现进度条
           H、口令管理
           I、设置口令
           J、完成安装
  1.2 Oracle的卸载:
    1、 开始->设置->控制面板->管理工具->服务 停止所有Oracle服务。
    2、 开始->程序->Oracle - OraHome81->Oracle Installation Products-> Universal Installer,单击“卸载产品”-“全部展开”,选中除“OraDb11g_home1”外的全部目录,删除。
    3、 运行regedit,选择HKEY_LOCAL_MACHINE\SOFTWARE\ORACLE,按del键删除这个入口。
    4、 运行regedit,选择HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services,滚动这个列表,删除所有Oracle入口(以oracle或OraWeb开头的键)。
    5、 运行refedit,HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\Application,删除所有Oracle入口。e
    6、 删除HKEY_CLASSES_ROOT目录下所有以Ora、Oracle、Orcl或EnumOra为前缀的键。
    7、 删除HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\MenuOrder\Start Menu\Programs中所有以oracle开头的键。
    8、删除HKEY_LOCAL_MACHINE\SOFTWARE\ODBC\ODBCINST.INI中除Microsoft ODBC for Oracle注册表键以外的所有含有Oracle的键。
    9、我的电脑-->属性-->高级-->环境变量,删除环境变量CLASSPATH和PATH中有关Oracle的设定。
    10、从桌面上、STARTUP(启动)组、程序菜单中,删除所有有关Oracle的组和图标。
    11、删除所有与Oracle相关的目录(如果删不掉,重启计算机后再删就可以了)包括:
         1.C:\Program file\Oracle目录。
         2.ORACLE_BASE目录(oracle的安装目录)。
         3.C:\WINDOWS\system32\config\systemprofile\Oracle目录。
         4.C:\Users\Administrator\Oracle或C:\Documents and Settings\Administrator\Oracle目录。
         5.C:\WINDOWS下删除以下文件ORACLE.INI、oradim73.INI、oradim80.INI、oraodbc.ini等等。
         6.C:\WINDOWS下的WIN.INI文件中若有[ORACLE]的标记段,删除该段。
    12、如有必要,删除所有Oracle相关的ODBC的DSN
    13、到事件查看器中,删除Oracle相关的日志 说明: 如果有个别DLL文件无法删除的情况,则不用理会,重新启动,开始新的安装,安装时,选择一个新的目录,则,安装完毕并重新启动后,老的目录及文件就可以删除掉了。
 
二、 用户管理
   2.1 创建用户
       注:创建用户只能在管理员下完成
       CREATE USER 用户名 IDENTIFIED BY 密码。
       |-CREATE USER demo IDENTIFIED BY 123456;
   2.2 用户分类
     |-管理员和普通用户
        |-管理员
          |-超级管理员:sys/bluedot
          |-管理员:system/bluedot
        |-普通用户:scott/tiger
                       hr/hr
     |--常见角色:sysdba、sysoper
   2.3 用户登录
     2.3.1 在命令行窗口登录[c/s]
        步骤:
           运行 sqlplus /nolog
           conn demo/123456
      2.3.2 另外的一种登录方式【B/S】
           输入网址----https://localhost:1158/em
  输入用户名密码进入主界面
   2.4 修改用户密码
      注:修改密码必须要在级别高的用户下进行修改
     ALTER USER 用户名 IDENTIFIED BY 密码;
     
     conn sys/bluedot as sysdba
     ALTER USER demo IDENTIFIED BY 654321;
   2.5 查询用户
       2.5.1查看用户信息
         1、SELECT * FROM DBA_USERS;--------查看所有用户的详细信息
         2、SELECT * FROM ALL_USERS;-------查看所有用户简要信息
         3、SELECT * FROM USER_USERS;------------查看当前用户的所用信息
      2.5.2 查看用户或角色系统权限(直接赋值给用户或角色的系统权限)
         SELECT * FROM DBA_SYS_PRIVS;----------全部
         SELECT * FROM USER_SYS_PRIVS; ---------当前用户
      2.5.3 查看角色(登录用户拥有的角色)所包含的的权限
         SELECT * FROM ROLE_SYS_PRIVS;
      2.5.4 查看用户对象权限
         SELECT * FROM DBA_TAB_PRIVS;
         SELECT * FROM ALL_TAB_PRIVS;
         SELECT * FROM USER_TAB_PRIVS;
      2.5.5 查看所有角色
         SELECT * FROM DBA_ROLES;
         SELECT * FROM DBA_ROLE_PRIVS;
         SELECT * FROM USER_ROLE_PRIVS;
 
      2.5.6 查看哪些用户有sysdba或sysoper系统权限(查询时需要相应权限)
         SELECT * FROM V$PWFILE_USERS;
 
      2.5.7 查看Oracle提供的系统权限
         SELECT name FROM SYS.SYSTEM_PRIVSILEGE_MAP;
   2.6 密码失效
      提示用户第一次连接的时候需要修改密码,让用户的密码到期
        |- ALTER USER 用户名 PASSWORD expire ;
   2.7 授权
       GRANT 权限/角色 TO 用户
       给 demo 用户以创建 session 的权限:GRANT create session TO demo;
       角色:-------------角色就是一堆权限的集合
       Create role myrole;
       Grant create table to myrole;
       Drop role myrole; 删除角色
      1.CONNECT, RESOURCE, DBA
      这些预定义角色主要是为了向后兼容。其主要是用于数据库管理。oracle建议用户自己设计数据库管理和安全的权限规划,而不要简单的使用这些预定角色。将来的版本中这些角色可能不会作为预定义角色。
      2.DELETE_CATALOG_ROLE, EXECUTE_CATALOG_ROLE, SELECT_CATALOG_ROLE 这些角色主要用于访问数据字典视图和包。
      3.EXP_FULL_DATABASE, IMP_FULL_DATABASE 这两个角色用于数据导入导出工具的使用。
        GRANT 权限(select、update、insert、delete) ON schema.table TO 用户
          |- GRANT select ON scott.emp TO test ;
          |- Grant all on scott.emp to test; --将表相关的所有权限付给 test
          |- Grant update(ename) on emp to test; 可以控制到列(还有 insert)
   2.8 收权
      REVOKE 权限/角色 ON schema.table FROM 用户
       |- REVOKE select ON scott.emp FROM test ;
   2.9 锁住一个用户
       ALTER USER 用户名 ACCOUNT LOCK|UNLOCK
         |- ALTER USER test ACCOUNT LOCK ;
         |- ALTER USER test ACCOUNT UNLOCK ;
    2.10 删除用户
            |-DROP USER 用户名;
                  |-Drop user demo;
           如果该用户下面已经存在表等一些数据库对象。则必须用级联删除
           |-DROP USER 用户名 CASCADE;
                   |-Drop user demo cascade;
    备注:帮助
        help index
        help conn --------显示具体的
        eidt---------------进入编辑文档
三、 Oracle的体系结构
   3.1 Oracle数据库的整体架构 (DBA)
                 ┌──────────────────────────────┐
┌────┐ │ Instance │
│ User │ │ ┌──────────────────────────┐ │
│ process│ │ │ ┌────────┐ SGA │ │
└────┘ │ │ │ Shared Pool │ │ │
    ↓ │ │ │ ┌─────┐ │ ┌────┐ ┌────┐ │ │
    ↓ │ │ │ │Library │ │ │Database│ │ Redo │ │ │
┌────┐ │ │ │ │ Cache │ │ │Buffer │ │ Log │ │ │
│ Server │ │ │ │ └─────┘ │ │Cache │ │ Buffer │ │ │
│process │ │ │ │ ┌─────┐ │ │ │ │ │ │ │
└────┘ │ │ │ │Data Dict │ │ └────┘ └────┘ │ │
     ↓ │ │ │ │ Cache │ │ │ │
     →→→→→→│ │ │ └─────┘ │ │ │
                 │ │ └────────┘ │ │
                 │ └──────────────────────────┘ │
                 │ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌───┐│
   │ │PMON│ │SNON│ │DBWR│ │LGWR│ │CHPT│ │OTHERS││
                 │ └──┘ └──┘ └──┘ └──┘ └──┘ └───┘│
                 └──────────────────────────────┘
                                                 ↑ ↓
               ┌─────┐ ┌───────────────────┐
               │Parameter │ │┌───┐ ┌────┐ ┌────┐│
               │ file │ ││Data │ │control │ │Redo Log││ ┌─────┐
               └─────┘ ││files │ │ files │ │ files ││ │Archived │
               ┌─────┐ │└───┘ └────┘ └────┘│ │Log files │
               │ Password │ │ Database │ └─────┘
        │ file │ │ │
               └─────┘ └───────────────────┘
由上图可知,Oracle数据库由实例和数据库组成。
   3.2 数据库存储结构
      3.2.1 数据库存储结构
      Oracle数据库有物理结构和逻辑结构。数据库的物理结构是数据库中的操作系统文件的集合。数据库的物理结构由数据文件、控制文件和重做日志文件组成。
      1、数据文件:数据文件是数据的存储仓库。
      2、重做日志文件:重做日志文件包含对数据库所做的更改记录,在发生故障时能够恢复数据。重做日志按时间顺序存储应用于数据库的一连串的变更向量。其中仅包含重建(重做)所有已完成工作的最少限度信息。如果数据文件受损,则可以将这些变更向量应用于数据文件备份来重做工作,将它恢复到发生故障的那一刻前的状态。重做日志文件包含联机重做日志文件(对于连续的数据库操作时必须的)和归档日志文件(对于数据库操作是可选的,但对于时间点恢复是必须的)。
      3、控制文件:控制文件包含维护和验证数据库完整性的必要的信息。控制文件虽小,但作用非常大。它包含指向数据库其余部分的指针:联机重做日志文件和数据文件的位置,以及更新的归档日志文件的位置。它还存储着维护数据库完整性所需的信息。控制文件不过数MB,却起着至关重要的作用。
      除了三个必须的文件外数据库还能有其它非必须的文件如:参数文件、口令文件及归档日志文件。
          1、实例参数文件:当启动oracle实例时,SGA结构会根据此参数文件的设置内置到内存,后台进程会据此启动。
          2、口令文件:用户通过提交用户名和口令来建立会话。Oracle根据存储在数据字典的用户定义对用户名和口令进行验证。
          3、归档重做日志文件:当重做日志文件满时将重做日志文件进行归档以便还原数据文件备份。
      3.2.2 Oracle数据库结构的16个要点(表空间-->段-->区-->块)
   1、一个数据文件只能归到某一个表空间上,每个表空间可以含一个或多个数据文件。包括系统数据和用户数据。
   2、表空间是包括一个或多个数据文件的逻辑结构。用于存放数据库表、索引、回滚段等对象的磁盘逻辑空间
   3、数据库文件是存放实际数据的物理文件。包括实例和数据库。
   4、数据文件可以在创建表空间时创建,也可以以增加的方式创建。
   5、数据文件的大小一般与操作系统限制有关。
   6、控制文件是Oracle的重要文件,主要存放数据文件、日志文件和数据库的基本信息,一般在数据打开时访问。
   7、日志文件在数据库活动时使用。
   8、临时表空间是用于存放排序段的磁间;临时表空间由一个或多个临时文件组成。
   9、归档日志文件由归档进程将联机日志文件读出并写到一个路径上的文件。
   10、Oracle实例由一组后台进程和内存结构组成。
   11、Oracle实例的内存结构常叫系统全局区,简称SGA。
   12、DBA_开头的数据字典存放的字符信息都是大写,而V$_开头的视图存放的都是小写。
   13、后台进程是一组完成不同功能的程序,主要包括DBWR、LGMR、CKPT等。
   14、数据字典是Oracle的重要部分,也就是用于系统内部的一组表。
   15、数据字典分为动态和静态两部分,静态主要是DBA_开头的数据字典,而动态则是以V$_开头的视图。
   16、SGA分为数据缓冲区、共享池和日志缓冲区。
     3.2.3 Oracle逻辑结构及表空间
        1.ORACLE逻辑结构
             ORACLE将数据逻辑地存放在表空间,物理地存放在数据文件中。
             一个表空间任何一个时刻只能属于一个数据库。
 
             数据库——表空间——段——区——ORACLE块
             每个数据库由一个或多个表空间组成,至少一个。
             每个表空间基于一个或多个操作系统的数据文件,至少一个,一个操作系统的数据文件只能属于一个表空间。一个表空间可以存放一个或多个段 segment。
             每个段由一个或多个区段extent组成。
             每个区段由一个或多个连续的ORACLE数据库块组成。
             每个ORACLE数据块由一个或多个连续的操作系统数据块组成。
             每个操作系统数据文件由一个或多个区段组成,由一个或多个操作系统数据块组成。
     
         ⑴、表空间(tablespace)
             表空间是数据库中最大的逻辑单位,每一个表空间由一个或多个数据文件组成,一个数据文件只能与一个表空间相联系。每一个数据库都有一个SYSTEM表空间,该表空间是在数据库创建或数据库安装时自动创建的,用于存储系统的数据字典表,程序系统单元,过程函数,包和触发器等,也可用于存储用户数据表,索引对象。表空间具有在线(online)和离线(offline)属性,可以将除SYSTME以外的其他任何表空间置为离线。
         ⑵、段(segment)
             数据库的段可以分为四类:数据段、索引段、回退段和临时段。
         ⑶、区
             区是磁盘空间分配的最小单位。磁盘按区划分,每次至少分配一个区。区存储与段中,它由连续的数据块组成。
         ⑷、数据块
             数据块是数据库中最小的数据组织单位与管理单位,是数据文件磁盘存储空间单位,也是数据库I/O的最小单位,数据块大小由DB_BLOCK_SIZE参数决定,不同的Oracle版本DB_BLOCK_SIZE的默认值是不同的。
         ⑸、模式对象
             模式对象是一种应用,包括:表、聚簇、视图、索引序列生成器、同义词、哈希、程序单元、数据库链等。
             最后,在来说一下Oracle的用户、表空间和数据文件的关系:
             一个用户可以使用一个或多个表空间,一个表空间也可以供多个用户使用。用户和表空间没有隶属关系,表空间是一个用来管理数据存储的逻辑概念,表空间只是和数据文件发生关系,数据文件是物理的,一个表空间可以包含多个数据文件,而一个数据文件只能隶属一个表空间。
             总结:解释数据库、表空间、数据文件、表、数据的最好办法就是想象一个装满东西的柜子。数据库其实就是柜子,柜中的抽屉是表空间,抽屉中的文件夹是数据文件,文件夹中的纸是表,写在纸上的信息就是数据。
      2.两类表空间:
           系统SYSTEM表空间 非系统表空间 NON-SYSTEM表空间
           系统SYSTEM表空间与数据库一起建立,在系统表空间中有数据字典,系统还原段。可以存放用户数据但是不建议。
           非系统表空间NON-SYSTEM表空间 由管理员创建。可以方便管理。
   3.3 实例的整体架构
       实例整体架构图:
                 ┌──────────────────────────────┐
                 │ Instance │
                 │ ┌──────────────────────────┐ │
                 │ │ ┌────────┐ SGA │ │
                 │ │ │ Shared Pool │ │ │
                 │ │ │ ┌─────┐ │ ┌────┐ ┌────┐ │ │
                 │ │ │ │Library │ │ │Database│ │ Redo │ │ │
                 │ │ │ │ Cache │ │ │Buffer │ │ Log │ │ │
                 │ │ │ └─────┘ │ │Cache │ │ Buffer │ │ │
                 │ │ │ ┌─────┐ │ │ │ │ │ │ │
                 │ │ │ │Data Dict │ │ └────┘ └────┘ │ │
                 │ │ │ │ Cache │ │ │ │
                 │ │ │ └─────┘ │ │ │
                 │ │ └────────┘ │ │
                 │ └──────────────────────────┘ │
                 │ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌───┐│
   │ │PMON│ │SNON│ │DBWR│ │LGWR│ │CHPT│ │OTHERS││
                 │ └──┘ └──┘ └──┘ └──┘ └──┘ └───┘│
                 └──────────────────────────────┘
       实例由内存和后台进程组成,它暂时存在于RAM和CPU中。当关闭运行的实例时,实例将随即消失。数据库由磁盘上的物理文件组成,不管在运行状态还是停止状态,这些文件就一直存在。因此,实例的生命周期就是其在内存中存在的时间,可以启动和停止。一旦创建数据库,数据库将永久存在。通俗的讲数据库就相当于平时安装某个程序所生成的安装目录,而实例就是运行某个程序时所需要的进程及消耗的内存。
       Oracle的内存架构包含两部分系统全局区(SGA)和程序全局区(PGA)。
       3.3.1 程序全局区
       3.3.2 系统全局区
           在操作系统提供的共享内存段实现的内存结构称为系统全局区(SGA)。SGA在实例启动时分配,在关闭时释放。在一定范围内,可以在实例运行时通过自动方式或响应DBA的指令,重新调整11g实例中的SGA及其中的组件的大小。
           由上图可知SGA至少包含三种数据结构:数据库缓冲区缓存、日志缓冲区及共享池。还可能包括:大池、JAVA池。可以使用show sga,查看sga的状态。
           1、共享池
                a.库缓存是内存区域,按其已分析的格式存储最近执行的代码。分析就是将编程人员编写的代码转换为可执行的代码,这是oracle根据需要执行的一个过程。通过将代码缓存在共享池,可以在不重新分析的情况下重用,极大地提高性能。
                b.数据字典缓存有时称为“行缓存”,它存储最近使用的对象定义:表、索引、用户和其他元数据定义的描述。
                c.PL/SQL区:存储的PL/SQL对象是过程、函数、打包的过程、打包的函数、对象类型定义和触发器。
           2、数据库缓冲区
                数据库缓冲区是oracle用来执行SQL的工作区域。
           3、日志缓冲区
                日志缓冲区是小型的、用于短期存储将写入到磁盘上的重做日志的变更向量的临时区域。日志缓冲区在启动实例时分配,如果不重新启动实例,就不能在随后调整其大小。
 后台进程有:
  1、PMON-----程序监控器
  2、SMON-----系统监控区
  3、DBWR-----数据写进程
  4、LGWR-----日志写进程
  5、CKPT-----检查点进程
  6、Others---归档进程
四、SQL语法基础(DDL、DCL、TCL、DML)
  SQL 全名是结构化查询语言(Structured Query Language),是用于数据库中的标准数据查询语言,IBM 公司最早使用在其开发的数据库系统中。1986 年 10 月,美国 ANSI 对 SQL 进行规范后,以此作为关系式数据库管理系统的标准语言 (ANSI X3. 135-1986),1987 年得到国际标准组织的支持下成为国际标准。不过各种通行的数据库系统在其实践过程中都对 SQL 规范作了某些编改和扩充。所以,实际上不同数据库系统之间的 SQL 语言不能完全相互通用
        DML 语句(数据操作语言)Insert、Update、 Delete、Select
        DDL 语句(数据定义语言)Create、Alter、 Drop
        DCL 语句(数据控制语言)Grant、Revoke
        TCL 事务控制语句 Commit 、Rollback、Savepoint
  4.1 入门语句
      普通用户连接: Conn scott/tiger
      超级管理员连接: Conn “sys/bluesot as sysdba”
      Disconnect; 断开连接-------------disc
      Save c:\1.txt 把 SQL 存到文件
      Ed c:\1.txt 编辑 SQL 语句
      @ c:\1.txt 运行 SQL 语句
      Desc emp; 描述 Emp 结构
      Select * from tab; 查看该用户下的所有对象
      Show user; 显示当前用户
      如果在 sys 用户下: 查询 Select * from emp; 会报错,原因:emp 是属于 scott,所以此时必须使用:select * from scott.emp; / 运行上一条语句
  4.2 DDL(数据定义语言)----改变表结构
     4.2.1 创建表
        CREATE TABLE name (
          tid VARCHAR2(5),
          tname VARCHAR2(20),
          tdate DATE,
          as VARCHAR(7,2)
        );
     4.2.2 添加一列
         ALTER TABLE 表名 ADD 列名 属性;
         ALTER TABLE student ADD age number(5);
     4.2.4 删除一列
         ALTER TABLE table_name DROP COLUMN column_name;
         ALTER TABLE student DROP COLUMN age;
     4.2.5 修改一列的属性
         ALTER TABLE table_name MODIFY column_name type;
         修改列名
         ALTER TABLE table_name RENAME COLUMN columnname TO newname;
         修改表名
         ALTER TABLE table_name RENAME TO newname;
     4.2.6 查看表中数据
         DESC table_name;
     4.2.7 删除表
         DROP TABLE table_name;
   4.3 DCL(数据控制语言)
     4.3.1 授权
        GRANT 权限/角色 TO 用户
        给 demo 用户以创建 session 的权限:GRANT create session TO demo;
        角色:-------------角色就是一堆权限的集合Create role myrole;
        Grant create table to myrole;
        Drop role myrole; 删除角色
         1.CONNECT, RESOURCE, DBA
         这些预定义角色主要是为了向后兼容。其主要是用于数据库管理。oracle建议用户自己设计数据库管理和安全的权限规划,而不要简单的使用这些预定角色。将来的版本中这些角色可能不会作为预定义角色。
         2.DELETE_CATALOG_ROLE, EXECUTE_CATALOG_ROLE, SELECT_CATALOG_ROLE 这些角色主要用于访问数据字典视图和包。
         3.EXP_FULL_DATABASE, IMP_FULL_DATABASE 这两个角色用于数据导入导出工具的使用。
          GRANT 权限(select、update、insert、delete) ON schema.table TO 用户
           |- GRANT select ON scott.emp TO test ;
           |- Grant all on scott.emp to test; --将表相关的所有权限付给 test
           |- Grant update(ename) on emp to test; 可以控制到列(还有 insert)
     4.3.2 收权
          REVOKE 权限/角色 ON schema.table FROM 用户
            |- REVOKE select ON scott.emp FROM test ;
    4.4 TCL(事务控制语言)
       事务的概念:事务是一系列对数据库操作命令的集合,它有边界(commit---commit)
       事务的特征:A ------原子性-----不可分割性-------要么执行要么不执行
                   C------一致性-----rollback
                   I-------隔离性-----锁的机制来保证的,锁有粒度【表、行】---------只读、修改锁
                             上锁---SELECT * FROM DEMO1 FOR UPDATE;
                             释放------commit、rollback
                   D -----持久性-------commit
          系统时间-----sysdate
                        to_date(‘2013/11/09’,‘yyyy/mm/dd’)--------修改日期格式
        转换函数
              1、To_char
                      select to_char(sysdate,'yyyy') from dual;
                      select to_char(sysdate,'fmyyyy-mm-dd') from dual;
                      select to_char(sal,'L999,999,999') from emp;
                      select to_char(sysdate,’D’) from dual;//返回星期
              2、To_number
                      select to_number('13')+to_number('14') from dual;
              3、To_date
                      Select to_date(‘20090210’,‘yyyyMMdd’) from dual;
        4.4.1 ROLLBACK
  回滚------回滚到它上面的离它最近的commit
 4.4.2 COMMIT
  提交-----------将数据缓冲区的数据提交到文件中去
 4.4.3 SAVEPOINT------保存点
  回滚点例子:
  INSERT INTO DEMO1(TID,TNAME) VALUES(11,'AS');
  SAVEPOINT P1;
  INSERT INTO DEMO1(TID,TNAME) VALUES(22,'AS');
  INSERT INTO DEMO1(TID,TNAME) VALUES(33,'AS');
  SAVEPOINT P2;
  INSERT INTO DEMO1(TID,TNAME) VALUES(44,'AS');
  ROLLBACK TO P2;
  COMMIT;
  INSERT INTO DEMO1(TID,TNAME) VALUES(55,'AS');
  ROLLBACK TO P1;----------无法回滚
    ------------查询结果:11,22,33 由于55没有提交所以没有写入文件
    4.5 DML(数据操作语言)---------改变数据结构
 4.5.1 insert 语句
  INSERT INTO table_name() VALUES();
  INSERT INTO table_name VALUES();
      插入空值时,用三种格式
  1、INSERT INTO demo VALUES('');
  2、INSERT INTO demo VALUES(' ');
  3、INSERT INTO demo VALUES(NULL);
  INSERT INTO demo(tid,tname,tdate) VALUES(1,null,sysdate);
  INSERT INTO demo(tid,tname,tdate) VALUES(1,'',to_date(sysdate,'yyyy-mm-dd'));
  INSERT INTO demo VALUES(1,'',to_date('2013/11/11','yyyy/mm/dd'));
 
  注意:
  1、字符串类型的字段值必须用单引号括起来,如:‘rain’;
  2、如果字段值里包含单引号需要进行字符串转换,把它替换成两个单引号‘’,如:‘''c''' 数据库中将插入‘c’;
  3、字符串类型的字段值超过定义长度会报错,最好在插入前进行长度校验;
  4、日期字段的字段值可以使用当前数据库的系统时间sysdate,精确到秒;
  5、INSERT时如果要用到从1开始自动增长的序列号,应该先建立一个序列号。
 
 4.5.2 update 语句
  UPDATE table_name SET column_name=值 WHERE 查询条件
  UPDATE demo SET tname='张三' WHERE tid=1;
  COMMIT;------是更新生效
 4.5.3 delete 语句-----不能回退
  DELETE TABLE table_name;--------------只能删除数据,不能释放空间
  TRUNCATE TABLE table_name;---------------删除数据并释放空间
  DELETE TABLE demo;
  TRUNCATE TABLE demo;
  4.5.4 select 语句
  A 、简单的 Select 语句
  SELECT * FROM table_name;
  SELECT * FROM demo;
  B、空值 is null
  SELECT * FROM demo where tname is null;

第五章 Select查询
结构: 执行顺序
SELECT * 5
       FROM table_name 1
            WHERE -----分组前的条件 2
   GROUP BY 3
HAVING -----分组后的条件 4
                           ORDER BY column_name ASC/DESC; 6
-----------------------------
子句、聚合函数、友好列 列名 AS 别名
-----------------------------
5.1 简单查询
5.1.1 查看表结构
DESC table_name;
DESC emp;
 
5.1.2查看所有的列
SELECT * FROM table_name;
SELECT * FROM emp;
 
5.1.3 查看指定列
SELECT 列名 FROM table_name;
SELECT empno FROM emp;
5.1.4 查看指定行
SELECT * FROM table_name WHERE column_name=值;
SELECT * FROM emp WHERE empno=7369;
5.1.5 使用算术表达式 + 、- 、/ 、*
SELECT ename,sal+1 FROM EMP;
ENAME SAL+1
---------- ----------
SMITH 801
ALLEN 1601
WARD 1251
SELECT ename,sal-2 FROM EMP;
ENAME SAL-1
---------- ----------
SMITH 799
ALLEN 1599
WARD 1249
SELECT ename,sal*2 FROM EMP;
ENAME SAL*2
---------- ----------
SMITH 1600
ALLEN 3200
WARD 2500
SELECT ename,sal/2 FROM EMP;
ENAME SAL/2
---------- ----------
SMITH 400
ALLEN 800
WARD 625
nvl(comm,0)的意思是,如果comm中有值,则nvl(comm,0)=comm; comm中无值,则nvl(comm,0)=0
5.1.3 连接运算符 ||
SELECT 'how'||'do' ||sno;
5.1.4 使用字段别名 AS
SELECT * FROM DEMO1 "Asd";-------带引号可以保证输入的结果有大小写
SELECT * FROM DEMO1 asd;
5.1.5 空值 IS NULL、 IS NOT NULL
SQL>SELECT * FROM EMP WHERE COMM IS NOT NULL AND SAL IN(SELECT ENAME,sal FROM emp WHERE ENAME LIKE '_O%') ;
5.1.6 去除重复行 DISTINCT
SQL>SELECT DISTINCT DEPTNO FROM EMP ORDER BY DEPTNO
SQL>SELECT DEPTNO FROM EMP GROUP BY DEPTNO ORDER BY DEPTNO
5.1.7 查询结果排序 ORDER BY ASC/DESC
逆序:
SQL> SELECT * FROM emp WHERE job='CLERK' OR ename='MILLER' ORDER BY SAL DESC;
顺序:
SQL> SELECT * FROM emp WHERE job='CLERK' OR ename='MILLER' ORDER BY SAL ASC;
SQL> SELECT * FROM emp WHERE job='CLERK' OR ename='MILLER' ORDER BY SAL ;
5.1.8 关系运算符 >、 < 、=、(!= or <>) MOD(模,类似于%)、BETWEEN AND、 NOT BETWEEN AND
SQL> SELECT DISTINCT MGR FROM emp WHERE MGR<>7788;
SQL>SELECT DISTINCT MGR FROM emp WHERE MGR BETWEEN 7788 AND 7902;
SQL>SELECT * FROM emp WHERE MOD(DEPTNO,100)=2;
SQL>SELECT * FROM EMP1 WHERE EMPNO NOT BETWEEN 7369 AND 7521;
SQL>SELECT * FROM EMP1 WHERE EMPNO>=7369 AND EMPNO<=7521;
5.1.9 操作 IN、NOT IN
SQL> SELECT ENAME,SAL FROM EMP WHERE SAL IN(SELECT MAX(SAL) FROM EMP1 GROUP BY DEPTNO);
5.1.10 模糊查询 LIKE、NOT LIKE----只针对字符型
% 表示零或多个字符
_ 表示一个字符
对于特殊符号可使用ESCAPE 标识符来查找
select * from emp where ename like '%*_%' escape '*'
上面的escape表示*后面的那个符号不当成特殊字符处理,就是查找普通的_符号
5.1.11 逻辑运算符 AND、OR、NOT
SQL> select * from emp where job='CLERK' OR ename='MILLER';
SQL> select * from emp where job='CLERK' AND ename='MILLER';
5.1.12 ANY、ALL
SQL>SELECT * FROM EMP WHERE EMPNO IN(7369,7521,7782);
SQL>SELECT * FROM EMP WHERE EMPNO>ANY(7369,7521,7782);--大于min
SQL>SELECT * FROM EMP WHERE EMPNO>ALL(7369,7521,7782);--大于max
SQL>SELECT * FROM EMP WHERE EMPNO<ANY(7369,7521,7782);--小于max
SQL>SELECT * FROM EMP WHERE EMPNO<ALL(7369,7521,7782);--小于min
5.1.13 练习
1、选择在部门30中员工的所有信息
Select * from emp where deptno=30;
2、列出职位为(MANAGER)的员工的编号,姓名
Select empno,ename from emp where job ="Manager";
3、找出奖金高于工资的员工
Select * from emp where comm>sal;
4、找出每个员工奖金和工资的总和
Select sal+comm,ename from emp;
5、找出部门10中的经理(MANAGER)和部门20中的普通员工(CLERK)
Select * from emp where (deptno=10 and job=?MANAGER?) or (deptno=20 and job=?CLERK?);
6、找出部门10中既不是经理也不是普通员工,而且工资大于等于2000的员工
Select * from emp where deptno=10 and job not in('MANAGER') and sal>=2000;
7、找出有奖金的员工的不同工作
Select distinct job from emp where comm is not null and comm>0;
8、找出没有奖金或者奖金低于500的员工
Select * from emp where comm<500 or comm is null;
9、显示雇员姓名,根据其服务年限,将最老的雇员排在最前面
select ename from emp order by hiredate ;
10、SQL>SELECT DEPTNO,MAX(SAL) AS tot,
               MIN(COMM) AS MCOMM,
               SUM(COMM) SUMC,
               TRUNC(AVG(SAL+NVL(COMM,0)))TAVG,
               ROUND(AVG(SAL+NVL(COMM,0)),2)RAVG,
               COUNT(*)
       FROM EMP
            HAVING COUNT(*)>3
                  GROUP BY DEPTNO
                        ORDER BY DEPTNO
           
            11、SQL>SELECT ENAME,SAL
                FROM EMP
                         WHERE SAL IN(SELECT MAX(SAL)
                               FROM EMP1
                                            GROUP BY DEPTNO);
5.2 多表查询
INNER JOIN:内连接
JOIN: 如果表中有至少一个匹配,则返回行
LEFT JOIN: 即使右表中没有匹配,也从左表返回所有的行
RIGHT JOIN: 即使左表中没有匹配,也从右表返回所有的行
FULL JOIN: 只要其中一个表中存在匹配,就返回行
5.2.1、笛卡尔集(Cross Join)------------列相加,行相乘
Select * from emp,dept;
5.2.2、等值连接(Equijoin)(Natural join..on)---------隐式内联
select empno, ename, sal, emp.deptno, dname from emp, dept where emp.deptno = dept.deptno;
5.2.3、非等值连接(Non-Equijoin)
select ename,empno,grade from emp,salgrade where sal between losal and hisal;
5.2.4、自联接(Self join)
select column_name from table_name1,table_name2 where 条件;
select e.empno,e.ename,m.empno,m.ename from emp e,emp m where m.mgr = e.empno;
5.2.5、内联接(Inner Join)----------显式外联
SELECT column_name(s)
FROM table_name1
INNER JOIN table_name2
ON table_name1.column_name=table_name2.column_name
5.2.6、 左外联接(Left Outer Join )
左外连接:在内联接的基础上,增加左表中没有匹配的行,也就是说,左表中的记录总会出现在最终结果集中
SELECT column_name(s)
FROM table_name1
LEFT JOIN table_name2
ON table_name1.column_name=table_name2.column_name
select s.sid,s.sname,s1.sid,s1.sname from student s,student1 s1 where s.sid=s1.sid(+);
1、先通过from自句判断左表和右表;
2、接着看加号作用在那个表别名上;
3、如果作用在右表上,则为左外连接,否则为右外连接
select empno,ename,dname from emp left outer join dept on emp.deptno = dept.deptno;
5.2.7、右外联接(Right Outer Join)
右外连接:在内联接的基础上,增加右表中没有匹配的行,也就是说,右表中的记录总会出现在最终结果集中
SELECT column_name(s)
FROM table_name1
RIGHT JOIN table_name2
ON table_name1.column_name=table_name2.column_name
右外联接转换为内联接
SELECT column_name(s)
FROM table_name1
RIGHT JOIN table_name2
ON table_name1.column_name=table_name2.column_name WHERE table_name1.column_name is not null;
select s.sid,s.sname,s1.sid,s1.sname from student s,student1 s1 where s.sid(+)=s1.sid;
select empno,ename,dname from emp right outer join dept on emp.deptno= dept.deptno;
select * from emp1 e right join dept d on e.deptno=d.deptno where e.deptno is not null;
5.2.8、全外联接(Full Outer Join)
SELECT column_name(s)
FROM table_name1
FULL JOIN table_name2
ON table_name1.column_name=table_name2.column_name
select empno,ename,dname from emp full outer join dept on emp.deptno = dept.deptno;
5.2.9、集合操作
 · UNION:并集,所有的内容都查询,重复的显示一次
  ·UNION ALL:并集,所有的内容都显示,包括重复的
 · INTERSECT:交集:只显示重复的
 · MINUS:差集:只显示对方没有的(跟顺序是有关系的)
SELECT column_name(s) FROM table_name1
UNION/INTERSECT/MINUS
SELECT column_name(s) FROM table_name2
首先建立一张只包含 20 部门员工信息的表:
 CREATE TABLE emp20 AS SELECT * FROM emp WHERE deptno=20 ;
1、验证 UNION 及 UNION ALL
 UNION:SELECT * FROM emp UNION SELECT * FROM emp20 ;
 使用此语句重复的内容不再显示了
 UNION ALL:SELECT * FROM emp UNION ALL SELECT * FROM emp20 ;
 重复的内容依然显示
2、验证 INTERSECT
 SELECT * FROM emp INTERSECT SELECT * FROM emp20 ; 只显示了两个表中彼此重复的记录。
 
MINUS:返回差异的记录
 SELECT * FROM emp MINUS SELECT * FROM emp20 ; 只显示了两张表中的不同记录满链接也可以用以下的方式来表示:
select t1.id,t2.id from table1 t1,table t2 where t1.id=t2.id(+) union
select t1.id,t2.id from table1 t1,table t2 where t1.id(+)=t2.id
5.3 子查询
5.3.1、单行子查询
select * from emp
where sal > (select sal from emp where empno = 7566);
5.3.2、 子查询空值/多值问题
如果子查询未返回任何行,则主查询也不会返回任何结果
(空值)select * from emp where sal > (select sal from emp where empno = 8888);
如果子查询返回单行结果,则为单行子查询,可以在主查询中对其使用相应的单行记录比较运算符
(正常)select * from emp where sal > (select sal from emp where empno = 7566);
如果子查询返回多行结果,则为多行子查询,此时不允许对其使用单行记录比较运算符
(多值)select * from emp where sal > (select avg(sal) from emp group by deptno);//非法----错误的
 
5.3.3、 多行子查询
select * from emp where sal > any(select avg(sal) from emp group by deptno);
select * from emp where sal > all(select avg(sal) from emp group by deptno);
select * from emp where job in (select job from emp where ename = 'MARTIN' or ename = 'SMITH');
5.3.4、 分页查询
Oracle分页
①采用rownum关键字(三层嵌套)
SELECT * FROM(
  SELECT A.*,ROWNUM num FROM (
SELECT * FROM t_order)A
WHERE ROWNUM<=15)
WHERE num>=5; --返回第5-15行数据
②采用row_number解析函数进行分页(效率更高)
SELECT xx.* FROM(
SELECT t.*,row_number() over(ORDER BY o_id)AS num
FROM t_order t
)xx
WHERE num BETWEEN 5 AND 15;
ROWID和ROWNUM的区别
1、ROWID是物理地址,用于定位ORACLE中具体数据的物理存储位置是唯一的18位物理编号,而ROWNUM则是根据sql查询后得到的结果自动加上去的
2、ROWNUM是暂时的并且总是从1开始排起,而ROWID是永久的。
解析函数能用格式
函数() over(pertion by 字段 order by 字段);
ROW_NUMBER(): Row_number函数返回一个唯一的值,当碰到相同数据时,排名按照记录集中记录的顺序依次递增。 row_number()和rownum差不多,功能更强一点(可以在各个分组内从1开时排序),因为row_number()是分析函数而rownum是伪列所以row_number()一定要over而rownum不能over。
RANK():Rank函数返回一个唯一的值,除非遇到相同的数据,此时所有相同数据的排名是一样的,同时会在最后一条相同记录和下一条不同记录的排名之间空出排名。rank()是跳跃排序,有两个第二名时接下来就是第四名(同样是在各个分组内)。
DENSE_RANK():Dense_rank函数返回一个唯一的值,除非当碰到相同数据,此时所有相同数据的排名都是一样的。
dense_rank()是连续排序,有两个第二名时仍然跟着第三名。他和row_number的区别在于row_number是没有重复值的。
dense_rank()是连续排序,有两个第二名时仍然跟着第三名。他和row_number的区别在于row_number是没有重复值的。
 下面举个例子:
SQL> select * from user_order order by customer_sales;
 REGION_ID CUSTOMER_ID CUSTOMER_SALES
---------- ----------- --------------
        10 30 1216858
         5 2 1224992
         9 24 1224992
         9 23 1224992
         8 18 1253840
【3】row_number()、rank()、dense_rank()这三个分析函数的区别实例
SQL>SELECT empno, deptno, SUM(sal) total,
           RANK() OVER(ORDER BY SUM(sal) DESC) RANK,
           dense_rank() OVER(ORDER BY SUM(sal) DESC)dense_rank,
           row_number() OVER(ORDER BY SUM(sal) DESC)row_number
FROM emp1 GROUP BY empno, deptno;
--------------------------------------------------
1 7839 10 5000 1 1 1
2 7902 20 3000 2 2 2
3 7788 20 3000 2 2 3
4 7566 20 2975 4 3 4
5 7698 30 2850 5 4 5
6 7782 10 2450 6 5 6
7 7499 30 1600 7 6 7
比较上面3种不同的策略,我们在选择的时候就要根据客户的需求来定夺了:
①假如客户就只需要指定数目的记录,那么采用row_number是最简单的,但有漏掉的记录的危险
②假如客户需要所有达到排名水平的记录,那么采用rank或dense_rank是不错的选择。至于选择哪一种则看客户的需要,选择dense_rank或得到最大的记录
Mysql分页采用limt关键字
select * from t_order limit 5,10; #返回第6-15行数据
select * from t_order limit 5; #返回前5行
select * from t_order limit 0,5; #返回前5行
Mssql 2000分页采用top关键字(20005以上版本也支持关键字rownum)
Select top 10 * from t_order where id not in (select id from t_order where id>5 ); //返回第6到15行数据其中10表示取10记录 5表示从第5条记录开始取
sql server 分页采用top关键字
5.3.5、 in 、exists
EXISTS 的执行流程
select * from t1 where exists ( select null from t2 where y = x )
可以理解为:
  for x in ( select * from t1 ) loop
 if ( exists ( select null from t2 where y = x.x ) then
        OUTPUT THE RECORD
 end if;
 end loop;
对于 in 和 exists 的性能区别:
  如果子查询得出的结果集记录较少,主查询中的表较大且又有索引时应该用 in,反之如果外层的主查询记录较少,子查询中的表大,又有索引时使用 exists。
  其实我们区分 in 和 exists 主要是造成了驱动顺序的改变(这是性能变化的关键),如果是 exists,那么以外层表为驱动表,先被访问,如果是 IN,那么先执行子查询,所以我们会以驱动表的快速返回为目标,那么就会考虑到索引及结果集的关系了 另外 IN 是不对 NULL 进行处理
如:
select 1 from dual where not in (0,1,2,null) 为空
第六章 约束
约束就是指对插入数据的各种限制,例如:人员的姓名不能为空,人的年龄只能在0~150 岁之间。约束可以对数据库中的数据进行保护。 约束可以在建表的时候直接声明,也可以为已建好的表添加约束。
 
6.1、NOT NULL:非空约束 例如:姓名不能为空
CREATE TABLE person(
pid NUMBER ,
name VARCHAR2(30) NOT NULL
) ;
 
alter table emp
-- 插入数据
INSERT INTO person(pid,name) VALUES (11,'张三');
-- 错误的数据,会受到约束限制,无法插入
INSERT INTO person(pid) VALUES (12);
 
6.2、 PRIMARY KEY:主键约束
 · 不能重复,不能为空 · 例如:身份证号不能为空。 现在假设pid字段不能为空,且不能重复。
DROP TABLE person ;
CREATE TABLE person
(
 pid NUMBER PRIMARY KEY , name VARCHAR(30) NOT NULL
) ;
-- 插入数据
INSERT INTO person(pid,name) VALUES (11,'张三');
-- 主键重复了
INSERT INTO person(pid,name) VALUES (11,'李四');
 
6.3、UNIQUE:唯一约束,值不能重复(空值除外) 人员中有电话号码,电话号码不能重复。
DROP TABLE person ;
CREATE TABLE person
(
 pid NUMBER PRIMARY KEY NOT NULL , name VARCHAR(30) NOT NULL , tel VARCHAR(50) UNIQUE
) ;
-- 插入数据
INSERT INTO person(pid,name,tel) VALUES (11,'张三','1234567');
-- 电话重复了
INSERT INTO person(pid,name,tel) VALUES (12,'李四','1234567');
 
6.4、CHECK:条件约束,插入的数据必须满足某些条件
 例如:人员有年龄,年龄的取值只能是 0~150 岁之间
DROP TABLE person ;
CREATE TABLE person(
   pid NUMBER PRIMARY KEY NOT NULL ,
 name VARCHAR2(30) NOT NULL ,
tel VARCHAR2(50) NOT NULL UNIQUE ,
age NUMBER CHECK(age BETWEEN 0 AND 150)
) ;
-- 插入数据
INSERT INTO person(pid,name,tel,age) VALUES (11,'张三','1234567',30);
-- 年龄的输入错误
INSERT INTO person(pid,name,tel,age) VALUES (12,'李四','2345678',-100);
 alter table product
add constriant chk_product_unitprice check(unitprice>0);
6.5、Foreign Key:外键
 例如:有以下一种情况:
 · 一个人有很多本书:
  |- Person 表
  |- Book 表:而且book 中的每一条记录表示一本书的信息,一本书的信息属于一个人
CREATE TABLE book(
 bid NUMBER PRIMARY KEY NOT NULL ,
 name VARCHAR(50) ,
 -- 书应该属于一个人 pid NUMBER
) ;
 如果使用了以上的表直接创建,则插入下面的记录有效:
INSERT INTO book(bid,name,pid) VALUES(1001,'JAVA',12) ;
 以上的代码没有任何错误,但是没有任何意义,因为一本书应该属于一个人,所以在此处的pid的取值应该与person 表中的pid一致。
 此时就需要外键的支持。修改book 的表结构
DROP TABLE book ;
CREATE TABLE book
(
 bid NUMBER PRIMARY KEY NOT NULL , name VARCHAR(50) ,
 -- 书应该属于一个人 pid NUMBER REFERENCES person(pid) ON DELETE CASCADE
 -- 建立约束:book_pid_fk,与person中的pid 为主-外键关系
 --CONSTRAINT book_pid_fk FOREIGN KEY(pid) REFERENCES person(pid)
) ;
 
INSERT INTO book(bid,name,pid) VALUES(1001,'JAVA',12) ;
6.6、级联删除
 此时如果想完成删除person 表的数据同时自动删除掉book 表的数据操作,则必须使用级联删除。
 在建立外键的时候必须指定级联删除(ON DELETE CASCADE)。
CREATE TABLE book
(
 bid NUMBER PRIMARY KEY NOT NULL , name VARCHAR(50) ,
 -- 书应该属于一个人
 pid NUMBER ,
 -- 建立约束:book_pid_fk,与person中的pid 为主-外键关系
 CONSTRAINT book_pid_fk FOREIGN KEY(pid) REFERENCES person(pid) ON DELETE CASCADE
) ;
DROP TABLE book ;
DROP TABLE person ;
CREATE TABLE person(
      pid NUMBER ,
      name VARCHAR(30) NOT NULL ,
      tel VARCHAR(50) ,
      age NUMBER
) ;
CREATE TABLE book(
      bid NUMBER ,
      name VARCHAR2(50) ,
      pid NUMBER
) ;
 
 以上两张表中没有任何约束,下面使用 alter 命令为表添加约束
ALTER TABLE table_name ADD CONSTRAINT column_name 约束;
1、 为两个表添加主键:
  · person 表 pid 为主键:
   ALTER TABLE person ADD CONSTRAINT person_pid_pk PRIMARY KEY(pid) ;
  · book 表 bid 为主键:
   ALTER TABLE book ADD CONSTRAINT book_bid_pk PRIMARY KEY(bid) ;
2、 为 person 表中的 tel 添加唯一约束:
  ALTER TABLE person ADD CONSTRAINT person_tel_uk UNIQUE(tel) ;
3、 为 person 表中的 age 添加检查约束:
  ALTER TABLE person ADD CONSTRAINT person_age_ck CHECK(age BETWEEN 0 AND
150) ;
 4、 为 book 表中的 pid 添加与 person 的主-外键约束,要求带级联删除
  ALTER TABLE book ADD CONSTRAINT person_book_pid_fk FOREIGN KEY (pid)
REFERENCES person(pid) ON DELETE CASCADE ;
 
Q:如何用alter添加非空约束
A:用 check约束
6.7、删除约束:
 ALTER TABLE book DROP CONSTRAINT person_book_pid_fk ;
alter table student drop unique(tel);
6.8、 启用约束
ALTER TABLE book enable CONSTRAINT person_book_pid_fk ;
6.9、 禁用约束
ALTER TABLE book disable CONSTRAINT person_book_pid_fk ;
第七章 SQL函数
7.1 单行函数
1、字符函数
Upper -------大写
SELECT Upper ('abcde') FROM dual ;
SELECT * FROM emp WHERE ename=UPPER('smith') ;
Lower --------小写
SELECT lower('ABCDE') FROM dual ;
Initcap--------首字母大写
Select initcap(ename) from emp;
Concat----联接
Select concat('a','b') from dual;
Select 'a'||'b' from dual;
Substr------截取
Select substr('abcde',length('abcde')-2) from dual;
Select substr('abcde',-3,3) from dual;
Length------长度
Select length(ename) from emp;
Replace------替代
Select replace(ename,'a','A') from emp;
Instr---------- indexof
Select instr('Hello World','or') from dual;
Lpad------------左侧填充 lpad() *****Smith
lpad('Smith',10,'*')
Rpad-------------右侧填充 rpad()Smith*****
rpad('Smith',10,'*')
Trim-------------过滤首尾空格 trim() Mr Smith
trim(' Mr Smith ')
2、数值函数
Round
select round(412,-2) from dual; --400
select round(412.313,2) from dual;
Mod
select MOD(412,3) from dual;
Trunc
select trunc(412.13,-2) from dual;
3、日期函数
Months_between()
select months_between(sysdate,hiredate) from emp;
Add_months()
select add_months(sysdate,1) from dual;
Next_day()
select next_day(sysdate,'星期一') from dual;
Last_day
select last_day(sysdate) from dual;
4.4、转换函数
To_char
select to_char(sysdate,'yyyy') from dual; select to_char(sysdate,'fmyyyy-mm-dd') from dual; select to_char(sal,'L999,999,999') from emp; select to_char(sysdate,’D’) from dual;//返回星期
To_number
select to_number('13')+to_number('14') from dual;
To_date
Select to_date(?20090210?,?yyyyMMdd?) from dual;
5、通用函数
NVL()函数
select nvl(comm,0) from emp;
NULLIF()函数
如果表达式 exp1 与 exp2 的值相等则返回 null,否则返回 exp1 的值
NVL2()函数 select empno, ename, sal, comm, nvl2(comm, sal+comm, sal) total from emp;
COALESCE()函数
依次考察各参数表达式,遇到非 null 值即停止并返回该值。
select empno, ename, sal, comm, coalesce(sal+comm, sal, 0)总收入 from emp;
CASE 表达式------区间
SQL>select empno,
          ename,
          sal,
          case deptno
when 10 then '财务部'
when 20 then '研发部'
when 30 then '销售部'
else '未知部门'
end 部门
from emp;
SQL>SELECT e.*,
    CASE
        WHEN sal>=3000 THEN '高'
        WHEN sal>=2000 AND sal<3000 THEN '中'
        WHEN sal<2000 AND sal>0 THEN '高'
        ELSE 'un'
     END ca
FROM emp1 e;
DECODE()函数------------离散的值
SQL>select empno, ename, sal,
    decode(deptno,
                                10, '财务部',
                                20, '研发部',
                                30, '销售部',
                                '未知部门') 部门
from emp;
 
单行函数嵌套
select empno, lpad(initcap(trim(ename)),10,' ') name, job, sal from emp;
7.2 分组函数
1、COUNT
如果数据库表的没有数据,count(*)返回的不是 null,而是 0
2、Avg,max,min,sum
3、nvl----分组函数与空值
分组函数省略列中的空值
select avg(comm) from emp; select sum(comm) from emp;
可使用 NVL()函数强制分组函数处理空值 select avg(nvl(comm, 0)) from emp;
4、GROUP BY 子句
出现在 SELECT 列表中的字段或者出现在 order by 后面的字段,如果不是包含在分组函数中,那么该字段必须同时在 GROUP BY 子句中出现。包含在 GROUP BY 子句中的字段则不必须出现在 SELECT 列表中。
可使用 where 字句限定查询条件,可使用 Order by 子句指定排序方式
如果没有 GROUP BY 子句,SELECT 列表中不允许出现字段(单行函数)与分组函数混用的情况。
select empno, sal from emp; //合法 select avg(sal) from emp; //合法 select empno, initcap(ename), avg(sal) from emp; //非法
 不允许在 WHERE 子句中使用分组函数。 select deptno, avg(sal) from emp where avg(sal) > 2000; group by deptno;
5、HAVING 子句
select deptno, job, avg(sal)
from emp
where hiredate >= to_date('1981-05-01','yyyy-mm-dd') group by deptno,job having avg(sal) > 1200 order by deptno,job;
6、分组函数嵌套
select max(avg(sal)) from emp group by deptno;
 
第八章 PLSQL变量与常量
1、声明变量
  变量一般都在PL/SQL块的声明部分声明,引用变量前必须首先声明,要在执行或异常处理部分使用变量,那么变量必须首先在声明部分进行声明。
  声明变量的语法如下:
Variable_name [CONSTANT] databyte [NOT NULL][:=|DEFAULT expression]
     注意:可以在声明变量的同时给变量强制性的加上NOT NULL约束条件,此时变量在初始化时必须赋值。
2、给变量赋值
  给变量赋值有两种方式:
  . 直接给变量赋值
   X:=200;
   Y=Y+(X*20);
  . 通过SQL SELECT INTO 或FETCH INTO给变量赋值
SELECT SUM(SALARY),SUM(SALARY*0.1)
INTO TOTAL_SALARY,TATAL_COMMISSION
FROM EMPLOYEE
WHERE DEPT=10;
3、常量
  常量与变量相似,但常量的值在程序内部不能改变,常量的值在定义时赋予,,他的声明方式与变量相似,但必须包括关键字CONSTANT。常量和变量都可被定义为SQL和用户定义的数据类型。
ZERO_VALUE CONSTANT NUMBER:=0;
4、标量(scalar)数据类型
  标量(scalar)数据类型没有内部组件,他们大致可分为以下四类:
   . number
. char
. date/time
. boolean
  表1 Numer
Datatype Range Subtypes description
BINARY_INTEGER -214748-2147483647 NATURAL
NATURAL
NPOSITIVE
POSITIVEN
SIGNTYPE
用于存储单字节整数。
要求存储长度低于NUMBER值。
用于限制范围的子类型(SUBTYPE):
 NATURAL:用于非负数
 POSITIVE:只用于正数
 NATURALN:只用于非负数和非NULL值
 POSITIVEN:只用于正数,不能用于NULL值
 SIGNTYPE:只有值:-1、0或1.
NUMBER 1.0E-130-9.99E125 DEC
DECIMAL
DOUBLE
PRECISION
FLOAT
INTEGERIC
INT
NUMERIC
REAL
SMALLINT 存储数字值,包括整数和浮点数。可以选择精度和刻度方式,语法:
number[([,])]。
缺省的精度是38,scale是0.
PLS_INTEGER -2147483647-2147483647 与BINARY_INTEGER基本相同,但采用机器运算时,PLS_INTEGER提供更好的性能 。
  表2 字符数据类型
datatype rang subtype description
CHAR 最大长度32767字节 CHARACTER 存储定长字符串,如果长度没有确定,缺省是1
LONG 最大长度2147483647字节 存储可变长度字符串
RAW 最大长度32767字节 用于存储二进制数据和字节字符串,当在两个数据库之间进行传递时,RAW数据不在字符集之间进行转换。
LONGRAW 最大长度2147483647 与LONG数据类型相似,同样他也不能在字符集之间进行转换。
ROWID 18个字节 与数据库ROWID伪列类型相同,能够存储一个行标示符,可以将行标示符看作数据库中每一行的唯一键值。
VARCHAR2 最大长度32767字节 STRINGVARCHAR 与VARCHAR数据类型相似,存储可变长度的字符串。声明方法与VARCHAR相同
  表3 DATE和BOOLEAN
datatype range description
BOOLEAN TRUE/FALSE 存储逻辑值TRUE或FALSE,无参数
DATE 01/01/4712 BC 存储固定长的日期和时间值,日期值中包含时间
LOB数据类型
  LOB(大对象,Large object) 数据类型用于存储类似图像,声音这样的大型数据对象,LOB数据对象可以是二进制数据也可以是字符数据,其最大长度不超过4G。LOB数据类型支持任意访问方式,LONG只支持顺序访问方式。LOB存储在一个单独的位置上,同时一个"LOB定位符"(LOB locator)存储在原始的表中,该定位符是一个指向实际数据的指针。在PL/SQL中操作LOB数据对象使用ORACLE提供的包DBMS_LOB.LOB数据类型可分为以下四类:
  . BFILE----------------二进制文件
  . BLOB--------------二进制对象
  . CLOB---------------字符型对象
  . NCLOB-------------nchar类型对象
操作符
  PL/SQL有一系列操作符。操作符分为下面几类:
  . 算术操作符
  . 关系操作符
  . 比较操作符
  . 逻辑操作符
  算术操作符如表4所示
operator operation
+ 加
- 减
/ 除
* 乘
** 乘方
  关系操作符主要用于条件判断语句或用于where子串中,关系操作符检查条件和结果是否为true或false,
表5PL/SQL中的关系操作符
operator operation
< 小于操作符
<= 小于或等于操作符
> 大于操作符
>= 大于或等于操作符
= 等于操作符
!= 不等于操作符
<> 不等于操作符
:= 赋值操作符
  表6 显示的是比较操作符
operator operation
IS NULL 如果操作数为NULL返回TRUE
LIKE 比较字符串值
BETWEEN 验证值是否在范围之内
IN 验证操作数在设定的一系列值中
  表7显示的是逻辑操作符
operator operation
AND 两个条件都必须满足
OR 只要满足两个条件中的一个
NOT 取反
第九章 PL/SQL--------动态SQL
PL/SQL动态SQL(原创)
概念:动态SQL,编译阶段无法明确SQL命令,只有在运行阶段才能被识别
动态SQL和静态SQL两者的异同
静态SQL为直接嵌入到PL/SQL中的代码,而动态SQL在运行时,根据不同的情况产生不同的SQL语句。
静态SQL在执行前编译,一次编译,多次运行。动态SQL同样在执行前编译,但每次执行需要重新编译。
静态SQL可以使用相同的执行计划,对于确定的任务而言,静态SQL更具有高效性,但缺乏灵活性;动态SQL使用了不同的执行计划,效率不如静态SQL,但能够解决复杂的问题。
动态SQL容易产生SQL注入,为数据库安全带来隐患。
动态SQL语句的几种方法
a.使用EXECUTE IMMEDIATE语句
包括DDL语句,DCL语句,DML语句以及单行的SELECT 语句。该方法不能用于处理多行查询语句。
b.使用OPEN-FOR,FETCH和CLOSE语句
对于处理动态多行的查询操作,可以使用OPEN-FOR语句打开游标,使用FETCH语句循环提取数据,最终使用CLOSE语句关闭游标。
c.使用批量动态SQL
即在动态SQL中使用BULK子句,或使用游标变量时在fetch中使用BULK ,或在FORALL语句中使用BULK子句来实现。
d.使用系统提供的PL/SQL包DBMS_SQL来实现动态SQL
 
动态SQL的语法
下面是动态SQL常用的语法之一
EXECUTE IMMEDIATE dynamic_SQL_string
[INTO defined_variable1, defined_variable2, ...]
[USING [IN | OUT | IN OUT] bind_argument1, bind_argument2,...]
[{RETURNING | RETURN} field1, field2, ... INTO bind_argument1,
bind_argument2, ...]
语法描述
dynamic_SQL_string:存放指定的SQL语句或PL/SQL块的字符串变量
defined_variable1:用于存放单行查询结果,使用时必须使用INTO关键字,类似于使用
SELECT ename INTO v_name FROM scott.emp;
只不过在动态SQL时,将INTO defined_variable1移出到dynamic_SQL_string语句之外。
bind_argument1:用于给动态SQL语句传入或传出参数,使用时必须使用USING关键字,IN表示传入的参数,OUT表示传出的参数,IN OUT则既可以传入,也可传出。
RETURNING | RETURN 子句也是存放SQL动态返回值的变量。
使用要点
a.EXECUTE IMMEDIATE执行DML时,不会提交该DML事务,需要使用显示提交(COMMIT)或作为EXECUTE IMMEDIATE自身的一部分。
b.EXECUTE IMMEDIATE执行DDL,DCL时会自动提交其执行的事务。
c.对于多行结果集的查询,需要使用游标变量或批量动态SQL,或者使用临时表来实现。
d.当执行SQL时,其尾部不需要使用分号,当执行PL/SQL 代码时,其尾部需要使用分号。
f.动态SQL中的占位符以冒号开头,紧跟任意字母或数字表示。
动态SQL的使用(DDL,DCL,DML以及单行结果集)
DECLARE
  v_table VARCHAR2(30):='emp1';
  v_sql LONG:='SELECT ename FROM emp1 WHERE empno=:1';--占位符\可以用任何符号(数字或字母)
  --v_no emp1.empno%TYPE:='&请输入号码';--&是变量绑定符 绑定的数据是字符串类型时必须要加引号
  --v_no emp1.empno%TYPE:=&请输入号码;
  v_name emp1.ename%TYPE;
BEGIN
  --EXECUTE IMMEDIATE v_sql INTO v_name USING IN v_no;
  dbms_output.put_line('ename='||v_name);
  --EXECUTE IMMEDIATE 'create table emp2 as select * from emp';
  --EXECUTE IMMEDIATE 'drop table '||v_table;
  --EXECUTE IMMEDIATE 'alter table emp enable row movement';
END;
BULK子句和动态SQL的使用
动态SQL中使用BULK子句的语法
EXECUTE IMMEDIATE dynamic_string --dynamic_string用于存放动态SQL字符串
[BULK COLLECT INTO define_variable[,define_variable...]] --存放查询结果的集合变量
[USING bind_argument[,argument...]] --使用参数传递给动态SQL
[{RETURNING | RETURN} --返回子句
BULK COLLECT INTO return_variable[,return_variable...]]; --存放返回结果的集合变量
使用bulk collect into子句处理动态SQL中T的多行查询可以加快处理速度,从而提高应用程序的性能。当使用bulk子句时,集合类型可以是PL/SQL所支持的索引表、嵌套表和VARRY,但集合元 素必须使用SQL数据类型。常用的三种语句支持BULK子句,分别为EXECUTE IMMEDIATE,FETCH 和FORALL。
使用EXECUTE IMMEDIATE 结合BULK子句处理多行查询。使用了BULK COLLECT INTO来传递结果。
SQL>declare
  type ename_table_type is table of emp1.ename%type index by binary_integer;
  type sal_table_type is table OF emp1.sal%type index by binary_integer;
     ename_table ename_table_type;
     sal_table sal_table_type;
     sql_stat varchar2(100);
     v_dno number := 7369;
begin
    sql_stat := 'select ename,sal from emp1 where deptno = :v_dno'; --动态DQL语句,未使用RETURNING子句
    execute immediate sql_stat
    bulk collect into ename_table,sal_table using v_dno;
    for i in 1..ename_table.count loop
        dbms_output.put_line('Employee ' || ename_table(i) || ' Salary is: ' || sal_table(i));
    end loop;
end;
使用FETCH子句结合BULK子句处理多行结果集
下面的示例中首先定义了游标类型,游标变量以及复合类型,复合变量,接下来从动态SQL中OPEN游标,然后使用FETCH将结果存放到复合变量中。即使用OPEN,FETCH代替了EXECUTE IMMEDIATE来完成动态SQL的执行。
SQL> declare
  2 type empcurtype is ref cursor;
  3 emp_cv empcurtype;
  4 type ename_table_type is table of tb2.ename%type index by binary_integer;
  5 ename_table ename_table_type;
  6 sql_stat varchar2(120);
  7 begin
  8 sql_stat := 'select ename from tb2 where deptno = :dno';
  9 open emp_cv for sql_stat using &dno;
 10 fetch emp_cv bulk collect into ename_table;
 11 for i in 1..ename_table.count loop
 12 dbms_output.put_line('Employee Name: ' || ename_table(i));
 13 end loop;
 14 close emp_cv;
 15* end;
在FORALL语句中使用BULK子句
下面是FORALL子句的语法
FORALL index IN lower bound..upper bound --FORALL循环计数
EXECUTE IMMEDIATE dynamic_string --结合EXECUTE IMMEDIATE来执行动态SQL语句
USING bind_argument | bind_argument(index) --绑定输入参数
[bind_argument | bind_argument(index)]...
[{RETURNING | RETURN} BULK COLLECT INTO bind_argument[,bind_argument...]]; --绑定返回结果集
FORALL子句允许为动态SQL输入变量,但FORALL子句仅支持的DML(INSERT,DELETE,UPDATE)语句,不支持动态的SELECT语句。
下面的示例中,首先声明了两个复合类型以及复合变量,接下来为复合变量ename_table赋值,以形成动态SQL语句。紧接着使用FORALL子句结合EXECUTE IMMEDIATE 来提取结果集。
SQL> declare
  2 type ename_table_type is table of tb2.ename%type;
  3 type sal_table_type is table of tb2.sal%type;
  4 ename_table ename_table_type;
  5 sal_table sal_table_type;
  6 sql_stat varchar2(100);
  7 begin
  8 ename_table := ename_table_type('BLAKE','FORD','MILLER');
  9 sql_stat := 'update tb2 set sal = sal * 1.1 where ename = :1'
 10 || ' returning sal into :2';
 11 forall i in 1..ename_table.count
 12 execute immediate sql_stat using ename_table(i) returning bulk collect into sal_table;
 13 for j in 1..sal_table.count loop
 14 dbms_output.put_line('The ' || ename_table(j) || '''' || 's new salalry is ' || sal_table(j));
 15 end loop;
 16* end;
常见错误
1、使用动态DDL时,不能使用绑定变量。
EXECUTE IMMEDIATE 'CREATE TABLE dsa '||'as select * from :1' USING IN v_table;
解决办法,将绑定变量直接拼接,如下:
EXECUTE IMMEDIATE 'CREATE TABLE dsa '||'as select * from '|| v_table;
2、不能使用schema对象作为绑定参数,下面的示例中,动态SQL语句查询需要传递表名,因此收到了错误提示。
EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM:tb_name ' into v_count;
解决办法,将绑定变量直接拼接,如下:
EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM ' || tb_name into v_count;
3、动态SQL块不能使用分号结束(;)
  execute immediate 'select count(*) from emp;' --此处多出了分号,应该去掉
 
4、动态PL/SQL块不能使用正斜杠来结束块,但是块结尾处必须要使用分号(;)
SQL> declare
  2 plsql_block varchar2(300);
  3 begin
  4 plsql_block := 'Declare ' ||
  5 ' v_date date; ' ||
  6 ' begin ' ||
  7 ' select sysdate into v_date from dual; ' ||
  8 ' dbms_output.put_line(to_char(v_date,''yyyy-mm-dd'')); ' ||
  9 ' end;
 10 /'; --此处多出了/,应该将其去掉
 11 execute immediate plsql_block;
 12* end;
4、空值传递的问题
下面的示例中对表tb_emp更新,并将空值更新到sal列,直接使用USING NULL收到错误提示。
  execute immediate sql_stat using null,v_empno;
正确的处理方法
    v_sal tb2.sal%type; --声明一个新变量,但不赋值
    execute immediate sql_stat using v_sal,v_empno;
5、日期和字符型必须要使用引号来处理
DECLARE
  sql_stat VARCHAR2(100);
  v_date DATE :=TO_DATE('2013-11-21','yyyy-mm-dd');
  v_empno NUMBER :=7900;
  v_ename emp.ename%TYPE;
  v_sal emp.sal%TYPE;
BEGIN
  sql_stat := 'SELECT ename,sal FROM emp WHERE hiredate=:v_date';
  EXECUTE IMMEDIATE sql_stat
  INTO v_ename,v_sal
  USING v_date;
  DBMS_OUTPUT.PUT_LINE('Employee Name '||v_ename||', sal is '||v_sal);
END;
6、单行SELECT 查询不能使用RETURNING INTO返回
下面的示例中,使用了动态的单行SELECT查询,并且使用了RETURNING子句来返回值。事实上,RETURNING coloumn_name INTO 子句仅仅支持对DML结果集的返回,因此,收到了错误提示。
SQL>declare
v_empno emp.empno%type := &empno;
 v_ename emp.ename%type;
begin
 execute immediate 'select ename from emp where empno = :eno' into v_ename using v_empno;
 dbms_output.put_line('Employee name: ' || v_ename);
end;
第十章 PL/SQL---------游标
游标的使用
    在 PL/SQL 程序中,对于处理多行记录的事务经常使用游标来实现。
4.1 游标概念
对于不同的SQL语句,游标的使用情况不同:
SQL语句
游标
非查询语句
隐式的
结果是单行的查询语句
隐式的或显示的
结果是多行的查询语句
显示的
游标名%属性名
显式游标的名字右用户定义,隐式游标名为SQL
隐式游标只是一个状态
4.1.1 处理显式游标
 
1. 显式游标处理
语法格式:
CURSOR cursor_name is select * from emp;
OPEN cursor_name;
FETCH cursor_name INTO variables_list;
CLOSE cursor_name;
例1:
DECLARE
  v_deptno NUMBER:=&inputno;
  v_row emp1%ROWTYPE;
  CURSOR v_cursor IS SELECT * FROM emp1 WHERE deptno=v_deptno;
BEGIN
  --打开
  OPEN v_cursor;
  --提取
  LOOP
    FETCH v_cursor INTO v_row;--先提取
    EXIT WHEN v_cursor%NOTFOUND;
    dbms_output.put_line('Employee Name: ' || v_row.ename || ' ,Salary: ' || v_row.sal);
  END LOOP;
  --关闭
  CLOSE v_cursor;
END;
显式游标处理需四个 PL/SQL步骤:
l 定义/声明游标:就是定义一个游标名,以及与其相对应的SELECT 语句。
格式:
 
    CURSOR cursor_name[(parameter[, parameter]…)]
           
           [RETURN datatype]
    IS
        select_statement;
        select_statement;
 
游标参数只能为输入参数,其格式为:
 
parameter_name [IN] datatype [{:= | DEFAULT} expression]
在指定数据类型时,不能使用长度约束。如NUMBER(4),CHAR(10) 等都是错误的。
[RETURN datatype]是可选的,表示游标返回数据的数据。如果选择,则应该严格与select_statement中的选择列表在次序和数据类型上匹配。一般是记录数据类型或带“%ROWTYPE”的数据。
 
l 打开游标:就是执行游标所对应的SELECT 语句,将其查询结果放入工作区,并且指针指向工作区的首部,标识游标结果集合。如果游标查询语句中带有FOR UPDATE选项,OPEN 语句还将锁定数据库表中游标结果集合对应的数据行。
格式:
 
OPEN cursor_name[([parameter =>] value[, [parameter =>] value]…)];
 
在向游标传递参数时,可以使用与函数参数相同的传值方法,即位置表示法和名称表示法。PL/SQL 程序不能用OPEN 语句重复打开一个游标。
 
l 提取游标数据:就是检索结果集合中的数据行,放入指定的输出变量中。
格式:
 
FETCH cursor_name INTO {variable_list | record_variable };
 
执行FETCH语句时,每次返回一个数据行,然后自动将游标移动指向下一个数据行。当检索到最后一行数据时,如果再次执行FETCH语句,将操作失败,并将游标属性%NOTFOUND置为TRUE。所以每次执行完FETCH语句后,检查游标属性%NOTFOUND就可以判断FETCH语句是否执行成功并返回一个数据行,以便确定是否给对应的变量赋了值。
l 对该记录进行处理;
l 继续处理,直到活动集合中没有记录;
l 关闭游标:当提取和处理完游标结果集合数据后,应及时关闭游标,以释放该游标所占用的系统资源,并使该游标的工作区变成无效,不能再使用FETCH 语句取其中数据。关闭后的游标可以使用OPEN 语句重新打开。
格式:
 
CLOSE cursor_name;
 
     注:定义的游标不能有INTO 子句。
 
例1. 查询前10名员工的信息。
DECLARE
   CURSOR c_cursor
   IS SELECT first_name || last_name, Salary FROM EMPLOYEES WHERE rownum<11;
   v_ename EMPLOYEES.first_name%TYPE;
   v_sal EMPLOYEES.Salary%TYPE;
BEGIN
  OPEN c_cursor;
  FETCH c_cursor INTO v_ename, v_sal;
  WHILE c_cursor%FOUND LOOP
     DBMS_OUTPUT.PUT_LINE(v_ename||'---'||to_char(v_sal) );
     FETCH c_cursor INTO v_ename, v_sal;
  END LOOP;
  CLOSE c_cursor;
END;
 
2.游标属性
 Cursor_name%FOUND 布尔型属性,当最近一次提取游标操作FETCH成功则为 TRUE,否则为FALSE;
 Cursor_name%NOTFOUND 布尔型属性,与%FOUND相反;
 Cursor_name%ISOPEN 布尔型属性,当游标已打开时返回 TRUE;
 Cursor_name%ROWCOUNT 数字型属性,返回已从游标中读取的记录数。
 
例2:没有参数且没有返回值的游标。
DECLARE
   v_f_name employees.first_name%TYPE;
   v_j_id employees.job_id%TYPE;
   
   CURSOR c1 --声明游标,没有参数没有返回值
   IS
      SELECT first_name, job_id FROM employees WHERE department_id = 20;
BEGIN
   OPEN c1; --打开游标
   LOOP
      FETCH c1 INTO v_f_name, v_j_id; --提取游标
      IF c1%FOUND THEN
         DBMS_OUTPUT.PUT_LINE(v_f_name||'的岗位是'||v_j_id);
      ELSE
         DBMS_OUTPUT.PUT_LINE('已经处理完结果集了');
         EXIT;
      END IF;
   END LOOP;
   CLOSE c1; --关闭游标
END;
 
例3:有参数且没有返回值的游标。
DECLARE
   v_f_name employees.first_name%TYPE;
   v_h_date employees.hire_date%TYPE;
   
   CURSOR c2(dept_id NUMBER, j_id VARCHAR2) --声明游标,有参数没有返回值
   IS
      SELECT first_name, hire_date FROM employees WHERE department_id = dept_id AND job_id = j_id;
BEGIN
   OPEN c2(90, 'AD_VP'); --打开游标,传递参数值
   LOOP
      FETCH c2 INTO v_f_name, v_h_date; --提取游标
      IF c2%FOUND THEN
         DBMS_OUTPUT.PUT_LINE(v_f_name||'的雇佣日期是'||v_h_date);
      ELSE
         DBMS_OUTPUT.PUT_LINE('已经处理完结果集了');
         EXIT;
      END IF;
   END LOOP;
   CLOSE c2; --关闭游标
END;
例4:有参数且有返回值的游标。
DECLARE
   TYPE emp_record_type IS RECORD(
        f_name employees.first_name%TYPE,
        h_date employees.hire_date%TYPE);
   v_emp_record EMP_RECORD_TYPE;
   v_emp_record EMP_RECORD_TYPE;
   CURSOR c3(dept_id NUMBER, j_id VARCHAR2) --声明游标,有参数有返回值
          RETURN EMP_RECORD_TYPE
   IS
      SELECT first_name, hire_date FROM employees WHERE department_id = dept_id AND job_id = j_id;
BEGIN
   OPEN c3(j_id => 'AD_VP', dept_id => 90); --打开游标,传递参数值
   LOOP
      FETCH c3 INTO v_emp_record; --提取游标
      IF c3%FOUND THEN
         DBMS_OUTPUT.PUT_LINE(v_emp_record.f_name||'的雇佣日期是'||v_emp_record.h_date);
      ELSE
         DBMS_OUTPUT.PUT_LINE('已经处理完结果集了');
         EXIT;
      END IF;
   END LOOP;
   CLOSE c3; --关闭游标
END;
 例5:基于游标定义记录变量。
DECLARE
   CURSOR c4(dept_id NUMBER, j_id VARCHAR2) --声明游标,有参数没有返回值
   IS
      SELECT first_name f_name, hire_date FROM employees WHERE department_id = dept_id AND job_id = j_id;
    --基于游标定义记录变量,比声明记录类型变量要方便,不容易出错
    v_emp_record c4%ROWTYPE;
BEGIN
   OPEN c4(90, 'AD_VP'); --打开游标,传递参数值
   LOOP
      FETCH c4 INTO v_emp_record; --提取游标
      IF c4%FOUND THEN
         DBMS_OUTPUT.PUT_LINE(v_emp_record.f_name||'的雇佣日期是'||v_emp_record.hire_date);
      ELSE
         DBMS_OUTPUT.PUT_LINE('已经处理完结果集了');
         EXIT;
      END IF;
   END LOOP;
   CLOSE c4; --关闭游标
END;
3. 游标的FOR循环
    PL/SQL语言提供了游标FOR循环语句,自动执行游标的OPEN、FETCH、CLOSE语句和循环语句的功能;当进入循环时,游标FOR循环语句自动打开游标,并提取第一行游标数据,当程序处理完当前所提取的数据而进入下一次循环时,游标FOR循环语句自动提取下一行数据供程序处理,当提取完结果集合中的所有数据行后结束循环,并自动关闭游标。
格式:
   FOR index_variable IN cursor_name[(value[, value]…)] LOOP
    -- 游标数据处理代码
   END LOOP;
其中:
index_variable为游标FOR 循环语句隐含声明的索引变量,该变量为记录变量,其结构与游标查询语句返回的结构集合的结构相同。在程序中可以通过引用该索引记录变量元素来读取所提取的游标数据,index_variable中各元素的名称与游标查询语句选择列表中所制定的列名相同。如果在游标查询语句的选择列表中存在计算列,则必须为这些计算列指定别名后才能通过游标FOR 循环语句中的索引变量来访问这些列数据。
注:不要在程序中对游标进行人工操作;不要在程序中定义用于控制FOR循环的记录。
 
例6:当所声明的游标带有参数时,通过游标FOR 循环语句为游标传递参数。
DECLARE
  CURSOR c_cursor(dept_no NUMBER DEFAULT 10)
  IS
  SELECT department_name, location_id FROM departments WHERE department_id <= dept_no;
BEGIN
    DBMS_OUTPUT.PUT_LINE('当dept_no参数值为30:');
    FOR c1_rec IN c_cursor(30) LOOP
   DBMS_OUTPUT.PUT_LINE(c1_rec.department_name||'---'||c1_rec.location_id);
    END LOOP;
    DBMS_OUTPUT.PUT_LINE(CHR(10)||'使用默认的dept_no参数值10:');
    FOR c1_rec IN c_cursor LOOP
   DBMS_OUTPUT.PUT_LINE(c1_rec.department_name||'---'||c1_rec.location_id);
    END LOOP;
END;
 
例7:PL/SQL还允许在游标FOR循环语句中使用子查询来实现游标的功能。
BEGIN
--隐含打开游标
   FOR r IN (SELECT * FROM emp1 WHERE deptno=v_deptno) LOOP
--隐含执行一个FETCH语句
      dbms_output.put_line('Employee Name: ' || r.ename || ' ,Salary: ' || r.sal);
--隐含监测c_sal%NOTFOUND
   END LOOP;
--隐含关闭游标
END;
 
4.1.2 处理隐式游标
对于非查询语句,如修改、删除操作,则由ORACLE 系统自动地为这些操作设置游标并创建其工作区,这些由系统隐含创建的游标称为隐式游标,隐式游标的名字为SQL,这是由ORACLE 系统定义的。对于隐式游标的操作,如定义、打开、取值及关闭操作,都由ORACLE 系统自动地完成,无需用户进行处理。用户只能通过隐式游标的相关属性,来完成相应的操作。在隐式游标的工作区中,所存放的数据是与用户自定义的显示游标无关的、最新处理的一条SQL 语句所包含的数据。
格式调用为: SQL%
 
注:INSERT, UPDATE, DELETE, SELECT(单查询) 语句中不必明确定义游标。
 
隐式游标属性
属性

SELECT
INSERT
UPDATE
DELETE
SQL%ISOPEN
 
FALSE
FALSE
FALSE
FALSE
SQL%FOUND
TRUE
有结果
 
成功
成功
SQL%FOUND
FALSE
没结果
 
失败
失败
SQL%NOTFUOND
TRUE
没结果
 
失败
失败
SQL%NOTFOUND
FALSE
有结果
 
成功
失败
SQL%ROWCOUNT
 
返回行数,只为1
插入的行数
修改的行数
删除的行数
 
例8: 通过隐式游标SQL的%ROWCOUNT属性来了解修改了多少行。
DECLARE
   v_rows NUMBER;
BEGIN
--更新数据
   UPDATE employees SET salary = 30000
   WHERE department_id = 90 AND job_id = 'AD_VP';
--获取默认游标的属性值
   v_rows := SQL%ROWCOUNT;
   DBMS_OUTPUT.PUT_LINE(
   DBMS_OUTPUT.PUT_LINE('更新了'||v_rows||'个雇员的工资');
--回退更新,以便使数据库的数据保持原样
   ROLLBACK;
END;
 
4.1.3 使用游标更新和删除数据
游标修改和删除操作是指在游标定位下,修改或删除表中指定的数据行。这时,要求游标查询语句中必须使用FOR UPDATE选项,以便在打开游标时锁定游标结果集合在表中对应数据行的所有列和部分列。
为了对正在处理(查询)的行不被另外的用户改动,ORACLE 提供一个 FOR UPDATE 子句来对所选择的行进行锁住。该需求迫使ORACLE锁定游标结果集合的行,可以防止其他事务处理更新或删除相同的行,直到您的事务处理提交或回退为止。
语法:
 
SELECT column_list FROM table_list FOR UPDATE [OF column[, column]…] [NOWAIT]
 
如果使用 FOR UPDATE 声明游标,则可在DELETE和UPDATE 语句中使用
WHERE CURRENT OF cursor_name子句,修改或删除游标结果集合当前行对应的数据库表中的数据行。
 
例9:从EMPLOYEES表中查询某部门的员工情况,将其工资最低定为 1500;
DECLARE
    V_deptno employees.department_id
    V_deptno employees.department_id%TYPE :=&p_deptno;
   
  CURSOR emp_cursor
  IS
  SELECT employees.employee_id, employees.salary FROM employees WHERE employees.department_id=v_deptno FOR UPDATE NOWAIT;
BEGIN
    FOR emp_record IN emp_cursor LOOP
    IF emp_record.salary < 1500 THEN
        UPDATE employees SET salary=1500 WHERE CURRENT OF emp_cursor;
    END IF;
    END LOOP;
    COMMIT;
END;
4.2 游标变量
与游标一样,游标变量也是一个指向多行查询结果集合中当前数据行的指针。但与游标不同的是,游标变量是动态的,而游标是静态的。游标只能与指定的查询相连,即固定指向一个查询的内存处理区域,而游标变量则可与不同的查询语句相连,它可以指向不同查询语句的内存处理区域(但不能同时指向多个内存处理区域,在某一时刻只能与一个查询语句相连),只要这些查询语句的返回类型兼容即可。
4.2.1 声明游标变量
游标变量为一个指针,它属于参照类型,所以在声明游标变量类型之前必须先定义游标变量类型。在PL/SQL中,可以在块、子程序和包的声明区域内定义游标变量类型。
语法格式为:
1.定义游标变量
TYPE cursortype IS REF CURSOR;
cursor_variable cursortype;
2.打开游标变量
OPEN cursor_variable FOR dynamic_string
[USING bind_argument[,bind_argument]...]
3.循环提取数据
FETCH cursor_variable INTO {var1[,var2]...| record_variable};
EXIT WHEN cursor_variable%NOTFOUND
4.关闭游标变量
CLOSE cursor_variable;
 
例10:使用游标变量(没有RETURN子句)
DECLARE
--定义一个游标数据类型
   TYPE emp_cursor_type IS REF CURSOR;
--声明一个游标变量
   c1 EMP_CURSOR_TYPE;
--声明两个记录变量
   v_emp_record employees%ROWTYPE;
   v_reg_record regions%ROWTYPE;
BEGIN
   OPEN c1 FOR SELECT * FROM employees WHERE department_id = 20;
   LOOP
      FETCH c1 INTO v_emp_record;
      EXIT WHEN c1%NOTFOUND;
      DBMS_OUTPUT.PUT_LINE(v_emp_record.first_name||'的雇佣日期是'||v_emp_record.hire_date);
   END LOOP;
--将同一个游标变量对应到另一个SELECT语句
   OPEN c1 FOR SELECT * FROM regions WHERE region_id IN(1,2);
   LOOP
      FETCH c1 INTO v_reg_record;
     
      EXIT WHEN c1%NOTFOUND;
      DBMS_OUTPUT.PUT_LINE(v_reg_record.region_id||'表示'||v_reg_record.region_name);
   END LOOP;
   CLOSE c1;
END;
 
例11:使用游标变量(有RETURN子句)
DECLARE
--定义一个与employees表中的这几个列相同的记录数据类型
   TYPE emp_record_type IS RECORD(
        f_name employees.first_name
        f_name employees.first_name%TYPE,
        h_date employees.hire_date
        h_date employees.hire_date%TYPE,
        j_id employees.job_id
        j_id employees.job_id%TYPE);
--声明一个该记录数据类型的记录变量
   v_emp_record EMP_RECORD_TYPE;
--定义一个游标数据类型
   TYPE emp_cursor_type IS REF CURSOR
        RETURN EMP_RECORD_TYPE;
--声明一个游标变量
   c1 EMP_CURSOR_TYPE;
BEGIN
   OPEN c1 FOR SELECT first_name, hire_date, job_id FROM employees WHERE department_id = 20;
   LOOP
      FETCH c1 INTO v_emp_record;
      EXIT WHEN c1%NOTFOUND;
      DBMS_OUTPUT.PUT_LINE('雇员名称:'||v_emp_record.f_name||' 雇佣日期:'||v_emp_record.h_date||' 岗位:'||v_emp_record.j_id);
   END LOOP;
   CLOSE c1;
END;
 
第十一章 视图
视图:是一个封装了各种复杂查询的语句,就称为视图。不存储数据,只存储定义,定义被保存在数据字典中
作用:1、可以保证安全,隐藏一些数据,保证数据不会被误删;
           2、多表连接,可以使复杂的查询易于理解和使用
15.1、创建视图
需要权限才能创建
grant create view to scott;
 CREATE OR REPLACE VIEW 视图名字(字段) AS 子查
 CREATE OR REPLACE VIEW v_表名_业务 AS 查询语句
建立一个只包含 20 部门雇员信息的视图(雇员的编号、姓名、工资)
 CREATE VIEW empv20 (empno,ename,sal) AS SELECT empno,ename,sal FROM emp WHERE deptno=20 ;
 现在直接更新视图里的数据 将 7369 的部门编号修改为 30。此操作在视图中完成。
   update empv20 SET deptno=30 where empno=7369 ; 此时,提示更新完成。
 默认情况下创建的视图,如果更新了,则会自动将此数据从视图中删除,之后会更新原本的数据。
 
在建立视图的时候有两个参数:
 · WITH CHECK OPTION à 保护视图的创建规则
CREATE OR REPLACE VIEW empv20
AS SELECT empno,ename,sal,deptno FROM emp WHERE deptno=20
WITH CHECK OPTION CONSTRAINT empv20_ck;----约束条件
ALTER TABLE emp1 add CONSTRAINT empv20_ck check(约束条件);
 再执行更新操作:
  update empv20 SET deptno=30 where empno=7369 ; à 此处更新的是部门编号,失败
   |- 之前是按照部门编号建立的视图,所以不能修改部门编号
  update empv20 SET ename='tom' where empno=7369 ; à 可以更新,更新的是名字,成功
 · WITH READ ONLY(只读,不可修改),视图最好不要轻易的修改
CREATE OR REPLACE VIEW empv20
AS SELECT empno,ename,sal,deptno FROM emp WHERE deptno=20
WITH READ ONLY;
 现在任意的字段都不可更改,所以现在的视图是只读的。
如果视图的基表有多行查询(比如:group by,distinct)那么该视图也是只读的
 
15.1、查看视图
SELECT * FROM v_emp;
update v_emp SET deptno=20 where empno=7369;
DELETE FROM v_emp WHERE empno=7369;
ROLLBACK;
DROP VIEW v_emp;
在视图终不能被修改删除,1、多表构成的视图;2、group by
资料:
http://database.51cto.com/art/200904/118306.htm
http://blog.csdn.net/fan_xiao_ming/article/details/6174065
第十六章 索引
工作原理:rowid
用执行计划检测索引是否起作用(set autot on exp)
执行计划 cbo(选择)和cro(规则)
   
16.1、索引
索引是一种用于提升查询效率的数据库对象,通过快速定位数据的方法,索引信息与表独立存放,Oracle数据库自动使用和维护索引
索引的存储
       索引和表都是独立存在的。在为索引指定表空间的时候,不要将被索引的表和索引指向同一个表空间,这样可以避免产生 IO 冲突。使 Oracle 能够并行访问存放在不同硬盘中的索引数据和表数据,更好的提高查询速度。
16.2、索引优缺点
建立索引的优点
  1.加快数据的检索速度;
  2.创建唯一性索引,保证数据库表中每一行数据的唯一性;
  3.加速表和表之间的连接;
  4.在使用分组和排序子句进行数据检索时,可以显著减少查询中分组和排序的时间。
索引的缺点
  1.索引需要占物理空间。
  2.当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,降低了数据的维护速度。
16.3、创建索引
创建索引的方式
1、自动创建:在定义主键或唯一键约束时系统会自动在相应的字段上创建唯一性索引
2、手动创建:用户可以在其他列上创建非唯一索引,以加速查询。
创建索引:创建索引一般有以下两个目的:维护被索引列的唯一性和提供快速访问表中数据的策略。
--在 select 操作占大部分的表上创建索引;
--在 where 子句中出现最频繁的列上创建索引;
--在选择性高的列上创建索引(补充索引选择性,最高是 1,eg:primary key)
--复合索引的主列应该是最有选择性的和 where 限定条件最常用的列,并以此类推第二列……。
--小于 5M 的表,最好不要使用索引来查询,表越小,越适合用全表扫描。
Create [UNIQUE|BITMAP] index
[schema.]index_name on [schema.]table_name(column_name[ASC|DESC],…n,[column_expression])|CLUSTER [schema.]cluster_name
[INITRANS integer]
[MAXTRANS integer]
[PCTFREE integer]
[PCTUESD integer]
[TABLESPACE tablespace_name]
[STORAGE storage_clause]
[NOSORT]
[REVERSE]
UNIQUE 指定索引所基于的列(或多列)值必须唯一。默认的索引是非唯一的。
BITMAP 指定建立位映射索引而不是B*索引。位映射索引保存的行标识符与作为位映射的键值有关。位映射中的每一位都对应于一个可能的行标识符,位设置意味着具有对应行标识符的行包含该键值。
ON table_name 建立基于函数的索引。用table_name的列、常数、SQL函数和自定义函数创建的表达式。指定column_expression,以后用基于函数的索引查询时,必须保证查询该column_expression不为空。
CLUSTER 创建cluster_name簇索引。若表不用schema限制,oracle假设簇包含在你自己的方案中。不能为散列簇创建簇索引。
NOSORT 数据库中的行以升序保存,在创建索引时不必对行排序。若索引列或多列的行不以升序保存,oracle会返回错误。
REVERSE 指定以反序索引块的字节,不包含行标识符。NOSORT不能与REVERSE一起指定。
CREATE INDEX idx_表名_列名 on 表名(列1,列2...)
create index abc on student(sid,sname);
create index abc1 on student(sname,sid);
这两种索引方式是不一样的
索引 abc 对 Select * from student where sid=1; 这样的查询语句更有效索引 abc1 对 Select * from student where sname=?louis?; 这样的查询语句更有效
因此建立索引的时候,字段的组合顺序是非常重要的。一般情况下,需要经常访问的字段放在组合字段的前面
16.4、使用索引的原则
--查询结果是所有数据行的 5%以下时,使用 index 查询效果最好;
--where 条件中经常用到表的多列时,使用复合索引效果会好于几个单列索引。因为当 sql 语句所查询的列,全部都出现在复合索引中时,此时由于 Oracle 只需要查询索引块即可获得所有数据,当然比使用多个单列索引要快得多;
--索引利于 select,但对经常 insert,delte 尤其 update 的表,会降低效率。
eg:试比较下面两条 SQL 语句(emp 表的 deptno 列上建有 ununique index):
语句 A:SELECT dname, deptno FROM dept WHERE deptno NOT IN (SELECT deptno FROM emp);
语句 B:SELECT dname, deptno FROM dept WHERE NOT EXISTS(SELECT deptno FROM emp WHERE dept.deptno = emp.deptno);
这两条查询语句实现的结果是相同的,但是执行语句 A 的时候,ORACLE 会对整个 emp 表进行扫描,没有使用建立在 emp 表上的 deptno 索引,执行语句 B 的时候,由于在子查询中使用了联合查询,ORACLE 只是对 emp 表进行的部分数据扫描,并利用了 deptno 列的索引,所以语句 B 的效率要比语句 A 的效率高。
 
----where 子句中的这个字段,必须是复合索引的第一个字段;
eg:一个索引是按 f1, f2, f3 的次序建立的,若 where 子句是 f2 = : var2, 则因为 f2 不是索引的第 1 个字段,无法使用该索引。
---- where 子句中的这个字段,不应该参与任何形式的计算:任何对列的操作都将导致表扫描,它包括数据库函数、计算表达式等等,查询时要尽可能将操作移至等号右边。 ----应尽量熟悉各种操作符对 Oracle 是否使用索引的影响:以下这些操作会显式
(explicitly)地阻止 Oracle 使用索引: is null ; is not null ; not in; !=; like ; numeric_col+0;date_col+0; char_col||' '; to_char; to_number,to_date 等。
Eg:
Select jobid from mytabs where isReq='0' and to_date (updatedate) >= to_Date ( '2001-7-18',
'YYYY-MM-DD');--updatedate 列的索引也不会生效。
在正确使用索引的前提下,索引可以提高检索相应的表的速度。当用户考虑在表中使用索引时,应遵循下列一些基本原则。
(1)在表中插入数据后创建索引。在表中插入数据后,创建索引效率将更高。如果在装载数据之前创建索引,那么插入每行时oracle都必须更改索引。
(2)索引正确的表和列。如果经常检索包含大量数据的表中小于15%的行,就需要创建索引。为了改善多个表的相互关系,常常使用索引列进行关系连接。
(3)主键和唯一关键字所在的列自动具有索引,但应该在与之关联的表中的外部关键字所在的列上创建索引。
(4)合理安排索引列。在create index 语句中,列的排序会影响查询的性能,通常将最常用的列放在前面。创建一个索引来提高多列的查询效率时,应该清楚地了解这个多列的索引对什么列的存取有效,对什么列的存取无效。
(5)限制表中索引的数量。尽管表可以有任意数量的索引,可是索引越多,在修改表中的数据时对索引做出相应更改的工作量也越大,效率也就越低。同样,目前不用的索引应该及时删除。
(6)指定索引数据块空间的使用。创建索引时,索引的数据块是用表中现存的值填充的,直到达到PCTFREE为止。如果打算将许多行插入到被索引的表中,PCTFREE就应设置得大一点,不能给索引指定PCTUSED。
(7)根据索引大小设置存储参数。创建索引之前应先估计索引的大小,以便更好地促进规划和管理磁盘空间。单个索引项的最大值大约是数据块大小的一半。
16.6、删除索引
 drop index PK_DEPT1;
16.7、索引类型
B树索引 B-tree indexes;
B树索引又可分为以下子类:
索引组织表Index-organized tables;
反转索引Reverse key indexes;
降序索引Descending indexes;
B树聚簇索引B-tree cluster indexes;
位图和位图联合索引Bitmap and bitmap join indexes;
基于函数的索引Function-based indexes;
应用域索引Application domain indexes;
B-Tree是一个平衡树的结构【注意这里的B表示Balanced平衡的意思,而不是Binary二叉】,B树索引也是Oracle里最为常见的索引类型。B树索引里的数据是已经按照关键字或者是被索引字段事先排好序存放的,默认是升序存放。
对于这幅B树存储结构图作以下几点介绍:
1 、索引高度是指从根块到达叶子块时所遍历的数据块的个数,而索引层次=索引高度-1;本图中的索引的高度是3,索引层次等于2;通常,索引的高度是2或者3,即使表中有上百万条记录,也就意味着,从索引中定位一个键字只需要2或3次I/O,索引越高,性能越差;
2、 B树索引包含两种数据块儿:分枝块(Branch Block)和叶子块(Leaf Block);
3 、分枝块里存放指向下级分枝块(索引高度大于2,即有超过两层分枝块的情况)或者直接指向叶子块的指针(索引高度等于2,即层次为1的索引);
4 、叶子块,就是位于B树结构里最底层的数据块。叶子块里存放的是索引条目,即索引关键字和rowid,rowid用来精确定位表里的记录;索引条目都是按照索引关键字+rowid已经排好序存放的;同一个叶子块里的索引条目同时又和左右兄弟条目形成链表,并且是一个双向链表;
5 、B树索引的所有叶子块一定位于同一层上,这是由B树的数据结构定义的。因此,从根块到达任何一个叶子块的遍历代价都是相同的;
B 树索引(B-Tree Index)
创建索引的默认类型,结构是一颗树,采用的是平衡 B 树算法:
l 右子树节点的键值大于等于父节点的键值 l 左子树节点的键值小于等于父节点的键值
位图索引(BitMap Index)
如果表中的某些字段取值范围比较小,比如职员性别、分数列 ABC 级等。只有两个值。
这样的字段如果建 B 树索引没有意义,不能提高检索速度。这时我们推荐用位图索引
Create BitMap Index student on(sex);
索引按功能和索引对象分还有以下类型。
    (1)唯一索引意味着不会有两行记录相同的索引键值。唯一索引表中的记录没有RowID,不能再对其建立其他索引。在oracle10g中,要建立唯一索引,必须在表中设置主关键字,建立了唯一索引的表只按照该唯一索引结构排序。
    (2)非唯一索引不对索引列的值进行唯一性限制。
    (3)分区索引是指索引可以分散地存在于多个不同的表空间中,其优点是可以提高数据查询的效率。
    (4)未排序索引也称为正向索引。Oracle10g数据库中的行是按升序排序的,创建索引时不必指定对其排序而使用默认的顺序。
    (5)逆序索引也称反向索引。该索引同样保持列按顺序排列,但是颠倒已索引的每列的字节。
    按照索引所包含的列数可以把索引分为单列索引和复合索引。索引列只有一列的索引为单列索引,对多列同时索引称为复合索引。
16.8、管理索引
1)先插入数据后创建索引
向表中插入大量数据之前最好不要先创建索引,因为如果先建立索引。那么在插入每行数据的时候都要更改索引。这样会大大降低插入数据的速度。
2)设置合理的索引列顺序
3)限制每个表索引的数量
4)删除不必要的索引
5)为每个索引指定表空间
6)经常做 insert,delete 尤其是 update 的表最好定期 exp/imp 表数据,整理数据,降低碎片(缺点:要停应用,以保持数据一致性,不实用);
     有索引的最好定期 rebuild 索引(rebuild期间只允许表的 select 操作,可在数据库较空闲时间提交),以降低索引碎片,提高效率
 
16.8、索引问题
1.一个表的查询语句可以同时用到两个索引。
 
2.索引是以独立于表存在的一种数据库对象,它是对基表的一种排序(默认是 B 树索引就是二叉树的排序方式),比如:
3.这样的查询效率,肯定是大于没有索引情况的全表扫描(table access full),但是有两个问题。
    问题一:建立索引将占用额外的数据库空间,更重要的是增删改操作的时候,索引的排序也必须改变,加大的维护的成本 问题二:如果经常查询 x=?和 y=?,那推荐使用组合 index(x,y),这种情况下组合索引的效率是远高于两个单独的索引的。
同时在用组合索引的时候,大家一定要注意一个细节:建立组合索引 index(x,y,z)的时候,那在查询条件中出现 x,xy,xyz,yzx 都是可以用到该组合索引,但是 y,yz,z 是不能用到该索引的。
第十三章 序列、同义词
13.1、 创建序列(sequence)
CREATE SEQUENCE seq
  INCREMENT BY 2--增量
  START WITH 2--起始值 不能小于min
  MAXVALUE 10--最大值
  MINVALUE 1--最小值
  CYCLE--/NOCYCLE 序列号是否可循环(到了maxvalue在从min开始)
  CACHE 5--/NOCACHE 缓存下一个值,必须满足大于1,小于等于(MAXVALUE-MINVALUE)/INCREMENT
  NOORDER--/NOORDER 序列号是否顺序产生
13.2、 属性 NextVal,CurrVal
--当前值 -----currval
SELECT seq.currval FROM dual;
--下一个值------nextval
SELECT seq.nextval FROM dual;
(必须先有 nextval,才能有 currval)
--在向表中插入数据时使用
INSERT INTO emp1(empno) VALUES(seq.nextval);
 使用 cache 或许会跳号, 比如数据库突然不正常 down 掉
(shutdown abort),cache中的sequence就会丢失. 所以可以在create sequence的时候用nocache防止这种情况
13.3、 修改
不能改变当前值,但是可以改变增量
ALTER SEQUENCE seq INCREMENT BY 3;
ALTER SEQUENCE seq CACHE 3;
13.4、 删除
 DROP SEQUENCE seq;
13.5、 同义词 (synonym)
Select * from dual;
为什么?因为同义词的存在
Dual 其实是 sys 用户下的一张表
select table_name from user_tables where lower(table_name) = 'dual';
1、概念
同义词是数据库方案对象的一个别名,经常用于简化对象访问和提高对象访问的安全性。在使用同义词时,Oracle数据库将它翻译成对应方案对象的名字。与视图类似,同义词并不占用实际存储空间,只有在数据字典中保存了同义词的定义。在Oracle数据库中的大部分数据库对象,如表、视图、同义词、序列、存储过程、包等等,数据库管理员都可以根据实际情况为他们定义同义词。
同义词,顾名思义就是两个词的意思一样,可以互相替换.
2、作用:
1) 多用户协同开发中,可以屏蔽对象的名字及其持有者。如果没有同义词,当操作其他用户的表时,必须通过user名.object名的形式,采用了Oracle同义词之后就可以隐蔽掉user名,当然这里要注意的是:public同义词只是为数据库对象定义了一个公共的别名,其他用户能否通过这个别名访问这个数据库对象,还要看是否已经为这个用户授权。
2) 简化sql语句。上面的一条其实就是一种简化sql的体现,同时如果自己建的表的名字很长,可以为这个表创建一个Oracle同义词来简化sql开发。
3)为分布式数据库的远程对象提供位置透明性。
4)Oracle同义词在数据库链接中的作用
数据库链接是一个命名的对象,说明一个数据库到另一个数据库的路径,通过其可以实现不同数据库之间的通信。
Create database link 数据库链名 connect to user名 identified by 口令 using ‘Oracle连接串’;
访问对象要通过 object名@数据库链名。同义词在数据库链中的作用就是提供位置透明性。
3、分类:
Create synonym dept for soctt.dept;(这样创建的同义词是私有的,只有创建者才能用)
Drop synonym dept;
Create public synonym dept for soctt.dept;(这样创建的同义词才是公有的)
Drop public synonym dept;
4、权限管理
与同义词相关的权限有CREATE SYNONYM、CREATE ANY SYNONYM、CREATE PUBLIC SYNONYM权限。
1:用户在自己的模式下创建私有同义词,这个用户必须拥有CREATE SYNONYM权限,否则不能创建私有同义词。
2:如果需要在其它模式下创建同义词,则必须具有CREATE ANY SYNONYM的权限。
3:创建公有同义词则需要CREATE PUBLIC SYNONYM系统权限。
5、查看同义词
SQL> SELECT * FROM DBA_SYNONYMS WHERE SYNONYM_NAME IN ( 'SYSN_TEST','PUBLIC_TEST');
OWNER SYNONYM_NAME TABLE_OWNER TABLE_NAME DB_LINK
------------------------------ ------------------------------
PUBLIC PUBLIC_TEST ETL TEST
ETL SYSN_TEST ETL TEST
SQL> SELECT * FROM USER_SYNONYMS
6、使用同义词
SELECT * FROM SYSN_TEST;
使用同义词可以保证当数据库的位置或对象名称发生改变时,应用程序的代码保持稳定不变,仅需要改变同义词;
当使用一个没有指定schema的同义词是,首先在用户自己的schema中寻找,然后再公共同义词中寻找
7、删除同义词
DROP [ PUBLIC ] SYNONYM [ schema. ] 同义词名称 [ FORCE ];
DROP SYNONYM SYSN_TEST;
DROP PUBLIC SYNONYM PUBLIC_TEST;--当同义词的原对象被删除是,同义词并不会被删除
8、编译同义词
ALTER SYNONYM T COMPILE; --当同义词的原对象被重新建立时,同义词需要重新编译
对原对象进行DDL操作后,同义词的状态会变成INVALID;当再次引用这个同义词时,同义词会自动编译,状态会变成VALID,无需人工干预,当然前提是不改变原对象的名称
问题锦集
1:公用同义词与私有同义词能否同名呢?如果可以,访问同义词时,是共有同义词还是私有同义词优先?
可以,如果存在公用同义词和私有同义词同名的情况,在访问同义词是,访问的是私有同义词的指向的对象。
2:为啥OE用户创建的公用同义词,HR用户不能访问呢?
因为HR没有访问OE模式下对象的权限,如果OE模式给HR用户赋予了SELECT对象等权限,那么HR用户即可访问。
3:对象、私有同义词、公共同义词是否可以存在三者同名的情况?
存在同名对象和公共同义词时,数据库优先选择对象作为目标,存在同名私有对象和公共对象时,数据库优先选择私有同义词作为目标
第十四章 函数
in 只读
out 只写
in out 可读写
 函数就是一个有返回值的过程。
定义一个函数:此函数可以根据雇员的编号查询出雇员的年薪
CREATE OR REPLACE FUNCTION myfun(eno emp.empno%TYPE)
RETURN NUMBER
AS
 rsal NUMBER ;
BEGIN
 SELECT (sal+nvl(comm,0))*12 INTO rsal FROM emp WHERE empno=eno ;
RETURN rsal ;
END ;
/
直接写 SQL 语句,调用此函数:
SELECT myfun(7369) FROM dual ;
第十五章 触发器
15.1分类:
DML触发器-----------基于表的(insert、alter、update)
替代触发器-----------基于VIEW的
系统触发器-----------基于系统的
好处:自动调用、记录日志、保证数据安全、用数据库触发器可以保证数据的一致性和完整性。
语法:
CREATE [OR REPLACE] TRIGGER trigger_name
{BEFORE | AFTER }
{INSERT | DELETE | UPDATE [OF column [, column …]]}
[OR {INSERT | DELETE | UPDATE [OF column [, column …]]}...]
ON [schema.]table_name | [schema.]view_name
[REFERENCING {OLD [AS] old | NEW [AS] new| PARENT as parent}]
[FOR EACH ROW ]
[WHEN condition]
PL/SQL_BLOCK | CALL procedure_name;
       
       BEFORE 和AFTER指出触发器的触发时序分别为前触发和后触发方式,前触发是在执行触发事件之前触发当前所创建的触发器,后触发是在执行触发事件之后触发当前所创建的触发器。
       FOR EACH ROW选项说明触发器为行触发器。行触发器和语句触发器的区别表现在:行触发器要求当一个DML语句操走影响数据库中的多行数据时,对于其中的每个数据行,只要它们符合触发约束条件,均激活一次触发器;而语句触发器将整个语句操作作为触发事件,当它符合约束条件时,激活一次触发器。当省略FOR EACH ROW 选项时,BEFORE 和AFTER 触发器为语句触发器,而INSTEAD OF 触发器则只能为行触发器。
       REFERENCING 子句说明相关名称,在行触发器的PL/SQL块和WHEN 子句中可以使用相关名称参照当前的新、旧列值,默认的相关名称分别为OLD和NEW。触发器的PL/SQL块中应用相关名称时,必须在它们之前加冒号(:),但在WHEN子句中则不能加冒号。
      WHEN 子句说明触发约束条件。Condition 为一个逻辑表达时,其中必须包含相关名称,而不能包含查询语句,也不能调用PL/SQL 函数。WHEN 子句指定的触发约束条件只能用在BEFORE 和AFTER行触发器中,不能用在INSTEAD OF 行触发器和其它类型的触发器中。
15.2、 触发器触发次序
1. 执行 BEFORE语句级触发器;
2. 对与受语句影响的每一行:
l 执行 BEFORE行级触发器
l 执行 DML语句
l 执行 AFTER行级触发器
3. 执行 AFTER语句级触发器
15.3、语句触发器
after 语句触发器
Before 语句触发器
例如:禁止工作人员在休息日改变雇员信息
create or replace trigger tr_src_emp
before insert or update or delete
on emp
begin
if to_char(sysdate,'DY','nls_date_language=AMERICAN') in( 'SAT','SUN') then
raise_application_error(-20001,'can?t modify user information in weekend');
end if;
end;
/
 
使用条件谓语---------inserting、updating、deleting
 create or replace trigger tr_src_emp
before insert or update or delete
on emp
begin
if to_char(sysdate,'DY') in( '星期六','星期天') then
case
when inserting then
  raise_application_error(-20001,'fail to insert');
when updating then
  raise_application_error(-20001,'fail to update');
 when deleting then
  raise_application_error(-20001,'fail to delete');
end case;
end if;
end;
/
15.4、行触发器
执行 DML 操作时,每作用一行就触发一次触发器。
Bofre 行触发器
例如:确保员工工资不能低于原有工资
Create or replace trigger tr_emp_sal
before update of sal
on emp
for each row
begin
if :new.sal<:old.sal then
 raise_application_error(-20010,'sal should not be less');
end if;
end;
/
after 行触发器
例如:统计员工工资变化
Create table audit_emp_change(
Name varchar2(10),
Oldsal number(6,2),
Newsal number(6,2),
Time date);
Create or replace trigger tr_sal_sal after update of sal on emp for each row declare v_temp int;
begin
select count(*) into v_temp from audit_emp_change where name=:old.ename; if v_temp=0 then
insert into audit_emp_change values(:old.ename,:old.sal,:new.sal,sysdate); else
 update audit_emp_change set oldsal=:old.sal,newsal=:new.sal,time=sysdate where name=:old.ename;
end if; end;
/
限制行触发器
Create or replace trigger tr_sal_sal
after update of sal
on emp
for each row when (old.job=?SALESMAN?)
declare
v_temp int;
begin
select count(*) into v_temp from audit_emp_change where name=:old.ename;
if v_temp=0 then
insert into audit_emp_change values(:old.ename,:old.sal,:new.sal,sysdate);
else
 update audit_emp_change set oldsal=:old.sal,newsal=:new.sal,time=sysdate where name=:old.ename;
end if;
end;
/
注意:
例如:如果要基于 EMP 表建立触发器。那么该触发器的执行代码不能包含对 EMP 表的查询操作编写 DML 触发器的时,触发器代码不能从触发器所对应的基表中读取数据。
Create or replace trigger tr_emp_sal
Before update of sal
on emp
For each row
declare
Maxsal number(6,2);
Begin
If :new.sal>maxsal then Select max(sal) into maxsal from emp;
Raise_application_error(-21000,?error?);
End if;
End;
/
 创建的时候不会报错。但是一旦执行就报错了
update emp set sal=sal*1.1 where deptno=30
DML触发器的限制
l CREATE TRIGGER语句文本的字符长度不能超过32KB;
l 触发器体内的SELECT 语句只能为SELECT … INTO …结构,或者为定义游标所使用的SELECT语句。
l 触发器中不能使用数据库事务控制语句 COMMIT; ROLLBACK, SVAEPOINT 语句;
l 由触发器所调用的过程或函数也不能使用数据库事务控制语句;
l 触发器中不能使用LONG, LONG RAW 类型;
l 触发器内可以参照LOB 类型列的列值,但不能通过 :NEW 修改LOB列中的数据;
 
 :NEW 修饰符访问操作完成后列的值
 :OLD 修饰符访问操作完成前列的值
特性
INSERT
UPDATE
DELETE
OLD
NULL
实际值
实际值
NEW
实际值
实际值
NULL
 
15.4 替代触发器
语法:
CREATE [OR REPLACE] TRIGGER trigger_name
INSTEAD OF
{INSERT | DELETE | UPDATE [OF column [, column …]]}
[OR {INSERT | DELETE | UPDATE [OF column [, column …]]}...]
ON [schema.] view_name --只能定义在视图上
[REFERENCING {OLD [AS] old | NEW [AS] new| PARENT as parent}]
[FOR EACH ROW ] --因为INSTEAD OF触发器只能在行级上触发,所以没有必要指定
[WHEN condition]
PL/SQL_block | CALL procedure_name;
例2:创建复杂视图,针对INSERT操作创建INSTEAD OF触发器,向复杂视图插入数据。
l 创建视图:
CREATE OR REPLACE FORCE VIEW "HR"."V_REG_COU" ("R_ID", "R_NAME", "C_ID", "C_NAME")
AS
 SELECT r.region_id,
    r.region_name,
    c.country_id,
    c.country_name
 FROM regions r,
    countries c
 WHERE r.region_id = c.region_id;
 
l 创建触发器:
CREATE OR REPLACE TRIGGER "HR"."TR_I_O_REG_COU"
INSTEAD OF INSERT
ON v_reg_cou
FOR EACH ROW
DECLARE
v_count NUMBER;
BEGIN
 SELECT COUNT(*) INTO v_count FROM regions WHERE region_id = :new.r_id;
 IF v_count = 0 THEN
    INSERT INTO regions
      (region_id, region_name
      ) VALUES
      (:new.r_id, :new.r_name
      );
 END IF;
 SELECT COUNT(*) INTO v_count FROM countries WHERE country_id = :new.c_id;
 IF v_count = 0 THEN
    INSERT
    INTO countries
      (
        country_id,
        country_name,
        region_id
      )
      VALUES
      (
        :new.c_id,
        :new.c_name,
        :new.r_id
      );
 END IF;
END;
 
创建INSTEAD OF触发器需要注意以下几点:
l 只能被创建在视图上,并且该视图没有指定WITH CHECK OPTION选项。
l 不能指定BEFORE 或 AFTER选项。
l FOR EACH ROW子可是可选的,即INSTEAD OF触发器只能在行级上触发、或只能是行级触发器,没有必要指定。
l 没有必要在针对一个表的视图上创建INSTEAD OF触发器,只要创建DML触发器就可以了。
 
15.5、系统事件触发器
语法:
CREATE OR REPLACE TRIGGER [sachema.]trigger_name
{BEFORE
{BEFORE|AFTER}
{ddl_event_list
{ddl_event_list | database_event_list}
ON { DATABASE | [schema.]SCHEMA }
[WHEN condition]
PL/SQL_block | CALL procedure_name;
其中: ddl_event_list:一个或多个DDL 事件,事件间用 OR 分开;
         database_event_list:一个或多个数据库事件,事件间用 OR 分开;
下面给出系统触发器的种类和事件出现的时机(前或后):
事件
允许的时机
说明
STARTUP
AFTER
启动数据库实例之后触发
SHUTDOWN
BEFORE
关闭数据库实例之前触发(非正常关闭不触发)
SERVERERROR
AFTER
数据库服务器发生错误之后触发
LOGON
AFTER
成功登录连接到数据库后触发
LOGOFF
BEFORE
开始断开数据库连接之前触发
CREATE
BEFORE,AFTER
在执行CREATE语句创建数据库对象之前、之后触发
DROP
BEFORE,AFTER
在执行DROP语句删除数据库对象之前、之后触发
ALTER
BEFORE,AFTER
在执行ALTER语句更新数据库对象之前、之后触发
DDL
BEFORE,AFTER
在执行大多数DDL语句之前、之后触发
GRANT
BEFORE,AFTER
执行GRANT语句授予权限之前、之后触发
REVOKE
BEFORE,AFTER
执行REVOKE语句收权限之前、之后触犯发
RENAME
BEFORE,AFTER
执行RENAME语句更改数据库对象名称之前、之后触犯发
AUDIT / NOAUDIT
BEFORE,AFTER
执行AUDIT或NOAUDIT进行审计或停止审计之前、之后触发
/*create or replace trigger tr_emp1_1
  --before update on emp1
  after update on emp1
  for each row
declare
  -- local variables here
begin
  if :new.sal<:old.sal then
    Raise_application_error(-20000, ':new.sal>:old.sal');
  end if;
end tr;*/
/*create or replace trigger tr_emp1_2
   after delete on emp1
   --before delete on emp1
   for each row
begin
  Raise_application_error(-20001, '不能删');
end;*/
create or replace trigger tr_emp1_3
after delete or update or insert on emp1
for each ROW
begin
  if deleting then
    if :new.sal>0 then
       Raise_application_error(-20000, 'deleting');
    end IF;
  /*elsif updating then
    if :new.sal<:old.sal then
       Raise_application_error(-20001, 'updating');
    end if;
  else
    if :new.sal<:old.sal then
       Raise_application_error(-20002, 'inserting');
    end if;*/
  end if;
end;
资料:
http://www.cnblogs.com/huyong/archive/2011/04/27/2030466.html
第十六章 存储过程
16.1、存储过程
CREATE OR REPLACE PROCEDURE procedure_name AS PL/SQL块
现在定义一个简单的过程,就是打印一个数字
CREATE OR REPLACE PROCEDURE myproc AS
 i NUMBER ;
BEGIN
 i := 100 ;
 DBMS_OUTPUT.put_line('i = '||i) ;
END ;
/
执行过程: exec 过程名字---------set serveroutput on
下面编写一个过程,要求,可以传入部门的编号,部门的名称,部门的位置,之后调用此过程就可以完成部门的增加操作。
CREATE OR REPLACE PROCEDURE myproc(dno dept.deptno%TYPE,
  name dept.dname%TYPE,
  dl dept.loc%TYPE)
AS
cou NUMBER ;
BEGIN
 -- 判断插入的部门编号是否存在,如果存在则不能插入
 SELECT COUNT(deptno) INTO cou FROM dept WHERE deptno=dno ;
 IF cou=0 THEN
  -- 可以增加新的部门
INSERT INTO dept(deptno,dname,loc) VALUES(dno,name,dl) ; DBMS_OUTPUT.put_line('部门插入成功!') ;
ELSE
  DBMS_OUTPUT.put_line('部门已存在,无法插入!') ;
 END IF ;
END ;
/
16.2 过程的参数类型:
? IN:值传递,默认的-----只读
? IN OUT:带值进,带值出---可读写
? OUT:不带值进,带值出----只写
IN OUT 类型:
CREATE OR REPLACE PROCEDURE myproc(dno IN OUT dept.deptno%TYPE,
name dept.dname%TYPE,
dl dept.loc%TYPE) AS
 cou NUMBER ;
BEGIN
 -- 判断插入的部门编号是否存在,如果存在则不能插入
 SELECT COUNT(deptno) INTO cou FROM dept WHERE deptno=dno ;
 IF cou=0 THEN
  -- 可以增加新的部门
  INSERT INTO dept(deptno,dname,loc) VALUES(dno,name,dl) ;
  DBMS_OUTPUT.put_line('部门插入成功!') ;
  -- 修改 dno 的值
  dno := 1 ;
 ELSE
  DBMS_OUTPUT.put_line('部门已存在,无法插入!') ; dno := -1 ;
 END IF ;
END ;
/
编写 PL/SQL 块验证过程:
DECLARE
 deptno dept.deptno%TYPE ; BEGIN
 deptno := 12 ;
 myproc(deptno,'开发','南京') ;
 DBMS_OUTPUT.put_line(deptno) ;
END ;
/
OUT 类型 不带任何值进,只把值带出来。
CREATE OR REPLACE PROCEDURE myproc(dno OUT dept.deptno%TYPE)
AS
 I number
BEGIN
  I:= dno;
END ;
/
执行上面的存储过程
DECLARE
 deptno dept.deptno%TYPE ;
BEGIN
deptno :=myproc(deptno) ;
 DBMS_OUTPUT.put_line(deptno) ;
END ;
/
第十七章 包
17.1 定义
包------规范和主体
包就是将一系列的相关联的PLSQL类型、项目和子程序等有计划的组织起来封装在一起
规范(包头)---------一个操作或应用的接口部分
主体----------对包的规范部分进行实现
语法;
包的规范
CREATE OR REPLACE PACKAGE package_name AS|IS
参数、类型(type)、异常(exception)、游标(cursor)、procedure、function
END[package_name];
包的主体
CREATE OR REPLACE PACKAGE BODY package_name AS|IS
参数、类型(type)、异常(exception)、游标(cursor)、procedure、function
END[package_name];
调用:
package_name.type_name;
package_name.item_name;
package_name.call_spec_name;
删除:
drop package package_name;
drop package body package_name;
好处:
1、模块化;-----提高应用程序的交互性
2、信息隐藏
例:
CREATE OR REPLACE PACKAGE DEMO_PKG
IS
  DEPTREC DEPT%ROWTYPE;
 
  --Add dept...
  FUNCTION add_dept(
           dept_no NUMBER,
           dept_name VARCHAR2,
           location VARCHAR2)
  RETURN NUMBER;
 
  --delete dept...
  FUNCTION delete_dept(dept_no NUMBER)
  RETURN NUMBER;
 
  --query dept...
  PROCEDURE query_dept(dept_no IN NUMBER);
END DEMO_PKG;
CREATE OR REPLACE PACKAGE BODY DEMO_PKG
IS
FUNCTION add_dept
(
   dept_no NUMBER,
   dept_name VARCHAR2,
   location VARCHAR2
)
RETURN NUMBER
IS
  empno_remaining EXCEPTION; --自定义异常
  PRAGMA EXCEPTION_INIT(empno_remaining, -1);
   /* -1 是违反唯一约束条件的错误代码 */
BEGIN
  INSERT INTO dept VALUES(dept_no, dept_name, location);
  IF SQL%FOUND THEN
     RETURN 1;
  END IF;
EXCEPTION
     WHEN empno_remaining THEN
        RETURN 0;
     WHEN OTHERS THEN
        RETURN -1;
END add_dept;
FUNCTION delete_dept(dept_no NUMBER)
RETURN NUMBER
IS
BEGIN
  DELETE FROM dept WHERE deptno = dept_no;
  IF SQL%FOUND THEN
    RETURN 1;
  ELSE
    RETURN 0;
   END IF;
EXCEPTION
  WHEN OTHERS THEN
    RETURN -1;
END delete_dept;
PROCEDURE query_dept
(dept_no IN NUMBER)
IS
BEGIN
      SELECT * INTO DeptRec FROM dept WHERE deptno=dept_no;
EXCEPTION
       WHEN NO_DATA_FOUND THEN
          DBMS_OUTPUT.PUT_LINE('温馨提示:数据库中没有编码为'||dept_no||'的部门');
       WHEN TOO_MANY_ROWS THEN
          DBMS_OUTPUT.PUT_LINE('程序运行错误,请使用游标进行操作!');
       WHEN OTHERS THEN
           DBMS_OUTPUT.PUT_LINE(SQLCODE||'----'||SQLERRM);
END query_dept;
BEGIN
    Null;
END DEMO_PKG;


一、数据库连接
    1、JDBC连接
          1、加载JDBC驱动程序;
                    Class.forName("com.mysql.jdbc.Driver");//oracle.jdbc.OracleDriver
2、创建数据库的连接;
Connection conn = DriverManager.getConnection(url,user,password);
3、创建一个Statement对象;
Statement stat = conn.createStatement() ;
//PreparedStatement pstat = conn.prepareStatement(SQL_classification_INSERT);
4、执行SQL语句;
executeQuery 、executeUpdate  和execute
ResultSet rs = stmt.executeQuery("SELECT * FROM ...") ;
//rs=pstat.executeQuery();
5、返回并处理结果;
while(rs.next()){
...
}
6、关闭连接;
rs.close() ;
stat.close();
conn.close();
    2、Hibernate连接
            <session-factory>
  <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
  <property name="connection.url">jdbc:mysql://localhost:3306/eshop_1</property>
  <property name="connection.username">root</property>
  <property name="connection.password">107510</property>
  <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
  <property name="myeclipse.connection.profile">eshop_1</property>
  <property name="show_sql">true</property>
  <property name="format_sql">true</property>
  <mapping class="com.yhtb.entity.TUsers" />
 </session-factory>

Configuration cfg=new Configuration().configure();
          SessionFactory sf=cfg.buildSessionFactory();------------------2级缓存
          Session session=sf.openSession();-------------------------------------1级缓存
          Transaction tx=session.beginTransaction();
          session.save()//增删改查的动作
          tx.commit();
          session.close();
          sf.close();
    3、SSH中数据源连接
             <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
  <property name="url" value="jdbc:oracle:thin:@127.0.0.1:1521:orcl"></property>
  <property name="driverClassName" value="oracle.jdbc.OracleDriver"/>
  <property name="username" value="scott"></property>
  <property name="password" value="tiger"></property>
  <property name="defaultAutoCommit" value="false"></property>
 </bean>
<bean id="sessionFactory"    class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
  <property name="dataSource">
   <ref bean="dataSource" /></property>
  <property name="hibernateProperties">
   <props><prop key="hibernate.dialect">org.hibernate.dialect.OracleDialect</prop>
    <prop key="hibernate.show_sql">true</prop>
    <prop key="hibernate.format_sql">true</prop></props></property>
  <property name="annotatedClasses"><list><value>com.rain.entity.Emp</value></list></property>
         </bean>

二、Oracle
    1、 事务的特性
        原子性、隔离性、持久性、一致性
        savepoint p
       commit
       rollback

    2、 动态SQL
            dml:
  ddl:
  占位符’:‘
declare
  v_no emp1.ename%type:='&请输入号码'; --&变量绑定符
  v_name emp1.ename%type;
  v_job emp1.job%type;
  v_sql long:='select ename,job from emp1 where ename=:xxx';--占位符
begin
   execute immediate v_sql into v_name,v_job using v_no;
   dbms_output.put_line('name= '||v_name||' job='||v_job);
end;
    3、游标
        1、分类:
            显示游标----游标名%属性名
            隐式游标----SQL%
        2、步骤;
      显示游标 语法格式:
CURSOR cursor_name is select * from emp;--声明游标
OPEN cursor_name;--打开游标
FETCH cursor_name INTO variables_list;--提取游标
CLOSE cursor_name;--关闭游标
例1:
DECLARE
  v_deptno NUMBER:=&inputno;
  v_row emp1%ROWTYPE;
  CURSOR v_cursor IS SELECT * FROM emp1 WHERE deptno=v_deptno;--声明游标
BEGIN 
  OPEN v_cursor; --打开
  --提取
  LOOP
    FETCH v_cursor INTO v_row;--先提取
    EXIT WHEN v_cursor%NOTFOUND;
    dbms_output.put_line('Employee Name: ' || v_row.ename || ' ,Salary: ' || v_row.sal);
  END LOOP;
  --关闭
  CLOSE v_cursor;
END;

--隐式游标
自动打开游标
自动关闭游标
通过隐式游标SQL的%ROWCOUNT属性来了解修改了多少行。
DECLARE
   v_rows NUMBER;
BEGIN
--更新数据
   UPDATE employees SET salary = 30000
   WHERE department_id = 90 AND job_id = 'AD_VP';
--获取默认游标的属性值
   v_rows := SQL%ROWCOUNT;
   DBMS_OUTPUT.PUT_LINE('更新了'||v_rows||'个雇员的工资');
--回退更新,以便使数据库的数据保持原样
   ROLLBACK;
END;
        3、应用中---for游标----无需声明、打开、提取、关闭
           BEGIN
--隐含打开游标
   FOR r IN (SELECT * FROM emp1 WHERE deptno=v_deptno) LOOP
--隐含执行一个FETCH语句
      dbms_output.put_line('Employee Name: ' || r.ename || ' ,Salary: ' || r.sal);
--隐含监测c_sal%NOTFOUND
   END LOOP;
--隐含关闭游标
         END;

    4、视图
               1、假表【不存储数据,只存储定义,定义被保存数据字典】
     2、作用:数据安全:(隐藏行或者列,保证数据不会被误删除)
           简化查询
     3、定义格式:
       CREATE OR REPLACE VIEW v_表名_业务
       as
         查询语句
    5、索引
    1、原理:先在索引中根据关键字找到记录的rowid,然后利用rowid在基表中直接定位记录并检索出来,所以速度快
    2、特征:1、索引自动维护
                    2、索引需要占据实际存储空间
                    3、对于表中的主键列,将自动建立唯一索引          
    3、语法:
    create index 索引名
    on
    表名(列1,列2,...)
    drop index 索引名
   4、作用:提高查询速度,通常情况下,索引应该建立在那些经常出现在where子句中的列上

    6、序列
          1、步骤
CREATE SEQUENCE seq
  INCREMENT BY 2--增量
  START WITH 2--起始值 不能小于min
  MAXVALUE 10--最大值
  MINVALUE 1--最小值
  CYCLE--/NOCYCLE 序列号是否可循环(到了maxvalue在从min开始)
  CACHE 5--/NOCACHE 缓存下一个值,必须满足大于1,小于等于(MAXVALUE-MINVALUE)/INCREMENT
  NOORDER--/NOORDER 序列号是否顺序产生
2、 属性   NextVal,CurrVal
          3、作用
                序列通常和触发器一起使用,来自动生成主键

    7、函数
          1、定义:函数就是一个有返回值的过程。
2、步骤:此函数可以根据雇员的编号查询出雇员的年薪
CREATE OR REPLACE FUNCTION myfun(eno emp.empno%TYPE) 
RETURN NUMBER 
AS
 rsal NUMBER ;
BEGIN
 SELECT (sal+nvl(comm,0))*12 INTO rsal FROM emp WHERE empno=eno ;
RETURN rsal ;
END ;
/
3、直接写 SQL 语句,调用此函数:
SELECT myfun(7369) FROM dual ;
v_dfd := EXEC myfun(7369);

    8、触发器
        1、分类;
DML触发器-----------基于表的(insert、alter、update)
替代触发器-----------基于VIEW的---行级
系统触发器-----------基于系统的
      2、创建步骤;
            CREATE [OR REPLACE] TRIGGER trigger_name
{BEFORE | AFTER }
{INSERT | DELETE | UPDATE [OF column [, column …]]}
[OR {INSERT | DELETE | UPDATE [OF column [, column …]]}...]
ON [schema.]table_name | [schema.]view_name 
[REFERENCING {OLD [AS] old | NEW [AS] new| PARENT as parent}]
[FOR EACH ROW ]
[WHEN condition]
PL/SQL_BLOCK | CALL procedure_name;
      3、作用
            自动调用、记录日志、保证数据安全、用数据库触发器可以保证数据的一致性和完整性。
       
         触发器(语句级、行级、谓词、分类、作用)
             基于表的触发器:[delete\update\insert]
create or replace trigger tr_src_emp 
before insert or update or delete 
on emp 
begin
if to_char(sysdate,'DY') in( '星期六','星期天') then 
case 
when inserting then
  raise_application_error(-20001,'fail to insert');  
when updating then
  raise_application_error(-20001,'fail to update'); 
 when deleting then
  raise_application_error(-20001,'fail to delete'); 
end case; 
end if; 
end;
/

    9、存储过程
        1、定义
            CREATE OR REPLACE PROCEDURE procedure_name 
            AS PL/SQL块
        2、参数类型
            •  IN:值传递,默认的-----只读
•  IN OUT:带值进,带值出---可读写
•  OUT:不带值进,带值出----只写
        3、作用
            将通用的执行过程封装起来

    10、包
            1、语法;
包的规范
CREATE OR REPLACE PACKAGE package_name AS|IS
参数、类型(type)、异常(exception)、游标(cursor)、procedure、function
END[package_name];

包的主体
CREATE OR REPLACE PACKAGE BODY package_name AS|IS
参数、类型(type)、异常(exception)、游标(cursor)、procedure、function
END[package_name];

2、调用:
package_name.type_name;
package_name.item_name;
package_name.call_spec_name;
           3、作用
                1、模块化;-----提高应用程序的交互性
                2、信息隐藏

    11、体系结构

三、Struts 2.1
          1、校验框架
2、配置文件
<struts>
  <package name="mypackage" extends="json-default">
    <action name="login" class="UsersAction" method="login">
      <result name="success" >/index.jsp</result>
      <result name="error" >/login.jsp</result>
    </action>
</package>
</struts>

3、国际化
<constant name="struts.i18n.encoding" value="utf-8" />
4、工作原理
1、struts1 工作原理

2、struts2工作原理


6、struts2标签
<%@taglib uri="/struts-tags" prefix="s"%>
7、EL表达式的四个范围
        pageScope、requestScope、sessionScope、appalicationScope
8、客户端校验和服务端校验的优缺点
        客户端校验比服务端校验快,但如果用户禁掉js的话,客户端校验即失效,服务端校验用户不能禁掉
9、struts2的校验框架------服务端校验有基于action的硬编码和基于xml配置文件两种-------------十三中内置校验器
一、基于Action的硬编码实现步骤
1、Action必须extends ActionSpport
2、对某个方法进行校验,需要在Action中添加一个validateXxx().该方法无需返回值,在该方法中加入 addFieldError(" "," ")或者addActionError(" ");
3、在配置文件struts.xml中,必须增加一个<result name="input">/验证页面</result>
4、在错误页面上显示错误信息。
   a、页面必须使用struts标签<s: addFieldError>、<s:addActionError>
    b、修改配置文件中的过滤器
          <filter-mapping>
    <filter-name>struts2</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
二、基于XML配置文件的实现步骤

a、找到对应的DTD文件头
<!DOCTYPE validators PUBLIC
    "-//OpenSymphony Group//XWork Validator 1.0.2//EN"
    "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">
四、Hibernate 3.3

        1、查询方式
            HQL【delete、update、select】
            QBC【条件】
            QBE【FindByExample】
             load/get查询
   native SQL查询
   命名SQL查询

        2、缓存
            一级缓存:session
            二级缓存:sessionFactory

        3、接口
            SessionFactory
            Session
            Transacation
            Query
            Criteroa

        4、对象状态
             瞬时态、持久态、游离态

        5、关联映射
            one-to-many,many-to-one,one-to-one,many-to-many
        6、hibernate常见主键增长方式:
            increment、identity、native、assigned、foreign、sequence
            select max(id) from TABLE
            id+1            n+1
        7、 hibernate的抓取策略:
               select、join、fetch
        8、hibernate的延迟策略:
              proxy
    lazy[关联级别、类级别]
        
五、Spring 3.0

1、Spring是什么?
   Spring是一个容器框架,它管理所有的JavaBean的生命周期
   Spring提供了六大模块:(core、aop、dao、orm、JEE、web)
   Spring提供了强大的解耦,【IOC/DI,aop】

2、IOC
   DI注入的方式:setter、construstor
        3、AOP

切面(aspect):用来切插业务方法的类。
连接点(joinpoint):是切面类和业务类的连接点,其实就是封装了业务方法的一些基本属性,作为通知的参数来解析。
通知(advice):在切面类中,声明对业务方法做额外处理的方法。
切入点(pointcut):业务类中指定的方法,作为切面切入的点。其实就是指定某个方法作为切面切的地方。
目标对象(target object):被代理对象。
AOP代理(aop proxy):代理对象。
AOP通知类型:
前置通知(before advice):在切入点之前执行。
后置通知(after returning advice):在切入点执行完成后,执行通知。
环绕通知(around advice):包围切入点,调用方法前后完成自定义行为。
异常通知(after throwing advice):在切入点抛出异常后,执行通知。
11、AJAX
      1、什么是AJAX
            AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)。
    2、ajax的特点:局部刷新
    3、Ajax所涉及的技术:JavaScript、XML、CSS、DOM(文档对象模型,在内存中以树结构存储的模型)
    4、Ajax的核心类:XMLHttpRequest               
            注意:不同的厂家ActiveXObject(IE5及以下)
    5、Ajax常见的框架:JQuery、DOJO、prototype(原型)、DWR(直接web远程访问)、YUI(雅虎用户界面)、ExtJS
    6、Ajax应用的开发步骤:
//1、创建XMLHttpRequest()对象
   if (window.XMLHttpRequest){// code for IE7+, Firefox, Chrome, Opera, Safari
     xmlhttp=new XMLHttpRequest();
   }else{// code for IE6, IE5
     xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
   }
 //2、处理响应(responseText或responseXML)
   xmlhttp.onreadystatechange=function(){
      if (xmlhttp.readyState==4 && xmlhttp.status==200){
        //局部刷新的代码,通常有以下语句        document.getElementById("data").innerHTML=xmlhttp.responseText;
        //js操作Html
       }
     };
   //3、向服务器发送请求
   xmlhttp.open("GET","/ajax1/index.jsp?t="+Math.random(),true);
   xmlhttp.send();//只有是GET提交时才赋值为NULL

12、JSON
    1、JSON是什么
           a、JavaScript 对象表示法(JavaScript Object Notation)。
          {
"employees": [
{ "firstName":"Bill" , "lastName":"Gates" },
{ "firstName":"George" , "lastName":"Bush" },
{ "firstName":"Thomas" , "lastName":"Carter" }
]
}
          b、JSON 是存储和交换文本信息的语法。类似 XML。
          c、JSON 比 XML 更小、更快,更易解析
    
13、js的对象
     1、内置对象
            String: var s = new String("23213");
            Date:      var d = new Date();
            Math:     Math.random();
            Array:     var a = new Array();
            Object:   var o = new Object();
    2、js的浏览器对象(BOM)
            window: window.alert()、 window.confirm、 window.setTimeout()                                               
            document:document.getElementById()、
                              document.getElementByTagName()
            location:window.location.href
    3、js中的DOM对象
        HTML、BODY、SELECT、INPUT
    4、js的自定义对象
          <script type="text/javascript">
  <!--
方法一:
 //1、定义类
  function person(name,sex){
   this.name=name;
   this.sex=sex;
  }
 //2、实例化
 var p1 = new person("rain","man");

方法二:--------------------JSON
定义并实例化:
var p2 = {"name":"你的","sex":"women"};

var p = [{"name":"张三丰","sex":"男","tel":{"t1":"332","t2":"445"}},{"name":"张无忌","sex":"男 "},{"name":"张翠山","sex":"男 "}];

 //3、显示数据
 alert(p.name);
 alert(p.sex);
 confirm(p.name);

//alert(p[1].name);
 //alert(p[0].sex);
 //confirm(p[2].name);
 alert(p[0].tel.t1);

//将字符串转化成对象-----------JSON
 var pp = '{"name":"张三丰","sex":"男","tel":{"t1":"332","t2":"445"}}';
 alert(eval('('+pp+')').name);

  //-->
  </script>

14、JQuery
        
    1、定义:Jquery是一个丰富的js库    
    2、JQuery对象就是通过Jquery包装DOM对象后产生的对象

<script type="text/javascript" src="jquery-1.11.0.js"></script>
 <script type="text/javascript">
 <!--/*//第一种格式:
  function f1(){
   alert('Hello World!');
  };
  $(document).ready(f1);
 //第二种格式:
  $(document).ready(function(){
   alert('Hello World!');
  });*/
 $(document).ready(function(){
   //$('#111').css('background-color','blue')
   // .css('width','234')
   // .css('height','333')//修改样式
   // .html('<hr/>hello')//修改值
   // .html();//取值
   //$('#111').css({'background-color':'blue','width':'120','height':'120'})//修改样式
   // .text('<hr/>hello');//修改值
   //$('.222,#111').html('<hr/>');
   //$('div:last').html('hehehhe');
   //$('div:first').html('hehehhe');
   //$('#111>p').html('<hr/>');
   //$('#111 p').html('<hr/>');
   //$('#111+.222').html('<hr/>');
   //$('#111 ~ p').html('<hr/>');
   //$('tr:odd').css({'background-color':'blue'});
   //$('tr:even').css('background-color','#eeffee');
   //$('tr:eq(0)').css({'background-color':'blue'});
   //$('tr:gt(1)').css({'background-color':'blue'});
   $('tr:lt(1)').css({'background-color':'blue'});
 });
 //--></script> </head>
 <body>
  <div id="111">sssssssssss
  <p>sfdsf</p>
  </div>
  <p>sfdsf</p>
  <div class="222">sssssssssss</div>
  <div >sssssssssss</div>
  <table border="1"><center>
 <tr><td>1</td><td>1</td></tr>
 <tr><td>22</td><td>22</td></tr>
 <tr><td>333</td><td>333</td></tr>
 <tr><td>4444</td><td>4444</td></tr>
  </table></center></body>

例2:
<script type="text/javascript" src="jquery-1.11.0.js"></script>
   <script type="text/javascript">
    $(function(){
     alert(222);
     $('button').click(function(){
      $('#list').load('index.jsp');
     });
    });
   </script>
  </head>
 
  <body>
    <div id="list"></div>
    <button>获取服务器数据</button>
  </body>
六、SSH
Spring----------3.0
        定义:是一个管理JavaBean生命周期的容器型的轻量型框架,包含六大模块DAO、ORM、Web、Core、JEE、AOP
Hibernate------3.3
        ORM持久型框架---映射---POJO的属性和表中的字段,对象和表,POJO的属性的类型与表中字段的属性的类型
Struts-----------1.3/2.1
        MVC的web轻量型框架

 


VO--------------------值对象
DTO------------------数据传输对象
BO--------------------业务对象
PO---------------------持久化对象
POJO-----------------简单无规则Java对象(JavaBean)
DAO-------------------数据访问对象

七、泛型DAO
        1、设计通用DAO接口 
      public interface IGenericDAO<T,ID extends Serializable>{
         public abstract void save(T entity);
         public abstract void update(T entity);
         public abstract void delete(ID id);
         public abstract T findById(ID id);
         public abstract List<T> findAll();
         public abstract List<T> findByExample(T entity);
         public abstract int count(T entity);
         public abstract pageVO<T> findByPage(T entity,int currentpage,int pageSize);
      }
 
2、设计通用DAO的实现类
     public class GenericDAOImpl<T,ID extends Serializable> extends HibernateDaoSupport implements IGenericDAO<T,ID>{
         protected class<?> clazz;
        //初始化clazz
        public GenericDAOImpl(){
 //1、得到我们的通用范型实现类的子类,例如:得到EmpDAOImpl
     Class<?> cls=getClass();
 //2、得到具体类【EmpDAOImpl】的父类,由于父类是范型类,所以,方法为:
     ParameterizedType ptype=(ParameterizedType)cls.getGenericSuperclass();
 //3、得到具体的参数实际类型
    clazz=(Class<?>)(ptype.getActualTypeArguments()[0]);
        }
 
         public void save(T entity){
             getHibernateTemplate().save(entity);
         }
         public void update(T entity){
             getHibernateTemplate().update(entity);
         }
         public void delete(ID id){
             getHibernateTemplate().delete(id);
         }
         public T findById(ID id){
               return T(getHibernateTemplate().get(clazz,id));
         }
         public List<T> findAll(){
   DetachedCriteria criteria=DetachedCriteria.forClass(entityClass);
  return getHibernateTemplate().findByCriteria(criteria);;
  }
         public List<T> findByExample(T entity){
  return getHibernateTemplate().findByExample(instance);
  }
         public int count(T entity){}
         public pageVO<T> findByPage(T entity,int currentpage,int pageSize){}
     
3、设计每个业务DAO接口,例如IEmpDAO
      public interface IEmpDAO extends IGenericDAO<Emp,Integer>{
          //新增自己DAO的特有方法:例如登录
          Emp login(String account,String password);
      }
4、设计每个业务DAO的实现类,例如EmpDAOImpl
      public class EmpDAOImpl extends GenericDAOImpl<Emp,Integer> implements IEmpDAO{
              public Emp login(String account,String password){
                  return null;
              }
      }
    }

购物车

 

 


链接:
1、JAVA
2、JDBC
3、OA开发
4、Oracle
5、WEB
6、AJAX
7、Hibernate
8、Spring
9、struts1
10、总结

1 0
原创粉丝点击