20200812 java 笔记

第一章
目标:
	A:Java简介
	B:Java环境搭建
	C:第一个应用程序
	D:输入与输出
	E:注释

1、什么是程序?
	我们为了让计算机帮我们完成某一项操作而编写的一系列有序的指令的集合。

2、Java
	它是标准的面向对象的编程语言
	1995年由Sun推出,2009年被甲骨文公司收购
   
   特点:跨平台,一次编写,到处运行,简单但是功能强大,运用广泛。

3、使用记事本开发Java程序的三个步骤:
	A:编写源程序(后缀名.java)
	B:编译源程序(产生.class文件)
		运行Dos窗口,
		操作指令:javac 文件名.java
	C:运行源程序
		Dos操作指令:java 类名

4、Dos命令
	A:进入某一个盘下面的文件夹
	     cd 路径--->回车
	比如:cd F:\TR1706\Java

	B:回到上一级目录
	    cd..--->回车

	C:回到根目录(盘符)
	    cd\--->回车

	D:清除当前屏幕上所有的指令
	    cls--->回车


5、编写第一个程序框架
	public class 类名{
		public static void main(String[] args){
			//指令			
			System.out.println("输出文字");	
	  	}
	}

   说明:A:严格区分大小写(String和System的S要大写)
	 B:所有的标点符号必须是英文半角
	 C:括号和双引号必须是成对的,每一句指令代码要以分号结束。
	 D:代码的缩进

6、Java文件名的命名规范
	A:文件名(类名)采用帕斯卡命名法(每个单词的首字母大写)
	例如:Demo.java		StudentInfo.java

	B:有public的类名必须与文件名相同,必须是字母、下划线开头,后面接字母、下划线和数字。
	(类名就是public class 后面的那个单词)

	C:文件名和类名不能用中文

7、输出语句
	A:System.out.print("输出后不换行");
	B:System.out.println("输出后换行");

8、特殊字符(转义字符)
	\t	退格(退4-8格)
	\n	换行

===============Java 数据类型和变量
1.内存
	程序运行时,临时存储数据的区域,计算机断电数据自动消失,内存中
	最小的存储单位为bit()8个位为一个字节

2.数据类型
	在java中,用来规定存储内容的类型 分为基本数据类型和对象类型

	4种整型,2种浮点型,1种字符型,1种布尔型

	A.整型
		byte 字节型,1个字节
		short 短整型,2个字节
		int   整型,4个字节 java中常用类型
		long	长整形 8个字节

	B.浮点型
		float 单精度 4个字节
		double 双精度 8个字节

	C.字符型(单字符)
		char 字符型 2个字节 char类型只能放一个汉字,并且值需要用
		单引号引起来 例如 char sex='男';

	D.布尔型(判断真假)
	boolean 布尔型,2个字节 值只能是truefalse 在计算机中,是01
		0代表false 1代表true 值不用引号

	E.对象中的特殊类型
	String(字符串类型) 用来存储一串字符,空间大小不限 值用双引号
3.变量
	可变的量,内存中用来存储数据的某一块有名字的空间
	
	使用变量:
	a.声明变量 语法:数据类型 变量名;
	b.变量赋值 语法:变量名=;
	c.调用变量的值 例如:System.out.println(name);
	注意:声明和赋值可以一步到位,直接用 数据类型 变量名=;
4.数据类型转换
	1.自动类型转换(小的类型转大的类型,大小指的是所占内存空间)
	比如:double a =1.5; int b=10; a+b会自动转换double类型

	2.强制类型转换(大的类型转小的类型)
	比如:double a =1.5; int b=10; int c=a+b;会报错
	因为a+b运算中,自动转换为double类型了,要直接存入int是不行的,
	必须要强制转换int c=(int)a+b;

5.扫描仪
	用来从控制台接收用户输入的数据
	步骤:
	1.导包(必须在public class上面定义)
	import java.util.Scanner; 注意分号结束

	2.创建
	Scanner input=new Scanner(System.in);除了input以外,都是固定的

	调用 具体看案例Demo.java

6.变量的命名规范
	1.使用驼峰命名法,第一个单词的首字母小写,后面的单词首字母大写
	2.变量名不能使用java保留字(39个)
	3.变量名不能重复
	4.变量必须声明才能使用
	5.以下划线,字母,$开头,后面接字母,下划线,$,和数字


=====================Java 运算符1
Java运算符

一、概念:
     用于在程序中进行一些数值运算或判断等,会针对一个或一个以上的操作数进行运算

二、分类:
          1、算术运算符:     +-*/%++--
               %:模/取余,小数模大数,结果永远为小数,比如1%5结果为10%5结果为0
               ++:一元运算符,在自身原来的数量上加一,根据操作数的位置不同,结果不同
                     比如:    int i = 5;
                               System.out.print(i++);//i++相当于在调用i的值之后,执行了i=i+1;输出结果为5
                               System.out.print(++i);//输出结果为7
		i++ 先取值 再自增
		++i 先自增 再取值
 	       --: 在自身原来的数量上减一 i----i跟 i++++i 同理 
	算术运算符只能用于相同类型或可兼容类型(比如intdouble就是可兼容的,在运算时,会自动转换为double2.关系运算符 < > <= >= == !=
	关系运算符是用于判断两个操作数之间的关系(也可以叫做关系表达式)
	结果只能boolean类型 true or false
	int a=10 int b=20 boolean c=a<b //结果为true

	关系运算符只能整型,浮点型,字符型
	字符型 char a='a' char A='A' boolean c=a==A;
	//false 因为a--97 A--65
	double类型和float类型在比较时,小数位为0或者5则结果为true45D==45F)
	小数位为其他数字的结果都为false 
	原理:doublefloat进行关系运算时,会将float转为double,在这个转换
	过程中 double的精度要求更高,精度值也会发生改变。

	3.逻辑运算符
	用于连接两个或者两个以上的关系表达式,运算的最终结果也是boolean类型
	true or false

	A. !逻辑非(取反)
	int a =10 int b=20 boolean c =!(a<b) //结果为false
	
	B. && 逻辑与(并且)
	必须两个表达式的结果同时为true,才为true,否则就是false
	int a =10 int b=20 boolean c=a>=10 && a<b //结果为true

	C.|| 逻辑或(或者)
	必须两个表达式的结果同时为false 才为false,有一个结果为true 才为true
	
	注意:在逻辑运算过程中,有一种情况是短路与,短路或,是为了提高运算
	效率 将第一个表达式就已经决定最终结果,那么第二个表达式不再运算

	比如:5<4 && 3==3 第一个结果已经是为false 那么3==3就不会再进行运算
	4<5 || 5>=4 第一个结果已经为true5>=4 的结果也没有意义就不会运算
4.三元(目)运算符
	由一个关系表达式,和两个值组成,语法:表达式?值1:值2
	当表达式的结果为true,三元运算的结果为值1,当false时,结果为值2

	注意 三元运算的最终结果的类型是由值1和值2的类型决定,值1和值2必须
	是同类型的或者能兼容的类型
	比如:int a =5 int b=6

	String c=a<b ? "真""假" 


================Java分支结构==============


一、程序结构
     1、顺序结构
               按照代码的书写顺序依次执行
     2、分支结构
               根据一定的条件选择性执行
     3、循环结构
               根据一定的条件循环反复地执行一段代码

