Java基础总结(超详细)

这是本人在学习Java基础时的笔记,仅供参考。

如有错误,请指出,谢谢啦!

目录

【1】接口、包、类、异常等

         一、接口:

二.异常:

【2】字符串

一.StringBuilder:可变字符串类型:

二.构造器:

三.查找字符串中的字符/子字符串的位置

四.截取子字符串的方法:

【3】面向对象、数组

一.面向过程:C,Basic,Pascal

扫描二维码关注公众号,回复: 4354581 查看本文章

二.类:用来定义一种抽象数据类型 

三、对象:是类产生的个体,即类的实例化            

四.构造方法:

五.this关键字:

【4】继承

一.继承:

二.关键字extends,用于继承语法

三.继承的传递性:

【5】重写、封装

一.回顾:

二.Object:是所有引用类型的顶级父类,

三.equals(Object obj)

四.访问权限控制修饰词

【6】数组、集合、list

一、集合概念:是一个用于存储多个对象的容器(对象).容器内的对象

二、与数组的区别?

三、集合框架中包含多种接口,抽象类,实现类等,用此来满足我们所需要的用于存储数据的数据结构。 

四、Collection与Collections的区别

五、子接口:List,Set,Queue

六、数组与集合之间的转换

七、 Iterator:迭代器接口

八、ArrayList& LinkedList

九、接口Queue

【7】list、set

一.复习:

二.泛型机制:

二.List排序

三.Set接口:

【8】map

一.Set集合:

二.Set集合的遍历

三.Map接口:集合框架中的另一个父接口

四.Map接口的子类:

五.javaBean规范:

【12】IO流01

一、概念

二、常用构造器

三、 绝对路径:是从根目录开始写的路径

四、常用方法

五、IO流:(Input,Output)

六、IO流的分类:

【13】IO流02

一.回顾 

二.缓冲流:

【14】IO流03

 一.对象流:

二.字符流:

三.子类中转换流:

四.缓冲流:

五.文件字符流:


【1】接口、包、类、异常等

一.接口

API:应用程序编程接口,即jdk文档手册,里面以类的形式提供了

    很多常用的功能。

常用的包与类:

    java.lang包:因为常用,所以不需要导包

                                 字符串,线程

    java.util包: 数组工具类,日期,集合等

    java.net包:  网络相关的  类型

    java.io包:    输入输出类型

    java.math包: 数学应用的相关类型

打包工具:javadoc

    (1)使用命令提示符界面:

               类信息中没有声明包,即使用默认包

        javadoc -d  path  *.java

        path:生成api文档的位置

   

               类信息中声明了包  如:package com

        javadoc -d  path  nameOfPackage

                如:

           javadoc -d  .\doc  com   

       

                 源文件在不同包下:

        javadoc -d  path  nameOfPackage1 nameOfPackage2....

                如:

           javadoc -d .\doc  com  demo

    (2)借助eclipse

        export--java--javadoc-->

       

              选择javadoc命令的路径

              选中要生成文档的项目

              选择生成文档的位置

===========================================

二.异常:

    在程序开发过程中出现的不正常情况,就是异常。比如,

    除数是0,参数为null,调用参数的成员变量或者方法,数组下标越界

    

异常分为两大类型

  (1)exception:程序员可以解决的:空指针,除数是0,数组下标越界

  (2)Error:程序员无法解决的:如内存溢出

 

   Throwable是这两种类型的父类

exception的分类:

      按照编译器是否检查进行分类:

  

    非检查性异常:也称之为运行时异常,即,编译器在检查语法期间,不做

                            异常检查。

    检查性异常:  也称之为编译时异常,此时,编译器会强制检查语法中的异常情况

                            如有异常,在编译期需要做异常处理 

                           

exception的结构:

   

异常的处理:

  (1)当异常出现时,终止程序

   (2)当异常出现时,我们使用处理机制进行处理异常。无序终止程序

  

       体验度:尽可能的选择异常处理机制。

异常处理机制

         基本思想:

             在可能出现异常的代码块区域,进行尝试检查,如果

             出现了异常信息,我们将这些信息封装成某一异常类型的对象。

             然后进行捕获与处理

  

 try{

     可能出现异常的代码块

   /*如果有异常,jvm会将异常信息,封装成对象

      将地址信息赋值给catch中的形参

   */

 }catch(Exception e){

          进行处理e

 }                                                

 

多catch语句块情况:

    当我们在尝试捕获异常对象时,想对多种不同的异常对象分别处理时,

    需要使用多个catch语句块   

   

  说明: 当在try中出现了异常信息,那么就不会再执行try中代码块的

             后续部分。进入相应的catch代码块中执行处理。

            

   多catch语句块情况下,catch处理的异常种类书写顺序:                                    

    先写子类异常类型,再写父类异常    

 

throw:抛出关键字,在本方法中出现的异常,不做try-catch处理。

             而是抛给调用者处理。需要使用throw关键字。

      

throws:声明异常关键字,通常用于方法的定义上,用于通知调用者            

 

    当throw的异常对象为检查性异常,方法上必须throws此异常类型

    如果throw的异常对象为非检查性异常,方法上不必throws此异常类型

   

方法重写时的throws的用法

     可行的:

           (1)可以相同

           (2)可以是部分

           (3)异常的子类型可行,可以是多个子类型  

    不行的:

           (1)不同的异常类型,不可以多声明

           (2)异常的父类型不行    

finally:

   是为try-catch提供了统一的出口。不管try与catch语句块是否

   发生了异常,最终都会执行finally里的代码块 。

    通常用于处理一些资源的关闭等操作:

           如读取文件时关闭操作,或者是删除临时文件

/  finally语句块可选。

【2】字符串

一.StringBuilder:可变字符串类型:

 

(字符串:底层是字符数组,及其对数组的操作)

特点:

(1)此类型是final修饰的

(2)没有重写equals方法

(3)此类型提供的大多数方法都带有返回值,

      即:  return this  返回同一个地址

二.构造器:

   StringBuilder()

///////

      构造了一个空的StringBuilder对象,初始容量为16。

   StringBuilder(String str)

      创建一个指定字符串的StringBuilder对象

常用方法:

   int length():

      返回有效字符的长度。

   StringBuilder append(Type a):

      将参数a追加到StringBuilder对象里,返回此对象

   StringBuilider insert(int index,Type a);

      将参数a插入到对象的下标index处

   StringBuilder  delete(int start,int end);

       删除此对象里的部分字符,从start开始,到end结束,注意:包前不包后    

   StringBuilder replace(int start,int end,String str);

      使用str替换此对象从start开始到end结束的子串

   StringBuilder reverse():

      将StringBuilder对象的内容进行翻转

     

StringBuffer:此类与StringBuilder用法一模一样。

      但是:

         在线程安全上考虑:

         StringBuffer线程安全

         StringBuilder线程不安全

         在执行效率上:

         StringBuffer效率低

         StringBuilder效率高  

练习:测试两种类型的效率高低。

================================================

String类型:(底层是字符数组+对数组的操作)

 

特点:

(1)是不可变的字符串类型,(不可变:对象的内容不能更改)

(2)final修饰的类型

(3)字符下标(索引/index)从0开头

(4)重写了equals方法和toString方法

(5)默认使用的是unicode字符集,任意字符都占两个字节。

 

构造器:

  String():

    创建一个空字符序列的字符串对象

  String(byte[] bs)

    创建一个字符串对象。使用默认字符集进行解码的字符串。

  String(byte[] bs,String charset)

    将字节数组使用指定字符集进行解码成相应的字符串对象

  String(char[] ch)

    将字符数组转换成字符串对象

  String(String str) 

    指定一个字符串字面量创建一个字符串对象

常用方法:

  int length():

    返回字符串对象的字符个数

  char charAt(int index):

    返回此字符序列中指定索引处的字符

  String concat(String another):

    将指定字符串another拼接到此字符序列的末尾,返回新对象

  boolean stratsWith(String prefix)/endsWith(String suffix)

    查看此字符序列是否以prefix为前缀/以suffix为后缀

  byte[] getBytes():

    将此字符串按照默认字符集编码成字节序列,返回一个新的字节数组

  byte[] getBytes(String charset)

    将此字符串按照指定的字符集编码成字节序列,返回新的字节数组

 

 

三.查找字符串中的字符/子字符串的位置

  int indexOf(int ch)

    返回字符ch在此字符串中第一次出现的下标(索引/位置)

  int intexOf(int ch,int fromIndex):

    返回字符ch从此字符串fromIndex下标开始,往后第一次出现的位置

  int indexOf(String str):

  int indexOf(String str,int fromIndex): 

     注意:返回-1,说明要找字符/子字符串 不存在查找序列中

  int lastIndexOf(int ch);

  int lastIndexOf(String str)

 

  int lastIndexOf(int ch,int endIndex)

  int lastIndexOf(String str,int endIndex)

    查找字符/子字符串截止到某一下标时,最后一次出现的位置。

 上述四个方法:

      查找字符/子字符串在此字符序列中最后一次出现的位置,找不到返回-1

     

四.截取子字符串的方法:

  String substring(int beginIndex)

         从此字符序列的beginIndex开始截取,截取到最后

  String substring(int beginIndex,int endIndex)

         从此字符序列的beginInde开始截取,截取到endIndex,包前不包后

 

