Java 面向对象 一

1,对象:对象是类的一个实例,有状态和行为。例如,一条狗是一个对象,它的状态有:颜色、名字、品种;行为有:摇尾巴、叫、吃等。是该类事物的具体体现

2,类:类是一个模板,它描述一类对象的行为和状态。是一组相关的属性和行为的集合

3方法:方法就是行为,一个类可以有很多方法。逻辑运算、数据修改以及所有动作都是在方法中完成的。

4,实例变量:每个对象都有独特的实例变量,对象的状态由这些实例变量的值决定。

5,面向过程:面向着具体的每一个步骤和过程,把每一个步骤和过程完成,然后由这些功能方法相互调用,完成需求。

6,面向对象:面向对象思想就是不断的创建对象,使用对象,指挥对象做事情。

7,Java中最基本的单位是类,Java中用class描述事物也是如此: 成员变量  就是事物的属性,成员方法  就是事物的行为

8,成员变量    和以前定义变量是一样的,只不过位置发生了改变。在类中,方法外。成员方法        和以前定义方法是一样的,只不过把static去掉

9,public class Student {

    //成员变量

    //姓名

    String name;

    //年龄

    int age;

   

    //成员方法

    //学习的方法

    public void study() {

        System.out.println("好好学习,天天向上");

    }

   

    //吃饭的方法

    public void eat() {

        System.out.println("学习饿了要吃饭");

      }

  }

10,对象的创建:类名 对象名 = new 类名()

11,对象如何访问成员呢?

   *     成员变量:对象名.变量名

   *      成员方法:对象名.方法名(...)

12,一个对象的内存图和方法区共用内存图:

 

12,两个引用指向同一个对象内存图:

 

 

13,成员变量和局部变量的区别:

   *      A:在类中的位置不同

   *          成员变量:类中,方法外

   *          局部变量:方法中或者方法声明上(形式参数)

   *      B:在内存中的位置不同

   *          成员变量:堆内存

   *          局部变量:栈内存

   *      C:生命周期不同

   *          成员变量:随着对象的创建而存在,随着对象的消失而消失

   *          局部变量:随着方法的调用而存在,随着方法的调用完毕而消失

   *      D:初始化值的问题

   *          成员变量:有默认值

   *          局部变量:没有默认值。必须先定义,赋值,最后使用

14,private关键字:

  a:是一个权限修饰符。

  b:可以修饰成员(成员变量和成员方法)

  c:被private修饰的成员只在本类中才能访问。

15,String name;

      //int age;

      private int age;

   

      public void setAge(int a) {

        if(a<0 || a>200) {

            System.out.println("你给的年龄有误");

        }else {

            age = a;

        }

    }

    public int getAge() {

        return age;

    }

   

    public void show() {

        System.out.println("姓名是:"+name+",年龄是:"+age);

    }

15,A:this:代表所在类的对象引用 ,方法被哪个对象调用,this就代表那个对象

  B:什么时候使用this呢局部变量和成员变量重名

16,构造方法:给对象数据进行初始化。

  A:构造方法格式

  a:方法名与类名相同

  b:没有返回值类型,连void都没有

  c:没有具体的返回值

17,如果你不提供构造方法,系统会给出默认构造方法

  如果你提供了构造方法,系统将不再提供

  构造方法也是可以重载的,重载条件和普通方法相同

18,如果方法的返回值是类名:其实返回的是该类的对象

19,类名作为形式参数:其实这里需要的是该类对象。

20,使用API:

  A:打开帮助文档

  B:点击显示,找到索引,看到输入框

21,C:你要学习什么内容,你就在框框里面输入什么内容

    举例:Random

  D:看包

  java.lang包下的类在使用的时候是不需要导包的

  E:看类的描述

    Random类是用于生成随机数的类

  F:看构造方法

    Random():无参构造方法

        Random r = new Random();

  G:看成员方法

     public int nextInt(int n):产生的是一个[0,n)范围内的随机数

        调用方法:

             看返回值类型:人家返回什么类型,你就用什么类型接收

             看方法名:名字不要写错了

             看形式参数:人家要几个参数,你就给几个,人家要什么数据类型的,你就给什么数据类型的

             int number = r.nextInt(100);

22,Scanner sc = new Scanner(System.in);String s = sc.nextLine();(录入字符串或基本数据类型)

23,String:

  A:"abc"是String类的一个实例,或者成为String类的一个对象

  B:字符串字面值"abc"也可以看成是一个字符串对象

  C:字符串是常量,一旦被赋值,就不能被改变

  D:字符串本质是一个字符数组

   String(String original),String(char[] value),String(char[] value, int index, int count)

23,== :基本数据类型:比较的是基本数据类型的值是否相同

      引用数据类型:比较的是引用数据类型的地址值是否相同

24,创建两种字符串对象的方式区别

 

通过构造方法创建的字符串对象和直接赋值方式创建的字符串对象有什么区别呢?

 *      通过构造方法创建字符串对象是在堆内存。

 *      直接赋值方式创建对象是在方法区的常量池。

25,Object:是类层次结构中的根类,所有的类都直接或者间接的继承自该类。 如果一个方法的形式参数是Object,那么这里我们就可以传递它的任意的子类对象。

26,//创建字符串对象

        String s1 = "hello";

        String s2 = "hello";

        String s3 = "Hello";

       

        //boolean equals(Object obj):比较字符串的内容是否相同

        System.out.println(s1.equals(s2));

        System.out.println(s1.equals(s3));

        System.out.println("-----------");

       

        //boolean equalsIgnoreCase(String str):比较字符串的内容是否相同,忽略大小写

        System.out.println(s1.equalsIgnoreCase(s2));

        System.out.println(s1.equalsIgnoreCase(s3));

        System.out.println("-----------");

       

        //boolean startsWith(String str):判断字符串对象是否以指定的str开头

        System.out.println(s1.startsWith("he"));

        System.out.println(s1.startsWith("ll"));

27, char[] toCharArray():把字符串转换为字符数组

  String toLowerCase():把字符串转换为小写字符串

  String toUpperCase():把字符串转换为大写字符串 

 28,

29,public StringBuilder append(任意类型):添加数据,并返回自身对象

30,public String toString():通过toString()就可以实现把StringBuilder转成String,StringBuilder(String str):通过构造方法就可以实现把String转成StringBuilder

31,对象数组:基本类型的数组:存储的元素为基本类型,对象数组:存储的元素为引用类型

32,

33,面向对象编程语言,而面向对象编程语言对事物的描述都是通过对象来体现的。

34,StringBuilder,数组。StringBuilder的结果只能是一个字符串类型,不一定满足我们的需求。 所以,我们目前只能选择数组了,也就是我们前面学习过的对象数组。  但是,数组的长度是固定的, 如果有时候元素的个数不确定的,我们无法定义出数组的长度,这个时候,java就提供了集合类供我们使用。

35,

  ArrayList<E>:

   *      大小可变数组的实现

   *      <E>:是一种特殊的数据类型,泛型。

   *      怎么用呢?

   *          在出现E的地方我们使用引用数据类型替换即可

   *          举例:ArrayList<String>,ArrayList<Student>

36, IO流用来处理设备之间的数据传输

   Java对数据的操作是通过流的方式

   Java用于操作流的类都在IO包中

    流按流向分为两种:输入流,输出流

 

 

  输出流写数据的步骤:

   *      A:创建输出流对象

   *      B:调用输出流对象的写数据的方法

   *      C:释放资源

    数据没有直接写到文件,其实是写到了内存缓冲区

    创建输出流对象做了哪些事情:

         *      A:调用系统资源创建了一个文件

         *      B:创建输出流对象

         *      C:把输出流对象指向文件

    相对路径:相对当前项目而言的,在项目的根目录下(a.txt)

    绝对路径:以盘符开始的路径(d:\\a.txt)

   close()和flush()方法的区别:

     flush():刷新缓冲区。流对象还可以继续使用。

   close():先刷新缓冲区,然后通知系统释放资源。流对象不可以再被使用了。

void write(String str):写一个字符串数据

void write(String str,int index,int len):写一个字符串中的一部分数据

void write(int ch):写一个字符数据,这里写int类型的好处是既可以写char类型的数据,也可以写char对应的int类型的值。'a',97

void write(char[] chs):写一个字符数组数据

void write(char[] chs,int index,int len):写一个字符数组的一部分数据