二、分支结构
     1if...          单分支结构(如果...)
          语法:if(关系表达式或布尔类型的值){
                         //当关系表达式结果为true时执行的代码
                    }

          例如:System.out.print("请输入一个成绩:");
                    int a = input.nextInt();
                    if(a >= 90){
                           System.out.println("考试通过,恭喜!");
                    }
          
     2if...else     双分支结构(如果...否则...)
          语法:if(关系表达式或布尔类型的值){
                         //当关系表达式结果为true时执行的代码
                    }else{
                         //上面的条件不满足,结果为false时,执行的代码
                    }
          例如:if(a >= 90){
                           System.out.println("考试通过,恭喜!");
                    }else{
                           System.out.println("考试未通过!");
                    }
     
     3if...else if... else..     多重if结构(如果...否则如果...否则...)
          语法:
                    if(条件1{
                         //条件1结果为true时执行的代码
                    }else if(条件2){
                         //条件1结果为false,并条件2结果为true时,执行的代码
                    }else{
                         //上面的条件不满足时,执行的代码
                    }
     注意:条件1false时,会进入下一个else if的判断,只要有任意一个条件满足,执行完代码后,这个多重if就结束了,或者直到所有的都不满足才会执行最后的else
               else if的顺序可以调换,但是调换后可能会影响最终的判断结果
          

三、String类型的判断
      1==           :只能判断固定值,比如:String a ="A";  "A"==a结果为true
      2equals()     :能判断控制台输入的字符串,比如:
                              String a = input.next();
                              "星期一".equals(a),如果输入的是星期一,结果就为true

四、两数交换
     输入三个整数,按照从小到大的顺序排列输出,代码参照Demo4.java
     

五、嵌套if结构
     在一个if结构中,包含了另一个完整的if结构(可以是单ifif..elseif...else if...)
     语法:
          if(条件1{
               //条件1满足了,再进行判断
               if(条件2{
                    
               }
          }else{
               //条件1不满足时,执行的代码
               if(条件3){

               }
          }

六、Switch选择结构
      1、通过switch关键字后的圆括号中的值,来选择对应的case执行,如果没有对应的case,则执行default。

      语法:
               switch(key){
                    case 常量值1:
                              //代码
                              break;
                    case 常量值2:
                              //代码
                              break;
                    default:
                              //代码
                              break;
               }
     注意:1、key可以是int型、char型、String型(jdk1.7+)、枚举(jdk1.5+),一般情况下,放变量名
               2break用来结束某一个case或者说结束switch结构,break可以省略但是会影响结果
               3case的顺序可以调换,但是case后的常量值不能重复
               4、如果多个case可以共享一段相同的代码,则将几个case连续写,中间不要代码和break,比如:
                      case "1":
  			case "3":
 			 case "5":
  			System.out.println("学习编程");
  			break;
               5、只能进行等值判断,相当于if结构的a==1或者"abc".equals(a)

七、如果做等值判断,是用if结构还是switch结构?
               选switchif结构需要不断的判断,而switch是直接通过key来
		指定case,不需要一层一层的判断,运行速度更快,结构也更加的
		清晰,如果多选择同时执行一样的代码,结构更简单


========================Java循环结构=========================
一、循环结构
     用来控制代码重复执行的一种结构,可以很大程度的减少重复代码,方便修改

二、三种
     1while循环:有入口条件,必须先判断,条件为true执行循环操作,为false则一次都不执行。
          语法:
            while(条件表达式){
                    //循环操作
            }
     
     注意: 任何循环结构都有四个要素:
               1、循环变量
               2、循环条件
               3、循环操作
               4、改变循环变量的值

     2do...while循环:没有入口条件,先执行后判断,最少会执行一次大括号中的循环操作
          语法:do{
                              
                    }while(条件表达式);
          
     3for循环:迭代循环
          语法: for(表达式1;表达式2;表达式3){
                              //循环体
                     }
               A、表达式1 : 定义循环变量
               B、表达式2 : 循环的条件
               C、表达式3 : 改变循环变量的值
               D、循环体

          A-->B-->D-->C(A步骤只执行一次)

          注意:for循环圆括号中的三个表达式,都可省略,但是两个分号不能省


三、breakcontinue的作用
     1break: 中途打断循环,结束整个循环
     2continue:结束本次循环,进入下一次循环

四、补充:扩展运算符
       +=-=*=/=
     
       比如:     int s = 1;
                      s += 6 ;     等价于    s = s + 6;
      
     快捷键:
          注释:选中要注释的内容 -->ctrl+shift+/  -->多行注释(ctrl+shift+\  取消多行注释)
                    ctrl+/     -->单行注释
          复制代码:ctrl+alt    + 上下键
          移动代码:alt + 上下键

     

=====================Java循环结构二

一、不固定次数的循环
     循环结构可以是死循环,通过输入的值来判断是否达到某个条件,来人为结束循环
     比如:
          for (int i = 0; i >= 0; i++) {
            System.out.println("请输入一个成绩:");
            int cj = input.nextInt();
            //通过判断每次输入的考试成绩,来决定是否结束,如果成绩大于等于90分,就break;
            if(cj >= 90){
                System.out.println("考试通过,恭喜");
                break;
            }else{
                System.out.println("考试不通过,请重考!");
            }
        }

二、双重循环
     1、一个循环结构中包含另一个完整的循环结构
     比如:for(){
                    for(){

                    }
               }
               
               while(){
                    for(){

                    }
               }
     注意:1、外层循环的变量与内层循环变量不能重复
               2、外层循环一次,内层循环一周(一周代表内层循环完毕)

	

===============Java 数组
一、数组:
    内存中的某一串连续的空间,用来存储相同类型的数据
二、数组四要素:
    1、数据类型(规定数组中值的类型)
    2、数组名/标识符(类似变量名,数组的名字)
    3、数组的元素(数组里存的值)
    4、数组的下标(从0开始)
三、定义:
    1、声明数组空间(开辟连续空间)
       数据类型 [] 数组名;
       数据类型  数组名[];
    
    2、分配空间
       数组名 = new 数据类型[长度];
    3、给数组的某个格子赋值
       数组名[下标] =;
    4、取值处理
       比如:输出System.out.print(数组名[下标]);
    
    步骤合一:
   	 声明和分配空间同时进行:
         数据类型 [] 数组名 = new 数据类型[长度];
         
        声明、赋值同时进行:
         数据类型 [] 数组名 = {1,2,3..};

    	声明、分配空间、赋值:
         数据类型 [] 数组名 = new 数据类型[]{1,2,3..};

	注意:
   	java.lang.ArrayIndexOutOfBoundsException数组下标越界

四、数组数据处理
    1、输出
       System.out.print(数组名[下标]);
    	
    2、循环输出
       for(int i = 0; i < 数组名.length ; i++){
        System.out.print(数组名[i]);
       }
    3、求总和
       double he = 0;
       for (int i = 0; i < money.length; i++) {
        he = he + money[i];
       }
       求平均
       double avg = he/数组名.length;
    4、求最大值,最小值
       //将第一个格子的值作为比较的参照
       int max=student[0],min=student[0];
       //循环从第二个格子开始
       for (int i = 1; i < student.length; i++) {
       //如果格子的值大于max,
       //就赋值给max,保证max永远是最大的
        if(max < student[i]){
            max = student[i];
        }
        if(min > student[i]){
            min = student[i];
        }
       }
      5、排序
       Arrays.sort(数组名);//从小到大升序排序

五、高级应用
    1、查询(查询某个值是否存在)
       操作:遍历数组,挨个比较
      
       String [] name = new String[]{"张三","李四","文五","赵六","黄土豪"};
       String mz = input.next();
       for (int i = 0; i < name.length; i++) {
        //进行比较
        if(mz.equals(name[i])){
          System.out.println("下标为:"+i);
        }
       }
    2、替换
       操作:先查找,再替换
       for (int i = 0; i < name.length; i++) {
        //进行比较
        if(mz.equals(name[i])){
            //输入一个新的名字
            String newMZ = input.next();
            //替换掉名字
            name[i] = newMZ;
        }
       }
    3、删除
       操作:先查找,再记录下标,从这个下标的位置开始循环到倒数第二个位置,
	循环外将后面的值赋给前面的,最后一个清空。
	请参考案例Demo1 Demo2
   
    4、冒泡排序
       原理:从第一个格子开始,依次和后面的格子进行比较,
	从大到小就判断前面的小于后面的,如果符合条件就进行交换,
	保证循环完第一轮,第一个格子是最大的或最小的,再进入第二轮。
	(所以必须双重循环)
    	int[] arr = new int[]{19,20,5,11,21};
    	for(int i=0;i<arr.length-1;i++){
        for(int j=i+1;j<arr.length;j++){
            if(arr[i] < arr[j]){
                int tmp = arr[i];
                arr[i] = arr[j];
                arr[j] = tmp;
            }
        }
    }
    

	
=======================java 方法
Java方法
一、方法
    概念:就是执行某个操作的最小模块,一个方法只做一件事情
    本质:
         给定一个值(参数)
         经过内部处理(方法体)
         返回一个值(返回值)
	

二、方法结构(必须定义在class)
    public 返回值类型   方法名(参数类型 参数名..{
        //方法体
        return 返回值;
    }
    说明:方法有返回值时,使用return 值,如果无返回值,返回值类型为void
          参数可以是0-n个
          方法名的命名规则与变量名相同

   1、无参无返回值
        public void xxx(){
        }
    调用:类名  对象名 = new 类名();
          对象名.方法名();
    
    
    2、无参有返回值
        public 返回值数据类型 xxx(){
          //必须有return,后面的返回值必须与方法规定的返回值类型匹配
            return 返回值;
        }
    调用:类名  对象名 = new 类名();
          接收类型 变量名  =  对象名.方法名();


   3、有参无返回值
        public void xxxx(参数类型 变量名1,参数类型 变量名2,){
        }
    	调用:类名  对象名 = new 类名();
          对象名.方法名(参数值);
	调用时,圆括号中的参数值,变量名可以与定义方法时的形式参数不同,
	类型要相同,我们称之为“实参”;
	
   4、有参有返回值
        public 返回值数据类型 xxx(参数类型 变量名1){
            return 返回值;
        }
    调用:类名  对象名 = new 类名();
          接收类型 变量名  =  对象名.方法名(参数值);

三、方法作用
    1、能多次调用,减少代码重复
    2、完成一个独立的任务,使得代码更加模块化
    3、方法是一个完整功能的最小结构(一个方法只做一件事)

四、使用方法的分析三要素
    1、能干什么(方法体)
    2、需要什么(方法参数)
    3、能给什么(返回值)

五、成员变量、局部变量
    1、成员变量直接定义在类中,生命周期直到类结束才结束,作用范围是整个类。所有该类中的方法都可以调用,并且修改后都会影响变量的值
    2、局部变量是定义在方法内部或者方法的参数,生命周期只到方法结束,作用范围仅限该方法内部。
       定义在某方法中的某结构中,比如if结构、for循环的大括号中,结束iffor循环,该变量生命周期就也结束了
    3、成员变量有默认值,局部变量没有,所以局部变量使用时必须先赋值。


=====================Java  OOP思想
一、OOP(面向对象,Object Oriented Program)
    三大特征:封装(安全性)、继承(重用性)、多态(扩展性)
二、类和对象
    1、什么是对象
       真实存在的实际事物,具有特征和行为,世界是由对象组成。
    2、什么是类
       说的清的都是类,说不清的也是泪!是抽象的虚拟的,用来描述对象的,
	将具有相同属性和方法的对象归为一类
    明星、车、电脑、空调、手机
三、先有类还是先有对象
    在生活中,是先有对象,再将对象归为一类
    在程序设计时,先要抽象出类,再创建对象
四、对象的特征
    属性:静态的、明显可见
    方法:动态的,是一种行为、操作、功能
五、定义类
    1public class 类名{
        //定义属性
        数据类型  变量名;
        
        //定义方法
        返回值类型  方法名(参数...){
        }
    }
    
    举例:
    public class XueSheng{
        /**
         *学生的名字
        */
        String mz;
        int age;//年龄
        char sex;//性别
        
        public void ziWoJieShao(){
            //输出上面的名字性别年龄
        }
        public void xueXi(){
        }
    }
    
    2、创建对象
    类名  对象名 = new 类名();
    举例:XueSheng  xs = new XueSheng();
    3、给对象赋值:
    //值可以是固定值、控制台输入、运算结果等
    对象名.属性名 =;
    举例:xs.mz = "周冰凯";
      xs.age = 18;
      xs.sex = '男';
    4、调用方法
    对象名.方法名();
    xs.ziWoJieShao();        
    xs.xueXi();
    注意:通常我们定义的类,叫做实体类,不能用作运行程序的,
	必须把main方法写在专门的程序类中。
六、对象的存放
    new 类名();//这是对象的实体,存放在堆空间
    对象名存在栈空间,然后通过=号来对实体的堆空间地址进行引用
    比如:XueSheng xs = new XueSheng();
    xs 存栈空间,存地址
    new XueSheng()存堆空间,并且有地址


OOP――封装

一、面向对象的设计理念
     第一步: 发现类(找出它的种类)
     第二步: 发现属性(找出它的属性)
     第三步: 发现方法(找出它的行为)
     最重要的:在发现属性和方法时,只需要和业务相关的就可以了。

二、构造方法
      用来创建对象,给对象赋初始值
      特点:与类同名,无返回值类型,使用new关键字调用

     语法:
               访问修饰符    类名(参数列表){
                    //构造方法一定是在自定义类中
               }
     使用:类名  对象名 =  new 类名();          

三、在构造时给对象属性赋值
       需要在构造方法中,定义参数
       public  类名(参数类型1  参数名1,参数类型2   参数名2){
               this.属性名  =  参数名1;
       }
      比如:
          public Dog(String name,String type,int love){
		this.name=name;
		this.type=type;
		this.love=love;
	}
     创建对象:Dog d = new Dog("菜菜","拉布拉多犬",10);
                      d.print();

四、方法重载
       特点:方法名相同,参数列表不同(个数不同,类型不同,顺序不同),写在同一个类中

      例如:public Dog(){

                }
   public Dog(String name,String type){

   }


五、在类中,无自定义构造方法,虚拟机会提供一个默认无参构造方法,
	当有自定义构造时,不论是有参还是无参,
	虚拟机都将不再提供默认无参构造方法。


六、封装
       为了提高代码的安全性,将类中的属性和方法内部隐藏起来

       实现步骤:
              1、将属性私有化,添加private访问修饰符
                   private int health=100;//在除该类的其他地方就不能直接用对象访问age

              2、定义public的getter和setter方法
                   //getter是无参有返回,用来提供值
 		 //setter是有参无返回,用来给属性赋值

  public void setHealth(int health) {
		if(health<0 || health>100){
			this.health=50;
			System.out.println("健康值只能是0-100之间");
		}else{
			this.health = health;
		}
		
	}
                  } 
     
  3、在getter和setter方法中,加入控制语句,代码如上。




OOP――继承

一、继承
     优点:优化程序代码设计,减少重复的代码,提高重用性,方便修改
     设计原理:将多个子类重复的属性和方法,提取到父类中,
     子类就只需要专心的设计独属于自己的特色部分,那么子类就一定会比父类
     更加优秀更强大。

二、继承的使用步骤
     1、编写父类(定义一个类)
          public class 父类{
               //定义子类通用的属性和方法
          }
      比如:狗和猫都属于宠物,那么宠物类就是他们共同的父类

     2、编写子类,继承父类,继承通过extends关键字实现
          public class 子类  extends 父类{
               //只需要定义子类的属性和方法
          }

三、子类通过super关键字来调用父类向它公开的属性和方法
          1、调用构造方法
               public 子类(){
                    super();//调用无参
               }
               public 子类(参数类型   参数名){
                    super(参数名 );//调用有参
               }
          注意:super()调用父类的构造方法,只能是写在代码第一行,上面不能有其他代码

          2、调用属性(写在子类的方法中)
               super.属性名

          3、调用方法(写在子类的方法中 )
               super.方法名();

  public Dog(String name) {
  //调用父类的构造方法,给名字赋值
  super(name);
  this.pinzhong = pinzhong;
      }

  public void print(){
  super.print();
  System.out.println("我是一只"+this.pinzhong);
  }

四、深入理解继承
          1、继承只能单继承,子类只能有一个直接父类
          2、子类不能继承父类构造方法和private私有属性和方法。(构造方法只能在子类中调用)
          3、有继承关系的类,创建对象的顺序:一定是先有父类,才有子类,所以一定会先调用父类的构造方法
          4、子类和父类的关系一定是is-a的关系,子类就是父类或者子类类型就是父类类型的其中一种(比如猫是动物、狗是动物)
          5、所有类的父类都是Object,当我们自定义一个类,
	    没有写extends去继承某个类时,它的父类一定是Object。
	    我们可以说子类是属于父类类型,也可以说子类就是属于Object类型

五、方法重写
          1、作用:减少程序员对代码的记忆量,更好的支持多态
          2、特点:1、必须是两个类中,存在继承关系,由子类来重写父类的方法,完善父类的不完善的功能
                   2、方法名相同、参数相同、返回值类型相同或者兼容、访问修饰符不能严于父类

六、访问修饰符
          1private     私有的(只能在本类当中访问)

          2、缺省的     (只能在同一个包中访问)

          3protected  被保护的(仅限于子类访问,不同包中,只需要导包)

          4public       公共的(随意访问,不同包也需要导包)


==========================继承2


八、抽象类和抽象方法
     1、抽象类:限制实例化(没有真实的对象)、定义抽象方法
     语法:访问修饰符   abstract  class 类名{

                }
     举例:public  abstract  class   DongWu{

               }

     2、抽象方法
          无法具体描述清楚的行为,就可以写成抽象方法
     语法:访问修饰符  abstract  返回值类型   方法名(参数列表);
     
     举例:public abstract void eat();
     
     特点:1、必须定义在抽象类中
               2、没有方法体,也就不需要{},直接在方法圆括号后分号结束
               3、子类必须重写父类所有的抽象方法
               4、子类如果不想重写父类抽象方法,那就将子类也变成抽象类

九、抽象类和抽象方法的关系
     1、抽象类里可以有抽象方法或普通方法
     2、抽象方法必须存在于抽象类中

十、final关键字
     1、可以修饰变量,那么该变量就是常量(值是固定的不能再更改)
    比如:private final double PI = 3.1415926;
     注意:常量一旦声明,值就不得更改,常量名采取全部大写命名
     
     2、可以修饰方法,那么该方法不能被重写(所以不能修饰抽象方法)
     比如:public final void eat() {
                }

     3、可以修饰类,那么该类不能被继承(所以不能修饰抽象类)
     比如:
               public final class DongWu {
                }

十一、static关键字
     1、静态的,凡是静态的方法,不能直接调用非静态的属性和方法
     2、静态的属性和方法,是属于该类的所有对象共用的,叫做类变量和类方法,可以直接用类名来调用
     比如:random()方法就是Math类中的静态方法,调用:Math.random();

     3、静态的属性、块{},会在构建类的时候(把类加载到内存中)就已经定义完成了,此动作是在创建对象之前完成的,所以之后再创建多少对象出来,这些静态的属性和块都不会再重复调用,所以静态块是最好的初始化数据的方式。
     4、我们可以将常量定义为静态的、将想要用类名直接调用的方法定义成静态的,为了方便取用。



===================多态
OOP――多态

一、多态
     生活中的多态,比如水(液态)、汽(气态)、冰(固态),同一种事物,在不同的环境下表现出的不同形态
     程序中的多态,同一种类型(父类),使用不同的实例(new子类对象)来执行不同的操作

二、多态的作用
     提高代码的可扩展性,灵活性

三、多态的使用
     1、使用父类作为形参,实际调用时,使用子类对象作为实参,从而实现多态
          //给宠物喂食的方法,不确定是喂给哪个对象,所以以父类Pet作为形式参数
          public static void feet(Pet p){
          p.eat();
  }
          调用时:
          feet(new Dog());//在实际调用时,new Dog实例来给狗喂食,new Cat给猫喂食


 2、使用父类作为返回值类型,实际调用时,以父类类型来接收返回值
          public Pet getPet(String typeId){
 	 Pet p=null;//宠物类型
  	switch (typeId) {
  	case "1":
           p = new Dog();
           break;
 	 case "2":
           p = new Penguin();
           break;
  	case "3":
           p = new Cat();
           break;
  	default:
           break;
  	}
  	return p;
  }
          调用时:
          Pet pet = getPet(x);
          pet.print();//该方法必须是子类重写过的!
	  pet.eat();//该方法必须是子类重写过的!

四、多态使用要求
       1、子类最好要重写父类的方法;
       2、使用父类类型,new子类对象,这种称为“向上转型对象”;
       3、多使用父类类型作为形参或返回值类型

五、向上转型对象的特点:
       1、只有向上转型的对象,才能调用到子类重写父类的方法。
       2、子类即属于自己、又属于父类、还属于Object类型

六、instanceof运算符
      1、当我们需要将向上转型的对象,向下转时(强制转换),最好先判断一下,这个对象是否是该子类的类型,这样不会那么容易报错
      public void play(Pet p){
//用instanceof判断,形参传递进来的p对象到底是属于哪种子类类型  
       if(p instanceof Dog){
  //强制转换
  ((Dog)p).techang();
   }else if(p instanceof Cat){
  ((Cat)p).techang();
   }else if(p instanceof Penguin){
  ((Penguin)p).techang();
  }
  }

     2、强制转换是为了临时让向上转型的对象,调用到子类独有的方法

七、总结使用多态的步骤:
     1、先编写父类,定义属性和方法

     2、编写子类,继承父类的属性和重写父类的方法

     3、编写测试类,创建向上转型对象,或者使用父类类型作为形参或返回值类型来实现多态


==================================接口

一、什么是接口
      是一种规范、一种标准(抽象方法),接口本身不实现任何功能。

      其实就是变相的抽象类,有几大特点:
     1、定义不使用class,而使用interface关键字
     2、接口中只能定义抽象方法,不能有非抽象方法,所以接口是最纯粹抽象类
     3、接口也不能实例化
     4、接口中只能定义静态常量
     5、接口可以支持类的多继承(但官方说法,叫实现),使用implements实现接口
     6、接口要求实现类实现它所有的抽象方法
     7、接口不能实现接口,但是接口可以继承接口

二、使用接口
     1、定义接口
          public interface 接口名{
                   //定义常量和抽象方法 
          }

     2、实现接口
          public class 类名  implements 接口1,接口2{
               //重写抽象方法
          }


=====================异常处理

一、异常
     1、程序在运行过程中出现的错误,导致程序终止运行。

     2、异常分为两大类:Error错误(无法挽救)、Exception异常(可以挽救)

二、异常处理机制
     由trycatchfinally三个代码块和throwthrows组成的,对异常进行处理的联动结构

     语法:try{
                    //有可能发生异常的代码
               }catch(异常类型  变量名){
                    //对异常进行捕获,并提示错误
               }finally{
                    //不论是有没有异常,都会执行的代码   
                    //通常用来做扫尾工作,比如关闭连接、关闭流等等
               }
     注意:
     1try/catch/finlly三个块的作用范围是独立的,变量不可共享,必须定义在异常处理机制的外面。
     2、三个块可以任意组合,但是try必须有,catch可以有0-多个
     3catch的顺序先子类后父类,无继承关系则随便

三、throwthrows
     throw     用于抛出异常(通常写在catch的大括号中)
     throws   用于声明异常(通常写在方法的形式参数括号后面)

     比如:(以后常用的异常结构)
     public void xxx() throws Exception{
          try{

          }catch(){
               throw new Exception("异常原因");
               //throw new RuntimeException("");
          }
     }

     注意:如果抛出的是Exception或IOException,则需要throws Exception来说明该方法有抛出异常
               如果抛出的是RuntimeException及其子类,则可声明,可不声明
               因为,Exception和IOException是受JVM监听的异常类型,而RuntimeException是运行时异常,JVM无法在编译时监听。

四、自定义异常
     有些问题我们可视作为异常,但是虚拟机并不认为这是异常,这种是逻辑异常,虚拟机不会处理,需要我们自定义一个类,成为Exception或者RuntimeException的子类,那么虚拟机就会监听这种逻辑异常了。

     自定义异常的使用步骤:
     1、创建一个类,继承Exception或RuntimeException,并且定义和父类相似的所有构造方法(alt + shift  + s + c)

     2、如需要统一异常错误提示,可以在自定义异常中,定义一个message(必须使用这个变量名),再定义getMessage()方法。

     3、在抛出异常时,throw new 自定义异常类();

五、使用异常处理的步骤:
     1、先使用try块来监听有可能出错的代码

     2、再catch捕获,但是要注意,在确定会出现何种异常类型的情况下,直接捕获该类型。捕获到异常后,可以选择在catch的大括号中throw抛出异常对象

     3、最后再定义finally,进行收尾工作。

============包装类和String类===============

一、包装类
     和基本数据类型一一对应的有八个:byte ――Byte、boolean――Boolean、char――Character、
int――Integer、double――Double、short――Short、long――Long、float――Float

二、装箱、拆箱
     将基本数据类型转换成包装类型,叫装箱
     将包装类型转换成基本数据类型,叫拆箱
     Java中支持自动装箱和拆箱

     举例://装箱
  Double b = new Double("2.1");
  System.out.println(b);

  //拆箱
  Double d = new Double(11.1);
  //double dd = d;自动拆箱
  //拆箱后强转
  int dd = cvd.doubleValue();
  System.out.println(dd);

三、String类型与基本数据类型的转换
          1、从基本数据类型转成String
                     int a = 10;
                     String s = a+"";
                     String s = Integer.toString(a);

          2、从String转成基本数据类型
                    使用包装类中的parseXxx()方法
                    String s2 = "123";
   int i = Integer.parseInt(s2);
   System.out.println(i+1);//最终结果为124
 
     注意:xxxValue()parseXxx()有可能发生NumberFormatException数字格式化异常

四、使用API帮助文档
          1、找包
          2、找类
          3、找方法

五、String    
      1、用来存储一串字符,其本质就是用char[]来一个一个存这些字符。
      2、特点:
          String中的字符串值一旦确定,便不能再修改,修改后就不是原来那个
          常量字符串存储在字符串常量池中,所以常量地址是相同的
          比如:String s = "abc";String s1="abc";s==s1结果为true
          常量字符串本身就是一个String对象,拥有String的方法
          比如:"abc".length();
          比较字符串是否相同,要使用equals方法


     3、方法:
           A、char charAt(int index)     根据index下标找到对应的字符,返回该字符
          比如:"你能找到Hello在哪吗?".charAt(4);结果为H

       B、boolean startsWith(String prefix)  判断是否以prefix为开始
          boolean endsWith(String suffix)    判断是否以suffix为结束
          比如:"你能找 到Hello 在哪吗你?".startsWith("你");结果为true

       C、String trim()     去除该字符串的前后空格
          比如:" I love you ".trim();//返回的字符串长度会少2

            D、int  indexOf(String s)          从左往右找,s第一次出现的位置
                  int  lastIndexOf(String s)    从左往右找,s最后一次出现的位置
                比如:String s3 = "Do you love me?";
                          int i = s3.indexOf("o");//1
                          int i1 = s3.lastIndexOf("o");//8

            E、int   length()           获取该字符串的长度         

            F、String subString(int beginIndex)     截取字符串,从beginIndex开始一直截到末尾
                 String subString(int beginIndex,int endIndex)    从begin开始截到end的前一个字
                比如:String s3 = "Do you Love me?";
                          int i = s3.indexOf("L");
                          String s = s3.substring(i,i+4);//结果为Love

            G、String[]  split(String s)     根据s来分割字符串
                  比如:String ss[] = "Do you love me?".split(" ");//ss的长度为4,ss[0]为Do

            H、String replaceAll(String s,String s1);     将s全部替换成s1
                    比如:String ss = "蔡康祺每天上课一脸懵逼蔡康祺每天没有带智商来上课".replaceAll("蔡康祺", "周冰凯");
                              ss的结果为:周冰凯每天上课一脸懵逼周冰凯每天没有带智商来上课?

            I、String toLowerCase();      将字符串全部转成小写
                String toUpperCase();      将字符串全部转成大写

            J、char[] toCharArray()          将字符串转成char数组


六、StringBuffer和StringBuilder
       他们是比String效率更高的字符串类型,相当于String的升级类,在操作字符串时,不会每次生成新的对象,而是在原基础上追加。

       StringBuffer:线程安全,相对来说效率较低(通常使用这种)
       StringBuilder:非线程安全,效率更高

       使用:
        1、将字符串或String类型的值转成StringBuffer和StringBuilder
            String name1="蔡康祺";
		StringBuffer sb=new StringBuffer(name1);

        2、将StringBuffer或StringBuilder转成String,使用toString()方法
             System.out.println(sb.toString());

        3、StringBuffer和StringBuilder使用append()方法追加字符
            sb.append("最近找了女朋友");
	sb.append("他女朋友的名字叫做蔡林");
               


============日期类与日历类

一、日期类
       java.util.Date     用来描述日期和时间
       java.sql.Date      java.util.Date的子类 ,用来存储日期
       java.sql.Time      java.util.Date的子类,仅表示时间
       java.sql.Timestamp      java.util.Date的子类,可以表示日期和时间


二、日期的特殊字符
      y(Year)     年份
     M(Month)	    月份
     d(Date)     日
     H/h(Hours)    时,大写的24小时制,小写为12小时制
     m(minutes)    分钟
     s(seconds)     秒钟
     E                    周几
     W(Week)  当前周是该月的第几周

三、如何使用
     1、构造方法创建时间
          java.util.Date  d = new Date();//获取当前电脑系统时间
          
     2、获得long类型的毫秒时间
          long  time  = System.currentTimeMillis();//获取系统的当前毫秒时间

     3、日期类型与String类型转换
          A、将Date转String    
               toLocaleString();     转成yyyy-MM-dd H:mm:ss
                
              SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
              sdf.format(new Date());//new Date()就是创建当前系统时间

 	4after()before()

          after() 判断前面的日期是否在参数中的日期之后
          before()判断前面的日期是否在参数中的日期之前
          Date d = new Date(1998,1,1);
  	Date d1 = new Date(2000,1,1);

  	boolean b = d.before(d1);
  	System.out.println(b);

  	5、单独获取日期时间
       getYear()
       getMonth()等等
       getTime()    获取毫秒时间,其实就是将Date类型转换成long类型

四、Date的子类
      1、java.sql.Date和父类Date只能允许导其中一个包,另一个在使用时,必须前面加包名
          比如:java.sql.Date  date = new java.sql.Date(long);

      2、子类与父类之间的转换
          A、将util.Date的类型转换成子类型(需要long类型进行中转)
               Date d = new Date();
               java.sql.Date  date = new java.sql.Date(d.getTime());


      3、String类型转换成java.util.Date或long型进行计算
           使用子类的valueOf方法,该方法为静态方法,可以直接使用类名调用
           String s = "2017-10-16 10:00:00";

 	 java.sql.Timestamp d = java.sql.Timestamp.valueOf(s);

	Date d1=new Date(d.getTime);
  	System.out.println(d1.toLocaleString());//再转成String类型

五、日历类
      1、用来描述日历的抽象类,功能比Date更详细,可以区分不同的时区、国家

      2、创建对象
           Calendar c = Calendar.getInstance();

      3get(字段) 方法     根据不同的时间字段获取具体信息
           System.out.println(c.get(Calendar.YEAR));
 	 System.out.println(c.get(Calendar.MONTH));
  	System.out.println(c.get(Calendar.DATE));
  	System.out.println(c.get(Calendar.DAY_OF_WEEK));
          Month为0-11,DAY_OF_WEEK本周第一天为周日

     4getTime()     获取完整的日期信息(返回为Date类型)
          Calendar c = Calendar.getInstance();
          c.getTime();

     5set(字段,)方法          设置不同的字段的日期信息
          c.set(Calendar.YEAR, 2014);
  	c.set(Calendar.MONTH, 5);//设置时,就会比实际的大1
  	c.set(Calendar.DATE, 1);

 6add(字段,天数)      给不同的日期字段推迟或提前天数,正数推迟、负数提前
     c.add(Calendar.MONTH, 11);

六、日历类用法
       1、从控制台接收一个年份和月份
       2、创建日历对象
       3、分别设置年、月、日(1号)
       4、获得当前月份有多少天
             int days = c.getActualMaximum(c.DATE);
       5、获得当前月第一天是这一周的周几
             int start = c.get(c.DAY_OF_WEEK);
       6、循环输出当月第一天前面的空格,比如1号为周日,start值为1
             for (int i = 1; i < start; i++) {
                System.out.print("\t");
 	}
  7、循环输出日期,判断每七次换一行,需要排除第一周的空格
 	 for (int i = 1; i <= days; i++) {
 	System.out.print(i+"\t");
  	//换行之前必须排除1号不是星期日的情况
  	if((start+i-1)%7==0){
                  System.out.println();
  	}
  }

===================集合一

一、什么是集合
      用来存储不同数据类型,可扩展大小的,类似数组的一种存储空间

      与数组的区别:
      1、数组定长,集合不定长
      2、数组定型,集合不定型
      3、数组的效率高,集合相对效率低
      4、集合中存储的是对象的引用,如果存入基本数据类型,JVM将自动完成装箱操作

二、集合框架
      1、接口:比如Collection,Map,代表一种规范,只定义方法(算法)
      2、实现类:存储元素的
      3、算法:就是定义对元素进行什么样的操作

三、三大集合接口
      1、List:Collection的子接口,有序、可存重复元素
      2、Set:Collection的子接口,无序、不可重复元素
      3、Map:以键值对的方式存储元素,无序,键不可重复,值可重复

四、List集合
       ArrayList:动态数组,以下标访问元素,在java.util包中
       1、定义集合
        List list = new ArrayList();
        
        2、方法
             add(Object o)    :为数组添加元素,类型为Object
             size()                  :获取集合中元素的个数(长度)
             remove(Object o):可以根据下标或对象直接移除某个元素,注意如果是整型,无法判断是元素还是下标,如需要按元素删除,请new Integer()包装一下
             get(int index)     :根据index下标来获得对应位置的元素
             set(int index,Object o):根据index下标来重新设置值。
             clear()                 :所有元素全部清除
             contains(Object o):判断集合中是否包含参数中指定的元素,有返回true
             isEmpty()            :判断集合中是否有元素,没有元素为true

	3、遍历集合
             A、for循环
                   for (int i = 0; i < list.size(); i++) {
                        System.out.println(list.get(i));
                   }
        
            B、增强for循环:foreach
                    for(元素类型  元素名 : 集合名){
                        System.out.println(元素名);
                    }

            C、Iterator   迭代器
                  用来降低程序的耦合性的一种隔离器,将原集合的数据复制一份到迭代器,
		迭代器可以帮忙打理数据,一旦迭代器中数据修改,
		原集合会立即得到修改,如果原集合修改了,
		但没有重新生成迭代器,会产生ConcurrentModificationException异常。
                工作原理:迭代器会有一个游标,数据是通过next()方法获取,每一次调用next()方法,获取完数据后,游标就会往后移动一格,那么下一次就可以获取到后面的元素。

                使用:Iterator it = 集合名.iterator();
                          while(it.hasNext()){
                                System.out.print(it.next());
                          }

	LinkedList集合    链表式集合
               查询慢,但是修改比ArrayList快


五、Set集合
            使用哈希算法来计算元素存储的位置,无下标概念,所以是无序。
            同是Collection的子接口,很多方法与List一致
    
            1remove(Object o):没有下标,只能通过元素来删除
            2、遍历集合时,不能使用普通for循环,只能用foreach和迭代器,迭代器用法与List一样
            3、Set在判断是否重复的对象时,需要该对象的类型,重写HashCode和equals方法。                
                (alt+shift+s+h)
            4、实现类HashSet无序,但是有一种TreeSet是可以排序的。


六、集合泛型
        限制集合的元素类型,方便批量处理(循环)
        语法:
        集合类型<某个类类型>  集合名 =  new 集合实现类型<>();
        比如:
        List<Dog>  list = new ArrayList<>();


七、关于集合的排序
        1、List集合的排序,可以使用冒泡排序,
	或者Collections.sort(List集合名);


	2、Set集合的排序,可以将set集合转成数组,如果是TreeSet,可以使用Comparable接口来排序。
            使用Comparable接口排序的时候,需要集合中元素对象的类,实现Comparable接口并重写compareTo()方法。例如:
            注意:如果这个实体类中,没有int类型的数据,那么String型的数据,直接使用compareTo方法比较就可以了,会直接按照a-z自然排序




=============================集合二
一、Map集合
       1、特点:以键值对的方式存储数据,键值对在程序中有个特殊的泛型Map.Entry,它代表的就是Map中存储的某个键值对对象
            一般使用子接口HashMap(无序),TreeMap(按key自然排序)
        2、创建集合
             Map<K,V> 集合名 = new HashMap<>();
             
             K代表map中的键的类型,一般情况不要使用对象类型
             V代表map中的值的类型
            
             比如:Map<Integer,String> map = new HashMap<>();
            
        3、方法:
             A、put(key,value);    添加一个键值对到集合中
             比如:map.put(2, "abcd");

             B、get(key);        通过键来获得对应的值
             比如:map.get(2);    得到的就是"abcd"

             C、remove(key)  通过键来删除键值对
             比如:map.remove(2);

             D、size()    获得集合长度

             E、clear()    清空集合所有元素

             F、replace(key,value)    根据key,用value替换掉对应的值
                  如果找不到key,不执行replace

             G、containtsKey(key)    是否包含某个键

             H、keySet()    获得键集合,返回类型为Set集合

             I、values()      获得值集合,返回类型为Collection

             J、entrySet()    获得键值对集合,返回类型为Set<Entry<K,V>>集合,泛型为Entry键值对型

        4、Map的取值
                A、用get(key)一个一个取
                     Map<Integer,String> map = new HashMap<>();
                     map.put(2, "abcd");

                     String s = map.get(2);//接收的类型,必须是集合泛型中Value的类型
                     System.out.print(s);

                B、循环取值
                      1)先取键循环,再根据键取值
                      Set<Integer> set = map.keySet();
                      for (Integer i : set) {
                            System.out.print(i+"\t");
                            System.out.println(map.get(i));
                      }

                     2)直接取值的集合,返回的是Collection接口类型
                     Collection<String> c = map.values();
                     for (String s : c) {
                            System.out.println(s);
                     }

                     3)取Map.Entry集合,返回的是Set<Entry<K,V>>类型
                     Set<Entry<Integer,String>> entry = map.entrySet();
                     Iterator<Entry<Integer,String>> it = entry.iterator();
                     while(it.hasNext()){
                        Entry<Integer,String> e = it.next();
                        System.out.print(e.getKey()+"\t");
                        System.out.println(e.getValue());
                        //在这个循环中,可以进行判断,根据某个键来修改值,Entry中有setValue()的方法是用来重新给键值对赋值的
                        if(e.getKey() == 121){
                              e.setValue("新值");
                        }
                     }