字符串转成字符数组的方法:

  char[] toCharArray()

        将此字符序列变成字符数组 

 

字符串中的字母转成大写/小写

  String toUpperCase()

        将字符串中的字母都变成大写,返回新字符串

  String toLowerCase()

        将字符串中的字母都变成小写,返回新字符串

前后去空格的方法:

  String trim()

        去掉此字符序列的前与后的空格

将任意参数变成字符串对象

  static String valueOf(Type v);

    将参数v变成字符串对象       

equals方法与==的区别

  ==:用来比较是不是同一个对象

  equals:用来比较两个对象的内容是否相同

 

String类型中重写了equals方法

 

 

常量池:

   jvm在使用字符串类型时,为了提高内存的使用率,当使用字面量(常量)

      进行给变量赋值时,在方法区内提供了用于存储字面量对象的一个常量池。

   

   原理:

     当使用字面量赋值时,先去方法区内的常量池中查询是否有相同字面量的对象,

     如果有,就返回常量池中对象的地址,没有的话,在常量池中创建此字面量的对象

     再返回。

                

 

  思考题:内存中有多少个对象

  String s1 = "123";

  String s2 = "456";

  String s3 = s1+s2;

  String s5 = new String("123"+"456");

【3】面向对象、数组

一.面向过程:C,Basic,Pascal

        核心思想: 自顶向下,逐步细分,模块化

        程序的基本单元:函数

            针对于函数来说:会接收一些数据,进行处理,然后再输出

                                         一些数据。

                               主函数

              函数1       

                         函数2     函数3

           如:吃(猪八戒,西瓜)

面向对象:C++,java,C#...相对面向过程,简单,好学。

        核心思想:使用类,对象,继承,封装,消息,动态绑定,静态绑定等进行程序设计

        程序的基本单元:类

   

        如:

              首先:设计猪妖类型,

              然后: 实例化一个猪妖

              其次: 初始化信息

              使用: 猪八戒.吃(西瓜)

抽象数据类型:用不同类型的数据的组合来描述一种新的事物。

      如:描述人类

                    String   姓名

                    int      年龄

                    char     性别

                    double   weight

                    String[]  爱好

       

二.类:用来定义一种抽象数据类型 

              定义上述描述的新的事物

      public class Person{

       //成员变量

       String name;

       int age;

       char gender;

       ....

       /*方法

         1:可以定义这种类型的一些共同行为

         2:可以使用这些方法来操作成员变量

       */

      }       

三、对象:是类产生的个体,即类的实例化            

          在程序的逻辑中被使用。

    

          如何实例化和初始化?

         new 构造方法(有参传参)

null与NullPointerException

    null:是引用类型的默认值

    NullPointerException:是程序在运行时产生的一种异常

                    如何产生的?? 

                    当引用变量没有指向任何对象时,

                    调用了类型中的成员变量或者方法

          reg:

             Person p = null;

             p.eat("面包");

             p.name = "张三";

引用变量:简称引用,

      存储的是堆中对象的地址信息,我们可以理解为变量

      指向了堆中的对象

方法   

    1、方法签名: 方法名+参数列表

    2、方法重载:

        在同一个类型中,方法名相同,参数列表不同,

        即方法的重载

    3、定义语法:

             修饰词   返回值类型   方法名(....){

      

       }

    4、调用语法:

                    没有static修饰的方法

                    必须使用引用.方法(有参传参);      

    

四.构造方法:

      作用:用来初始化对象的成员变量

      定义语法: 修饰词  类名(...){}

      调用语法: new 构造方法();  

   

      无参构造器:没有定义构造器时,系统会默认提供无参构造器

  

      注意:只要定义了构造器,系统不再提供默认构造器

     

成员变量与局部变量的区别:

    成员变量

        定义位置:在方法外,类体中

        默认值:有默认值,构造器中可以不对成员变量初始化

        内存位置:在堆中

        生命周期:从对象实例化开始出现,到对象消失    

    局部变量

        定义位置:在方法内(包含小括号内的形参)     

        默认值: 没有默认值,必须初始化再使用  

        内存位置:在栈帧中

        生命周期:从声明时开始,到方法结束后,栈帧消失时。

 

内存管理:

    jvm将内存分成三大主要区域,堆,栈,方法区,用来存储数据。

    堆(heap):存储new出来的对象,给成员变量分配空间       

    栈(stack):jvm在执行程序时,在栈中,会为每一个方法分配一

           个空间(即栈帧),用来存储方法的局部变量。

    方法区:用来存储jvm加载的字节码文件的信息(类的信息)

             包含类的方法,方法只有一份,堆中的对象共享

             这份方法,在使用非static修饰的方法时,需要

             对象来调用(即动态绑定到对象上) 

垃圾回收机制:(GC)

     jvm的一个独有线程(程序),用于回收没有任何引用指向的对象。

     System.out.println((new Person()).name);

     上述产生的对象,以后再也无法使用,如果类似的这样情况

     有很多,对象来不及被处理,内存剩余空间就会越来越小,

     有可能出现内存溢出情况。

     因此需要一个处理机制,即垃圾回收机制。没有被引用的对象

     会被视为垃圾,等待GC被回收

    (因为有垃圾绘制机制,所有java程序猿无需单向内存溢出或泄露情况)

================================================

五.this关键字:

      在普通方法或构造器中,操作的成员变量如果与局部变量名称相同时,

      为了避免出现歧义,应该在成员变量前使用this.进行区分

      当没有歧义时,this.可以省略不写       

   

     在构造器中:还可以使用this关键字调用本类中的其他构造方法 

      语法格式: this(有参传参)

      只能在构造器中的首行首句上使用

==============================================

经典俄罗斯方块游戏:

 

     画面最多能放入20行,10列的方块

    画面中的最小单元:

         是一个小方块

    

    

     设计需求分析: 最多有200个方块,这些方块有共同特征

                               有共同行为   

                              

          最小单元: Cell来定义方块这种事物

              

                             成员变量: 行号row,列号col

                             方法:   drop()

                      left()

                      rigth()

                             重载上述三个方法,通过形参决定移动的步数    

                            

                      toString(); 

===========================================

数组:

    基本数据类型数组,元素是基本类型的数据。

 

    引用数据类型数组,元素是对象      

 

     初始化的方法:

        静态初始化:

                  元素类型[] 变量名  = {}

                 动态初始化:

                 (1)规定长度的

                

                 (2)不规定长度的

  

 引用数据类型的数组使用规定长度的方式进行初始化时,

 默认值是null;

 如:

    Cell[]  cs = new Cell[10];

   

    cs里有地址,数组对象的地址。此对象里有10个null。

   

        第一个元素存储(0,3)的方格

    cs[0] = new Cell(0,3);

        第二个元素存储(0,4)的方法

    cs[1] = new Cell(0,4);

   

   

PS:引用类型的数组对象内,存储的是元素对象的地址信息   

   

===================================================

比最小单元大点的

   游戏中有很多T对象,我们可以抽象出来一种T类型

    所有的T对象的共同特征:

               四个方格

  所有的T对象的共同行为:

        向左   moveLeft()

        向右   moveRight()

        向下   moveDrop()

 重载 上述三个方法

    toString()

           public class  T{

                  Cell[] cs;

                  public T(){

                     cs = new Cell[4];

                     ...

                  }

          

           }  

   

  

   

   格式自动对齐快捷键:ctrl+shift+f 

【4】继承

一.继承:

      现实世界中:通过分析多种类型,然后发现有一些共同特征和共同行为

                            再将这些种类,归纳为一种新类型

                            如:  黄色皮肤的人

                                      白色皮肤的人

                                      黑色皮肤的人

                     |

                                         人

                                      

                            再如:    小狗 --能动,能吃,能睡,能叫(汪汪)

                                              小猫--能动,能吃,能睡,能叫(喵喵)

                        .......

                       |

                                          动物

   计算机语言中:

               先编写父类类型,在编写子类型,然后再有对象

               如:  先编写Animal类型

                         再编写 Dog类或Cat类型        继承父类的成员变量和方法

                再使用数据时,要么创建Dog对象/Cat对象                                                         

                                                      

      子类可以父类中继承一些成员变量,和方法。子类还可以添加自己的

      独有成员变量和方法。

   

      子类:也叫派生类

      父类:也叫超类,基类  

 

二.关键字extends,用于继承语法

      格式:

      public class subClass extends SuperClass{

     

      } 

 

继承中的构造器:

         子类不能继承父类的构造器,但是,子类中的构造器可以调用

         父类的构造器

         语法: super(有参传参);

          作用:可以更好的给继承过来的成员变量赋值

        

        

    PS:子类中的构造器一定会有一个调用了父类的构造器

              父类中如果没有无参构造器,子类需要显式调用父类构造器

              如果父类中有无参构造器,子类中的构造器可能隐式调用

              了父类的无参构造器.即:隐藏了super()

             

    super()与this()的区别

         相同点:都是调用构造器,而且必须放在首行首句。

     不同点:super()是调用父类的构造器

         this()是调用本类中其他构造器

 