如何实现数据的换行?

 *      \n可以实现换行,但是windows系统自带的记事本打开并没有换行,这是为什么呢?因为windows识别的换行不是\n,而是\r\n

 *      windows:\r\n

 *      linux:\n

 *      mac:\r

 * 如何实现数据的追加写入?

 *      FileWriter(String fileName, boolean append) 

  //创建输出流对象

        //FileWriter fw = new FileWriter("c.txt");

        FileWriter fw = new FileWriter("c.txt",true); //表示追加写入,默认是false

       

        for(int x=0; x<10; x++) {

            fw.write("hello"+x);

            fw.write("\r\n");

        }

       

        //释放资源

        fw.close();

    }

FileReader 读取文件类,int read():一次读取一个字符

输入流读文件的步骤:

 *      A:创建输入流对象

 *      B:调用输入流对象的读数据方法

 *      C:释放资源

过测试,我们知道,如果读取数据的返回值是-1的时候,就说明没有数据了,这也是我们循环的结束条件

//创建输入流对象

        FileReader fr = new FileReader("FileWriterDemo.java");

        //创建输出流对象

        FileWriter fw = new FileWriter("Copy.java");

       

        //读写数据

        int ch;

        while((ch=fr.read())!=-1) {

            fw.write(ch);

        }

       

        //释放资源

        fw.close();

        fr.close();

    }

 

 

 

 

//创建输入流对象

        FileReader fr  = new FileReader("FileWriterDemo.java");

        //创建输出流对象

        FileWriter fw = new FileWriter("Copy.java");

       

        //读写数据

        char[] chs = new char[1024];

        int len;

        while((len=fr.read(chs))!=-1) {

            fw.write(chs, 0, len);

        }

       

        //释放资源

        fw.close();

        fr.close();

    }

len 是实际返回的数组长度

BufferedWriter,BufferedReader

 BufferedWriter

       void newLine():写一个换行符,这个换行符由系统决定,不同的操作系统newLine()方法使用的换行符不同

windows:\r\n

linux:\n

mac:\r

 BufferedReader

       String readLine():一次读取一行数据,但是不读取换行符

BufferedReader br = new BufferedReader(new FileReader("FileWriterDemo.java"));

复制文本的五种方式:

A:利用基本流一次读写一个字符

B:利用基本流一次读写一个字符数组

C:利用缓冲流一次读写一个字符

D:利用缓冲流一次读写一个字符数组

E:利用缓冲流的特有方法一次读写一个字符串

public static void main(String[] args) throws IOException {

        //创建输入缓冲流对象

        BufferedReader br = new BufferedReader(new FileReader("FileWriterDemo.java"));

        //创建输出缓冲流对象

        BufferedWriter bw = new BufferedWriter(new FileWriter("Copy.java"));

       

        //读写数据

        String line;

        while((line=br.readLine())!=null) {

            bw.write(line);

            bw.newLine();

            bw.flush();

        }

        //释放资源

        bw.close();

        br.close();

    }

ArrayList集合中的字符串数据存储到文本文件项目根目下的array.txt中

每一个字符串元素作为文件中的一行数据

从项目根目录下的array.txt文本文件中读取数据到ArrayList集合中,并遍历集合,每一行数据作为一个字符串元素

组合关系概念

   在类型A中的成员变量的数据类型是类型B时,此时A和B就是组合关系。

继承的概述
* 继承是面向对象的三大特征之一,也是面向对象开发的重点。
* 用来解决代码重复出现的问题。是类与类关系的一种。
* 从类与类的设计角度来看,子类应该是父类的一种时才可以使用继承。

继承的好处
* 提高了代码的复用性。
* 提高了代码的扩展性。
* 为多态提供了前提

继承的特点
* 子类拥有父类(除构造方法以外)的所有成员变量和成员方法。
* 子类可以直接访问父类非private修饰的成员。
* 子类可以在父类的基础上进行扩展,子类可以添加自己特有的成员变量和成员方法。
* 子类可以使用自己的方式实现父类的功能。(方法重写)
* 构造方法不能被继承,但子类可以间接访问父类的构造方法。

继承的格式
* class 子类类名 extends 父类类名{

}

 父类:描述同一类事物的共性

一个文件里可以定义多个class 但是只能有一个public 而且必须是修饰类名

 java 支持单继承,不支持多继承,支持多层继承。

java中所有类都是object 子类,object是所有类的超类。

通过setter&getter方法访问父类private成员
* 在实际开发中,成员变量都是使用private修饰的
* 子类无法直接访问父类private修饰的成员,此时父类应该为private 成员变量提供setter & getter方法
* 子类可以通过setter & getter方法间接访问父类的private 成员变量。

### 方法重写概念和格式
* 方法重载的概念
* 在同一个类中,方法名相同,参数列表不同,与返回值无关。

* 方法重写的概念
* 在子类中,出现了和父类方法声明完全一样的方法就是方法重写。
* 方法名,参数列表,返回值类型都一样,只是方法体不一样。

* 方法重写的格式
* 和父类方法声明一样,只是方法体不一样。

* 方法重写的场景
* 当父类方法的功能不能满足子类使用时,子类可以重写父类的方法来自己实现该方法的功能。

### 方法重写的注意事项
* 子类重写父类方法后,调用方法不再调用父类的方法,而是调用子类重写后的方法。
* 子类重写父类方法时,使用的权限修饰符要大于等于父类方法的权限。
* public > protected > 默认 > private
* 父类private修饰的方法不能被子类重写,即使子类有完全相同的方法也不属于重写,属于重新定义了一个新的方法。

### this和super访问成员变量和成员方法
* this.成员变量名; 访问的是本类成员变量,如果本类没有,则去父类查找,查找则编译通过,否则编译失败。
* super.成员变量名; 访问的是父类的成员变量,直接去父类找,不管本类是否有该成员变量,如果父类没有,则去父父类查找,查找则编译通过,否则编译失败。。
* this.成员方法(参数列表);
* super.成员方法(参数列表);

* 访问原则
* 就近原则
* this:本类 > 父类 > ...> Object
* super:父类 > 父类 > ...> Object

### this和super访问构造方法
* 调用本类的构造方法
* this(参数列表); 调用本类指定参数的构造方法

* 调用父类的构造方法
* super(参数列表); 调用父类指定参数的构造方法,如果没有指定参数,则调用父类无参数构造。

* 注意事项
* 使用this调用本类构造方法的语句必须是第一行有效语句,且该语句只能出现在构造方法中。
* 使用super调用父类构造方法的语句必须是第一行有效语句,且该语句只能出现在构造方法中。
* 每一个构造方法中默认第一行都会有super()语句调用父类无参数构造。
* this和super调用构造方法时不能同时出现。

 

 

 

this 有四种用法。1,区别成员变量。2,本类对象的引用。3,访问成员变/成员方法。4,访问构造方法

什么时候可以考虑将该方法定义为抽象方法?
* 当子类都会重写该方法时,就可以将该方法定义为抽象方法。

抽象方法的概念
* 被abstract修饰的,只有方法声明,没有方法体的方法就是抽象方法。

抽象方法的格式
* 修饰符 abstract 返回值类型 方法名(参数列表);

* 抽象类的概念
* 被abstract修饰的类就是抽象类。
* 具有抽象方法的类就是抽象类。

* 抽象类的格式
* 修饰符 abstract class 类名{}

* 抽象类的特点
* 抽象类不能直接创建对象。原因:因为调用抽象方法没有意义。
* 类和方法都必须使用abstract关键字修饰。
* 子类必须重写父类中抽象方法,如果没有重写,则该子类也必须定义抽象类。

* 抽象类的作用
* 用来描述一种数据类型应该具备的基本特征(成员变量)和行为(成员方法),如何实现该行为由子类通过
方法重写完成。

* 抽象类的常见问题
* 抽象类可以有构造方法吗?如果有?构造方法有什么意义?
* 有,子类可以通过super来访问抽象父类的构造方法给父类的成员变量赋值。

* 抽象类中可以不定义抽象方法吗?
* 可以

* abstract关键字不能和哪个关键字一起使用?
* private,因为private修饰的方法不能被子类重写,而abstract修饰的
方法要求子类要重写。

* 抽象类一定是父类吗?
* 一定父类

* 接口的概念
* 接口也是一种数据类型,比抽象类更加'抽象'的类型。
* 接口是功能的集合,用来描述功能,如何实现该功能由实现类(接口的子类)通过方法重写来完成。