========================mysql

一、数据库
       用来存储数据的仓库

二、为什么使用数据库(持久化)
        1、存储大量数据,方便访问
        2、结构化数据,稳定,安全,可共享
        3、保持信息统一、一致、完整
        4、通过组合分析,产生新的有用信息(多表联合)

三、应用程序与数据库的关系
        1、应用程序:响应用户操作,并显示结果,向数据库请求数据,要求界面美观,操作方便

        2、数据库:存储数据,向程序提供数据,保证数据的安全、稳定、完整、高效

四、时下流行的数据库
        1、Oracle    产品免费、服务收费大型数据库(甲骨文)
        2、MySql    免费、小型(网站网络数据库)(甲骨文)
        3、SqlServer    产品收费、自带窗体的大型数据库(微软)
        4、DB2        IBM公司,支持多操作系统

五、数据库关键名词
        1、库、数据库:保存数据的仓库,在Mysql中一个数据库代表一个独立的结构的整体
        2、表、数据表:一般存于数据库中,代表某个类型的数据,由行和列组成
        3、记录:代表一个实体对象的完整信息,在数据库中通常是一行代表一条记录
        4、字段:代表一个实体的每一个属性,可以分不同类型,通常在数据库表中显示为列名
        
六、NaviCat
        针对mysql、oracle这类本身无窗体的数据库设计的可视化应用程序。
        在使用时,需要和数据库进行关联(新建一个连接,连接时注意用户名为root,密码为空或自定义)