三.继承的传递性:

             继承特征有传递特性,B类型继承了A类型的特征,C类型继承了

             B类型的特征。C类型也间接继承了A类型的特征

继承的另外一特点:

            单继承: 一个子类只能继承一个父类。但是一个父类可以有

                          多个子类      

==================================

练习:

   设计一个动物类型Animal

      int age

   设计一个鱼类型Fish

      boolean isWater

   设计金鱼GoldFish类型,

       String color;

   鲨鱼Shark类型,

       int size

   娃娃鱼BabyFish类型

      int size

      String name

   分别创建对象,进行测试

  

   一个源文件中,只能有一个public修饰的类,而且此类必须与文件名一致。

  其他类可以不用修饰词

  main也需要在public修饰的类中,才能生效。

】  

======================================

方法的重写(override)

        子类可以继承父类的方法,在继承时,我们可以在子类中

         编写与父类中的方法名相同,参数列表也相同的方法。这就是

        重写。

     

    (1)父子类关系,方法名相同,参数列表相同

    (2)返回值类型可以相同,也可以不同[

            子类方法的返回值类型必须是父类方法的返回值类型的子类]   

 

父类型的变量可以引用子类型的对象

    如:

      Animal   a = new GoldFish();

      Animal类型的变量a引用了子类型GoldFish的对象  

      符合人类的思维:

                    这条金鱼是动物   

                    

编译期绑定:

    在编译过程中,变量只能调出本类型中的方法

     在编译期间,  方法静态绑定到变量上

运行期绑定

    在运行过程中,真正执行的方法的逻辑与对象的类型有关系。

    简单说成:方法在运行期间,动态绑定到对象上。

   

   

成员变量的调用与变量的类型有关系(与编译期和运行期无关)    

    

                    

 

【在创建子类对象时,在内存中会不会产生父类对象??】

【答案1: 会产生,没有父类对象,哪来的子类对象】

【答案2: 不会产生,创建子类对象时,子类对象的成员变量包含两部分:

       一部分为从父类中继承过来的

               在成员变量前有默认的super.

       一部分是自己本类中的

               在成员变量前有默认的this.

              

        如果子类中独有的与继承过来的成员变量重名时,必须

        显式指定使用super.或者是this.

        如果子类中没有与继承过来的成员变量相同名时,我们可以

        隐式不写,或者使用super.与this.其中任意一个。        

       

         为了避免不必要的麻烦,子类的成员变量尽可能不要与父类的

         成员变量同名      

【5】重写、封装

一.回顾:

   java继承是定义一种的新的类型,从已有的类中吸收

       成员变量和方法,新的类型可以添加新的方法和成员变量。

      这种方式可以提高代码的复用性,缩短开发周期,

      减少开发费用。

构造器:子类不能继承父类的构造器,使用super(有参传参)

               只能调用父类的构造器。

               子类中的构造器,至少有一个调用了父类的构造器。

  

        super(有参传参)与this(有参传参),不能共存。

                而且只能放在首行首句。

方法的重写:

          子类可以重新编写继承父类的方法。

      (1)方法名相同,参数列表相同

      (2)返回值类型可以相同,也可以是

         父类方法的返回值类型的子类型

      (3)修饰词可以不变,或者可以比父类的修饰权限更大

父类型的变量引用子类型的对象

          变量能调用的方法与成员变量

         方法:

                  编译期: 变量只能调用出本类型中的方法

                  运行期: 变量调用出方法执行逻辑与对象的类型有关

          成员变量:

                  变量调用出的成员变量一定是本类型中的成员变量

                如:Person p = new Student();

          p.name------>super.name

          p.age ------>super.age

          //p.score---->编译错误,p类型中没有成员变量score

=========================================

二.Object:是所有引用类型的顶级父类,

系统都会默认使引用类型extends Object.

此类中提供了常用的方法:

1:toString():

           在Object中,返回的是类全名@HashCode值,

           即对象的内存堆中的位置信息

     

          【类有类名和类全名之分:

                 类名:即最短的名称

                 类全名:从包名开始写的名称

           如:  String 是类名

        java.lang.String是类全名                 

          】

  此方法会在输出变量时,或引用变量进行拼接时默认调用。

 

  而查看地址信息,通常没有必要,我们通常要查看的是

  对象的成员变量信息

 

 因此我们都需要重写toString()方法,用于查看对象的详情

  格式:

   "[成员变量1="+成员变量1+",成员变量2="+成员变量2+"]"

 

三.equals(Object obj)

  Object类型中的此方法中的逻辑是比较调用者this与形参obj

    的地址信息是否相等。

    简单说成:比较this与obj是不是同一个对象 

 

  所以在定义类型时,继承过来的equals方法 我们要重写。

  重写规则:

   (1)   查看传进来的obj是不是null

              if(obj==null){

                  return false;

              }

   (2): 查看传进来的obj是不是this.

         if(obj==this){

              return true;

         }

   (3)   查看穿进来的obj是不是本类型

             if(obj.getClass()!=this.getClass()){

                  return false;

             }   

             可以改成

             if(!(obj instanceof Person)){

                  return false;

             }

             

             

instanceof关键字:

        作用是判断引用变量指向的对象是否属于某一类型

       语法:

        boolean f =  变量名  instanceof  类型名

----------------------------------

练习:

       定义一个类型Point,

       添加无参与全参构造器

       添加计算到原点的距离方法

       重载一个到另外一点的距离方法 

       重写toString与equals

      

       ==与equals()方法的区别???

       回去自己整理

      

================================      

package: 包. 

        作用:用于管理源文件,区分类全名

        命名规则:域名后缀.域名.项目名.模块名

        声明位置:在源文件的首行首句。

    

    

    

    

        类全名:从包开始写起的名称

       

    常用的包:

    java.lang.*,因为里面的类型非常常用。因此不需要导包

    java.util.*,此包下封装了很多常用的工具类

    java.io.*,此包下封装了io流的类型

    java.net.*,此包下封装很多关于网络的多种类型

 

import: 导包关键字:

        在class之上,package之下。

        用于声明 类的 类全名,在逻辑中就可以使用短的类名。

        优点: 可以减少代码的书写。  

四.访问权限控制修饰词

    private,protected,public,默认的(default)

   

    修饰类时:

           外部类:可以使用public和默认的

           内部类:可以使用public,protected,默认的,private

          

    修饰成员变量:四个都可以进行修饰         

                可见性不一样

 

            本类中     同包下    不同包子类中      其他   

public       true           true     true       true

protected    true        true     true

default      true        true

private      true

 

 

    在实际开发中,成员变量要尽可能的设置成不可见,

     好处是,提高代码的安全性。即用private修饰

    为了在其他类中可以对成员变量进行重新设置值或者获取值

    我们可以定义相应成员变量的共有方法来进行操作。

 

  public void setName(String name){

            this.name = name;//修饰成员变量的值

  }

  public  String  getName(){

         return name;

  }  

 

   修饰方法:

         与修饰成员变量的可见性一致。

        

    方法的重写:    

         子类不能重写父类的私有方法 

修饰词final:最终的,最后的

 

(1)修饰类,

          被final修饰的,不能再有子类了。        

(2)修饰成员变量

           可以直接初始化  

           也可以在构造器中初始化

           不能再其他任何地方再次赋值

      修饰局部变量

         只能初始化一次。  

(3)修饰方法

       被final修饰的方法,不能再子类中重写     

      

      

 常量:

        因为常量是一些特殊值,我们可以定义成final, public,static进行修饰。

       

           

      

【6】数组、集合、list

复习:

一、集合概念:是一个用于存储多个对象的容器(对象).容器内的对象

                就是元素,元素都是引用类型。

        PS:容器内存储的都是对象的地址。

二、与数组的区别?

    相同点:都是容器(数据结构),用来存储多个数据的,

    不同点

            数组:可以存储基本数据类型

            集合:只能存储引用数据类型

三、集合框架中包含多种接口,抽象类,实现类等,用此来满足我们所需要的用于存储数据的数据结构。 

四、Collection与Collections的区别

   Collection:是集合的父接口,定义了集合框架中常用的抽象方法

   Collections:是集合的工具类,定义了很多用于操作集合对象的

                               工厂/工具方法

五、子接口:List,Set,Queue

    List:存储此接口实现类的数据,有序,可重复。

          有序:存储时与添加的顺序相关。有对应的索引/下标标记位置。

               从0开始

          重复:存储的元素可以是同一个,也可以是对象内容相同不同对象

               根据元素的equals方法进行判断

 

    常用方法(序)  

   E set(int index,E newElement)

         使用新元素newElement替换下标index上的元素,返回原元素。

   boolean remove(int index):

          移除此集合中下标为index上的元素  

   List<E> subList(int fromIndex,int endIndex):

           截取此集合中的一部分,即截取子集,从fromIndex到endIndex

           包前不包后

      PS:此方法在堆中不会产生新的集合对象。

                 变量引用的父集的一部分。

                 修改子集,会影响父集        

   int lastIndexOf(Object obj):

            返回此集合指定元素obj最后一次出现的下标。找不到返回-1.              