* 接口的定义格式
* interface 接口名{
// 功能
}

* 接口的定义格式
* interface 接口名{
// 功能
}

* 接口的使用格式
* class 类名 implements 接口名{
// 重写接口的方法
}

* 接口的特点
* 接口中不能有构造方法,不能创建对象。
* 接口中的方法(在JDK1.8之前,不包括1.8)都是抽象方法,在jdk1.8之后接口中的方法可以有默认实现。接口的
实现类可以不重写有默认实现的方法。
* 有默认的修饰符
* public abstract
* 接口中的成员变量就一个常量。
* 常量有默认的修饰符:public static final
* 接口可以继承接口,且可以多继承。

* 如何选择接口和抽象类
* 当某个功能是某种数据类型共有的。此时应该将该功能定义在抽象类中。否则应该将该功能定义
在接口中,需要该功能的类通过实现接口重写方法来获得该功能。

* 注意事项
* 类可以在继承一个类的同时实现多个接口。
* 接口和父类可以有同名的抽象方法,子类只需要重写一个方法即可。
* 类实现接口时,必须重写接口中的所有抽象方法,否则该类也必须定义为抽象类。

* 接口和抽象类的区别(面试题)
* 相同点
* 都不能创建对象。

* 不同点
* 抽象类可以有构造方法,接口不能有构造方法。
* 抽象类可以定义普通的成员变量,接口的成员变量是常量。
* 抽象类可以有普通方法(有方法体的方法),JDK1.8之前接口中的方法都是抽象方法,JDK1.8之后接口中的方法可以默认的实现。
* 抽象类的成员没有默认修饰符,而接口中的成员有默认修饰符
* 方法:public abstract
* 常量:public static final
* 抽象类只能单继承,接口可以多继承
* 类可以实现多个接口。

### 多态的概述
* 多态的概念
* 面向对象的三大特征之一。
* 同一种事物表现出来的多种形态。


* 多态的前提
* 必须有子父类关系或类实现接口
* 必须要有方法重写
* 必须要有父类引用指向子类对象

* 多态的格式
* 父类类名 变量名 = new 子类类名();
* 比如:Animal a = new Dog();

* 多态的好处和弊端
* 弊端:不能调用子类特有的成员(成员变量和成员方法)。
* 好处
* 提高了代码的扩展性。
* 提高了代码的复用性。
* 提高了代码的维护性。

### instanceof关键字
* 作用
* 判断某个引用变量指向的具体的数据类型是什么
* 一般使用在多态之后用来判断父类引用到底指向哪个一个子类类型的对象。

* 格式
* boolean b = 引用变量名 instanceof 类名;

* 注意事项
* 毫无关系的两个类型不能进行判断。
* instanceof 关键字之前的引用类型和 之后的数据类型 必须有子父类关系或类实现接口关系

* static关键字的作用
* static是一个修饰符
* 一般用来修饰成员变量,成员方法,代码块等。
* 被static修饰的成员属于类,不再属于某个对象。可以被该类的所有对象共享。

* 成员变量的分类
* 静态变量或类变量:有static修饰的
* 成员变量或实例变量:没有static修饰的

* 静态变量和成员变量的区别
* 静态变量
* 在内存中只有一份,只会分配一次内存。
* 在类加载的时候完成静态变量的初始化。
* 可以通过对象名访问(不推荐)
* 可以通过类名访问(强烈推荐)

* 成员变量
* 每创建一个对象,就会为该对象的成员变量分配内存空间。
* 每一个对象都有自己的成员变量,互不干扰。
* 只能通过对象名访问

* 成员方法的分类
* 静态方法或类方法:有static修饰的
* 成员方法或实例方法:没有static修饰的

* 静态方法和成员方法的区别
* 静态方法
* 可以通过对象名访问(不推荐)
* 可以通过类名方法(强烈推荐)

* 成员方法
* 只能通过对象名访问

* static关键字注意事项
* 静态方法中不能使用this和super关键字
* 静态方法中不能访问非静态的成员。
* 非静态方法中可以访问静态成员和非静态成员。

* static关键字的使用场景
* 什么时候可以将成员变量使用static修饰
* 如果该成员变量的值在该类的所有对象中都是相同的,则就应该将该成员变量定义为静态变量。

* 什么时候可以将成员方法使用static修饰
* 如果该成员方法中没有使用到任何非静态成员,则可以将该方法定义为静态方法。
* 定义工具类,工具类中的方法一般都是静态方法。

静态代码块

### 权限修饰符
* public:任意包下的任意类都可以访问。
* protected:同包下的任意类或子类都可以访问
* 默认:同包下的任意类都可以访问
* private:只能在本类中访问

### 内部类
* 内部类的概念
* 在类A中定义了另一个类B,则类B称为内部类,类A就称为外部类。
* 内部类的class文件的名字:外部类名$内部类名.class
* 内部类可以访问外部类的任意成员,包括private修饰的

* 内部类的分类
* 成员内部类:和成员变量是同级关系,定义为在成员位置的类。
* 局部内部类:和局部变量是同级关系,定义为在方法内部的类。
* 匿名内部类
* 静态内部类(不讲)

### 成员内部类
* 定义格式
* class 外部类 {
class 内部类{

}
}

* 访问方式
* 间接访问
* 在外部类中提供一个方法创建成员内部类的对象并调用方法,
在其他类创建外部类的对象,调用外部类的方法。

* 直接访问
* 外部类.内部类 变量名 = new 外部类().new 内部类();

* 注意事项
* 如果成员内部类使用private修饰,则不能使用直接访问方式创建成员内部类的对象,只能间接访问。
* 当成员内部类和外部类出现同名的成员时,要访问外部类的成员,则要使用以下格式访问:
* 外部类名.this.成员变量名;
* 外部类名.this.成员方法(参数列名);
* 在成员内部类中不能定义静态变量,如果要定义,则该成员内部类需要定义为静态内部类。

* 使用场景
* 当一个类除了外部类使用时,没有其他地方再使用该类,则可以将该类定义为外部类的一个内部类。
* 当描述事物A时,发现事物A内部还具备另一事物B,而且事物B需要使用到事物A的成员数据,此时就应该将事物B作为事物A的内部类。
class 人 {
氧气
血液
class 心脏 {

}
}


### 局部内部类
* 定义格式
* 定义在外部类的方法中
class 外部类名{
public void test(){
class 局部内部类{

}
}
}

* 访问方式
* 只能在方法内部访问

* 注意事项
* 不能使用权限修饰符修饰局部内部类。
* 局部内部类方法中如果访问了局部变量,则该局部变量就不能再赋值。该局部变量就变成了常量了。

 

### 匿名内部类(重要)
* 匿名内部类
* 没有明确的类的语法,直接就创建已知类的子类对象或接口的实现类对象。

* 匿名内部类的格式
* new 类或接口(){
// 重写方法
}
* 匿名内部类可以定义构造方法吗?
* 不能,因为不知道类名是什么

### 学习目标
* 能够说出Object类中equals方法的作用
* 能够说出Object类中toString方法的作用

* 能够辨别程序中异常和错误的区别

* 说出异常的分类
* 说出虚拟机处理异常的方式
* 列举出常见的四个运行期异常
* ArithmeticException
* ArrayIndexOutOfBoundsException
* NullPointerException
* StringIndexOutOfBoundsException

* 能够使用try...catch关键字处理异常

* 能够使用throws关键字处理异常

* 能够自定义异常类

Object的方法使用

### Object类中equals方法
* equals方法默认比较什么
* 默认是通过==比较两个对象在内存中的地址是否相同

* 重写equals方法的目的
* 因为比较两个对象的地址值判断两个对象是否相同是没有任何意义,一般判断两个对象是否是同一个对象是通过比较两个对象的成员变量值来判断,如果两个对象的成员变量值都相同,则认为是同一个对象。

### Object类中toString方法
* toString方法默认返回值
* 类全名@对象地址值的十六进制

* toString的调用时机
* 直接调用:直接通过对象名调用toString()
* 间接调用:打印输出该对象时,系统会自动调用该对象的toString方法

* 重写toString方法的目的
* 打印一个对象时希望看到该对象的成员变量对应的值。

### 异常的概述
* 什么是异常
* Java程序在编译或运行过程中出现的问题。

* 异常的继承体系
* Throwable:Java 语言中所有错误或异常的超类
* Error:错误
* Exception:异常