=====================mysql T-Sql
1、TSQL建库建表
2、数据完整性
3、约束、外键关系


一、数据类型
       int    整型      bigint    大整型
       double浮点型        decimal(数字,小数后的长度)   定点型
       char   字符型       varchar   字符串型       text    文本型

二、建库
       create  database  库名;
       create database if not exists 库名;   //如果数据库不存在,则创建

       在建库的语句上方,最好加上一句判断
       drop database if exists demo;//如果数据库存在,则删除

	/*查看刚刚创建的名为test1的数据库*/
	SHOW CREATE DATABASE test1;

	/*修改数据库的字符集,如果没有效果直接在navicat工具修改,修改过后需要重新启动*/
	ALTER DATABASE test1 DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;

三、建表
       语法:
        create table 表名(
                字段名1   数据类型(长度)    [约束条件0-n个],
                字段名2   数据类型(长度)    [约束条件0-n个]
        );

       比如:
        use 数据库名;    //在建表前,最好指定数据库,否则表会建在当前查询编辑器所在的数据库
	/*如果表存在先删除*/
	DROP TABLE IF EXISTS student;       
 	create table student
        (
            stuid int primary key not null auto_increment,
            stuname VARCHAR(20) null
            
        );

四、数据完整性
       为了保证数据库中的数据的准确性、正确性、以及尽量避免冗余
       (冗余就是数据、字段的重复)

       1、实体完整性:能够唯一标识表中的每一条记录
          实现方式:主键约束、唯一约束、自增长
       2、域完整性(字段完整性):表中的字段的数据正确性,确保不会输入非法值或无效值
      实现方式:限制字段类型、默认值、检查约束、非空约束
       3、引用完整性:维护表之间的数据完整性
      实现方式:外键约束(建立外键联系另一个表的主键或唯一键)
       4、自定义完整性:根据业务需求定义特殊的规则
      实现方式:存储过程、触发器、规则等