六、数组与集合之间的转换

       1、集合转数组

      Object[] toArray()

      E[]  toArray(E[] e);

       2、数组转集合

      List Arrays.asList(数组参数);

            注意:数组转成的集合,不能进行增删操作,否则会出现

            运行时异常.可以进行替换操作,但是会数组变量

        有影响。

            如果想要成功进行增删操作,可以将元素,存入新

            的集合中。

七、 Iterator:迭代器接口

    (1)迭代器的作用使用用来遍历集合元素。是一个接口。Collection接口

         提供一个方法 Iterator iterator()

    (2)Collection的实现类使用内部类定义了迭代器子类。

    (3)迭代器提供了统一的方法,用于遍历集合元素。

    常用方法:

     boolean hasNext():

                  判断集合中是否有下一个元素

     E next():

                  取出集合中的下一个元素  

     void remove():         

         在使用迭代器对集合进行遍历时,不能使用集合的移除方法

         移除集合的元素。必须使用迭代器自己提供的移除才行。

   

    1、  增强for循环-foreach循环。

     for(元素类型 变量名:要遍历的集合或者数组){

         

     }

    

     与经典for循环的区别:

     (1)增强for循环中无法使用下标。

     (2)经典for循环中可以使用下标。跟下标有关的逻辑,随便写。

八、ArrayList& LinkedList

    (1)ArrayList

                 底层是基于动态数组的数据结构。是有存放顺序的。          

    (2)LinkedList

       底层是基于双链表的数据结构。每一个存储单元,都涉及到其他两个引用。

 

     优缺点: 在执行get()/set()时,ArrayList的效率高,LinkedList需要移动指针,效率低

                 在增加/删除操作时,LinkedList效率高,ArrayList效率低(需要扩容,移动元素)。

        ps:当然,在元素的数量大的情况下,区别才明显。        

 

    (3)Vector:是一个比较古老的集合类型,线程安全,但是效率特别低。

                           虽然安全,也不建议使用。

九、接口Queue

    Queue也是Collection的子接口,是一种数据结构,队列。

        队列:通常都是一端进(offer),另一端出(poll)。

    

        进出原则:FIFO

    

    

        因为队列要经常进行增删操作,所以使用Linkedlist

        实现了Queue接口. 

       

        常用方法:

    boolean offer(E e):

                元素从队尾进入队列。

    E poll():

               从队首移除元素,返回被移除的元素。当队列没有元素时

               返回null.

    E peek():

                查看队首元素,不移除。队列中没有元素时,返回null.       

        注意: 为了避免移除队列的队首时出现null,我们最好先查看队首

                 是不是null.

                

  

   Deque:是一个Queue的子接口,实现的是双端队列的数据结构。

                  双端队列:两端都可以进,也都可以出。

                 

         boolean offerFirst(E e);

         boolean offerLast(E e);

         E pollFirst();

         E pollLast();

         E peekFirst();

         E peekLast();

  

       栈的数据结构:先进后出:FILO

                我们可以将双端队列的一端进行禁止操作。另一端进或

                出,即Stack

               

        void push(E e):

           将元素 e推进栈中

        E pop():

                        将栈中的最顶端的元素,移除。   

  可以

                           

【7】list、set

一.复习:

  集合框架中的父接口:Collection

 子接口: List,Queue,Set

 List:有序(索引是按照添加顺序指定的),可重复(存放同一个对象多次,equals方法相同的不同对象)

         能存储null元素,没有个数限制。

 派生出两个子类:

 ArrayList:基于动态数组的数据结构,有连续的索引,从0开始

                  在使用get/set方法时,效率高

 LinkedList:基于双链表的数据结构,每个节点上都有前后两个元素的引用。

                    在add/remove方法时,效率高

 迭代器:用来遍历集合的。提供了hasNext():询问是否有下一个元素

       next():用来获取下一个元素。

       ps:在迭代期间,想删除集合的元素,需要使用迭代器自己的remove()方法

 foreach循环:

     for(元素类型  变量:要遍历的集合或数组){

             逻辑

     }

       实现原理:使用了迭代器思想

Queue:队列,进出原则:FIFO

             方法: boolean offer(E e)---进

            E poll()-----出

            E peek()-----查看队首

Deque:队列的子接口,双端队列,两端都可以进可以出

             方法:

            boolean offerFirst(E e)

            boolean offerLast(E e)

            E pollFirst()

            E pollLast()

            E peekFirst()

            E peekLast()

栈:  双端队列的特殊情况:一端禁止进出。FILO

          方法:  void push(E e)--进栈

                E pop()-----出栈

==========================================

二.泛型机制:

   (1)概念

   jdk1.5版本开始使用的新特性,本质是进行"参数化类型",在类

   ,接口,方法的定义上都可以使用,用来指定数据类型名的。

   (2)集合在定义时,可以用泛型机制来指定元素的类型,这样

            编译器在编译期间就可以进行检查元素类型是否匹配,避免了

           程序在运行时出现过多的错误 

   (3)集合框架中的所有类型(接口,抽象类,实现类)都是用了

            泛型机制   

   (4)泛型机制的参数只能传引用类型。                

   

        练习:  自定义一个类型,练习泛型机制

               定义一个类型MyContaionner:

               使用泛型机制,用于规定要存储的元素类型

===============================================

二.List排序

Comparable接口:       

       如何定义集合中元素之间的大小之分?我们需要在定义元素类型

       时实现Comparable接口,实现接口内的compareTo(E e)。实现此接口的类型的对象之间可以进行

       比较。

 

 方法:

    int  compareTo(E e):

        比较规则:

       (1)this与e比较,this-e,

                  如果大于0,返回大于0的一个数

                  如果等于0,   返回0

                  如果小于0,  返回小于0的一个数

                  按照升序排序

       (2)e-this,降序排序

 工具类:Collections

        提供了一个sort(Collection c)方法,

        对集合里的元素进行排序 

        

       

     练习:定义一个类型Point,在集合List中存储五个Point对象

             按照到原点的距离长短进行降序排序。    

            

 Comparator比较器接口:

           如果元素类型已经实现了comparable接口,定义了默认的比较规则。

           之后,再想换其他比较规则时,不修改源码。可以利用比较器接口

           来重新定义比较规则 

    

     方法:

     int compare(E o1,E o2);

        比较规则:

        升序: o1-o2

        降序: o2-o1

===========================================

三.Set接口:

        特点1: 无序,存储的元素与添加顺序无关

        特点2: 不可重复(使用元素的equals方法来判定是否重复)

        特点3: 能存储null元素,只能存储一次。

Hash算法机制

Set集合在添加或查看元素时,当集合中的元素过多时,就是进行

      多次的比较,效率变低。

     在设计元素类型时,提供hash算法,用于返回对象的一个int值。

      在内存中开辟很多小的区域,用于存储一定范围的返回值的对象。

     当我们想添加元素或查看元素,先计算此元素的返回值,然后去

     相应区域中查找遍历,

   --如果在这个区域没有找到对象,说明

       集合中可以添加这个对象。

   --如果有,然后查看两个对象的equals的返回值

         --如果为true,  不能添加 

         --如果为false, 可以添加,添加至

                      对应的链表结构中(尽可能的避免发生)

重写HashCode方法:

       重写规则:尽可能的让所有的成员变量都参与运算,

                         尽可能的避免出现hash值碰撞

注意:

       重写的必要性:

   (1)如果重写了equals(), 有必要重写hashCode方法

   (2)如果equals()返回true, hashCode返回值有必要相同

   (3)如果equals()返回false,hashCode返回值不一定相同,

            如果返回值不同,可以提高检索的效率

   

   反过来说:

    (1)hashCode值相同,equals方法可能不同

    (2)hashCode值不同,equals方法一定不同     

 

Set接口派生的子类      

   HashSet:通过实现hash算法的一种数据结构,

                        无序,不重复

   LinkedHashSet:通过实现hash算法的一种数据结构,但是

                         通过链表来维持顺序。顺序与添加顺序一致。

   TreeSet: 使用二叉树的一种数据结构,顺序与自然排序有关系。

   支持定制排序

【8】map

一.Set集合:

      特点:无序,不重复。

存储时采用了hash算法机制,计算存储位置。

 

HashCode方法

    Object是引用类型的父类,提供了hashCode()方法以及equals()方法

        因此我们在定义类型时,一般都重写hashCode和equals方法。

        重写的重要性:

    equals方法我们用来判断集合中的元素是否重复

    hashCode方法我们在使用Set集合时,必须要重写,因为

        我们采用的hash算法计算Set集合元素的存储位置。

   

    int hashCode():

        Object提供的方法是通过地址计算hash值,不可控。

                我们需要在自定义类中重写此方法。

                重写原则:    尽可能的让所有成员变量都参与运算

                                        尽可能的减少hash值的碰撞

           

    public int hashCode(){

       int result = 7;--定义一个局部变量,进行初始化

       int prime = 53 --定义一个局部变量,赋值为素数

       result = prime*result+field1;

       result = prime*result+field2;

        return result;

    }

=================

二.Set集合的遍历

   因为Set集合是无序的,无下标可言,因此不能使用经典for

   循环。我们可以使用迭代器原理。

  

   (1) 调用集合的iterator()获取迭代器

   (2) 使用foreach循环