* 异常的分类
* 编译时异常
* 运行时异常

### 异常和错误的区别
* 异常
* Java程序在编译或运行过程中出现的问题。
* 异常一般是JVM产生
* 可以针对异常进行处理,处理完成后代码可以继续进行,如果不处理则程序直接退出。

* 错误
* Java程序在运行过程中出现的问题。
* 错误往往是由系统产生的,由系统反馈给JVM
* 错误往往是摧毁性的,一旦出现,没有具体的处理方式,只能修改代码,程序直接退出。

### Throwable常用方法
* String getMessage()
* 获得创建异常对象时指定的消息字符串内容。

* String toString();
* 获得异常对象的类全名和消息字符串内容。

* void printStackTrace()
* 打印异常的栈信息,追溯异常根源。

### 异常的处理方式
* JVM默认处理方式
* 将异常的类名,原因,位置等信息输出到控制台,并结束程序的运行。
* JVM接收到异常对象时,会调用异常对象的printStackTrace()。

* 手动处理方式
* 捕获处理
* 抛出处理

### 异常处理之捕获处理
* 捕获处理的格式
try {

} catch(异常类名 变量名){

} finally{

}

* 格式说明
* try代码块:用来存放可能出现异常的代码
* catch代码块:用来存放处理异常的代码

### 异常处理之多catch处理
* 捕获处理的格式
try {

} catch(异常类名 变量名){

} ... catch(异常类名 变量名){

}

* 格式说明
* try代码块:用来存放可能出现异常的代码
* catch代码块:用来存放处理异常的代码

* 注意事项
* 平级关系的异常类:没有先后顺序。
* 上下级关系异常类:越高级的父类要放在越后面。

### finallay代码块
* 特点
* 只要进入的try,不管是否出现异常,finally代码块的代码一定会被执行。

* 作用
* 一般使用释放资源,比如关闭IO流或数据库相关资源

### 异常处理之抛出处理
* throws和throw的作用
* throw:抛出一个异常对象,将该异常对象抛给方法的调用者,
方法内部没有出异常进行捕获处理则会结束方法的运行。
* throws:声明方法可能出现的异常类型,告诉方法调用对可能出现的异常进行处理。

* throw关键字使用格式
* throw new 异常类名("异常信息");
* 只能抛出Exception或Exception的子类对象。

* throws关键字使用格式
* 修饰符 返回值类型 方法名(参数列表) throws 异常类名1,异常类名1...{}
* 多个异常类名之间使用逗号分隔

* throws和throw使用位置
* throw:方法体
* throws:方法声明上

### 方法重写时异常的处理细节(针对编译时异常)
* 父类方法声明上没有声明抛出异常时
* 子类在重写父类方法时也不能声明抛出异常。

* 父类方法声明上声明抛出了一个异常类型时
* 子类在重写父类方法时可以抛出和父类相同的异常类型或其子类类型。

* 父类方法声明上声明抛出了多个异常类型时
* 子类在重写方法是可以抛出父类异常类型的子集。

* 小结
* 子类重写方法时不能抛出比父类方法声明大的异常。

### 编译时异常和运行时异常的区别
* 运行时异常的概念
* RuntimeException及其子类都属于运行时异常。

* 编译时异常的概念
* 除了运行时异常以为的所有异常都属于编译时异常。

* 运行时异常的特点
* 方法内部抛出的异常是运行时异常,则方法声明可以声明,也可以不声明。
* 方法声明上声明的异常是运行时异常,则方法调用者可以处理,也可以不处理。

* 编译时异常的特点
* 方法内部抛出的异常是编译时异常,则方法声明必须对该异常进行声明。
* 方法声明上声明的异常是编译时异常,则方法调用者必须对异常进行处理。

### 自定义异常
* 自定义异常步骤
* 命名规范:XxxxException
* 继承关系
* Exception:如果要求一定要处理,则继承该异常
* RuntimeException:不要求一定要处理,则继承该异常
* 构造方法
* 无参数构造
* 有参数构造

* 案例
* Person
age
NoAgeException

### 常见问题
* 程序出现问题的时候如何判断是错误还是异常?
* 可以通过控制的错误信息来判断,如果类名是以Error结尾则是错误,以Exception结尾则是异常。

* 捕获异常时是不是捕获Exception即可?
* 不是,因为实际开发中,需要针对不同的异常有不同的处理方式。

* 什么时候使用抛出处理?什么时候使用捕获处理?
* 如果当前代码是直接跟用户打交道的,则应该捕获处理,如果不是,则可以使用抛出处理。

* 父类方法没有声明抛出编译时异常,子类覆盖方法时发生了异常,怎么办?
* 子类重写方法时不能抛出编译时异常,但可以将编译时异常包装成运行时异常再抛出。

* 为什么java编译器对运行时异常管理的如此松散?
* 因为运行时异常可以通过良好的编程习惯避免。

### 异常处理之捕获处理
* 捕获处理的格式
try {

} catch(异常类名 变量名){

} finally{

}

* 格式说明
* try代码块:用来存放可能出现异常的代码
* catch代码块:用来存放处理异常的代码

### Date类基本使用
* Date类
* 时间日期类

* Date类的构造方法
* Date(); 创建日期对象,代表当前系统时间
* Date(long date) 根据指定的毫秒值创建日期对象。

* Date类的成员方法
* long getTime() 获得当前时间的毫秒值(从1970.1.1 00:00:00到当前时间经过的毫秒数)
* void setTime(long time) 设置毫秒值

* 毫秒值
* 1秒 = 1000毫秒
* 时间零点
* 1970 年 1 月 1 日 00:00:00

### DateFormat类基本使用
* DateFormat类的概述
* 是一个格式化日期对象的类。
* 是一个抽象类,不能直接创建对象。

* 如何使用DateFormat格式日期对象
* 使用DateFormat的子类SimpleDateFormat来格式化日期对象。

* SimpleDateFormat常用构造方法
* SimpleDateFormat()
* 使用默认格式创建日期格式化对象
* SimpleDateFormat(String pattern)
* 根据指定的格式创建日期格式化对象。

* SimpleDateFormat常用方法
* String format(Date date)
* 将日期对象转换为字符串
* Date parse(String source)
* 将日期字符串转换为日期对象

* 日期对象转字符串步骤
* 创建日期格式化类SimpleDateFormat对象并指定日期模式。
* 调用format(Data d)方法进行转换,获得字符串对象。

* 字符串转日期对象步骤
* 创建日期格式化类SimpleDateFormat对象并指定日期模式。
* 调用parse(String dateStr)进行转换,获得日期对象


* 注意事项
* 将日期字符串转换为日期对象时指定的日期模式必须在字符串模式一致。

* 日期模式
yyyy 年
MM 月
dd 日
HH 时
mm 分
ss 秒

### Calendar类基本使用
* Calendar类的概述
* 是一个日历类,是一个抽象类,不能直接创建对象。

* 获取Calendar子类对象
* static Calendar getInstance()
* 获得一个日历对象

* Calendar常用方法
* Date getTime();
* 获得日期对象

* int get(int field)
* 返回给定日历字段的值。

* getTimeInMillis()
* 获得毫秒值

* void add(int field, int amount)
* 将指定日历字段的值在当前值的基础上偏移一个值
* amount为正数,则向后偏移
* amount为负数,则向前偏移

* void set(int field,int value)
* 将指定日历字段的值设置为指定的值

* void set(int year,int month,int date)
* 将日历的年月日设置为指定值

* 注意事项
* 获得的月份需要加1才是正确的月份。

### Math类常用方法
* Math 类包含用于执行基本数学运算的方法,如初等指数、对数、平方根和三角函数。
* Math类常用方法
* static int abs(int a) 求a的绝对值
* static double ceil(double a) 返回大于等于参数a的最小整数
* static double floor(double a) 返回小于等于参数a的最大整数
* static double pow(double a, double b) 求a的b次方
* static double random() 返回0.0到1.0的随机数:[0,1) 本质还是Random类
* static int round(double a) 返回a的四舍五入的值

### System类常用方法
* static long currentTimeInMillis() 重点
* 获得当前系统的毫秒值

* static void exit(int status)
* 退出JVM,终止程序运行
* status == 0 正常退出
* status == 负数 异常退出

* static void gc()
* 运行垃圾回收器。 通知垃圾回收器回收垃圾。什么时候会进行垃圾回收取决垃圾回收器心情,不同JVM有不同的回收策略。