五、建立表的约束
       1、主键、自增长(int类型的主键字段)、唯一、非空、默认值都可以在建表时加上
           比如:create table staff
        (
            staffid int primary key not null auto_increment,
            staffname VARCHAR(20) null default 'xxx',
            salary     decimal(10,2) null default 0,
            telephone varchar(11)  null unique
        );
        primary key    主键
        not null          不允许为空
        null                允许为空
        default 值       默认值
        auto_increment    自增长
        unique           唯一约束

      2、单独添加约束
           语法:alter table 表名 add constraint 约束名 约束类型 [约束规则];
            A、	  添加主键约束
                  alter table 表名 add constraint pk_1234  primary key(字段名);
                 
		 删除主键约束
                  alter table 表名 drop primary key;

            B、添加唯一约束
                alter table 表名 add unique(字段名1,字段名2);
                修改唯一约束
                alter table 表名 modify 字段名 类型(长度) unique;
                删除唯一约束
                alter table 表名 drop index 字段名;
	    C、外键约束
                可以限制该表中内容必须是另一个表中存在的内容,比如学生表的班级字段和班级表中的班级字段
                在这个关系中,外键约束中的两个字段,主键所在的表为主表,外键所在的表为外表。(比如classid是班级表的主键,classid在学生表中并不是主键,而是外键)
                有主外键约束的表,在删除数据时,先删外表中所有引用的内容,再删主表内容
		
		1、用代码创建约束
                语法:alter table 外表名 add constraint   外键名  foreign key  外表名(字段)  references    主表名(字段名);  

                比如:给学生表引用班级表
                alter table student add constraint fk_student_class_112
		foreign key  student(classid)  references    class(classid);  

            D、非空约束
                 alter table 表名 modify 字段名 类型 not null;
                 取消非空:
                 alter table 表名 modify 字段名 类型 null;

            E、默认值
                 alter table 表名 modify 字段名 类型 default '值';

===================mysql-CURD==========
一、CRUD代表数据库中的增(create)删(delete)改(update)查(result)的操作

二、新增语句
       语法: insert  [into]  表名[(字段1,字段2)]   values(1,2);

       例子:insert into student(studentNo,studentName,studentPwd,GradeId)  values("1","张三","123456",1);
             insert into student values("1","张三","123456",1);
        如果表名后面有圆括号指定字段,into可省略
        如果没有指定字段,into一定要加,并且值必须是所有字段都赋值

	增加语句常见错误:
      1、 Column count doesn't match value count at row 1        值和字段数量不匹配  
      2、Duplicate entry '1007' for key 'PRIMARY'           主键不能为空
      3、Column 'teacher_id' cannot be null    该字段teacher_id不能为空
      4、 Unknown column 'TR20' in 'field list'                             TR20的值与字段类型不匹配(要求String,插入了未加双引号的值)
      5、Data too long for column 'class_name' at row 1              值超过了字段的最大长度
      6、 Cannot add or update a child row: a foreign key constraint fails (`demo`.`tb_essay_question`, CONSTRAINT `fk_tb_essay_question_123` FOREIGN KEY (`teacher_id`) REFERENCES `tb_teacher` (`teacher_id`))                外键引用错误

二、更新语句(修改)
 语法:update  表名   set   字段名="值",字段名2="值"  [where 条件]

 例子:UPDATE student SET LoginPwd='123456' WHERE StudentNo='5';

三、删除语句
 语法:delete  from 表名   [where 条件]

 例子 :delete from student where studentNo='1';


四、查询语句
      1、简单查询(查询该表的所有内容)
           select   *   from 表名;

       
==================单表查询(select查询)

一、从数据库中将需要的数据查询出来,存入一个临时的结果集中。

二、语法:
       select [distinct] * | 字段列表(中间逗号隔开)
       from  表名
       [where 条件]
       [group by 字段列表 [having 筛选条件]]
       [order by 字段列表]
       [limit [offset] 记录数,页数]

三、简单查询
        1、查询所有字段的所有记录
             select * from 表名

        2、按字段查询所有记录
             

        3、查询非空的记录
             select * from 表名  where 字段名  is not null
             查询为空的记录
             select * from 表名  where 字段名  is null

        4、按大小、等值、不等值判断,>,<,>=,<=,!=,<>
             select * from 表名  where 字段名>=;

        5、按范围查询(只查数值范围,值1必须小于值2)
              select * from 表名  where 字段名  between  值1  and 值26、按不连续的区间查询
             select * from 表名  where 字段名   in(1,2.....);
             不在这个区间内的
            select * from 表名  where  字段名  not  in(1,2.....);
	  7、模糊查询
             like关键字和通配符的使用

             %    通配0-n个字符
             _     通配1个字符

             select * from 表名  where  字段名  like  "%值%"
            
        8、多条件查询,and和or关键字的使用
             and  且,前后表达式必须全部满足
             or     或,只要任意一个表达式满足
        
            select * from 表名  where  条件1  and 条件2  or 条件3
            and和or同时使用,and优先,如果or写在前面并且想要先执行,需要圆括号。
            select * from xinxi where (bname like "王%" or edlevel=5)
		and salary between 2000 and 3000;
            
        9、聚合函数
             count(* | 字段名) :计记录数,注意*号通常按主键数统计,字段名如果有Null,则忽略不计 
             sum (字段名):求总和
             avg (字段名):求平均
             max (字段名):求最大值
             min (字段名):求最小值
             
             where条件后不可以写聚合函数

        10、分组查询
             group by 
             
             1、不带筛选的分组查询
             select 字段名1,字段名2 from 表名  where 条件
             group by 字段名1,字段名2;
             
            例如:查询部门为2并且姓王的员工的平均工资
                      select deptid,avg(salary) as '王姓' from xinxi
                      where deptid=2 and bname like '王%'
                      group by deptid;

            2、带筛选的分组查询(where后的条件中,只能查表中现有的字段,不能使用聚合,带有统计的条件必须用having)
            例如:寻找雇员平均工资大于3000的部门的最高和最低薪水
            select deptid,MAX(salary),MIN(salary) from xinxi
            GROUP BY deptid HAVING avg(salary)>3000;


===============多表连接查询

一、外键关系
       一个表的某个字段,引用自另一个表的字段,被引用的是主表中的主键或唯一键

二、关联关系
       1、一对一
            人与身份证、公司与营业执照等等,通常这种为自连接

       2、一对多、多对一
            学生与班级,通常班级是被引用,作主表,学生是外表

       3、多对多
            试题与试卷,一个试题可以被多份试卷引用,一份试卷又能引用多个试题,通常采取"中间表",
            这个中间表即引用试题,又引用试卷,中间表可以没有主键

       注意:有外键关联的表之间,删除先删外表,增加和修改通常是从主表开始,通常修改不要改主键

三、连接查询
       1、内连接,把多个表的信息都显示,如果没有,以Null代替
            语法:select * from 表1 inner join 表2 on 表1.字段=2.字段
                      inner join  表3 on 表1.字段=3.字段
                      [where 条件];
			或者:
                      select * from 表1,2,3 where 表1.字段=2.字段  and 表1.字段=3.字段
		     [where 条件];

            比如:部门表和员工表,以部门编号作为外键
            select bname,cname,salary,edlevel,hiredate
            from bumen as a inner join xinxi as b
            on a.id=b.deptid;

	2、左连接,以left join左边的表为主,右边表没有的记录,以Null代替
             语法:select * from 表1 left join 表2 on 表1.字段=2.字段
             
             比如:
             select bname,cname,salary,edlevel,hiredate
             from xinxi as a left join bumen as b
             on b.id=deptid;

	3、右连接,以right join右边的表为主
             语法:select * from 表1 right  join 表2 on 表1.字段=2.字段


        4、自连接,是表的某个字段的数据引用自本身表中的主键或唯一键的记录内容
	  比如:select a.id,b.cname as '子分类',a.cname as '父分类'
                      from fenlei as a,fenlei as b  where a.id=b.pid;
            查询的时候,一定要取别名,把一个表分成2个表
 	
	5、子查询
            将某个查询的结果作为另一个查询的条件或删改的条件,通常用于有连接关系的表之间
            子查询可以代替查询单表所有内容的内连接,如果要在结果集中显示两个表以上的字段内容,子查询不可用。

            比如:SELECT * FROM emplooye1 e WHERE e.d_id IN (SELECT d_id FROM door1 WHERE d_name = '研发部');
            注意:子查询的结果返回多少个值,多个值要用in

            比如:update emplooye1 set money=money+1000
                      where deptid =(select id from bumen where cname="研发部");
            注意:子查询的字段只能有一个,不能用*
            在不能确定子查询结果时,先选中子查询的查询语句,ctrl+shift+R单独运行一下。

        6、分页查询
            select * from 表名 limit 开始位置,每页显示条数;

            比如:查出工资最高的三个员工信息
                      select * from emplooye1 order by money desc limit 3;
                      

===========================JDBC

一、什么是JDBC
        Java DataBase Connectivity   数据库连接技术,进行程序中数据持久化存储到数据库中的一项技术

二、JDBC的工作原理
      JAVA API:负责连接、执行、处理数据库得到的结果等等
                DriverManager:驱动管理者,负责管理不同的数据库驱动程序。
                Connection:数据库连接,负责连接数据库,以及数据传输
                Statement:数据库执行对象,负责执行Sql语句
                ResultSet:结果集,负责处理数据

三、天龙八步
       1、为工程导入驱动程序包(mysql-connector-...jar),如上
       2、加载驱动
            Class.forName("com.mysql.jdbc.Driver");
       3、准备连接字段
            /*String url="jdbc:mysql://localhost:3306/studentmanager";*/
            String url = "jdbc:mysql://localhost:3306/数据库名?useUnicode=true&characterEncoding=utf-8&useOldAliasMetadataBehavior=true";
            String user = "root";
            String password = "123456";
       4、获得连接对象
            Connection con = DriverManager.getConnection(url,user,password);
       5、创建执行对象
            Statement  st = con.createStatement();
       6、执行Sql语句
            int  i = st.executeUpdate("增删改sql语句");
            ResultSet rs = st.executeQuery("查询语句");
       7、处理结果
            if(i>0){修改成功}
    
            
       8、关闭连接,先创建的后关闭,注意异常处理
            st.close();
            con.close();

四、PreparedStatement接口
       1、Statement在执行sql语句时,可能会遭受“sql注入攻击“
        
            

    2、使用PreparedStatement进行sql语句”预编译“,可以有效避免注入攻击,在编译程序文件时就进行,不会在运行中反复编译,效率更高。
         其他步骤一致,只在创建执行对象和执行sql语句时不同
         //5、创建执行对象
        String sql="select * from users where username=? and password=?";
        st =con.prepareStatement(sql);
        //绑定参数
        st.setObject(1, name);
        st.setObject(2, pwd);
        //6、执行Sql

        ResultSet rs = st.executeQuery();