Set集合的元素:

         不能轻易修改参与hash值算法的成员变量。

         否则容易引起内存溢出。

         原因:成员变量修改后,会出现新的hash值,但是存储位置还在

                  原hash值的位置上。因此操作时,找不

                  到具体的存储位置。 

                 

子类:

   HashSet:

           无序,不重复,底层使用hash算法计算存储位置。

           增加删除时效率高    

   LinkedHashSet:是HashSet的子类

           底层使用hash算法计算存储位置,同时使用链表来维护

           顺序,顺序与添加顺序一致。     

           在查看检索时,效率比较高   

   TreeSet:是SortedSet子接口的实现类,使用二叉树的数据结构维护

            元素的顺序。

=========================================

三.Map接口:集合框架中的另一个父接口

    Map集合,用于储存一一对应的元素数据,第一个对象可以作为

        索引,第二个对象作为值,我们称之为key-value,键值对。

 

    储存数据的特点:

     (1)以key-value形式进行存储。

     (2)key与value都必须是引用类型

     (3)key可以为null。

     (4)key与value是单向一对一映射。

     (5)key不能重复

存储机制:

     Map是基于数组和链表的数据结构进行存储数据。

     作为key的对象采用了hash算法计算存储的数组

     (散列数组,散列桶)的位置.如果计算出来的位置,

           数组中此位置没有元素,就可以添加到

           散列桶内,如果有元素,key的equals方法

           返回值为false,就会存储在散列桶元素对应的单向链表中。

           如果key的equals方法返回true,就进行替换(覆盖)。

     PS:使用Map集合,做为key的数据类型应该重写equals和

      HashCode方法  

常用方法:

      V  put(K k,V v):

            作用:用于存储一对key-value.  返回被替换的value值

                  如果不是替换就返回null

      V  get(K k):

                   作用:通过key对象,获取对应的value对象,如果集合中

                   没有此key,返回null

 Map集合的遍历

      Set<K>  keySet();

            用于获取Map中所有的key对象,返回一个Set集合

      Set<Entry<K,V>>  entrySet();

            将key-value封装成内部类对象,返回Entry对象的Set集合                       

      Collection<V> values();

           将map集合中的所有value封装到一个Collection集合中。

装载因子和HashMap的优化

      装载因子:DEFAULT_LOAD_FACTOR = 0.75f

      默认容量:DEFAULT_INITIAL_CAPACITY 

           16,就是数组的容量

      元素个数: size   

          

   当我们创建一个HashMap对象时,底层数组的初始容量为16。当存储的数据的

   个数 size/DEFAULT_INITIAL_CAPACITY等于DEFAULT_LOAD_FACTOR时,

   数组开始扩容。此时最佳。

   如果小于0.75扩容,比较占内存。

   如果大于0.75扩容,操作的元素比较多。

  

  

    public V put(K key, V value) {

        return putVal(hash(key), key, value, false, true);

    }

    --->

    final V putVal(int hash, K key, V value, boolean onlyIfAbsent,

                   boolean evict) {

        /**/         

        Node<K,V>[] tab; Node<K,V> p; int n, i;

        if ((tab = table) == null || (n = tab.length) == 0)

            /* 没有存储元素,*/

            n = (tab = resize()).length;

        if ((p = tab[i = (n - 1) & hash]) == null)

            tab[i] = newNode(hash, key, value, null);

        else {

            Node<K,V> e; K k;

            if (p.hash == hash &&

                ((k = p.key) == key || (key != null && key.equals(k))))

                e = p;

            else if (p instanceof TreeNode)

                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);

            else {

                for (int binCount = 0; ; ++binCount) {

                    if ((e = p.next) == null) {

                        /* hash碰撞 */

                        p.next = newNode(hash, key, value, null);

                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st

                            treeifyBin(tab, hash);

                        break;

                    }

                    if (e.hash == hash &&

                        ((k = e.key) == key || (key != null && key.equals(k))))

                        break;

                    p = e;

                }

            }

            if (e != null) { // existing mapping for key

                V oldValue = e.value;

                if (!onlyIfAbsent || oldValue == null)

                    e.value = value;

                afterNodeAccess(e);

                return oldValue;

            }

        }

        ++modCount;

        if (++size > threshold)

            resize();

        afterNodeInsertion(evict);

        return null;

    }

     

  

            

      内部类Node,封装了一个key-value数据,同时还存储了下一个节点的引用

   static class Node<K,V> implements Map.Entry<K,V> {

        final int hash;

        final K key;

        V value;

        Node<K,V> next;

 

        Node(int hash, K key, V value, Node<K,V> next) {

            this.hash = hash;

            this.key = key;

            this.value = value;

            this.next = next;

        }                  

============================

四.Map接口的子类:

HashMap与HashTable的区别

   (1)HashTable是一个古老的类。不建议使用

   (2)HashTable是一个线程安全的类,HashMap线程不安全

   (3)HashTable的key不能是null,HashMap可以是null

LinkedHashMap:是HashMap子类,使用链表来维护key-value的顺序,在迭代时顺序与添加顺序一致。

TreeMap:

        是SortedMap子接口的实现类,使用了二叉树的数据结构,维护填入集合的顺序。

    (1)自然排序:

       往TreeMap里添加的key对象,可以实现Comparable接口。重写compareTo方法

    (2)定制排序:做为key对象的数据类型,可以不实现Comparabel接口。

       需要创建一个比较器Comparator对象。实现compare方法

Properties:

     是HashTable的子类型,用于封装属性文件的key-value信息

     因为在文件里写的都是字符串,因此Properties的key与value

     都是字符串类型

=============================================

File类型

   java.io.File类型,可以对硬盘上的文件以及目录,进行操作。

      如查看文件/目录的属性信息,创建,删除文件/目录。此类型

      不能查看和修改文件里的内容。

常用构造器:

   File(String pathname):

            指定一个路径,创建一个File对象

            路径:

            (1)文件的路径,要写到文件的扩展名为止

            (2)目录的路径,要写到当前目录的名称为止         

    

常用方法:

    boolean exists():

             判断指定路径的File对象是否存在

    exists();//

    isFile();

    isDirectory();

    getName());

    lastModified();

    isAbsolute();

    getAbsolutePath();

    getParent();

    length();    

                           

五.javaBean规范:

        程序开发者默认遵循的一种规范

    (1)提供两个构造器

    (2)给成员变量提供get/set方法

       String name

       getName()

       setName(String name);

       Bean:豆子的意思,get/set方法名上的后续单词称之为bean.

                         在命名方法时,作为bean的单词首字母要大写,成员变量

                         要尽可能的与bean名一致,首字母小写。

    (3)重写hashCode方法和equals方法

    (4)重写toString()                    

   

 线程

9】线程01

一.线程:还会涉及到一些名词概念:

    程序,进程,线程,多进程,多线程

 

 

二.进程:是一个运行中的程序的实例。         

进程的两个特点:

    (1)是一个实体,都有自己独立的地址空间,分为文本区域,数据区域和堆栈。

    文本区域用来存储编写的程序的代码,数据区域用来存储运行时所需要的

数据(动态分配的内存),堆栈用来存储运行时涉及到的指令和本地变量

 

    (2)是一个"运行中的程序",程序本身是一个没有生命的实体,只有当处理器

赋予它生命时,它才能称之为一个活动的实体,即进程

进程是操作系统级别的基本单元。

通俗点说:进程就是操作系统运行的一个任务(一个应用程序运行时,就对应一个进程)

 

 

三.线程的状态图解析:

(1) 新建状态:即新建一个线程对象,设置好需要执行的任务

(2) 就绪状态: 调用线程的start方法,进入准备状态,等待cpu分配时间片段

(3) 运行状态:当cpu将时间片段给了线程对象后,线程开始执行任务。

(4) 阻塞状态:正在运行中的线程由于某种原因,放弃了cpu的使用权

             即该线程放弃时间片段,进入阻塞状态。

         阻塞状态分为三种:

         等待阻塞: 运行中的线程调用wait方法时,jvm将

                    此线程放入等待池中  

         同步阻塞: 运行中的线程想要获取同步的锁对象时,

如果锁对象被其他占用,

                         则,jvm将此线程放入锁池中

         其他阻塞: 当线程中执行到阻塞方法或者是Thread.sleep()或者是其他线程的join时,该线程进行阻塞状态

(5) 当线程执行完任务后,表示结束

 

四.线程的创建方式(3)

   (1)继承Thread类,重写run方法,定义任务内容。然后调用

       start方法,用于启动线程。(切记,不是调用run方法)

   (2)实现接口Runnable,重写run方法,定义任务内容,然后将任务

            传给Thread对象,然后由Thread调用strat方法,执行任务

   (3)使用FutureTask创建对象,再使用Callable创建子类对象,

            重写call方法(相当于run方法),再将Callable对象传给

      FutureTask,再将FutureTask对象传给Thread对象,调用

      start方法,启动线程 

     

 第二种方式与第一种比较

 (1)将线程对象和任务对象分开,降低了耦合度,便于维护    

 (2)避免了java中单继承的限制

 (3)适合相同的任务代码块处理同一个资源

 第三种方式:call方法带有返回值。

 

线程API:

  常用构造器:

     Thread(Runnable r):

           创建一个指定任务的线程对象

     Thread(Runnable r,String name)

          创建一个指定任务,并且指定名称的线程对象     

     Thread(String name)

          创建一个指定名称的线程对象

 常用方法:

  

 