* static Properties getProperties()
* 获得操作系统的属性

* static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length) 重点
* 数组复制
* src:源数组,要复制的数组
* srcPos:源数组的起始索引
* dest:目标数组
* destPos:目标数组的起始索引
* length:要复制元素的个数

### 基本数据类型包装类
* 包装类的作用
* 能够将基本数据类型和字符串进行相互转换。
* "10" ==> 10
* 10 ==> "10"

* 八种基本数据类型的包装类
* int Integer
* char Character
* byte Byte
* short Short
* long Long
* float Float
* double Double
* boolean Boolean

### Integer包装类基本使用
* Integer构造方法
* Integer(int value)
* Integer(String str)

* Integer常用方法
* static int parseInt(String str)
* 将整数字符串转换为整数类型,字符串必须是数字组成。
* int intValue()
* 将构造方法指定参数字符串转为整型数据。

* Integer了解方法
* static int MIN_VALUE:整数最小值
* static int MAX_VALUE:整数最大值
* static String toBinaryString(int i) 将整数i转换为二进制字符串
* static String toHexString(int i) 将整数i转换为十六进制字符串
* static String toOctalString(int i) 将整数i转换为八进制字符串

### 自动装箱和自动拆箱
* 自动装箱和自动拆箱的概述
* JDK1.5的新特性
* 基本数据类和其包装类类型可以直接参与运算。

* 自动装箱的概念
* Java自动将基本数据类型转为为其包装类类型的过程则称为自动装箱。
* int age = 100;
* Integer in = age;
* 自动拆箱的概念
* Java自动将包装类转换为其基本数据类型的过程称为自动拆箱。

* 注意事项
* 自动装箱和自动拆箱是由编译器根据语法规则自动完成的动作。

 


### 正则表达式的概念和作用
* 正则表达式的概念
* 一个用来定义匹配规则的字符串

* 正则表达式的作用
* 用来校验某个字符串是否符合规则。

* String和正则表达式相关方法
boolean matches(String regex)
* 判断当前字符串是否符合指定的规则
String[] split(String 正则的规则)
* 使用正则表达式切割字符串
String replaceAll( String 正则规则,String 字符串)
* 将符合正则规定的子串替换成指定的字符串

### 正则表达式语法规则
* 字符
* x 匹配x字符

* 字符类
* [abc] 匹配abc中任意一个字符
* [^abc] 匹配除abc以外任意一个字符
* [0-9] 匹配任意一个数字
* [a-zA-Z] 匹配任意一个字母
* [a-zA-Z_0-9] 匹配字母数字下划线任意一个
* 中括号可以放很多个字符,但匹配时只能匹配其中一个。

* 预定义字符类
* . 通配符,可以匹配除\r和\n以外的任意一个字符。
* \d 等价[0-9] 匹配任意一个数字
* \w 等价[a-zA-Z_0-9] 匹配字母数字下划线任意一个
* \s 匹配空格字符

* 数量词
* x? x可以出现0或1次
* x* x可以出现0或多次
* x+ x可以出现1次或多次
* x{n} x刚刚要出现n次
* x{n,} x至少要出现n次,可以等于n
* x{n,m} x至少出现n次,最多m次,[n,m]


### 正则表达式匹配练习
* 方法:boolean matches(String 正则的规则)
* 例子:
* 检查手机号码是否合法
* 规则:1开头,第二位可以是34578 后面9位数0-9
* 正则表达式:

* 检查QQ是否合法
* 规则:0不能开头,全是数字,位数5到10位
* 正则表达式:

### 正则表达式切割练习
* 方法:String[] split(String 正则的规则)
* 例子
* 2016-10-24 按照-切割字符串
* 18 22 44 66 按照空格切割字符串
* 192.168.1.204 按照点切割字符串

### 正则表达式替换练习
* 方法:String replaceAll( String 正则规则,String 字符串)
* 例子:
* "Hello12345World6789012" 将所有数字替换为 “#”
*

## 学习目标
* 说出Collection集合的常用功能
* add size remove

* 能够使用迭代器对集合进行取元素
* 能够说出集合的使用细节
* 能够使用集合存储自定义类型
* 能够使用foreach循环遍历集合
* 能够使用泛型定义集合对象
* 能够阐述泛型通配符的作用
* 能够斗地主案例

### 今天内容
* 迭代器,增强for,泛型

### 迭代器的概述和使用
* 什么是迭代器
* 是一个用来遍历集合的对象。

* 如何获得迭代器对象
* Iterator<E> iterator()

* Iterator的常用方法
* boolean hasNext()
* 判断当前指针指向的位置是否有元素
* 如果有,则返回true,否则返回false

* E next()
* 返回当前指针指向位置的元素,并将指针下移指向下一个元素。

* 迭代器的好处
* 屏蔽了众多集合的内部实现,对外提供了统一的遍历方式。
* 可以遍历所有单列的集合。

* 迭代过程
* 通过hasNext()方法判断当前指针指向的位置是否有元素
* 如果有元素,则调用next()方法获得该位置的元素,并将指针下移指向下一位元素。

* 注意事项
* 如果没有元素可迭代了,仍然调用next()方法会抛出异常。

### 增强for
* 增强for
* JDK1.5新特性
* 专门用来遍历数组和集合
* 本质还是迭代器。

* 增强for格式
* for(数据类型 变量名:数组名或集合名){

}

* 注意事项
* 使用增强for遍历引用数据类型时,通过引用变量修改对象的属性值会影响集合中对象的属性值。

### 集合中泛型的使用
* 集合中存在什么样的安全隐患
* 集合默认可以存储任意类型的对象。
* 当在存储String的集合中,存储一个Integer类型,调用String类型的特有方法就会报错,导致程序崩溃。

* 集合中泛型的使用
* 创建集合使用泛型指定集合只能存放的数据类型。
* 遍历集合时不需要进行类型转换。

* 泛型的好处(优点)
* 增强了集合安全性,把运行时的错误转为编译时错误。
* 省去了类型强转的麻烦。

* 集合中使用泛型注意事项
* 在泛型中没有多态的概念,要不左右两边的数据类型要保持一致,要不只写一边。推荐两边都写一样的。
* 泛型不准使用基本数据类型,如果需要使用基本数据类型,要使用基本数据类型对应的包装类。

### 泛型方法
* 需求
* 定义一个方法,方法可以接收任意类型的参数,方法返回值类型要和实际参数的类型一致。

* 泛型概述
* 泛型变量可以理解为数据类型的占位符。
* 泛型变量还可以理解为数据类型的变量。

* 泛型变量的命名规范
* 只要是一个合法的标识符就可以,一般使用一个大写字母表示
* T Type
* E Element
* K key
* V value

* 什么是泛型方法
* 方法声明上使用了泛型变量的方法就是泛型方法。

* 泛型方法的格式
* 权限修饰符 <泛型变量> 返回值类型 方法名(参数列表) {}

### 泛型类的定义和使用
* 需求
* 一个方法可以接收任意类型的数组,将数组元素进行反转
* 一个方法可以接收任意类型的数组,将数组元素拼接成字符串返回

* 什么是泛型类
* 在类上使用了泛型变量的类

* 泛型类的格式
* class 类名<泛型变量>{}

* 泛型类的使用方式
* 在创建泛型类对象时需要指定泛型变量的具体数据类型
* 泛型类名<具体的数据类型> 变量名 = new 泛型类名<具体的数据类型>()
* 如果在创建泛型类的对象时没有指定泛型变量的具体数据类型,则默认是Object
* 静态方法上不能使用类定义的泛型变量,如果要使用,则需要将该方法定义泛型方法,由该方法自己定义泛型变量。

### 泛型接口
* 需求
* 增删改查
* 用户信息

* 什么是泛型接口
* 使用了泛型变量的接口就是泛型接口

* 泛型接口的格式
* interface 接口名<泛型变量>{}

* 泛型接口的实现方式
* 实现接口的同时指定泛型变量的具体数据类型。
* 不够灵活,无法在创建对象时修改泛型变量的数据类型了。

* 实现接口时不指定泛型的具体数据类型,由使用者在使用实现类时指定泛型变量的具体数据类型。(推荐使用)
* 比较灵活,可以在创建对象时指定泛型变量的具体数据类型。

### 泛型上下限(了解)
* 泛型上下限引入
* 需求1
* 定义一个方法可以接收任意类型的集合对象
* 集合对象只能存储Integer或者是Integer的父类数据。