五、JDBC常见的异常
       1、No value specified for parameter 3   
            占位符?比实际绑定的参数多

       2、Parameter index out of range (3 > number of parameters, which is 2
            占位符比实际参数少

        3、You have an error in your SQL syntax
            Sql语句语法错误

        4、Communications link failure
            数据库服务没有启动


七、将数据库中查出的数据,封装到对应的实体类,可以添加到集合(具体看案例)


=================java 分层开发

一、分层开发
       1、将功能由大化小,分而治之,提高开发效率
       2、专注实现自己的功能,提高质量
       3、便于方法重用、程序扩展

二、分层模式:
       两层:Dao --> Ui
       三层:Dao --> Biz -->Ui 
       
       Dao:是一个数据库的表与程序中类的转换器,也可以叫做数据存取对象,专门负责操作数据库,进行增删改查

       Biz:是业务逻辑层,用来隔离用户与Dao层,将用户需求转化成数据操作,调用Dao层对应的方法。
        
       Ui:界面层,直接面对用户,调用Biz的方法。

三、使用分层开发和通用增删改查Dao的步骤
        1、先准备分层工程
            

        2、准备公共的BaseDao
            

        3、开始实现某个功能
             先从Ui开始,制定需求的方法,调用Biz层对应的方法
             由Biz层的方法决定调用Dao的哪些数据库增删改查的方法
             再Dao层写出对应Biz所需求的操作
        比如:Ui层有“注册”需求,提供用户信息
                  Biz判断注册需求中,需要两个操作,第一查找用户是否存在,第二用户不存在做数据库新增
                  Dao就只负责写查找用户方法和新增方法

             
        4、进行异常处理


======================GUI

一、GUI
       Graphical User Interface  图形用户接口

       有两大方案:
       awt,位于java.awt包中,用来建立图形界面
       swing,位于javax.swing包,以awt为基础,有更灵活的组件能制作出更优雅的界面。

二、图形用户界面的结构:
       1、先有窗体,JFrame
       2、再添加组件,Component

三、开发图形界面的步骤:
       1、创建一个类,继承JFrame
       2、定义布局
       3、向窗口添加组件
       4、为组件添加响应事件

四、如何创建JFrame窗体
       1、定义一个类,继承JFrame
            public class JFrame1 extends JFrame{
            }

        2、编写自定义窗体类的构造方法
            public JFrame1(){
                 this.setTitle("这是我的第一个窗体");
                 this.setSize(500, 300);
                 this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            }
            setTitle():   设置窗体的标题
            setSize():设置窗体的宽高
            setDefaultCloseOperation():设置窗体关闭时进行的操作
                    该方法的参数类型:
                    EXIT_ON_CLOSE    关闭窗口时立即终止程序
                    DISPOSE_ON_CLOSE :自动隐藏并释放窗体
                    DO_NOTHING_ON_CLOSE : 关闭时什么都不做
            setVisible():设置窗体是否可见,默认为false,通常写在构造方法最后一行
            setLocationRelativeTo(null):设置窗体在屏幕居中,如果null换成另一个窗体对象,则位于该窗体的中央。


五、JPanel
        面板,是Swing中其他组件的容器
        默认布局方式:流式布局,从左到右,从上到下

        使用步骤:
        JPanel  jpanel = new JPanel();
        this.add(jpanel);//将面板添加到窗体

六、JLabel、JTextField
       JLabel标签:专门放置纯文本,不可直接在界面中编辑
       JTextField文本框:相当于input,可以输入内容

       1、JLabel
      JLabel lbl1 = new JLabel("韬睿科技欢迎您");
      lbl1.setHorizontalAlignment(JLabel.CENTER);//JLabel改变文字的对齐方式
      lbl1.setFont(new Font("宋体", Font.PLAIN, 12));//JLabel改变文字的大小类型
       jpanel.add(lbl1);//添加到面板
    

       2、JTextField
       JTextField jtxt1 = new JTextField(20);//参数中的20为文本框的长度
       jpanel.add(jtxt1);//添加到面板

        3、JButton
        JButton btn = new JButton("按钮");//创建按钮对象
        jpanel.add(btn);//添加到面板

        4、JPasswordField
        JPasswordField  jtxt1 = new JPasswordField(20);//参数中的20为文本框的长度 
       jpanel.add(jtxt1);//添加到面板
       jtxt1.setEchochar('*');//设置隐藏显示的字符形状

七、常用布局方式
       1、空布局        null
       2、流式布局     FlowLayout    从左到右,从上到下
       3、边界布局     BorderLayout    分东南西北中,默认居中
       4、表格布局     GridLayout     按表格的行列
 
       使用空布局:
       面板/窗体对象.setLayout(null);  //设置为空布局
       组件对象.setBounds(x,y,width,height);//x为水平距离,y为垂直距离,以组件的左上角为准

八、设置背景、字体颜色大小
       组件对象.setBackground(Color.颜色值)//设置背景
       组件对象.setFont(new Font(字体类型,字体风格,字体大小));
             比如:setFont(new Font("微软雅黑",Font.BOLD,20));

       组件对象.setForeground(Color.颜色值)//设置字体颜色



============================Swing事件

一、什么是事件
       由某些特定情况下发生的某种行为的过程,程序中比如点击登录按钮进行登录

       1、组成:
            事件:就是发生的事件、行为操作
            事件源:由谁来触发这个事件的,比如鼠标单击、键盘按下,“谁干的”
            事件监听器:就是用来监听事件源,这样才能知道事件是否被触发,“什么时候干”
            事件处理方法:就是事件中详细的行为,就是要“干什么”

       2、步骤:
            A、首先要有组件对象、事件源
            B、创建监听器
            C、编写事件

二、提示框
       JOptionPane.showMessageDialog(null,"提示信息");
       JOptionPane.showConfirmDialog(null, "提示信息", "提示框的标题",
      JOptionPane.CANCEL_OPTION);
       最后一个参数,是弹框的按钮选项,有很多种。
       CANCEL_OPTION:确定和取消
       OK_CANCEL_OPTION:是、否、取消


三、监听器使用的三种方式
       1、直接用匿名内部类
             //给登录按钮绑定点击事件
                btn.addActionListener(new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                          //判断用户名和密码是否正确
                           if("admin".equals(jtxt.getText())&& "123456".equals(jtxt1.getText())){
                                     new FlowLayoutDemo();
                                     //将当前窗体关闭
                                     JFrame1.this.dispose();
                           }else{
                                 JOptionPane.showMessageDialog(null, "账户密码错误");
                            }
                    }
                });
            注意:匿名内部类是独立的一个类,在该类中使用this访问的是它本身
                      而我们通常需要的不是它,因此要指向外部的那个类则需要类名.this

        2、内部类
   	public class JFrame1 extends JFrame{
           JButton btn;
           public JFrame1(){    
               btn = new JButton("登          录");
               btn.addKeyListener(new KeyListers());
               //设置登录按钮为该窗体默认按钮
               this.getRootPane().setDefaultButton(btn); 
           }
           
           class KeyListers extends KeyAdapter{
             @Override
             public void keyPressed(KeyEvent e) {
               if(e.getKeyText(e.getKeyCode()).equalsIgnoreCase("Enter")){
                  btn.doClick();
                }
             }
           }
      }
           注意:
               1、内部类中不能访问外部类的局部变量,但是可以访问成员变量

 3、以本类作为监听器
            public class JFrame1 extends JFrame implements ActionListener{

            @Override
            public void actionPerformed(ActionEvent e) {
                 //由于一个窗体中有很多组件
                //这种方式一定要在事件方法中,判断事件源
                e.getSource();
            }
      }

=================主题与布局

一、主题
       一种设置界面组件风格的工具

       使用:
       JFrame.setDefaultLookAndFeelDecorated(true);//允许设置外观装饰
       UIManager.setLookAndFeel("主题名");//设置主题
    
        注意:必须在JFrame对象创建之前先写,最好在构造方法第一行就写

       主题名:
       jdk自带:
                javax.swing.plaf.metal.MetalLookAndFeel
                com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel
                com.sun.java.swing.plaf.motif.MotifLookAndFeel
                com.sun.java.swing.plaf.windows.WindowsLookAndFeel
                com.sun.java.swing.plaf.windows.WindowsClassicLookAndFeel

 		JTattoo:外部导入(与Mysql驱动包导入方式一致)
            
                com.jtattoo.plaf.noire.NoireLookAndFeel  柔和黑
                com.jtattoo.plaf.smart.SmartLookAndFeel 木质感+xp风格
                com.jtattoo.plaf.mint.MintLookAndFeel  椭圆按钮+黄色按钮背景
                com.jtattoo.plaf.mcwin.McWinLookAndFeel 椭圆按钮+绿色按钮背景
                com.jtattoo.plaf.luna.LunaLookAndFeel  纯XP风格
                com.jtattoo.plaf.hifi.HiFiLookAndFeel  黑色风格
                com.jtattoo.plaf.fast.FastLookAndFeel  普通swing风格+蓝色边框
                com.jtattoo.plaf.bernstein.BernsteinLookAndFeel  黄色风格
                com.jtattoo.plaf.aluminium.AluminiumLookAndFeel 椭圆按钮+翠绿色按钮背景+金属质感
                com.jtattoo.plaf.aero.AeroLookAndFeel xp清新风格
                com.jtattoo.plafacryl.AcrylLookAndFeel 布质感+swing纯风格

二、布局
        一般用于JPanel这类顶层容器,让容器内的组件按既定的方式摆放,
	好处就是可以兼容不同的界面分辨率大小

      布局管理器:LayoutManager
      布局类:
            FlowLayout:流式布局,从左往右,直到最右边摆放不下自动换行
            可在设置组件的布局方式时设置默认对齐方式(有Left左对齐、Right右对齐、Center居中)
            jpanel.setLayout(new FlowLayout(FlowLayout.LEFT))

	    BorderLayout:边界布局,分东(East)、南(South)、西(West)、北(North)、中(Center)五个方向设置位置
            特点:默认居中,每个方向组件大小是靠内容撑开,东西向的宽度需要设置,南北向的高度需要设置。居中的大小无法设置
            

            GridLayout:网格布局,按行和列进行规律的布局。
            特点:很整齐,可以单行、单列进行布局,也可以多行多列,
            创建布局时,构造方法中有4个参数:
            int rows :行
            int cols :int hgap: 水平间距
            int vgap: 垂直间距

	CardLayout:卡片布局,可以让面板重叠在一起,像卡片一样翻页
            使用的步骤:
            先添加按钮,再在卡片面板中添加子面板,通过按钮的点击事件,调用卡片布局的方法进行切换。

            卡片布局的方法:
            CardLayout.show(父容器对象,子面板的名字);//使用该方法,创建子面板的时候,添加到父容器的方法需要两个参数,比如:
            fuPanel.add(子容器对象, “子容器名”);
            
            java.awt.CardLayout.first(父容器对象)
            切换到第一个
            java.awt.CardLayout.previous(父容器对象)
            切换到上一个
            java.awt.CardLayout.next(父容器对象)
            切换到下一个
            java.awt.CardLayout.last(父容器对象)
            切换到最后一个

============================选择组件

一、JComboBox
      1、创建对象
            JComboBox<类型> cbx = new JComboBox<>();

      2、给下拉列表添加列表项
           addItem();
           //准备一个数组或集合
           String[] str = {"长沙","株洲","湘潭"};
           //循环这个数组,逐个 将内容添加到JComboBox
          for (String s : str) {
              cbx.addItem(s);
          }
           或者准备好一个数组,在创建JComboBox的时候放入构造方法
           JComboBox<类型> cbx = new JComboBox<>(数组名);

     3、常用的属性和方法:
           setEditable(boolean):设置可编辑,默认为false
           addItem(Object anObject):添加列表项,可以是任意类型
           getItemCount():获得列表项的个数
           getSelectedItem():获得选中的列表项,返回Object对象

     4、事件:
          ItemListener

          //给JComboBox添加事件
     cbx.addItemListener(new ItemListener() {
        @Override
        public void itemStateChanged(ItemEvent e) {
          //判断当前点击的选项,是否是被选中的
           if(e.getStateChange()==ItemEvent.SELECTED){
             //e.getItem()就是获得选中项
             System.out.println(e.getItem());
          }
        }

     });
            
二、JRadioButton
       1、创建一个ButtonGroup按钮分组
             ButtonGroup bg = new ButtonGroup();
       2、创建JRadioButton
             btn1 = new JRadioButton("男");
             btn2 = new JRadioButton("女");
       3、添加进组
             bg.add(btn1);
             bg.add(btn2);
             然后只能将JRadioButton直接添加到面板
             pnl.add(btn1);
             pnl.add(btn2);
       4、设置按钮状态
            //默认选中
            btn2.setSelected(true);
            //判断是否选中
            boolean isSelected()

       5、给单选按钮绑定事件,以本类作为监听器
        //给JRadioButton添加监听器,this表示本类对象,因为是以本类作为监听器的实现类
     btn1.addItemListener(this);
      btn2.addItemListener(this);
    @Override
   public void itemStateChanged(ItemEvent e) {
     //e.getSource()可以获得按钮对象
     JRadioButton obj = (JRadioButton)e.getSource();
     if(obj==btn1){
        //获得点击的单选按钮的文本值
        System.out.println(obj.getText());
     }

   }

三、JCheckBox
      使用方式和JRadioButton的创建以及方法和事件都差不多,不用分组,可以多选



=====================================JTable

目标:
        JDialog
        JTable

一、JDialog
        模块化窗体,这类窗体一旦打开,不可操作其他窗体。
        使用方式与JFrame类似。