练习:

    桌子上总共有20个豆子,有两个人来取豆子,每个人每次只

    能取一个豆子。并输出桌子上剩余的豆子数。

   

   

五.线程的优先级:

1-10,10为最高级别,1为最低级别,5为默认级别

Thread.MIN_PRIORITY--最小优先级

Thread.MAX_PRIORITY--最高优先级

Thread.NORM_PRIORITY--默认优先级

 

守护线程:线程分两类,一类是普通线程(前台线程),

                  一类是守护线程(后台线程)。

            当线程只剩下守护线程后,所有线程都结束。 

           

           

static sleep(long time):

  线程的静态方法,用于使当前线程进入阻塞状态,时间为time毫秒。

 time毫秒后,会进入就绪状态。如果期间被打断,会出现异常

 InterruptException           

  

  

join():

    作用是将当前线程插入到某一个线程中,使某一个线程进入阻塞状态。

    当前线程执行完后,另一个线程进入就绪状态。

   

 

10】线程02

一.回顾

程序,进程,线程,多进程,多线程

(1)程序:可以实现多个功能的代码体。也叫软件。

(2)进程:有两个特点

       -- 是一个实体:有自己的地址空间,如文本区域,数据区域,堆栈区域

       -- 是一个运行中的程序,cpu赋予程序生命时,就是一个进程。

      进程是操作系统的一个任务

(3)线程:是进程里的一个任务,是一个顺序执行流。

                有自己独立的堆栈,与其他线程共享进程的地址空间

(4)多进程:针对于古老的操作系统来说,现在的操作系统都是多进程的。

                 可以同时运行多个程序

(5)多线程:一个进程中的多个任务,可以同时进行多个顺序执行流。

               好处: 

               1)提高cpu的资源利用率

               2)可以共享同一个资源(静态资源,同一个对象实例)

并发原理:

     cpu在一个时间片段里,只能做一件事。微观上,cpu是将时间细分成

          很多个小的时间片段,尽可能的将时间片段平均分给多个线程,所以

          针对于某一个线程来说,是走走停停,断断续续的。但是在宏观上,

         人类感觉不出,看似是这些线程是同时进行的,这就是并发原理。

二.线程的三种创建方式:

(1)继承Thread类,重写run方法,调用start方法,启动线程

      进行就绪状态

(2)实现Runnable接口,重写run方法,传给Thread对象....

(3)创建Callable的子类对象,重写call方法,传给FutureTask对象,再将

   FutureTask对象传给Thread对象,.........

三.线程的状态:

(1)线程的创建(任务的确定)

(2)调用start方法,进入就绪状态

(3)运行状态:cpu将时间片段给线程,执行run方法里的任务逻辑

(4)阻塞状态:线程放弃cpu的时间片段,进入阻塞。

                 等待阻塞: wait()

                 同步阻塞: 要获取的锁对象,已经被占用。

                 其他阻塞:  sleep(),join(),其他类的阻塞方法(sc.nextInt())

(5)死亡状态: 线程任务结束或者由于异常造成的run方法停止。

常用构造器:

   Thread(String name);

   Thread(Runnable r)

   Thread(Runnable r,String name)

常用方法:

   String getName()

   long getId()

   int  getPriority()

   State getState()

   boolean isAlive()

   boolean isDaemon()

   boolean isInterrupt();

四.线程调度:

    多线程时,谁先执行是不可控的,是由cpu的线程调度来分配的。

    但是我们可以通过线程的优先级来尽可能的让线程调度来调控线程

    所需要的时间片段。

   优先级:从1-10,越来越高。

    1是最低的优先级,对应的常量:MIN_PRIORITY

  10是最高的优先级:MAX_PRIORITY

    5是默认的优先级:    NORM_PRIORITY

 

  对应的方法:

   void  setPriority(int priority)

五.守护线程:

     线程共分两大类:分别为普通线程和守护线程.多线程程序,

     在只剩下守护线程时,会结束所有线程。

    方法:

  void setDaemon(boolean flag)

    设置为true时,是守护线程。

 

static void sleep(long time):

      使当前线程放弃时间片段,进入阻塞状态,超时后,会进入就绪状态。

      如果没有超时,而是被打断,会出现检查性异常:InterruptException  

void interrupt()

      打断阻塞状态下的线程对象。

void join()

       将当前线程A加入到线程B中,线程B进入阻塞状态,直到线程A

       结束,线程B进入就绪状态,等待被分配时间片段。

   

练习:

      两个线程A和B:

      线程A的任务是计算1到100的和。

      线程B的任务是获取线程A计算的结果。

     

static void yield()

     线程对象让步的功能:让出时间片段,此线程进入就绪状态。

 

六.同步锁:

   当多个线程操作临界资源时,可能会出现线程安全隐患问题。

   临界资源可能是:

  (1)某一个静态变量

  (2)某一个实例变量

  如果想解决这样的问题,需要使用同步操作。

 

  异步操作:多线程的并发操作,相当于各干各的

  同步操作:相当于一个做完,另一个再做。

 

 线程在内部提供了一个内置的锁机制保证原子性,用于线程进行同步操作。

 锁需要两点:

 (1) 锁是一个对象,

 (2) 如果想进行同步,多个现象操作的必须是同一个锁

        synchronized(锁对象的引用){

               需要同步的代码块

        }

七.锁机制:

当一个线程进入同步的代码块后,就会获得锁对象的使用权。其他线

            程如果执行到此处,会发现锁对象被占用,只能处于等待状态(锁池),

            当线程执行完同步的代码后或者出现异常,都会自动释放锁。

          

合适的锁对象:

       必须是一个引用类型,而且必须使多个线程都可以使用这个锁对象,

       因此this对象比较适合

 

同步代码块的范围:

    (1)可以是方法内的一部分代码,可以也是全部代码(相当于给方法上了锁)

    (2)成员方法上添加修饰词synchronized,锁对象为this

             如果一个类的所有成员方法都使用了同步关键字,当某一个线程

            操作了其中一个方法,另外的线程即使操作的不是这个方法,

            也会进入锁池状态

       

    (3)静态方法上也可以添加synchronized,锁对象为类对象,

              调用方法:类名.class,每一种类都有一个唯一的类对象        

        

 

wait()/notify()notifyAll():

上述的方法都是Object类型提供的,用来调控线程的状态的。

使用位置必须是同步块中,如果不是同步块中,会报异常

 

wait():

     当前获取锁对象的线程准备释放锁,给其他线程获取锁的机会。

wait(long time):

     当前获取锁对象的线程如果没有被通知,在延迟time毫秒后,自动释放锁对象

wait(long time,int naons):

     功能一样,只不过比上一个方法延迟的时间更加精确。

 

notify()/notifyAll():

  当前获取锁对象的线程准备释放锁,使用此方法通知处于使用wait方法等待的线程,

 natify():只会随机通知等待线程中的其中一个。

 notifyAll():通过所有等待的线程来竞争锁。

 

 

生产者--消费者--仓库模式:此模式脱离了仓库没有任何意义。

(1)仓库用来存储数据。

(2)仓库不满的情况下,生产者可以生产

(3)仓库中满足消费者的需求时,消费者就可以消费

 

/*作业1:

   第一个线程输出1,2,3,4,5

   第二个线程输出6,7,8,9,10

   第三个线程输出11,12,13,14,15

   第一个线程输出16,17,18,19,20

   第二个线程输出..........

   第三个线程输出........

   直到输入75停止。

   作业2:

         模拟小张一家四口(小张,小张媳妇,小张他爸,小张他妈)

        分别拿着小张的银行卡去银行存取钱。 

*/

 

 

 

 

 

 

同步代码块内:

   (1)尽可能的不要使用sleep()和yield(),

            因为比较占cpu资源

   (2)同步块越小越好,省cpu的资源。

=================================

 前提:有多个线程时

 并发操作:多个线程同时开启,微观上断断续续,宏观上同时发生

                断断续续:同一个方法内的两行代码不一定是两个挨

                                 着的时间片段

 同步操作:在并发的基础上,同一个方法内的两行代码执行时间片段

               可以不挨着,但是其他线程不能对这两行代码的执行权 ,

              保证了代码的原子性。即这两行代码是同步的,当前线程执行完后,

              其他线程才有执行权。

想实现同步操作,提供了一个锁机制。

        我们将需要同步的代码加上一个内置锁对象,当某一个线程

      执行到此代码时,会获取锁对象,其他线程需要等待。当获取锁对象的

      线程执行完同步块(或者是因为异常)都会释放锁对象。其他线程

      通过cpu的线程调用才有机会获取锁对象的使用权

 

    synchronized(锁对象){

    } 

   

     锁对象:多个线程一定要使用同一个锁,否则没有记性同步操作

=====================================

线程池:

   (1)如果每个任务都需要创建线程对象,内存开销大

   (2)方便管理线程对象。

线程池的原理: 就是一些线程的集合,线程的状态不

                    是死亡状态,当线程池接收外面的任务时,

                    线程池的管理器会查看是否有空闲线程,如果

                    有,就会将任务分配给它,如果没有,任务处于

                    等待队列中.