* 需求2
* 定义一个方法可以接收任意类型的集合对象
* 集合对象只能存储Number或者是Number的子类数据。

* 泛型的通配符
* ? 匹配任意类型数据,不需要定义就可以使用。
* 不能用来定义泛型方法和泛型类,泛型接口
* 一般?不会单独使用,一般会结合泛型上下限使用

泛型下限
* ? super Integer 只能传递Integer或Integer的父类类型
泛型上限
* ? extends Number 只能传递Number或Number的子类类型

### 并发修改异常
* java.util.ConcurrentModificationException:并发修改异常
* Java官方规定:在使用迭代器迭代集合的过程中,不能调用集合的add,clear方法来修改集合的长度。

* 如何解决并发修改的问题
* 使用普通for遍历(要求集合有索引)
* 使用ListIterator遍历

### 学习目标
* 能够说出List集合的特点
* 使用List存储的数据结构
* 能够说出List常见的三个的特点
* 能够说出Set集合的特点
* 说出哈希表的特点
* 使用HashSet集合存储自定义元素
* 说出判断集合元素唯一的原理

### 数据存储结构
* 队列
* 先进先出(First In First Out) FIFO
* 栈
* 先进后出(First In Last Out) FILO

* 数组
* 增删慢:每次增加或删除元素都需要移动大量的元素。
* 查询快:直接根据索引获得元素。

* 链表
* 增删快:每次增加或删除元素不需要移动大量元素,只需要修改上一个元素记住下一个元素的地址值
* 查询慢:每次查询元素都需要从链表头或链表尾部开始查询。

### 单列集合
* 单列集合的继承体系
* Collection 接口是所有单列集合根接口(父类)
* Collection
* List
* ArrayList
* LinkedList
* Set
* HashSet
* LinkedHashSet

### List接口和Set接口的特点
* List接口的特点
* 有序(存和取顺序一致),有索引,元素可重复

* List接口的常用子类
* ArrayList
* LinkedList

* List集合的遍历方式
* 普通for
* 迭代器
* 增强for


* Set接口的特点
* 无序(存和取的顺序不一致),无索引,元素不可重复

* Set接口的常用子类
* HashSet
* LinkedHashSet

* Set集合的遍历方式
* 迭代器
* 增强for

### ArrayList集合的特点
* 有序,有索引,元素可重复
* 底层是数组结构
* 增删慢,查询快
* 线程不安全,效率高。

### LinkedList集合的特有方法
* void addFirst(E e) 将元素插入到链表头
* void addLast(E e) 将元素插入到链表尾部
* E removeFirst() 删除链表头元素,返回被删除的元素
* E removeLast() 删除尾部元素,返回被删除的元素
* E pollFirst() 删除链表头元素,返回被删除的元素
* E pollLast() 删除尾部元素,返回被删除的元素
* E peekFirst() 查看链表头的元素,并不删除该元素。
* E peekLast() 查看链表尾的元素,并不删除该元素

* LinkedList的索引决定了查询元素从链表头还是链表尾部开始查询
* 如果索引大于集合长度的一半,则从链表尾部开始查询
* 如果索引小于集合长度的一半,则从链表头开始查询

### LinkedList集合的特点
* 有序,有索引,元素可重复
* 底层是链表结构
* 增删快,查询慢
* 还支持队列和栈结构

### LinkedList支持队列和栈结构
* LinkedList支持队列结构:先进先出
* void offer(E e) 将元素添加到队列中
* E poll() 获得队列中的第一个元素,会将元素从队列中删除
* E peek() 获得队列中的第一个元素,但不删除

* LinkedList支持栈结构:先进后出
* push(E e) 将元素压入栈顶
* E pop() 获得栈顶的元素并删除
* E peek() 获得栈顶的元素,但不删除

### 如何选择ArrayList和LinkedList
* 如果不需要增删元素,则选择ArrayList
* 如果需要大量增删元素,则选LinkedList

### HashSet的特点和使用
* 特点
* 无序(存和取的顺序不一致),无索引,元素不可重复
* 底层是哈希表
* 查询增删都比较快

* 什么是哈希表
* 数组和链表的结合体。

### LinkedHashSet的特点
* 继承HashSet
* 能够保证存和取的顺序一致。

### 对象的哈希值-hashCode方法
* 概述
* 对象的哈希值就是一个十进制整数。
* 通过父类Object的hashCode方法获得。默认返回值是对象在内存中的地址值。
* 哈希值是对象存储到哈希表的依据。

* int hashCode()
* 获得对象的哈希码值。

* 字符串重写了hashCode方法
* 通过将每一个字符的ASSIC码相加。只要内容相同,得出哈希值就相同。


### 哈希表的存储过程
* 哈希表的数据结构图
![](哈希表的数据结构.JPG)
* 加载因子:表中填入的记录数 / 哈希表的长度 <br>
* 比如:加载因子是0.75,数组的长度为16,其中存入16 * 0.75 = 12个元素。如果再存入第十三个(>12)元素。那么此时会扩充哈希表(再哈希),底层会开辟一个长度为原长度2倍的数组。把老元素拷贝到新数组中,再把新元素添加数组中。当存入元素数量 > 哈希表长度 * 加载因子,就要扩容,因此加载因子决定扩容时机。

* 哈希表的存储过程(存取原理):每存入一个新的元素都要走以下五步
* (1)调用对象的hashCode()方法,获得要存储元素的哈希值。
* (2)将哈希值与表的长度(即数组的长度)进行求余运算得到一个整数值,该值就是新元素要存放的位置(即是索引值)。
* 如果索引值对应的位置上没有存储任何元素,则直接将元素存储到该位置上。
* 如果索引值对应的位置上已经存储了元素,则执行第3步。

* (3)遍历该位置上的所有旧元素,依次比较每个旧元素的哈希值和新元素的哈希值是否相同。
* 如果有哈希值相同的旧元素,则执行第4步。
* 如果没有哈希值相同的旧元素,则执行第5步。

* (4)比较新元素和旧元素的地址是否相同
* 如果地址值相同则用新的元素替换老的元素。停止比较。
* 如果地址值不同,则新元素调用equals方法与旧元素比较内容是否相同。
* 如果返回true,用新的元素替换老的元素,停止比较。
* 如果返回false,则回到第3步继续遍历下一个旧元素。

* (5)说明没有重复,则将新元素存放到该位置上并让新元素记住之前该位置的元素。

### HashSet存储自定义对象
* 需求
* 定义一个Person类,包含姓名和年龄等成员变量。
* 创建多个Person对象存储到HashSet集合中。
* 要求属性值完全相同的对象只存储一个。

* 哈希表的存储自定义对象
* 默认对象的hashCode是从Object中继承的
* Object的hashCode是根据内存地址计算出来的
* 所以只要对象的地址不同,hashCode就不会相同。
* 所以就算两个对象属性值完全相同,他们两个也不会判定为重复元素。

* 自定义对象重写hashCode和equals
* 重写自定义对象的hashCode方法
* 尽可能让不同的属性值产生不同的哈希值,这样就不用再调用equals方法去比较属性,效率比较高。

* 小结
* 当使用HashSet存储自定义类型,如果没有重写该类的hashCode与equals方法,则判断是否重复的依据是根据对象地址值,如果想通过内容比较元素是否相同,需要重写该类的hashcode与equals方法。

### ArrayList判断对象是否重复的原理
* 需求
* 定义一个学生类,包含姓名和身份证号码
* 创建三个学生对象学生添加到ArrayList集合中。
* 要求
* 有两个学生的姓名和身份证是一样的。
* 相同姓名和身份证号的学生只存储一个。

* ArrayList的contains方法判断元素是否重复原理。
* 传入的元素的equals方法依次与集合中的旧元素所比较,从而根据返回的布尔值判断是否有重复元素。
* 当ArrayList存放自定义类对象时,当自定义类在未重写equals方法前,判断是否重复的依据是地址值。如果想根据内容判断是否为重复元素,则需要重写自定义类的equals方法。
* 底层依赖于equals()方法。

### HashSet判断对象是否重复的原理
* HashSet的add/contains等方法判断元素是否重复原理
* 将新元素与集合中已有的旧元素的HashCode值进行比较。
* 哈希值相同,再通过比较地址值或equals方法比较内容是否相同。
* 只要地址或内容相同,则表示包含。否则表示不包含。
* 哈希值不同,直接返回false表示不包含。
* 底层依赖于hashCode()和equals()。