二、JTable
       是窗体中用于展示数据的视图,JTable本身不可以存储数据,也不可以直接对数据进行操作。
       在Swing中,提供了几种可操作数据和提供数据的模型接口:
            TableColumnModel    列模型
            ListSelectionModel    选中模型
            TableModel    表模型(常用)

       1、JTable的使用步骤
           //创建表格的模型
         Object[] head = {"姓名","性别","年龄","就诊科室"};
         //主体内容
         Object[][] body = new Object[2][head.length];
         body[0][0] = "xxxx";
         body[0][1] = "男";
         body[0][2] = 12;
         body[0][3] = "儿科";
         //表模型
         TableModel tm = new DefaultTableModel(body,head);
           //创建表
         JTable table = new JTable(tm);
                 //table.setModel(tm); //创建表的时候没有加模型,可以使用setModel()
                //创建面板
         JScrollPane jsp = new JScrollPane(table);
            
       2、设置表格的不可编辑(在创建表格时就设置)
      JTable table = new JTable(tm){
        @Override
        public boolean isCellEditable(int row, int column) {
          return false;
        }
     };

        3、设置行高、居中、线条颜色
      //设置表格内容居中
     DefaultTableCellRenderer render = new DefaultTableCellRenderer();
      render.setHorizontalAlignment(SwingConstants.CENTER);
      table.setDefaultRenderer(Object.class, render);
     //线条颜色
      table.setGridColor(Color.red);
     //设置行高
     table.setRowHeight(50);

        4、绑定事件
       table.addMouseListener(new MouseAdapter() {
        @Override
        public void mouseClicked(MouseEvent e) {
          //双击事件
           if(e.getClickCount()==2){
             //拿当前选中行的每列的值
             int row = table.getSelectedRow();
             String name = table.getValueAt(row, 0).toString();
             String sex = table.getValueAt(row, 1).toString();
             System.out.println(name +"\t" + sex);
          }
        }

     });

三、二维数组
          数据类型[][]   二维数组名  = new 数据类型[行数][列数];

      赋值:先给二维数组的行赋值(数组)
                二维数组名[下标]  =  数组;

                再给数组的某一行的某一个位置赋值(对应类型)  
                二维数组名[行下标][列下标]  =  值;

      取值:
            二维数组名[行下标][列下标]=========================IO流(一)

一、持久化
      将程序运行时内存中的数据永久的保存到电脑文件或数据库中
      
      1、存入文件中,使用IO流读和写
      2、存入数据库,使用JDBC进行存和取

二、文件
      1、File类
            代表电脑存储中的文件对象或文件夹对象,可以对文件和文件夹进行操作

      2、创建文件对象
            File  file = new File("路径\\文件夹名\\文件名.扩展名");
           有扩展名代表文件,无扩展名可代表文件夹
 
      3、方法
           file.mkdirs();    创建文件夹
           file.createNewFile();创建文件(异常处理)
           file.exists();    判断文件对象是否存在
           file.getPath();  获得文件路径
           file.getAbsolutePath();  获得文件的绝对路径
           file.getName();获得文件名称
           file.isDirectory();判断是否为文件夹
           file.isFile();      判断是否是文件
           file.lastModified() 获得文件的最后修改时间,long类型
           file.delete()    删除文件
           file.length()    获取文件长度
	具体操作请看案例1

三、IO流
       I    代表input  输入
       O  代表output输出
       Stream   代表在内存和文件中输入输出的数据流动
    
       InputStream:输入流,从硬盘文件读取到内存中进行处理
       OutputStream:输出流,从内存写入到硬盘文件中永久保存

       1、FileOutputStream:字节输出流,输出流的子类
       使用:
        //创建输出流
        OutputStream os = new FileOutputStream("abc.txt",true);
        System.out.println("请输入一串字符:");
        //从控制台输入一串字符
        String s = new Scanner(System.in).next();
        //将字符串写入文件中
        os.write(s.getBytes());//将String类型转成byte数组
        os.write(s.getBytes(),开始位置,写入的字节个数);
        注意:一个中文汉字占2个字节
              FileOutputStream可以直接创建文件进行写入,
	构造方法中第二个参数为是否追加,默认为false,
	每一次都会创建新的文件替换原来的。如果为true,则在原文件中追加

	2、FileInputStream:字节输入流,从硬盘中读取到程序内存中
        使用:
        //创建输入流
        InputStream os = new FileInputStream("abc.txt");
        //将文件中的内容读取
        byte[] b = new byte[10];
        int x = os.read(b);//先读取一行,读完数组会暂时存入byte数组中
        //如果后面没有内容,read方法返回值为-1
        while(x!=-1){
           System.out.println(new String(b));
           //读取下一行
           x = os.read(b);
        }

	  3、复制(边读边写)
具体看案例

=============IO流2
IO流(二)

一、字符流
       专门用来处理字符、字符串等等
       (字节流可以用来处理文本、图片、音频、视频等等,字符流只能处理文本文件)

二、字符流
       读取:Reader、FileReader(字符从硬盘(或其他)读到内存)
       写:Writer、FileWriter(内存中的字符写入硬盘(或其他))