线程池的类型:ExecutorService

另外一个类Executors里提供了多个静态方法

       来获取线程池对象

      

    方法1:

    newSingleThreadExecutor():

       获取单个线程的线程池对象,内部维护了一个无界队列用于存储任务

  方法2:

    newFixedThreadPool(int nThreads)

       创建一个固定数量线程的线程池,维护一个为无界队列

   方法3:

    newCachedThreadPool()

       创建一个可以根据需求来创建新线程的线程池对象,如果有可

       重用的,会优先使用。

   方法4:  

    newScheduledThreadPool(int corePoolSize)

       创建一个线程池,可以进行设置延迟或者是定时来执行任务

                               

   

   

     

 

 

 

 

 

 

 

 

 

11】线程03           

 一.同步代码块内:

   (1)尽可能的不要使用sleep()和yield(),

            因为比较占cpu资源

   (2)同步块越小越好,省cpu的资源。

=================================

 二.前提:有多个线程时

 并发操作:多个线程同时开启,微观上断断续续,宏观上同时发生

          断断续续:同一个方法内的两行代码不一定是两个挨

                                 着的时间片段

 同步操作:在并发的基础上,同一个方法内的两行代码执行时间片段

          可以不挨着,但是其他线程不能对这两行代码的执行权 ,

          保证了代码的原子性。即这两行代码是同步的,当前线程执行完后,

          其他线程才有执行权。

想实现同步操作,提供了一个锁机制

        我们将需要同步的代码加上一个内置锁对象,当某一个线程

      执行到此代码时,会获取锁对象,其他线程需要等待。当获取锁对象的

      线程执行完同步块(或者是因为异常)都会释放锁对象。其他线程

      通过cpu的线程调用才有机会获取锁对象的使用权

 

    synchronized(锁对象){

    } 

   

     锁对象:多个线程一定要使用同一个锁,否则没有记性同步操作

三.线程池:

   (1)如果每个任务都需要创建线程对象,内存开销大

   (2)方便管理线程对象。

线程池的原理: 就是一些线程的集合,线程的状态不

                    是死亡状态,当线程池接收外面的任务时,

                    线程池的管理器会查看是否有空闲线程,如果

                    有,就会将任务分配给它,如果没有,任务处于

                    等待队列中.

线程池的类型:ExecutorService

另外一个类Executors里提供了多个静态方法

       来获取线程池对象

      

    方法1:

    newSingleThreadExecutor()

       获取单个线程的线程池对象,内部维护了一个无界队列用于存储任务

  方法2:

    newFixedThreadPool(int nThreads)

       创建一个固定数量线程的线程池,维护一个为无界队列

   方法3:

    newCachedThreadPool()

       创建一个可以根据需求来创建新线程的线程池对象,如果有可

       重用的,会优先使用。

   方法4:  

    newScheduledThreadPool(int corePoolSize)

       创建一个线程池,可以进行设置延迟或者是定时来执行任务

 

 

 

【12】IO流01

java.io.File类型

一、概念

       可以用来创建,删除文件/目录,还可以查看文件/目录的属性信息。

      但是不可以修改文件里的数据。如果需要修改,应该使用输入/输出流。

二、常用构造器

    File(String pathname)

        创建一个指定路径的File对象

    File(File parent,String child)

       在指定parent路径下,创建一个child的file对象

    File(String parent,String child)

       在指定parent路径下,创建一个child的file对象

   

三、 绝对路径:是从根目录开始写的路径

          window: 从盘符开始书写:

                  D:\a\f1.txt

                  D:\a\b

          linux:  /home/scott/f1.txt

                  /home/scott       

       相对路径: 相对某一文件/目录的路径,不是从根路径书写。

          reg: f2.txt相对于a目录的路径:

          window:    b\f2.txt

          linux:     b/f2.txt

          reg: f3.txt相对于f2.txt的路径

                  ../c/f3.txt

                         

            

             

四、常用方法

    boolean exists();判断指定的路径是否存在

    boolean isFile();判断指定路径是不是文件

    boolean isDirectory();判断指定路径是不是目录

    String getName();获取文件/目录名称

    long lastModified();获取文件/目录的最后修改时间

    boolean isAbsolute();判断指定路径是不是绝对路径

    String getAbsolutePath();获取绝对路径

    String getParent();获取父目录的路径

    long length();获取文件大小  

   

    文件/目录创建方法:

    boolean createNewFile();创建文件

    boolean mkdir();创建目录

    boolean mkdirs();创建多级目录

    文件/目录的删除方法

    boolean delete()

           可以删除文件,删除目录时,需要目录下没有文件或子目录

    File[] listFiles()

        获取目录里的file对象

 

递归:

        递归思想:分成递与归。一层层递进,最后再一层层归。

    两种递归:

      (1) 方法调用自己  

      (2)  方法A调用方法B,方法B调用A

  举例:

     n*(n-1)*......*1                    

     

     z = f(n) 计算n的阶乘

       = n*f(n-1)

       = n*(n-1)*f(n-2)

       = n*(n-1)*......*1

      

       f(n)是一个函数:

               里的逻辑:

                n*f(n-1)

练习:

    斐波那契数列:  第n个数是第n-1个数与第n-2个数的和。

   

    1,1,2,3,5,8,13,.......

   

    计算第10个数的值。

===============================================

五、IO流:(Input,Output)

    我们在做项目时,除了自定义的一些数据外,还可能需要从"外界"

    引入数据,或者将数据导出到"外界"。这时,我们需要I/O操作。

     外界:指的可能是  键盘,显示器,硬盘,另外一个程序。

  输入:又叫读入操作

           数据时从"外界"流向程序

  输出:又叫写出操作

           数据时从程序流向"外界"

 

  流: 就是数据序列, 一经创建成功,就会打开一个通道。所以使用完

       应该进行关闭操作。

六、IO流的分类:

   (1)按照流向分类:

           输入流

           输出流

   (2)按照处理的数据单位分类:

                字节流

                字符流

   (3)按照功能分类:

                节点流:直接连接两个设备的流类型

                处理流:对节点流再次封装与处理的流类型

======================================

字节流:

       抽象父类 InputStream/OutputStream

文件字节流:

    FileInputStream/FileOutputStream

 

   (1)构造器:

        FileInputStream(File file)

                创建一个指定路径的File对象的文件输入流对象

        FileInputStream(String name)

                创建一个指定路径的字符串的文件输入流对象

        常用方法:

    int read()

                 读取该流中的一个字节数据,即8位二进制,存储到一个int数

                 据的低八位上             

                 如果返回-1,读至文件末尾,

   long skip(long n)

           跳过流中n个字节

    int read(byte[] b)

                读取字节存入byte数组中,最多能读b.length个字节

                返回的是实际读取的字节个数

    int available()

                查看此输入流中剩余的字节数量

               

    (2)构造器

       FileOutputStream(File file)

       FileOutputStream(File file, boolean append)

       FileOutputStream(String name)

       FileOutputStream(String name, boolean append)

             创建一个指定路径的输出流对象,append表示在文件末尾追加

       

       PS:如果指定路径下的文件名不存在,会自动创建。

                    如果父路径不存在,则报异常FileNotFoundException

             常用方法:

       void write(int b)

                   写出参数b中的一个字节,int类型的低八位。

       void write(byte[] b)

                   将字节数组b中的字节按顺序写出

       void write(byte[] b,int off,int len)

                  将字节数组b中的字节按顺序写出,从下标off,写len个                    

【13】IO流02

一.回顾 

File:可以创建,删除,查看文件/目录的信息。但是不

            能查看/修改文件里的内容

删除目录时:需要注意使用递归思想(不能直接删除不为空的目录)

IO流:

       用途,传输数据。

       输入:读取数据

       输出: 写出数据

       流:数据序列

分类:

   (1)按照流向分类

   (2)按照处理的单位分类

   (3)按照功能分类

字节流

      抽象父类:

   InputStream:定义了字节输入流的常用方法

       int available()

       void close();

       int read():读取一个字节,存入int的低八位上,范围是0-255

       int read(byte[] b):

                                    读取字节存入字节数组b中,返回的是读取的有效字节个数。

       int read(byte[] b,int off,int len)

       skip(int n);

   OutputStream:定义了字节输出流的常用方法

       void close();

       void flush();//冲刷,作用是将流的数据,冲刷进文件中

       void write(int b);写一个字节

       void write(byte[] b);写一个字节数组

       void write(byte[] b,int off,int len)

子类

    FileInputStream/FileOutputStream

       继承了字节流的抽象父类。重写了方法,并且提供了自己独有的方法

       构造器:

       FileInputStream(File file)

       FileInputStream(String path)

   

       FileOutputStream(File file)

       FileOutputStream(File file,boolean append)

       FileOutputStream(String pathname)

       FileOutputStream(String pathname,boolean append)

     

       PS:所有的输出流,对于指定的路径中的文件若是不存在,

                    都会自动创建。

===================================================

二.缓冲流:

BufferedOutputStream:字节缓冲输出流

        在写数据时,如果一个字节一个字节的写,写的次数明显很多,效率就会变得很低。

        如何提高效率呢。

        缓冲输出流的特点是:在流里维护了一个缓冲区,写字节时,先将字节

        写入缓冲区, 当缓冲区满时,再一次性的将数据写到文件里。这样就

        降低了写的次数,因此提高了效率。

   

        因此缓冲输出流缺失即时性,可以使用flush方法进行冲刷

   

        常用构造器

        BufferedOutputStream(OutputStream out)

                创建一个指定字节输出流的缓冲流对象

        BufferedOutputStream(OutputStream out,int size)

                创建一个指定字节输出流的缓冲流对象,并设置缓冲区的大小

        PS:当一次写的字节超出缓冲区大小,会出现溢出情况,溢出的字节

                      会先写出到文件中   

        

         常用方法:

        void write(int b):

                        写int数据的低八位,写入缓冲区内

        void write(byte[] b,int off,int len)

                        写指定长度len的字节数组,写入缓冲区 

                       

                       

                       

                       

    BufferedInputStream:字节缓冲输入流

       在读取字节时,也是一个字节一个字节的读,次数多,效率低。

       使用缓冲输入流,内部维护了一个缓冲区,默认8k,先一次性将缓冲区装满

       等待读取.

       当将缓冲区的数据读完,缓冲区再次存储后续数据。读取的次数明显降低

        效率高     

    

       构造器:

       BufferedInputStream(InputStream is);

       BufferedInputStream(InputStream is,int size);

    常用方法:

       int read(byte[] bs)

              读取缓冲区里的字节存储bs中,

              当一次性得去的字节小于缓冲区,我们是从缓冲区里读数据。

              此时,效率高 

                    

              当一次性读取的字节超出缓冲区大小。

              不使用缓冲区,直接从文件里读。

       

       int read(byte[] bs,int off,int len)            

================================================

数据字节流,与缓冲流一样,父类都是过滤字节流(

     FilterOutputStream/FilterInputStream   

         )

    这两个类提供了几个特殊的方法,可以直接写基本数据类型

 

 

数据输出流:DataOutputStream

    构造器:

    DataOutputStream(OutputStream os)

        创建一个指定字节输出流的数据输出流对象

  

     常用方法:

            除了提供写一个字节和写一个字节数组的方法外,还提供了如下方法     

      writeByte(int b)

      writeShort(int s)

      writeInt(int i)

      writeLong(long l)

      writeFloat(float f)

      writeDouble(double d);

      writeChar(int c);

      writeBoolean(boolean b)

      writeUTF(String s);

               

                                   

               

                   

   

          

【14】IO流03

 一.对象流:

    有的时候,我们可能需要将内存中的对象持久化到硬盘上,或者将

    硬盘中的对象信息读到内存中,这个时候我们需要使用对象输入

    输出流。

   

     序列化: 是对象转换成一个字节序列的过程,是一个写操作

  反序列化:   一个字节序列转换成对象的过程 ,是一个读操作

 

ObjectOutputStream

          构造器:

         

     ObjectOutputStream(OutputStream out)

          创建一个指定字节输出流的对象输出流对象。

         

          常用方法: 除了提供了一些基本数据类型的写方法外,还提供了

     void writeObject(Object obj)

                将内存中的对象持久化到硬盘上

                   

ObjectIntputStream

     ObjectIntputStream(OutputStream out)

          创建一个指定字节输入流的对象输入流对象。

         

          常用方法: 除了提供了一些基本数据类型的读方法外,还提供了

     Object readObject();

               从硬盘上读取一个字节序列,转换成对象

              

Serializable:序列化接口

          如果想将对象序列化,那么对象的类型必须实现此接口。此接口

          内什么都没有,只是一个序列化标识。

 

serialVersionUID:

      每个能序列化的对象,在被序列化时,系统会默认给此对象的类计算一个

      序列化版本号。不同的平台默认提供的序列化版本号多数情况下不会相同。

      因此当我们反序列时,如果硬盘里存储的对象的版本号与当前设计的类型

      的版本号不一致。会出现运行时异常:

   java.io.InvalidClassException,这种情况叫不兼容问题。

  

      如果我们想解决不兼容问题。我们应该手动提供版本号。尽可能的相同

      这样来解决不兼容问题

     

      另外一种情况:

          序列化过后,可能会修改类型,如果使用系统默认提供的

          版本号,在反序列时,会有异常,如果手动提供,不出现异常

         多出来的成员变量,以默认值的形式,赋值给反序列化回来的对象。

transient:成员变量的一个修饰词,可以理解为瘦身。

     有的时候,在序列化对象时,我们不需要将对象的某些成员变量

     值持久化到硬盘上(因为不重要),此时,我们可以在这些成员变量

     前添加修饰词transient(保存时,进行减肥)

================================================

二.字符流:

     在输出输入操作时,以字符为单位进行操作,默认是unicode编码集

     字符流的抽象父类分别是

   Writer/Reader

   Writer提供了字符输出流的常用方法

        void close():关闭

        void write(char[] cbuf):写一个字符数组

        void write(char[] cbuf, int off, int len)

                   写一个字符数组的一部分

        write(int c):写一个字符

        write(String str):写一串字符

        write(String str, int off, int len)

                写字符串的一部分

   Reader提供了字符输入流的常用方法

        int read():读一个字符,存储到int的低16位

        int read(char[] cbuf):将数据读进字符数组中,返回的是读取的有效字符个数

        int read(char[] cbuf, int off, int len)

                  将字符读入数组的一部分。

============================================

三.子类中转换流:

    OutputStreamWriter:

              将字符转换成字节写出到硬盘上

        构造器:         

    OutputStreamWriter(OutputStream out)

       创建一个指定字节输出流的字符输出流对象,采用的是系统默认的编码集

    OutputStreamWriter(OutputStream out, Charset cs)

    OutputStreamWriter(OutputStream out, CharsetEncoder enc)

    OutputStreamWriter(OutputStream out, String charsetName)

        创建一个指定字节输出流的字符输出流对象,采用指定编码集。

   

     write(int a);

            当a的低16位,如果被设计成相应的字符时,如果两个字节都是

            有效字节,会写出两个。如果低16位对应是无效字符,或是有效

            字节只有一位时,会写一个字节。     

   

   

   

     

   

    InputStreamReader()

             将字节转换成字符读进程序中

    构造器:

    InputStreamReader(InputStream in)

        创建一个使用默认字符集的InputStreamReader。 

    InputStreamReader(InputStream in, Charset cs)

    InputStreamReader(InputStream in, CharsetDecoder dec)

    InputStreamReader(InputStream in, String charsetName)

    创建一个使用指定字符集的InputStreamReader。 

====================================================

四.缓冲流:

 

PrintWriter:提供了丰富的方法,比BufferedWriter更加常用,此类型提供了

             行自动刷新的功能

        构造器:      

       PrintWriter(File file)

       PrintWriter(OutputStream out)

       PrintWriter(OutputStream out, boolean autoFlush)       

       PrintWriter(String fileName)

       PrintWriter(Writer out)

       PrintWriter(Writer out, boolean autoFlush)

      

       上述构造器,有第二个参数的,可以设置为true,表示行自动刷新。 

       只有一个参数的构造器,相当有两个参数时,设置为false的情况,即取消了

       行自动刷新的功能

      

     常用方法:

        println()

                通过写入行分隔符字符串来终止当前行。

        println(boolean x)

       打印一个布尔值,然后终止该行。 

       void println(char x)

       打印一个字符,然后终止该行。 

       void println(char[] x)

       打印字符数组,然后终止行。 

       void println(double x)

       打印双精度浮点数,然后终止行。 

       void println(float x)

       打印一个浮点数,然后终止该行。 

       void println(int x)

       打印一个整数,然后终止该行。 

       void println(long x)

       打印一个长整型,然后终止行。 

       void println(Object x)

       打印一个对象,然后终止该行。 

       void println(String x) 

    

BufferedReader:提供了一个缓冲区

      

        构造器:  

      BufferedReader(Reader in)

            创建使用默认大小的输入缓冲区的缓冲字符输入流。 

      BufferedReader(Reader in, int sz)

            创建使用指定大小的输入缓冲区的缓冲字符输入流。

        常用方法: 

      String readLine():

                读一行字符串,读至换行符号为止,返回的数据不包含换行符

                当返回值为null时,表示读至文件末尾

=====================================

五.文件字符流:

   FileWriter/FileReader

  

   FileWriter:相当于OutputStreamWriter与

              FileOutputStream合起来的功能,内部也维护

                了一个缓冲区,但是需要手动flush

   构造器:

       FileWriter(File file)

       FileWriter(File file, boolean append)

       FileWriter(String fileName)

       FileWriter(String fileName, boolean append)

      

       append:表示追加,但是此流不能设置字符集。

       常用方法与 OutputStreamWriter的差不多

      

   FileReader:相当于InputStreamReader和FileInputStream合起来的功能

                内部也维护了一个缓冲区

   构造器:

      FileReader(File file)

      FileReader(String fileName)

   常用方法与InputStreamReader的方法差不多

=============================================

System是一个final修饰的类型

        两个成员变量

        out:是PrintStream类型,默认的输出目的地是控制台console

        in:  是InputStream类型, 默认的数据源是键盘 

   

猜你喜欢

转载自blog.csdn.net/superXZT/article/details/84773955
今日推荐