### 集合小结
* 阐述整个单列集合体系。
* Collection 父类
* List:有序,有索引,元素可重复
* ArrayList:底层是数组,增删慢,查询快,线程不安全,效率高。
* LinkedList:底层是链表,增删快,查询慢,线程不安全,效率高。
* Set:无序,无索引,元素不可重复
* HashSet:底层哈希表,数组和链表的结合体,增删查询都比较快
* LinkedHashSet:继承HashSet 能保证存储顺序一致。

* list和set集合中不同类的使用场景。
* 元素可重复,只能从List接口选择
* 如果不需要增删元素,则选择ArrayList
* 如果需要大量增删元素,则选LinkedList

* 元素不可重复,优先选择set
* 要求存储顺序则选择LinkedHashSet,否则随便选择LinkedHashSet和HashSet

### 学习目标
* 能够说出Map集合特点
* 使用Map集合添加方法保存数据
* 使用”键找值”的方式遍历Map集合
* 使用”键值对”的方式遍历Map集合
* 能够使用HashMap存储自定义键值对的数据
* 能够说出可变参数的作用
* 能够使用集合工具类
* 能够使用HashMap编写斗地主洗牌发牌案例

### 今天的内容
* Map集合
* 方法可变参数
* Collections和Arrays工具类
* 斗地主案例的完善

* 需求
* 存储我们班的所有学生的姓名
* 可以使用单列集合存储。ArrayList
* 获得张三学生

“001”:zhangsan
"002":lisi


### Map集合
* Map集合的特点
* 是一个双列集合,每次存储元素时需要存储两个元素,一个元素称为键,一个元素称为值。
* 键必须的唯一的,值可以重复。

* 继承体系
* Map:接口,可以看成双列集合的父类
* HashMap
* LinkedHashMap

* 注意事项
* 键必须的唯一,如果键重复会使用新值替换旧值,并返回旧值。

* Map接口常用方法
* V put(K key, V value) 增加/修改
* 存储键值对到map集合中
* 如果key已经存在,则会使用新值替换旧值,并返回旧值。
* 如果可以不存在,则直接添加。

* V get(Object key) 查
* 根据键获得值
* 如果key不存在,则返回null

* V remove(Object key) 删
* 根据键删除键值对,返回键对应值
* 如果key不存在,则什么也发送

* int size()
* 获得键值对的数量

### Map集合的遍历方式
* 通过keySet方法遍历
* 调用map集合的keySet方法获得键集合
* 通过增强for或迭代器遍历键集合,获得每一个键
* 通过map的get(Object key)方法根据键获得对应的值。

* 通过entrySet方法遍历
* 调用map集合的entrySet方法获得Entry集合
* 通过增强for或迭代器遍历Entry集合,获得每一个Entry对象
* 调用Entry对象的getKey()和getValue()方法获得键和值。

### Entry对象
* 概念
* 每一个键值对都对应一个Entry对象

* Entry类常用方法
* K getKey() 获得键
* V getValue() 获得值

### LinkedHashMap的特点
* 继承HashMap,能够保证存取顺序一致。

### Map存储自定义对象
* 当自定义对象作为键时,为了保证相同成员变量的对象只存储一个时,需要重写自定义类的hashCode和equals方法。

### 方法可变参数
* 前提:数据类型确定,参数个数任意。
* 格式:数据类型...变量名
* 本质:数组
* 注意事项
* 一个方法参数列表中只能有一个可变参数,且只能出现在参数列表的最后一个。


### Collections工具类常用方法
* static boolean addAll(Collection c, T... elements)
* 将数组元素添加到指定的集合c中

* static int binarySearch(List list, T key)
* 要求:集合中的元素必须是有序的,从小到大排好序。
* 使用二分法在指定的集合list中查询指定的元素key
* 如果找到则返回该元素在集合中的索引值。
* 如果没有找到,返回值=-插入点-1 ==> -5 = -插入点-1 ==> 插入点 = 4

* static void sort(List<T> list)
* 使用默认比较器对集合中的元素进行排序,默认升序排序、
* static <T> void sort(List<T> list, Comparator c)
* 使用自定义比较器对集合中的元素进行排序。
* static void shuffle(List<?> list)
* 将指定集合元素打乱顺序。

### Arrays工具类常用方法
* static List<T> asList(T... a)
* 将数组转换为集合,集合长度是固定的。

* static int binarySearch(Object[] a, Object key)
* 要求:数组中的元素必须是有序的,从小到大排好序。
* 使用二分法在指定的数组中查询指定的元素key
* 如果找到则返回该元素在数组中的索引值。
* 如果没有找到,返回值=-插入点-1 ==> -5 = -插入点-1 ==> 插入点 = 4

* static void sort(Object[] str) 对数组进行排序,默认升序排序
* static String toString(Object[] a) 将数组内容拼接成字符串
* static void fill(int[] a, int val) 将指定数组的元素填充为指定值val
* static boolean equals(int[] a, int[] a2) 判断两个数组的长度,内容是否一样,如果是返回true,否则返回false

### 集合转数组
* Object[] toArray()
* 将集合元素添加到对象数组中并返回该对象数组

* T[] toArray(T[] a)
* 当传入的数组能够存储集合中元素时,该方法内部就会将集合中的元素添加到传入的数组中,并返回传入的数组。
* 当传入的数组不能够存储完集合中的元素时,该方法内部会创建一个新的数组并将集合中的元素添加到新的数组中,并将新数组作为返回值返回。此时传入的数组只起到一个确定新数组数据类型的作用。

## 学习目标
* 能够说出File对象的创建方式
* 能够说出File类获取名称的方法名称
* 能够说出File类获取绝对路径的方法名称
* 能够说出File类获取文件大小的方法名称
* 能够说出File类判断是否是文件的方法名称
* 能够说出File类判断是否是文件夹的方法名称
* 能够辨别相对路径和绝对路径
* 能够遍历文件夹
* 能够解释递归的含义
* 能够使用递归的方式计算5的阶乘
* 能够说出使用递归会内存溢出隐患的原因

### 今天内容
* File
* 递归

### File类的概述
* File类是文件和目录路径名的抽象表示形式。
* 一个File对象就对应一个文件或文件夹。
* 作用:用来操作硬盘上的文件或文件夹。

### 相对路径和绝对路径
* 绝对路径
* 从盘符开始,在系统中具有唯一性。
* "c:/java/jdk/aaa.txt"

* 相对路径
* 相对某个目录而已,不具有唯一性。
* c:/java/ jdk/aaa.txt
* d:/aaa/ jdk/aaa.txt

* FileReader fr = new FileReader("a.txt");a.txt文件相对项目的根目录而已

### File类构造方法
* File(File parent, String child)
* 根据父路径文件对象和子路径字符串创建文件对象
* parent+child=绝对路径

* File(String pathname)
* 根据文件路径字符串创建文件对象。

* File(String parent, String child)
* 根据父路径字符串和子路径字符串创建文件对象
* parent+child=绝对路径

### File类文件创建功能的方法
* boolean createNewFile()
* 根据构造方法指定的文件路径创建文件,只能创建文件,不能创建文件夹。
* 如果文件已经存在,则返回false,如果文件不存在,则创建,
* 如果文件不存在,则创建,创建成功返回true

### File类文件夹创建功能的方法
* boolean mkdir();
* 创建单级文件夹,只能创建文件夹
* 如果存在,则返回false
* 如果不存在,则创建,创建成功返回true。

* boolean mkdirs();
* 创建多级文件夹,只能创建文件夹,
* 如果父文件夹不存在,则会先创建父文件夹。创建成功返回true。

### File类删除文件功能的方法
* boolean delete();
* 删除文件或文件夹
* 如果是文件,则直接删除,删除成功返回true,否则返回false。
* 如果是文件夹,则要求文件夹必须是一个空文件夹,否则删除不了。

### File类判断功能的方法
* boolean isDirectory();
* 判断文件对象是否是一个文件夹
* 如果是返回true,否则返回false

* boolean isFile();
* 判断文件对象是否是一个文件
* 如果是返回true,否则返回false

* boolean exists();
* 判断文件或文件夹是否存在
* 存在返回true,否则返回false

### File类获得功能的方法
* long length();
* 获得文件的大小,单位:字节
* 只能获得文件的大小,不能获得文件夹的大小。