三、字符输入流
       1、创建
       Reader  r = new FileReader("文件路径")2、读取
       char[] c  = new char[1024];
       int x = r.read(c);//read方法返回值是读取到的字符个数,读到末尾返回-1
       while(x!=-1{
                x = r.read(c);//下一次读取
       }
       3、关闭流
            r.close();
四、字符输出流
       1、创建
       Writer  w = new FileWriter("文件路径")2、读取
       char[] c  = new char[1024];
       w.write(c);
       3、关闭流
        w.flush();
        w.close();


五、缓冲流
       1、作用:将读取的数据存入内存中的某个区域(缓冲区),一次性进行读或写,可以加快读写的速度(可以一次读一行或写一行)

        2、本质上,还是流,只是将普通的字符流包装成高级流
              
        3、包装缓冲输入流BufferedReader
             Reader  r =new FileReader();
             BufferedReader br = new BufferedReader(r);

        4、包装缓冲输出流BufferedWriter
              Writer   w = new FileWriter();
              BufferedWriter bw = new BufferedWriter(w);
            


==================正则表达式 regex
正则表达式描述了一种字符串的匹配模式,可以用来检查一个串是否含有某子串,或是特定字符串是否匹配特定规则.
换句话说就是记录文本规则的一段代码。其目的在于精确地过滤字符,找到想要的字符。
结构:正则表达式是由普通字符(例如字符 a 到 z)以及特殊字符(称为"元字符")组成的文字模式
 
第一小节:元字符 
下面是一些常见的元字符
\b  代表单词的开头或结尾,即单词的分界.匹配的是一个位置。 
'en' 很多单词都包含,women men engage ,如果想要准确地找'en'这个单词,
应当使用\b来表达分界,例如:\ben\b

\d 匹配数字 例如 :0~9


\s 匹配任意空白字符 

\w 匹配字母数字或下划线或汉字 例如:a-z或0~9或_或汉字

.  匹配除换行符以外的任意字符 

\n 换行符

^ 匹配字符串的开始,多用在输入验证
$ 匹配字符串的结束,多用在输入验证
*  代表数量,,指定前边的内容可以连续重复使用任意次
 
学习正则的表达式最好的方法是从例子学习,下面将介绍大量的实例

eg : \bhi\b.*\blucy\b  
解释:显示一个单词hi,中间跟任意字符,不包括换行,最后是lucy

eg: 0\d\d-\d\d\d\d\d\d\d\d 
 解释:以0开头然后两个任意数字然后-然后8位任意数字
为了避免烦人的重复可以{数字}来表达次数,有关次数在后文会详细介绍
eg: 0\d{2}-\d{8} 解释:0开始然后是两位数字,然后是-,然后是8位数字,表示必须连续出现的匹配次数,其中-并不是元字符 ,只是普通字符,匹配它本身而已
eg: ^\d{5,12}$  解释:以数字开头,数字结尾,长度512位
 
 
第二小节:字符转义 \
如果想查询元字符.*本身,你没办法指定他们,
这时候就要使用\来取消这些字符的特殊意义,
因此,使用\.\* ,查找‘\’本身也要转义\\
eg: www.baidu.com   www\.baidu\.com   
eg:c:\\user   c:\\\\user  
 
第三小节:重复又称限定符  {}
类似 *+{2},{2,5} 都是表示次数的方式。
*:多次或0+1次或多次
?0次或1{n}:n次
{n,}n次或多次
{n,m}:n-m次
eg: window\d+  解释:windows后跟一个或多个数字
eg: ^\d{m,n}$      解释:m到n位数字
eg: \ba\w+y\b     解释: 一个以a开头,中间是1个或多个任意字符,然后是以y结尾的单词  eg: any , 
 
 
第四小节:字符类 []
如果想要查找数字字母,空白很简单因为有\w \d \s ,但是对于预定义字符集没有办法。这时可以自己定义使用字符类 
[a-z]  小写字母a到z任意一个,[A-Z]大写字母A到Z任意一个。[0-9]任意一个数字,其效果与\d类似。[a-z0-9A-Z]等同于\w。
eg:[aeiou]                      解释:匹配任意一个英文元音字母 
eg: [,.!]                       解释:匹配任意一个标点
eg:^[a-zA-Z][a-zA-Z0-9_]{4,15}$      
解释:判断帐号是否合法(字母开头,然后是字母数字下划线结尾,出现415)
eg: ^[a-zA-Z]\w{5,17}$          解释: 匹配密码(以字母开头不区分大小写,然后是字母数字下划线结尾 ,出现517次,与上例异曲同工)
eg:[\u4e00-\u9fa5]             解释: 匹配中文字符的正则表达式
 
 
 
 
第五小节:分支条件 |
分支条件在正则表达式里指的是有几种匹配规则 ,如果满足任意一种规则都匹配
用|把不同的规则隔开,
注意:使用分支条件是有顺序的,优先匹配到最先匹配到的分支,匹配分之是将会从左到右如果满足了某个分之就不再管其他分支 。
eg : \d{5}-\d{4}|\d{5}               解释:表达式匹配5位数字然后-然后4位数字,或者直接5位数字,
如果把分支顺序改一下则是 
eg:\d{5}|\d{5}-\d{4}               解释: 如果匹配到5位数字,则后面的分支就不再进行匹配。         
eg :  0\d{2}-\d{8}|0\d{3}-\d{7}  					解释:匹配一种三位区号8位本地号码或是一种4位区号,7位本地号码
eg:^\d{15}|\d{18}$                解释:身份证号(15位、18位数字), 以数字开头,数字结尾,15位数字\d{15}18位数字\d{18} 
eg:^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$  
解释:手机号码。遇到较长的正则表达式记住要拆开分解来看。先不看括号里的
                                                                                                                     大框架是^()\d{8}$ ()里的某些东西开头,数字结尾,共8位数字,然后是()里的内容,就是对手机号
                                                                                                                     前三位的特殊性进行规则匹配
                                                                                                                    13[0-9]14[5|7]15[0|1|2|3|5|6|7|8|9]18[0|1|2|3|5|6|7|8|9] 就是四个分支而已。
第六小节:分组()
正则表达式用处最多的就是()了,()在正则表达式里成为分组。
分组常常和重复即限定符连起来一起使用。用以表达括号里的东西作为一个整体重复出现多少次。
eg:(\w+\d?{3}   解释:数字字母下划出现一次或多次然后出现0次或1次一个数字,这样的整体出现3次。
eg: ^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$    
解释:Email地址  开头^是一次或多次+任意字符\w分组(字符类[-+.]出现-+.任意一个,
                                                                                             然后是一次或多次\w) 这个分组出现0次或多次,
                                                                                             然后是@任意多个\w接着又是分组([-.]\w+)出现*次,然后是出现一个.然后是\w+最后是结尾$分组([-.]\w+* 
                                                                                             email的标准是 用户名@邮箱域名.com       有的还会有. eg:zhangsan@sina.com   zhangsan.Mr.kk@sina.com
eg: ^((0?[1-9])|((1|2)[0-9])|30|31)$         解释:一个月的31(0109131)
eg: (\d{1,3}\.){3}\d{1,3}                          解释:简单的ip地址匹配   13位数字然后. 这个组合出现3次最后再加一个13位的数字 eg:192.0.0.1
eg:((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)  解释:完整的ip4地址匹配 拆解来看结构是(){3}(),分组作为一个整体出现3次,然后又是一个分组。
                                                                                                    括号里(2[0-4]\d|25[0-5]|[01]?\d\d?)继续拆分其实就是三个分支,2[0-4]\d  200-24925[0-5]  250-255[01]?\d\d?    0-9或者0-99或者199 [01] 匹配任何一个数字0,1
                                                                                                    总体来看就是满足这三个分支任意一个都行,然后出现一个.这样的分组出现三次,最后一个分组一样就是不带.
                                                                                                    这 样就好理解多了。
第七小节:反义
 
eg: 想查找除了数字以外任意字符都行 这时需要用到反义
\W :匹配任意不是字母,数字,下划线,汉子的字符 大写W
\S匹配任意不是空白的字符   大写S
\D匹配任意非数字的字符   大写D
\B匹配不是单词开头或结束的位置   大写B
[^x]匹配除了x的任意字符
[^aeiou]匹配除了aeiou这几个字母以外的任意字符
\S+匹配 1个或多个不是空白的字符
eg:<a[^>]+>  解释: 匹配用尖括号括起来的以a开头除了>的一个或多个字符,:匹配用尖括号括起来的以a开头的字符串
 
 
第八小节:正则表达式的运算符优先级
正则表达式从左到右进行计算,并遵循优先级顺序,这与算术表达式非常类似。

相同优先级的从左到右进行运算,不同优先级的运算先高后低。
下表从最高到最低说明了各种正则表达式运算符的优先级顺序:

运算符				描述
\				转义符
(), (?:), (?=), []		圆括号和方括号
*, +, ?, {n}, {n,}, {n,m}	限定符
^, $, \任何元字符、任何字符	定位点和序列(即:位置和顺序)
|				替换,"或"操作
 
第九小节:后向引用 (exp) ,(?<name>exp),(?''exp)
 
百科下来的术语是这样解释:使用小括号指定一个子表达式后,匹配这个子表达式的文本(也就是此分组捕获的内容)可以在表达式或其它程序中作进一步的处理。默认情况下,每个分组会自动拥有一个组号,规则是:从左向右,以分组的左括号为标志,第一个出现的分组的组号为1,第二个为2,以此类推。
后向引用 用于重复搜索前面某个分组匹配的文本 
其核心就是捕获
(exp) exp匹配到的东西放到默认组里,后续用这个组里匹配到的东西 就用\1
(?<name>exp) exp匹配到的东西放到名为name的组里,后续用这个组里匹配到的东西 就用 \k<name>
eg: 第一种写法  \b(\w+)\b\s+\1\b   解释:\1代表分组1匹配的文本, 首先是一个单词然后是单词开始和结束之间的多余1个的字母或数字会被捕获到编号为1的分组,然后是1个或几个空白字符,最后是分组1中捕获的内容, eg summer summer
      第二种写法  \b(?<word>\w+)\b\s+\K<word>\b
      第三种写法   \b(?'word'\w+)\b\s+\K'word'\b
eg:  第一种写法  \b(a\w+y)\b\s+\1\b  解释:单词axxy然后被捕获放到1号组里,然后\s空格,然后是调用1号组捕获到的东西,可能就是 any  any
      第二种写法  \b(?<hehe>a\w+y )\b\s+\K<hehe>\b
      第三种写法   \b(?'hehe'a\w+y )\b\s+\K'hehe'\b
 
第十小节:零宽断言(?=exp)(?<=exp)
所谓断言就是表达式exp
零宽断言就是查找指定某些内容之前或之后的内容而不包括表达式部分
(?=exp) 零宽度正预测先行断言.断言自身出现的位置之后能匹配的表达式
eg:    \b\w+(?=ing\b)   解释:匹配\w+之后以ing结尾的单词但不包括ing的部分  eating 去掉ing的部分 即 eat
eg:   \b[aeiou]\w+(?=ed\b)   解释: 匹配元音字母的任意一个开头,然后是任意字符,1次或多次,最后是以ed结尾的单词但不包含ed的部分, apped 去掉ed  即app
 
(?<=exp)  零宽度正回顾后发断言,它断言自身出现的位置的前面能匹配表达式exp
(?<=\pre)\w+\b 匹配单词以re开头但不包括re的部分  Prefixes 即 fixes
eg:(?<=\s)\d+(?=\s)  解释:(?<=\s)  零宽断言,匹配1个或多个数字,前面是(?<=\s) 但不包含空格的部分,后面是(?=\s) ,但不包含空格的部分。即以空白符间隔的数字
后向引用和零宽断言连起来使用
eg:(?<=<(\w+)>).*(?=<\/\1>)等价于 (?<=<(?<label>\w+)>).*(?=<\/\k<label>>)     解释:匹配不带属性的html标签里的内容  匹配.*前面是<1个或多个\w>,但不包含这部分,
                                                                                                                                             后面是<转义\/,捕获前面分组(\w+)的内容 >但不包含这部分
                                                                                                                                             eg: <p>xxxxx</p>,匹配的就是xxx这部分
 
第十一小节:负向零宽断言(?!exp)(?<!exp)
(?!exp)零宽度负预测先行断言
断言此位置的后面不能匹配表达式exp
eg :\d{3}(?!\d)  解释:匹配三位数字,后面不能是数字
eg:  [1-9]\d{5}(?!\d)   解释:匹配开头是19任意一位,然后是5位数字,后面不能是数字。中国邮政编码: (中国邮政编码为6位数字)
 
(?<!exp)零宽度负回顾后发断言  断言此位置前面不能匹配的表达式exp
eg:  \b ((?<![aeiou ]>)\w)+\b  解释:匹配不包含元音连续字符串的单词
eg:  (?<![0-9])\w+           解释: 匹配前面不是数字的字符
 
 
第十二小节:贪婪与懒惰
贪婪
正则表达式在满足整体表达式的规则下会贪婪尽可能多的匹配
eg: qweqweqwe     q.*e      匹配以q开始,以e结束最多字符
会匹配到 qweqweqwe  而不是 qweqwe  或者qwe

懒惰
满足整条表达式时尽可能少的匹配,
在后面加一个?即可
*? :重复任意次,但尽可能少重复
+? :重复1次或多次,,但尽可能少重复
?? :重复0次或1次,但尽可能少重复
{n,}?  :重复n次以上,但尽可能少重复
{n,m}?:重复n到m次,但尽可能少重复
eg:  qweqweqwe   q.*?e  匹配以q开始,以e结束最短字符.
会匹配到 qwe


正则表达式的20个示例
1 . 校验密码强度

密码的强度必须是包含大小写字母和数字的组合,不能使用特殊字符,长度在8-10之间。

^(?=.*\\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$
2. 校验中文

字符串仅能是中文。

^[\\u4e00-\\u9fa5]{0,}$
3. 由数字、26个英文字母或下划线组成的字符串

^\\w+$
4. 校验E-Mail 地址

同密码一样,下面是E-mail地址合规性的正则检查语句。

[\\w!#$%&'*+/=?^_`{|}~-]+(?:\\.[\\w!#$%&'*+/=?^_`{|}~-]+)*@(?:[\\w](?:[\\w-]*[\\w])?\\.)+[\\w](?:[\\w-]*[\\w])?
5. 校验身份证号码

下面是身份证号码的正则校验。1518位。

15位:

^[1-9]\\d{7}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{3}$
18位:

^[1-9]\\d{5}[1-9]\\d{3}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{3}([0-9]|X)$
6. 校验日期

“yyyy-mm-dd“ 格式的日期校验,已考虑平闰年。

^(?:(?!0000)[0-9]{4}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)|(?:[0-9]{2}(?:0[48]|[2468][048]|[13579][26])|(?:0[48]|[2468][048]|[13579][26])00)-02-29)$
7. 校验金额

金额校验,精确到2位小数。

^[0-9]+(.[0-9]{2})?$
8. 校验手机号

下面是国内 131518开头的手机号正则表达式。(可根据目前国内收集号扩展前两位开头号码)

^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\\d{8}$
9. 判断IE的版本

IE目前还没被完全取代,很多页面还是需要做版本兼容,下面是IE版本检查的表达式。

^.*MSIE [5-8](?:\\.[0-9]+)?(?!.*Trident\\/[5-9]\\.0).*$

10. 校验IP-v4地址

IP4 正则语句。

\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\b
11. 校验IP-v6地址

IP6 正则语句。

(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))
12. 检查URL的前缀

应用开发中很多时候需要区分请求是HTTPS还是HTTP,通过下面的表达式可以取出一个url的前缀然后再逻辑判断。

if (!s.match(/^[a-zA-Z]+:\\/\\//))
{
    s = 'http://' + s;
}
13. 提取URL链接

下面的这个表达式可以筛选出一段文本中的URL。

^(f|ht){1}(tp|tps):\\/\\/([\\w-]+\\.)+[\\w-]+(\\/[\\w- ./?%&=]*)?
14. 文件路径及扩展名校验

验证windows下文件路径和扩展名(下面的例子中为.txt文件)

^([a-zA-Z]\\:|\\\\)\\\\([^\\\\]+\\\\)*[^\\/:*?"<>|]+\\.txt(l)?$
15. 提取Color Hex Codes

有时需要抽取网页中的颜色代码,可以使用下面的表达式。

^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$
16. 提取网页图片

假若你想提取网页中所有图片信息,可以利用下面的表达式。

\\< *[img][^\\\\>]*[src] *= *[\\"\\']{0,1}([^\\"\\'\\ >]*)
17. 提取页面超链接

提取html中的超链接。

(<a\\s*(?!.*\\brel=)[^>]*)(href="https?:\\/\\/)((?!(?:(?:www\\.)?'.implode('|(?:www\\.)?', $follow_list).'))[^"]+)"((?!.*\\brel=)[^>]*)(?:[^>]*)>
18. 查找CSS属性

通过下面的表达式,可以搜索到相匹配的CSS属性。

^\\s*[a-zA-Z\\-]+\\s*[:]{1}\\s[a-zA-Z0-9\\s.#]+[;]{1}
19. 抽取注释

如果你需要移除HMTL中的注释,可以使用如下的表达式。

<!--(.*?)-->
20. 匹配HTML标签

通过下面的表达式可以匹配出HTML中的标签属性。

<\\/?\\w+((\\s+\\w+(\\s*=\\s*(?:".*?"|'.*?'|[\\^'">\\s]+))?)+\\s*|\\s*)\\/?>



=============线程
一、什么是线程?
	简单的讲,线程就是一个程序内部的顺序控制流。也可以说是程序中不同的执行路径。

	A、单线程:main执行m1,再m1调用m2,再m3...执行完返回时,先回到m3,再到m2→m1→main

	B、多线程:main执行m1,m1调用其他方法的时候,main方法无需等待返回,直接可以再执行其他的方法。

二、多线程的工作原理?
	程序运行时,一个主线程会立即运行,由主线程产生其他线程。
	这些子线程会争夺cpu的占用权,每个线程所占的“时间片”很短暂,
	JVM会不断的转换时间片的拥有权,哪个线程得到,哪个就运行。
	主线程最后完成执行,通常执行一些关闭动作,释放资源。


三、如何创建线程?
	1、第一种方式:继承Thread
	
	   A、创建两个类分别继承Thread,并重写run()方法,线程需要执行的操作在run()方法中。

	   B、在主线程中,new线程子类的对象,并调用start()启动线程。


	2、第二种方式:实现Runnable接口
	 
	   Runnable接口:提供一种激活方式(给非Thread子类),由于Thread是它的实现类,因此,它可以让无法继承Thread类的类具备线程特性,也就是说可以调用start()方法。

	   A、创建两个类分别实现Runnable接口,并重写run()方法。
	
	   B、在主线程中,new Runnable接口实现类的对象,再用Thread构造方法转换该对象,让他具备线程特效,再调用start()。


四、Thread的休眠方法:sleep()
	让线程进入就绪状态,暂时中止,sleep(millis)参数指定单位为毫秒。

    案例:每一秒钟输出一次当前时间

	while(true){
		//获取当前时间
		System.out.println(new Date().toLocaleString());
		try {
			new Thread().sleep(1000);//一秒钟休眠一次
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
五、线程的优先级:
	数字越大,优先级越高,默认为5

	Thread.NORM_PRIORITY:默认
	Thread.MAX_PRIORITY:最大
	
	使用方法:(设置优先级)
		线程对象.setPriority(Thread.MAX_PRIORITY|数字)


六、线程同步*
	当多个线程同时操作一个对象(共享资源),使用了同步,cpu会给被占用的资源上锁,其他线程使用不了cpu,要等第一个线程释放后,其他线程才能使用。

	线程同步的步骤:
	
	A、创建一个线程类,创建方法,使用synchronized修饰这个方法。如:
	   @Override
		public void run() {
		//线程同步   给定同一个对象
		synchronized (this.b) {
			b.notify();//调用 notify( )方法进入监视器
			try {
				功能代码块
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			try {
				b.wait();//wait()方法告知被调用的线程退出监视器并进入等待状态
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		}

	B、创建第二个线程类,方式如上,只是功能代码块变化
	
	
	C、在主线程中创建一个实例化资源对象,创建两个接口实现类对象,
	包装成线程,再分别启动线程。
	public static void main(String[] args) {
		//资源对象
		ZiYuan z1=new ZiYuan(10);
		//创建Runnable实现类的对象,封装成线程。并启动。
		Thread thread=new Thread(new T1(z1));
		thread.start();
		
		Thread thread1=new Thread(new T1(z1));
		thread1.start();
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值