* String getName();
* 获得文件或文件夹的名字

* String getAbsolutePath()
* 获得文件夹或文件的绝对路径字符串

* File getAbsoluteFile()
* 获得文件夹或文件的绝对路径文件对象

* String getParent()
* 获得文件或文件夹的父路径字符串
* 除了文件名或文件夹名以为的部分

* File getParentFile();
* 获得文件或文件夹的父路径文件对象

### File类list获得功能方法
* String[] list()
* 获得当前文件夹下所有的子文件或子文件夹,返回字符串数组
* 字符串数组中存储的就是子文件或子文件夹的名字
* 要求:文件对象封装的路径必须是一个文件夹。

* File[] listFiles()
* 获得当前文件夹下所有的子文件或子文件夹,返回文件数组
* 文件数组中存储的就是子文件或子文件夹的File对象
* 要求:文件对象封装的路径必须是一个文件夹。

### 递归概述
* 什么是递归
* 指方法内部自己调用自己。
* 方法a调用方法a,则称为递归。

* 递归的分类
* 间接递归:方法A调用方法B,方法B调用方法C,方法C调用方法A。
* 直接递归:方法A调用方法A。

* 递归的注意事项
* 必须要有出口,结束递归的条件。
* 递归次数不要太多
* 构造方法中不能使用递归。

### 递归练习题
* 求1到n的和(n>=10 && n <= 100)
* 求n!阶乘(n>=10 && n <= 100)

### 递归遍历指定文件夹下的所有文件(包括子文件夹)

### 文件过滤器
* 获得指定文件下包括子文件夹下所有的avi文件
File[] listFiles(FileFilter filter)
* 根据指定过滤器来筛选指定文件夹下的文件

FileFilter接口的方法
* accept方法的调用时机
* 每当获得一个子文件或子文件夹时,都会将该子文件或子文件夹作为参数调用accpet方法。
* 返回true表示该文件或文件夹需要添加到数组中作为返回值
* 返回false表示该文件或文件夹不需要添加到数组中作为返回值。

### File类两个静态变量
* static String pathSeparator
* 与系统有关的路径分隔符。
* mac和linux是:
* windows是;

* static String separator
* 与系统有关的目录分隔符。
* mac和linux是 /
* windows是 \

### 今天内容
* 转换流
* 对象流
* 打印流
* 第三方工具

### 字符流的回顾
* 分类
* Reader:抽象类,所有字符输入流的父类
* FileReader 继承 InputStreamReader 继承 Reader
* BufferedReader 继承 Reader

* Writer:抽象类:所有字符输出流的父类
* FileWriter 继承 OutputStreamWriter 继承 Writer
* BufferedWriter 继承 Writer

* 作用
* 将内存中的数据保存到文本文件中。
* 将文本文件的数据读取到内存中。

### 编码表的概述
### 转换流的概述
* 转换流
* 字节流和字符流相互转换的桥梁。

* 乱码出现的原因
* 读取数据使用的编码和存储数据时使用的编码不一致导致的。

* 为什么需要使用转换流
* FileReader或FileWriter操作文本文件时,一旦涉及到具体的编码方式时,就会
出现乱码问题。

* 分类
* InputStreamReader
* OutputStreamWriter

### OutputStreamWriter流概述
* OutputStreamWriter类概述
* 字符输出流
* 继承Writer 本质也是字符流,只能操作文本文件。

* OutputStreamWriter类作用
* 字符流通向字节流的桥梁

* OutputStreamWriter类构造方法
* OutputStreamWriter(OutputStream out) 默认是GBK码表
* OutputStreamWriter(OutputStream out, String charsetName)
* 目前可以传递的字节输出流:FileOutputStream,BufferedOutputStream
* charsetName:指定编码表 可以指定:"gbk"或“utf-8”

* OutputStreamWriter类成员方法
* write()
* 可以写出一个字符串,一个字符数组,一个字符

* 字符流转换字节流的过程
* 由字符输出转换流查询指定的码表得到对应的字节
* 然后将字节交给字节输出流输出到目标文件中。

### InputStreamReader类的概述
* InputStreamReader类的概述
* 字符输入流,继承Reader 也只能操作文本文件。

* InputStreamReader类作用
* 字节流通向字符流的桥梁

* InputStreamReader类构造方法
* InputStreamReader(InputStream in)
* InputStreamReader(InputStream in,String charsetName)
* 目前可以传递的字节输出流:FileInputStream,BufferedInputStream
* charsetName:指定编码表 可以指定:"gbk"或“utf-8”

* InputStreamReader类成员方法
* read()
* 可以读一个字符,一个字符数组。

* 字节流转换字符流的过程
* 先由字节流从目标文件读取数据
* 然后将读取的字节输出交给字符输入转换流对象
* 由字符输入转换流对象查询指定的编码表得到对应字符。

### 转换流子父类的小结
* InputStreamReader 可以修改码表,一般可以指定 gbk和utf8
* FileReader 不能修改码表,只能使用默认的码表:GBK
* BufferedReader

* OutputStreamWriter 可以修改码表,一般可以指定 gbk和utf8
* FileWriter 不能修改码表,只能使用默认的码表:GBK
* BufferedWriter

### 序列化和反序列化的概念
* 对象序列化的概念
* 将对象以流的形式保存到文件的过程称为对象序列化。
* 实现对象序列化操作:ObjectOutputStream

* 对象的反序列化概念
* 从文件中将对象读取出来的过程称为对象的反序列化。
* 实现对象反序列化操作:ObjectInputStream

* 对象流的分类
* 对象输出流:ObjectOutputStream
* 对象输入流:ObjectInputStream

### ObjectOutputStream的使用
* ObjectOutputStream构造方法
* ObjectOutputStream(OutputStream out)
* 传递一个字节输出流,可以传递的字节输出流对象:FileOutputStream,BufferedOutputStream

* ObjectOutputStream常用方法
* void writeObject(Object obj)
* 将对象obj写出到流关联的文件中

* 类的对象要想实现序列号操作,则必须实现两个操作
* 实现一个接口:Serializable
* 提供一个固定的序列号:private static final long serialVersionUID = -7095410184877126563L;

* 注意事项
* 静态成员变量不能被序列化到文件中,因为静态成员变量是属于类的成员,不属于对象的成员。
而对象序列化操作只会保存和对象相关的数据。

* java.io.NotSerializableException: com.itheima.对象流.Student
* 对象不能被序列化。

### Serializable接口
* 没有任何方法,是一个标记性接口。
* 只有实现了该接口的对象才能够被序列化。

### ObjectInputStream的使用
* ObjectInputStream构造方法
* ObjectInputStream(InputStream in)
* 传递一个字节输入流,可以传递的字节输入流对象:FileInputStream,BufferedInputStream

* ObjectInputStream常用方法
* Object readObject();
* 从对象输入流关联的文件中读取对象。

### transient关键字
* transient 瞬时,瞬间
* 格式
* 修饰符 transient 数据类型 变量名;
* 作用
* 用来修饰成员变量,能够保证该成员变量的值就不会被序列化到文件中。

### 如何解决序列号冲突问题
* 自己提供序列号,不让系统自动生成。
* private static final long serialVersionUID = -7095410184877126563L;


### 打印流
* 作用
* 为其他流增加输出数据的功能,使其能方便原样输出各种数据类型的值。

* 分类
* 字符打印流:PrintWriter
* 字节打印流:PrintStream

* 特点
* 打印流没有输入流,只有输出流

* 常用方法
* print(数据类型 变量名) 输出数据不换行
* println(数据类型 变量名) 输出数据自动换行

### 第三方工具CommonsIO使用
* 使用步骤
* 在项目根目录下创建一个文件夹:lib
* 将第三方jar复制到lib文件夹下
* 选中jar包-->右键--> Build Path --> add to Build Path

* FilenameUtils工具类常用方法
* getExtension(String path)
* getName()
* isExtension(String fileName,String ext)

* FileUtils工具类常用方法
* readFileToString(File file)
* writeStringToFile(File file,String content)
* copyDirectoryToDirectory(File srcDir,File destDir)
* copyFile(File srcFile,File destFile)

### 使用Eclipse生成jar包

 

 

 

 

 

 

 

 

 

 

 

 

 

posted @ 2019-03-20 14:34  JSCHEN180425  阅读(192)  评论(0编辑  收藏  举报