Java期末复习知识点 下

碎碎念~

终于来到了最后一堆啦,但其实好像前面的知识也没有消化地很好,但是会在不断地码代码的过程中好好吸收消化这些知识滴~

完结撒花~

在末尾的那一些知识其实自己还是没有理解好,最主要的是怎么把知识转化到在代码上展现出来,今天琢磨课程设计琢磨地有点秃呜呜呜,一团浆糊

再说明一下,以下的笔记都是来自动力节点杜老师的网课外加自己的一些理解噢,如果有不对的地方欢迎评论区指出~


目录

访问控制权限

    访问控制权限都有哪些?

        以上的4个访问控制权限:控制的范围是什么?

        访问控制权限修饰符可以修饰什么?

JDK类库的根类:Object

        什么是API?

    toString()方法

    equals()方法

       finalize()方法。

hashCode方法:

数组

    数组的优点和缺点,并且要理解为什么。

    一维数组的静态初始化和动态初始化

    一维数组的遍历

    二维数组的静态初始化和动态初始化

    二维数组的遍历

    数组的拷贝:System.arraycopy()方法的使用

    常见的算法:

冒泡排序:

选择排序:

二分法查找(折半查找):

String类。

    对String在内存存储方面的理解:

    String的构造方法。(没听懂)

        String类常用的21个方法。

包装类

八种基本数据类型对应的包装类

    什么是自动装箱和自动拆箱,代码怎么写?

    日期类

数字类

随机数

枚举

java的异常处理机制

什么是UML?有什么用?

集合概述

    集合在java JDK中哪个包下?

    在java中集合分为两大类:

关于Java.util.Collection接口中的常用的方法

迭代器遍历集合

关于集合元素的remove

List接口中的常用方法。

ArrayList

IO流

java.io包下需要掌握的流有16个:

多线程

反射机制


完整类名带包名(这句话在心里形成印象)

1、访问控制权限

    1.1、访问控制权限都有哪些?


        4个。
        private    私有
        public 公开

        protected    受保护
        默认(default)啥也不写


    
    1.2、以上的4个访问控制权限:控制的范围是什么?


        private 表示私有的,只能在本类中访问
        public 表示公开的,在任何位置都可以访问(所以说不同包也可以?
        “默认”表示只能在本类,以及同包下访问。
        protected表示只能在本类、同包、子类中访问。

        访问控制修饰符            本类            同包            子类            任意位置
        ---------------------------------------------------------------------------
        public                    可以            可以            可以            可以
        protected                可以            可以            可以            不行
        默认                        可以            可以            不行            不行
        private                    可以            不行            不行            不行

        这个不要死记硬背,自己下去之后编写代码自己测试。

        范围从大到小排序:public > protected > 默认 > private


    
    1.3、访问控制权限修饰符可以修饰什么?


        属性(4个都能用)
        方法(4个都能用)
        类(public和默认能用,其它不行。)
        接口(public和默认能用,其它不行。)
        .....

2、JDK类库的根类:Object

    2.1、这个老祖宗类中的方法我们需要先研究一下,因为这些方法都是所有子类通用的。
    任何一个类默认继承Object。就算没有直接继承,最终也会间接继承。

    2.2、Object类当中有哪些常用的方法?
        我们去哪里找这些方法呢?
            第一种方法:去源代码当中。(但是这种方式比较麻烦,源代码也比较难)
            第二种方法:去查阅java的类库的帮助文档。
    


        什么是API?


            应用程序编程接口。(Application Program Interface)
            整个JDK的类库就是一个javase的API。
            每一个API都会配置一套API帮助文档。
            SUN公司提前写好的这套类库就是API。(一般每一份API都对应一份API帮助文档。)
        
        目前为止我们只需要知道这几个方法即可:
            protected Object clone()   // 负责对象克隆的。
             int hashCode()    // 获取对象哈希值的一个方法。
            boolean equals(Object obj)  // 判断两个对象是否相等
            String toString()  // 将对象转换成字符串形式
            protected void finalize()  // 垃圾回收器负责调用的方法

    2.3、toString()方法


1、源代码长什么样?
    public String toString(){
        return this.getClass().getName()+“@”+Integer.toHexString(hashCode());
}
源代码上toString()方法的默认实现是:
    类名@对象的内存地址转化为十六进制的形式

toString()方法设计的目的是:通过调用这个方法可以将一个“Java对象”转换成“字符串”形式
        以后所有类的toString()方法是需要重写的。
        重写规则,越简单越明了就好。

        System.out.println(引用); 这里会自动调用“引用”的toString()方法。
输出引用的时候,会自动调用该引用的toString方法
    
        String类是SUN写的,toString方法已经重写了。
    


    2.4、equals()方法


public boolean equals(Object obj){
    return(this==obj);
}
以上这个方法是Object类的默认实现
Sun公司设计equals方法的目的是什么?
以后编程的过程当中,都要通过equals方法来判断两个对象是否相等
equals方法是判断两个对象是否相等的
判断两个基本数据类型的数据是否相等直接使用“==”就行
判断两个Java对象是否相等,不能使用“==”,因为双等号比较的是两个对象的内存地址
在object类中的equals方法中,默认采用的是双等号判断两个Java对象是否相等,而双等号判断的两个Java对象的内存地址,我们应该判断两个Java对象的内容是否相等,所以老祖宗的equals方法不够用,需要子类重写
        以后所有类的equals方法也需要重写,因为Object中的equals方法比较
        的是两个对象的内存地址,我们应该比较内容,所以需要重写。

        重写规则:自己定,主要看是什么和什么相等时表示两个对象相等

        基本数据类型比较实用:==
        对象和对象比较:调用equals方法

        String类是SUN编写的,所以String类的equals方法重写了。
        以后判断两个字符串是否相等,最好不要使用==,要调用字符串对象的equals方法。
    
        注意:重写equals方法的时候要彻底。

1、String类已经重写了equals方法,比较两个字符串不能使用==,必须使用equals,equals是通用的
String类已经重写了toString()方法
Java中的基本数据类型比较是否相等用双等号,引用类型判断相等用equals方法
    

        2.5、finalize()方法。


        这个方法是protected修饰的,在Object类中这个方法的源代码是?
            protected void finalize() throws Throwable { }


hashCode方法:


    在Object中的hashCode方法是怎样的?
        public native int hashCode();
这个方法不是抽象方法,带有native关键字,底层调用c++程序
hashCode()方法返回的是哈西码:
    实际上就是一个Java对象的内存地址,经过哈西算法,得出的一个值
    所以该方法的执行结果可以等同看做一个Java对象的内存地址

3、匿名内部类


Java语言中的数组是一种引用数据类型,不属于基本数据类型,数组的父类是object
数组实际上是一个容器,可以同时容纳多个元素(数组是一个数据的集合)
数组:字面意思是“一组数据”
数组当中可以存储“基本数据类型”的数据,也可以存储“引用数据类型”的数据
数组因为是引用类型,所以数组对象是堆内存当中(数组是存储在堆当中的)
数组当中如果存储的是“Java对象”的话,实际上存储的是对象的“引用(内存地址)
数组一旦创建,在Java中规定,长度不可变(数组长度不可变)
Java中的数组要求数组中元素的类型要统一
所有的数组对象都有Length属性(Java自带的),用来获取数组中元素的个数
所有的数组都是拿“第一个小方框的内存地址”作为整个数组对象的内存地址。(数组中首元素的内存地址作为整个数组对象)
数组中每个元素都有下标,第一个元素的下标是1,最后一个元素的下标是:Length-1
下标非常重要,因为我们对数组中元素进行“存取”的时候,都要用到下标


1、数组


    1.1、数组的优点和缺点,并且要理解为什么。


        第一:空间存储上,数组中的元素内存地址是连续的(这是数组存储元素的特点)。数组实际上是一种简单的数据结构
        第二:每个元素占用的空间大小相同。
        第三:知道首元素的内存地址。
        第四:通过下标可以计算出偏移量。
        通过一个数学表达式,就可以快速计算出某个下标位置上元素的内存地址,
        直接通过内存地址定位,效率非常高。

因为以上四点    优点:检索效率高。(查询某个下标上的元素时效率极高,可以说是查询效率最高的一个数据结构)

        缺点:由于为了保证数组中每个元素的内存地址连续,随机增删效率较低,因为随机增删元素会涉及到后面元素统一向前或向后位移的操作,
数组无法存储大数据量。因为很难在内存空间上找到特别大的连续的内存空间
        注意:数组最后一个元素的增删效率不受影响
每一个元素的内存地址在空间存储上是连续的
每一个元素类型相同,所以占用空间大小一样

    1.2、一维数组的静态初始化和动态初始化


        静态初始化:
            int[] arr = {1,2,3,4};
            Object[] objs = {new Object(), new Object(), new Object()};
        

        动态初始化:
            int[] arr = new int[4]; // 初始化一个4个长度的int类型数组,每个元素默认值0
            Object[] objs = new Object[4]; // 4个长度,每个元素默认值null(位置先占上,不存东西)
            String【】 names=new String【6】
    当你确定数组中存储哪些具体的元素时,采用静态初始化方式
    不确定的时候,就用动态初始化
                后期赋值,注意下标别越界


main方法上面的“String【】 args”有什么用?
谁负责调用main方法(JVM)
JVM调用main方法的时候,会自动传一个String数组过来
主要是用来接收用户输入参数的

    1.3、一维数组的遍历


        for(int i = 0; i < arr.length; i++){
            System.out.println(arr[i]);
        }
下标越界:下标越界异常
 从最后一个元素遍历到第一个元素
for(int i = a.length-1;i>0;i--)//颠倒顺序输出

关于一位数组的扩容
在Java开发中,数组长度一旦确定不可变,那么数组满了怎么办?
先创建一个大容量的数组,再将小容量的数组拷贝进去
数组扩容效率较低,最好预估准确,可以减少数组的扩容次数

System.arrayCopy

二维数组其实是一个特殊的一维数组,特殊在这个一维数组当中的每一个元素是一个一维数组
三维数组是一个特殊的二维数组
a【二维数组中的一维数组的下标】【一维数组的下标】
a【0】【0】:表示第一个一维数组中的第一个元素


    1.4、二维数组的静态初始化和动态初始化


        静态初始化:
            int[][] arr = {
                                    {1,2,34},
                                    {54,4,34,3},
                                    {2,34,4,5}
                                };

            Object[][] arr = {
                                    {new Object(),new Object()},
                                    {new Object(),new Object()},
                                    {new Object(),new Object(),new Object()}
                                };
        动态初始化:
            int[][] arr = new int[3][4];
            Object[][] arr = new Object[4][4];
            Animal[][] arr = new Animal[3][4];
            // Person类型数组,里面可以存储Person类型对象,以及Person类型的子类型都可以。
            Person[][] arr = new Person[2][2];
            ....

    1.5、二维数组的遍历

        for(int i = 0; i < arr.length; i++){ // 外层for循环负责遍历外面的一维数组。(外层循环三次,负责纵向)
            // 里面这个for循环负责遍历二维数组里面的一维数组。
            for(int j = 0; j < arr[i].length; j++){
                System.out.print(arr[i][j]);
            }
            // 换行。(相当于一维数组遍历完了要换行)
            System.out.println();
        }

    1.6、main方法上“String[] args”参数的使用(非重点,了解一下,以后一般都是有界面的,用户可以在界面上输入用户名和密码等参数信息。

    1.7、数组的拷贝:System.arraycopy()方法的使用


        数组有一个特点:长度一旦确定,不可变。
        所以数组长度不够的时候,需要扩容,扩容的机制是:新建一个大数组,
        将小数组中的数据拷贝到大数组,然后小数组对象被垃圾回收。

    1.8、对数组中存储引用数据类型的情况,要会画它的内存结构图。

    2.1、常见的算法:

        排序算法:
            冒泡排序算法
            选择排序算法

        查找算法:
            二分法查找
        
        以上算法在以后的java实际开发中我们不需要使用的。
        因为java已经封装好了,直接调用就行。
        只不过以后面试的时候,可能会有机会碰上。
    
    2.2、算法实际上在java中不需要精通,因为java中已经封装好了,
    要排序就调用方法就行。例如:java中提供了一个数组工具类:
        java.util.Arrays
            Arrays是一个工具类。
            其中有一个sort()方法,可以排序。静态方法,直接使用类名调用就行。

3、冒泡排序:

参与比较的数据:9 8 10 7 6 0 11
第1次循环:
8 9 10 7 6 0 11 (第1次比较:交换)
8 9 10 7 6 0 11 (第2次比较:不交换)
8 9 7 10 6 0 11 (第3次比较:交换)
8 9 7 6 10 0 11 (第4次比较:交换)
8 9 7 6 0 10 11 (第5次比较:交换)
8 9 7 6 0 10 11 (第6次比较:不交换)
最终冒出的最大数据在右边:11

参与比较的数据:8 9 7 6 0 10
第2次循环:
8 9 7 6 0 10(第1次比较:不交换)
8 7 9 6 0 10(第2次比较:交换)
8 7 6 9 0 10(第3次比较:交换)
8 7 6 0 9 10(第4次比较:交换)
8 7 6 0 9 10(第5次比较:不交换)

参与比较的数据:8 7 6 0 9
第3次循环:
7 8 6 0 9(第1次比较:交换)
7 6 8 0 9(第2次比较:交换)
7 6 0 8 9(第3次比较:交换)
7 6 0 8 9(第4次比较:不交换)

参与比较的数据:7 6 0 8
第4次循环:
6 7 0 8(第1次比较:交换)
6 0 7 8(第2次比较:交换)
6 0 7 8(第3次比较:不交换)

参与比较的数据:6 0 7
第5次循环:
0 6 7(第1次比较:交换)
0 6 7(第2次比较:不交换)

参与比较的数据:0 6
第6次循环:
0 6 (第1次比较:不交换)

for(int i = 6; i > 0; i--){ // 6次
    //7条数据比6次
    //6条数据比5次
    //5条数据比4次
    //4条数据比3次
    //3条数据比2次
    //2条数据比1次
    for(int j = 0; j < i; j++){
    
    }
}

4、选择排序:

    选择排序比冒泡排序的效率高。
    高在交换位置的次数上。
    选择排序的交换位置是有意义的。

    循环一次,然后找出参加比较的这堆数据中最小的,拿着这个最小的值和
    最前面的数据“交换位置”。


    参与比较的数据:3 1 6 2 5 (这一堆参加比较的数据中最左边的元素下标是0)
    第1次循环之后的结果是:
    1 3 6 2 5 

    参与比较的数据:3 6 2 5 (这一堆参加比较的数据中最左边的元素下标是1)
    第2次循环之后的结果是:
    2 6 3 5 

    参与比较的数据:6 3 5 (这一堆参加比较的数据中最左边的元素下标是2)
    第3次循环之后的结果是:
    3 6 5 

    参与比较的数据:6 5 (这一堆参加比较的数据中最左边的元素下标是3)
    第4次循环之后的结果是:
    5 6

    注意:5条数据,循环4次。

5、二分法查找(折半查找):


    
    第一:二分法查找建立在排序的基础之上。
    第二:二分法查找效率要高于“一个挨着一个”的这种查找方式。
    第三:二分法查找原理?
        10(0下标) 23 56 89 100 111 222 235 500 600(下标9) arr数组
        
        目标:找出600的下标
            (0 + 9) / 2 --> 4(中间元素的下标)
        
        arr[4]这个元素就是中间元素:arr[4]是 100
        100 < 600
        说明被查找的元素在100的右边。
        那么此时开始下标变成:4 + 1

            (5 + 9) / 2 --> 7(中间元素的下标)
            arr[7] 对应的是:235
            235 < 600
            说明被查找的元素在235的右边。
        
        开始下标又进行了转变:7 + 1
            (8 + 9) / 2 --> 8
            arr[8] --> 500
            500 < 600
            开始元素的下标又发生了变化:8 + 1
            (9 + 9) / 2 --> 9
            arr[9]是600,正好和600相等,此时找到了。
            

6、介绍一下java.util.Arrays工具类。
    所有方法都是静态的,直接用类名调用
    主要使用的是两个方法:
        二分法查找,排序
    以后要看文档,不要死记硬背。


1、String类。


String表示字符串类型,属于引用数据类型,不属于基本数据类型
在Java中随便使用双引号括起来的都是String对象,例如"abc"
Java中规定,双引号括起来的字符串,是不可变的,也就是说"abc"生死不变
在JDK当中双引号括起来的字符串,例如“abc”都是直接存储在“方法区”的“字符串常量池”当中的
因为字符串在实际的开发中使用太频繁,为了执行效率,所以把字符串放到了方法区的字符串常量池当中

    1.1、对String在内存存储方面的理解:


        第一:字符串一旦创建不可变。
        第二:双引号括起来的字符串存储在字符串常量池中。
        第三:字符串的比较必须使用equals方法。(用双等号不保险)
        第四:String已经重写了toString()和equals()方法。

    1.2、String的构造方法。(没听懂)

        String s = "abc";
        String s = new String("abc");
        String s = new String(byte数组);
        String s = new String(byte数组, 起始下标, 长度);
        String s = new String(char数组);
        String s = new String(char数组, 起始下标, 长度);


    
    1.3、String类常用的21个方法。

2、StringBuffer/StringBuilder
消耗内存
    2.1、StringBuffer/StringBuilder可以看做可变长度字符串。
    2.2、StringBuffer/StringBuilder初始化容量16.
    2.3、StringBuffer/StringBuilder是完成字符串拼接操作的,方法名:append
    2.4、StringBuffer是线程安全的。StringBuilder是非线程安全的。
    2.5、频繁进行字符串拼接不建议使用“+”

包装类

3、八种基本数据类型对应的包装类


    3.1、包装类存在有什么用?
        方便编程。
    3.2、八种包装类的类名是什么?
        Byte
        Short
        Integer
        Long
        Float
        Double
        Boolean
        Character
    3.3、所有数字的父类Number
    3.4、照葫芦画瓢:学习Integer,其它的模仿Integer。
    3.5、什么是装箱?什么是拆箱?


池:cache,就是缓存机制
缓存优点:效率高
缓存缺点:耗费内存
引用数据类型转化成基本数据类型(拆箱)
基本数据类型转化成引用数据类型(装箱)

1、八种基本数据类型对应的包装
八中包装类中其中6个都是数字对应的包装类,他们的父类都是Number,可以先研究一下Number中公共的方法
number是一个抽象类,无法实例化对象
Number类中有这样的方法:
byte byteValue()
以byte形式返回指定的数值
abstract double doubleValue()
以double 形式返回指定的数值
abstract float floatValue()
以float形式返回指定的数值
abstract int intValue()
以int 形式返回指定的数值
abstract long longValue()
以long形式返回指定的数值
shart shortValue()
以short形式返回指定的数值
这些方法其实所有的数字包装类的子类都有,这些方法是负责拆箱的


    1.1、什么是自动装箱和自动拆箱,代码怎么写?


好处是方便编程
自动装箱(int类型自动转换为integer)
基本数据类型自动转换成包装类
自动拆箱:包装类自动转换成基本数据类型
有了自动拆箱后,Number类中的方法就用不着了
        Integer x = 100; // x里面并不是保存100,保存的是100这个对象的内存地址
        Integer y = 100;
        System.out.println(x == y); // true

        Integer x = 128;
        Integer y = 128;
        System.out.println(x == y); // false

    1.2、Integer类常用方法。
        Integer.valueOf()

        Integer.parseInt("123")
        Integer.parseInt("中文") : NumberFormatException

    1.3、Integer String int三种类型互相转换。


    
2、日期类


    2.1、获取系统当前时间
        Date d = new Date();
    2.2、日期格式化:Date --> String
        yyyy-MM-dd HH:mm:ss SSS
        SimpleDateFormat sdf = new SimpleDate("yyyy-MM-dd HH:mm:ss SSS");
        String s = sdf.format(new Date());
    2.3、String --> Date
        SimpleDateFormat sdf = new SimpleDate("yyyy-MM-dd HH:mm:ss");
        Date d = sdf.parse("2008-08-08 08:08:08");
    2.4、获取毫秒数
        long begin = System.currentTimeMillis();
        Date d = new Date(begin - 1000 * 60 * 60 * 24);

3、数字类


    3.1、DecimalFormat数字格式化
        ###,###.## 表示加入千分位,保留两个小数。
        ###,###.0000 表示加入千分位,保留4个小数,不够补0
    3.2、BigDecimal
        财务软件中通常使用BigDecimal

4、随机数


    4.1、怎么产生int类型随机数。
        Random r = new Random();
        int i = r.nextInt();
    4.2、怎么产生某个范围之内的int类型随机数。
        Random r = new Random();
        int i = r.nextInt(101); // 产生[0-100]的随机数。

5、枚举


    5.1、枚举是一种引用数据类型。
    5.2、枚举编译之后也是class文件。
    5.3、枚举类型怎么定义?
        enum 枚举类型名{
            枚举值,枚举值2,枚举值3
        }
    5.4、当一个方法执行结果超过两种情况,并且是一枚一枚可以列举出来
    的时候,建议返回值类型设计为枚举类型。



总结一下之前所学的经典异常:
空指针异常:NullPointerException
类型转换异常:ClassCastException
数组下标越界异常:IndexOutOfBoundsException

什么是异常,Java提供异常处理机制有什么用?
以下程序执行过程中发生了不正常的情况,而这种不正常的情况叫做:异常
Java语言是很完善的语言,提供了异常的处理方式,以下程序执行过程中出出现了不正常情况,那把把该异常信息打印输出到控制台,供程序员参考。程序员看到异常信息之后,可以对程序进行修改,让程序更加的健壮
0、异常处理机制
    0.1、java中异常的作用是:增强程序健壮性。
    0.2、java中异常以类和对象的形式存在。
    


1、java的异常处理机制

    1.1、异常在java中以类和对象的形式存在。每一个异常类都可以创建异常对象
那么异常的继承结构是怎样的?
    我们可以使用UML图来描述一下继承结构。
    画UML图有很多工具,例如:Rational Rose(收费的)、starUML等....
        Object
        Object下有Throwable(可抛出的)
        Throwable下有两个分支:Error(不可处理,直接退出JVM)和Exception(可处理的)
        Exception下有两个分支:
            Exception的直接子类:编译时异常(要求程序员在编写程序阶段必须预先对这些异常进行处理,如果不处理编译器报错,因此得名编译时异常。)。
            RuntimeException:运行时异常。(在编写程序阶段程序员可以预先处理,也可以不管,都行。)
    
    1.2、编译时异常和运行时异常,都是发生在运行阶段。编译阶段异常是不会发生的。
    编译时异常因为什么而得名?
        因为编译时异常必须在编译(编写)阶段预先处理,如果不处理编译器报错,因此得名。
        所有异常都是在运行阶段发生的。因为只有程序运行阶段才可以new对象。
        因为异常的发生就是new异常对象
    
    1.3、编译时异常和运行时异常的区别?

        编译时异常一般发生的概率比较高。
            举个例子:
                你看到外面下雨了,倾盆大雨的。
                你出门之前会预料到:如果不打伞,我可能会生病(生病是一种异常)。
                而且这个异常发生的概率很高,所以我们出门之前要拿一把伞。
                “拿一把伞”就是对“生病异常”发生之前的一种处理方式

                对于一些发生概率较高的异常,需要在运行之前对其进行预处理。

        运行时异常一般发生的概率比较低。
            举个例子:
                小明走在大街上,可能会被天上的飞机轮子砸到。
                被飞机轮子砸到也算一种异常。
                但是这种异常发生概率较低。
                在出门之前你没必要提前对这种发生概率较低的异常进行预处理。
                如果你预处理这种异常,你将活的很累。
        突然感觉Java也太可爱了吧哈哈哈哈哈哈


        假设你在出门之前,你把能够发生的异常都预先处理,你这个人会更加
        的安全,但是你这个人活的很累。
        
        假设java中没有对异常进行划分,没有分为:编译时异常和运行时异常,
        所有的异常都需要在编写程序阶段对其进行预处理,将是怎样的效果呢?
            首先,如果这样的话,程序肯定是绝对的安全的。
            但是程序员编写程序太累,代码到处都是处理异常
            的代码。
    
    1.4、编译时异常还有其他名字:
        受检异常:CheckedException
        受控异常
    
    1.5、运行时异常还有其它名字:
        未受检异常:UnCheckedException
        非受控异常
    
    1.6、再次强调:所有异常都是发生在运行阶段的。

    1.7、Java语言中对异常的处理包括两种方式:

        第一种方式:在方法声明的位置上,使用throws关键字,抛给上一级。
            谁调用我,我就抛给谁。抛给上一级。

        第二种方式:使用try..catch语句进行异常的捕捉
            这件事发生了,谁也不知道,因为我给抓住了。

        举个例子:
            我是某集团的一个销售员,因为我的失误,导致公司损失了1000元,
            “损失1000元”这可以看做是一个异常发生了。我有两种处理方式,
            第一种方式:我把这件事告诉我的领导【异常上抛】
            第二种方式:我自己掏腰包把这个钱补上。【异常的捕捉】
            
            张三 --> 李四 ---> 王五 --> CEO
        
        思考:
            异常发生之后,如果我选择了上抛,抛给了我的调用者,调用者需要
            对这个异常继续处理,那么调用者处理这个异常同样有两种处理方式。

    1.8、注意:Java中异常发生之后如果一直上抛,最终抛给了main方法,main方法继续
    向上抛,抛给了调用者JVM,JVM知道这个异常发生,只有一个结果。终止java程序的执行


2、什么是UML?有什么用?


    UML是一种统一建模语言。
    一种图标式语言(画图的)
    UML不是只有java中使用。只要是面向对象的编程语言,都有UML。
    一般画UML图的都是软件架构师或者说是系统分析师。这些级别的人员使用的。
    软件设计人员使用UML。

    在UML图中可以描述类和类之间的关系,程序执行的流程,对象的状态等.

    盖大楼和软件开发一样,一个道理。
        盖楼之前,会先由建筑师画图纸。图纸上一个一个符号都是标准符号。
        这个图纸画完,只要是搞建筑的都能看懂,因为这个图纸上标注的这些
        符号都是一种“标准的语言”。
    
    在java软件开发当中,软件分析师/设计师负责设计类,java软件开发人员
    必须要能看懂。
 


1、集合概述

    1.1、什么是集合?有什么用?

        数组其实就是一个集合。集合实际上就是一个容器。可以来容纳其它类型的数据。

        集合为什么说在开发中使用较多?
            集合是一个容器,是一个载体,可以一次容纳多个对象。
            在实际开发中,假设连接数据库,数据库当中有10条记录,
            那么假设把这10条记录查询出来,在java程序中会将10条
            数据封装成10个java对象,然后将10个java对象放到某一个
            集合当中,将集合传到前端,然后遍历集合,将一个数据一个
            数据展现出来。
集合起到一个承载的作用

    1.2、集合不能直接存储基本数据类型,另外集合也不能直接存储java对象,
    集合当中存储的都是java对象的内存地址。(或者说集合中存储的是引用。)
        list.add(100); //自动装箱,转成Integer类型放到了list里面
        注意:
            集合在java中本身是一个容器,是一个对象,也有内存地址
            集合中任何时候存储的都是对象的“引用”。

    1.3、在java中每一个不同的集合,底层会对应不同的数据结构。往不同的集合中
    存储元素,等于将数据放到了不同的数据结构当中。
    什么是数据结构?
    数据存储的结构就是数据结构。不同的数据结构,数据存储方式不同。例如:
        数组、二叉树、链表、哈希表...
        以上这些都是常见的数据结构。

        你往集合c1中放数据,可能是放到数组上了。
        你往集合c2中放数据,可能是放到二叉树上了。
        .....
        你使用不同的集合等同于使用了不同的数据结构。

        你在java集合这一章节,你需要掌握的不是精通数据结构。java中已经将数据结构
        实现了,已经写好了这些常用的集合类,你只需要掌握怎么用?在什么情况下选择
        哪一种合适的集合去使用即可。

        new ArrayList(); 创建一个集合,底层是数组。
        new LinkedList(); 创建一个集合对象,底层是链表。
        new TreeSet(); 创建一个集合对象,底层是二叉树。
        .....

    1.4、集合在java JDK中哪个包下?


        java.util.*;
            所有的集合类和集合接口都在java.util包下。
    
    1.5、为了让大家掌握集合这块的内容,最好能将集合的继承结构图背会!!!
        集合整个这个体系是怎样的一个结构,你需要有印象。

    1.6、在java中集合分为两大类:


        一类是单个方式存储元素:
            单个方式存储元素,这一类集合中超级父接口:java.util.Collection;

        一类是以键值对儿的方式存储元素
            以键值对的方式存储元素,这一类集合中超级父接口:java.util.Map;
所有集合继承terable的意思是:所有集合都是可迭代的(可遍历的)

2、总结重点:

    第一个重点:把集合继承结构图背会。

    第二个重点:把Collection接口中常用方法测试几遍。

    第三个重点:把迭代器弄明白。

    第四个重点:Collection接口中的remove方法和contains方法底层都会调用equals,
                    这个弄明白。


关于Java.util.Collection接口中的常用的方法


1、Collection中能存放什么元素?
没有使用"泛型"之前,Collection中可以存储object的所有子类型
使用了"泛型"之后,Collection中只能存储某个具体的类型
集合后期我们会学习“泛型”语法,目前先不用管,Collection中什么都能存
只要是Object的子类型就行(集合中不能直接存储基本数据类型,也不能存储Java对象,知识存储Java对象的内存地址)

Collection中的常用方法
boolean add(Object e)向集合中添加元素
int size()获取集合中元素的个数
c.size();
void clear()清空集合
c.add();
boolean contains(Object o)判断当前集合中是否包含元素o,包含返回ture,不包含返回false
boolean flag = c.contains(“绿巨人”);
System.out.println(flag);//
boolean remove(Object o) 删除集合中的某个元素
c.remove()
boolean isEmpty()判断该集合中元素的个数是否为0
c.isEmpty()

Object【】 toArray() 调用这个方法可以把集合转换成数组
Object【】 objs = c.toArray();


迭代器遍历集合

关于集合遍历/迭代专题
以下讲解的遍历方式是所有Collection通用的一种方式
在Map集合中不能用,在所有的Collection以及子类中使用

第一步:获取集合对象的迭代器对象Iterator
Iterator it = c.iterator();//迭代器对象it,最初并没有指向第一个元素
第二部:通过以上获取的迭代器对象Iterator中的方法:
    boolean hasNext()如果仍有元素可以迭代,则返回true
    Object next() 返回迭代的下一个元素

boolean hasNext = it.hasNext();这个方法返回true,表示还有元素可以迭代,这个方法返回false表示没有更多的元素可以迭代了
Object obj = it.next();这个方法让迭代器前进一位,并且将指向的元素返回(拿到)

boolean hasNext = it.hasNext();
if(hasNext){
//不管你当初存进去什么,取出来统一都是object
Object obj = it.next();
System.out.println(obj);
}


关于集合元素的remove


深入Collection集合的contains方法
    boolean contains(Object o)
        判断集合中是否包含某个对象o
        如果包含返回true,如果不包含返回false

contains方法是用来判断集合中是否包含某个元素的方法
调用了equals方法进行比对
rquals方法返回ture,就表示包含这个元素

list集合存储元素特点:有序可重复(存进去的顺序和取出来的顺序一样)不是说按照大小排序的意思
有序:List集合中的元素有下标
从0开始,以1递增
可重复:存储一个1,还可以再存储1

set集合:无序不可重复(存进去是这个顺序,取出来就不一定了)
该集合中元素没有下标

1、List接口中的常用方法。


    List是Collection接口的子接口。所以List接口中有一些特有的方法。
        void add(int index, Object element)
        Object set(int index, Object element)
        Object get(int index)
        int indexOf(Object o)
        int lastIndexOf(Object o)
        Object remove(int index)
参数是object

因为有下标,所以List集合有自己比较特殊的遍历方式

2、迭代器迭代元素的过程中不能使用集合对象的remove方法删除元素,
要使用迭代器Iterator的remove方法来删除元素,防止出现异常:

    ConcurrentModificationException

3、ArrayList


    ArrayList集合初始化容量10
    扩容为原容量1.5倍。
    底层是数组。

    数组优点和缺点要能够说出来!
    另外要注意:ArrayList集合末尾增删元素效率还是可以的。

4、链表数据结构


    第一:单向链表和双向链表数据结构要理解。
    第二:链表数据结构的优点和缺点要能够说出来。

5、Vector:
    Vector初始化容量是10.
    扩容为原容量的2倍。
    底层是数组。
    Vector底层是线程安全的。

    怎么得到一个线程安全的List:
        Collections.synchronizedList(list);

6、JDK5.0新特性:泛型
    第一:集合使用泛型来减少向下转型的操作。
    第二:怎么使用泛型?
    第三:怎么自定义泛型?

7、JDK5.0新特性:
    foreach
    对数组怎么遍历?
        for(int i : arr){
            System.out.println(i);
        }
    对集合怎么遍历?
        for(String s : list){
            System.out.println(s);
        }

8、JDK8新特性:钻石表达式
    List<String> list = new ArrayList<>();
    类型自动推断!


1、掌握Map接口中常用方法。

2、遍历Map集合的两种方式都要精通。
    第一种:获取所有key,遍历每个key,通过key获取value.
    第二种:获取Set<Map.Entry>即可,遍历Set集合中的Entry
        调用entry.getKey() entry.getValue()

3、了解哈希表数据结构。

4、存放在HashMap集合key部分和HashSet集合中的元素需要同时重写hashCode和equals。

5、HashMap和Hashtable的区别。
    HashMap:
        初始化容量16,扩容2倍。
        非线程安全
        key和value可以为null。

    Hashtable
        初始化容量11,扩容2倍+1
        线程安全
        key和value都不能是null。

6、Properties类的常用两个方法。
    setProperty
    getProperty

7、了解自平衡二叉树数据结构。
    左小右大原则存储。
    中序遍历方式。

8、TreeMap的key或者TreeSet集合中的元素要想排序,有两种实现方式:
    第一种:实现java.lang.Comparable接口。
    第二种:单独编写一个比较器Comparator接口。

9、集合工具类Collections:
    synchronizedList方法
    sort方法(要求集合中元素实现Comparable接口。)

1、集合这块最主要掌握什么内容?
    1.1、每个集合对象的创建(new)
    1.2、向集合中添加元素
    1.3、从集合中取出某个元素
    1.4、遍历集合
    1.5、主要的集合类:
        ArrayList
        LinkedList
        HashSet (HashMap的key,存储在HashMap集合key的元素需要同时重写hashCode + equals)
        TreeSet
        HashMap
        Properties
        TreeMap


2、IO流,什么是IO?


    I : Input
    O : Output
    通过IO可以完成硬盘文件的读和写。

3、IO流的分类?

    有多种分类方式:

        一种方式是按照流的方向进行分类:
            以内存作为参照物,
                往内存中去,叫做输入(Input)。或者叫做读(Read)。
                从内存中出来,叫做输出(Output)。或者叫做写(Write)。

        另一种方式是按照读取数据方式不同进行分类:
            有的流是按照字节的方式读取数据,一次读取1个字节byte,等同于一次读取8个二进制位。
            这种流是万能的,什么类型的文件都可以读取。包括:文本文件,图片,声音文件,视频文件等....
                假设文件file1.txt,采用字节流的话是这样读的:
                    a中国bc张三fe
                    第一次读:一个字节,正好读到'a'
                    第二次读:一个字节,正好读到'中'字符的一半。
                    第三次读:一个字节,正好读到'中'字符的另外一半。

            有的流是按照字符的方式读取数据的,一次读取一个字符,这种流是为了方便读取
            普通文本文件而存在的,这种流不能读取:图片、声音、视频等文件。只能读取纯
            文本文件,连word文件都无法读取。
                假设文件file1.txt,采用字符流的话是这样读的:
                    a中国bc张三fe
                    第一次读:'a'字符('a'字符在windows系统中占用1个字节。)
                    第二次读:'中'字符('中'字符在windows系统中占用2个字节。)
    
    综上所述:流的分类
        输入流、输出流
        字节流、字符流

4、Java中的IO流都已经写好了,我们程序员不需要关心,我们最主要还是掌握,
在java中已经提供了哪些流,每个流的特点是什么,每个流对象上的常用方法有
哪些????
    java中所有的流都是在:java.io.*;下。

    java中主要还是研究:
        怎么new流对象。
        调用流对象的哪个方法是读,哪个方法是写。

5、java IO流这块有四大家族:
    四大家族的首领:
        java.io.InputStream  字节输入流
        java.io.OutputStream 字节输出流

        java.io.Reader        字符输入流
        java.io.Writer        字符输出流

        四大家族的首领都是抽象类。(abstract class)

        所有的流都实现了:
            java.io.Closeable接口,都是可关闭的,都有close()方法。
            流毕竟是一个管道,这个是内存和硬盘之间的通道,用完之后一定要关闭,
            不然会耗费(占用)很多资源。养成好习惯,用完流一定要关闭。

        所有的输出流都实现了:
            java.io.Flushable接口,都是可刷新的,都有flush()方法。
            养成一个好习惯,输出流在最终输出之后,一定要记得flush()
            刷新一下。这个刷新表示将通道/管道当中剩余未输出的数据
            强行输出完(清空管道!)刷新的作用就是清空管道。
            注意:如果没有flush()可能会导致丢失数据。


    注意:在java中只要“类名”以Stream结尾的都是字节流。以“Reader/Writer”结尾的都是字符流。

6、java.io包下需要掌握的流有16个:


    
    文件专属:
        java.io.FileInputStream(掌握)
        java.io.FileOutputStream(掌握)
        java.io.FileReader
        java.io.FileWriter

    转换流:(将字节流转换成字符流)
        java.io.InputStreamReader
        java.io.OutputStreamWriter

    缓冲流专属:
        java.io.BufferedReader
        java.io.BufferedWriter
        java.io.BufferedInputStream
        java.io.BufferedOutputStream

    数据流专属:
        java.io.DataInputStream
        java.io.DataOutputStream

    标准输出流:
        java.io.PrintWriter
        java.io.PrintStream(掌握)

    对象专属流:
        java.io.ObjectInputStream(掌握)
        java.io.ObjectOutputStream(掌握)

7、java.io.File类。
    File类的常用方法。

8、java io这块还剩下什么内容:
    第一:ObjectInputStream ObjectOutputStream的使用。
    第二:IO流+Properties集合的联合使用。

1、拷贝目录。

2、关于对象流
    ObjectInputStream
    ObjectOutputStream

    重点:
        参与序列化的类型必须实现java.io.Serializable接口。
        并且建议将序列化版本号手动的写出来。
            private static final long serialVersionUID = 1L;

3、IO + Properties联合使用。
    IO流:文件的读和写。
    Properties:是一个Map集合,key和value都是String类型。


4、多线程

    4.1、什么是进程?什么是线程?
        进程是一个应用程序(1个进程是一个软件)。
        线程是一个进程中的执行场景/执行单元。

        一个进程可以启动多个线程。
    
    4.2、对于java程序来说,当在DOS命令窗口中输入:
        java HelloWorld 回车之后。
        会先启动JVM,而JVM就是一个进程。
        JVM再启动一个主线程调用main方法。
        同时再启动一个垃圾回收线程负责看护,回收垃圾。
        最起码,现在的java程序中至少有两个线程并发,
        一个是垃圾回收线程,一个是执行main方法的主线程。
    
    4.3、进程和线程是什么关系?举个例子

        阿里巴巴:进程
            马云:阿里巴巴的一个线程
            童文红:阿里巴巴的一个线程
        
        京东:进程
            强东:京东的一个线程
            妹妹:京东的一个线程
        
        进程可以看做是现实生活当中的公司。
        线程可以看做是公司当中的某个员工。

        注意:
            进程A和进程B的内存独立不共享。(阿里巴巴和京东资源不会共享的!)
                魔兽游戏是一个进程
                酷狗音乐是一个进程
                这两个进程是独立的,不共享资源。

            线程A和线程B呢?
                在java语言中:
                    线程A和线程B,堆内存和方法区内存共享。
                    但是栈内存独立,一个线程一个栈。
            
                假设启动10个线程,会有10个栈空间,每个栈和每个栈之间,
                互不干扰,各自执行各自的,这就是多线程并发。
            
            火车站,可以看做是一个进程。
            火车站中的每一个售票窗口可以看做是一个线程。
            我在窗口1购票,你可以在窗口2购票,你不需要等我,我也不需要等你。
            所以多线程并发可以提高效率。

            java中之所以有多线程机制,目的就是为了提高程序的处理效率。

    4.4、思考一个问题:
        使用了多线程机制之后,main方法结束,是不是有可能程序也不会结束。
        main方法结束只是主线程结束了,主栈空了,其它的栈(线程)可能还在
        压栈弹栈。

    4.5、分析一个问题:对于单核的CPU来说,真的可以做到真正的多线程并发吗?

        对于多核的CPU电脑来说,真正的多线程并发是没问题的。
            4核CPU表示同一个时间点上,可以真正的有4个进程并发执行。

        什么是真正的多线程并发?
            t1线程执行t1的。
            t2线程执行t2的。
            t1不会影响t2,t2也不会影响t1。这叫做真正的多线程并发。

        单核的CPU表示只有一个大脑:
            不能够做到真正的多线程并发,但是可以做到给人一种“多线程并发”的感觉。
            对于单核的CPU来说,在某一个时间点上实际上只能处理一件事情,但是由于
            CPU的处理速度极快,多个线程之间频繁切换执行,跟人来的感觉是:多个事情
            同时在做!!!!!
                线程A:播放音乐
                线程B:运行魔兽游戏
                线程A和线程B频繁切换执行,人类会感觉音乐一直在播放,游戏一直在运行,
                给我们的感觉是同时并发的。
        
        电影院采用胶卷播放电影,一个胶卷一个胶卷播放速度达到一定程度之后,
        人类的眼睛产生了错觉,感觉是动画的。这说明人类的反应速度很慢,就像
        一根钢针扎到手上,到最终感觉到疼,这个过程是需要“很长的”时间的,在
        这个期间计算机可以进行亿万次的循环。所以计算机的执行速度很快。
    
5、java语言中,实现线程有两种方式,那两种方式呢?

    java支持多线程机制。并且java已经将多线程实现了,我们只需要继承就行了。

    第一种方式:编写一个类,直接继承java.lang.Thread,重写run方法。
        // 定义线程类
        public class MyThread extends Thread{
            public void run(){
            
            }
        }
        // 创建线程对象
        MyThread t = new MyThread();
        // 启动线程。
        t.start();
    
    第二种方式:编写一个类,实现java.lang.Runnable接口,实现run方法。
        // 定义一个可运行的类
        public class MyRunnable implements Runnable {
            public void run(){
            
            }
        }
        // 创建线程对象
        Thread t = new Thread(new MyRunnable());
        // 启动线程
        t.start();
    
    注意:第二种方式实现接口比较常用,因为一个类实现了接口,它还可以去继承
    其它的类,更灵活。

6、关于线程对象的生命周期?
    新建状态
    就绪状态
    运行状态
    阻塞状态
    死亡状态

1、(这部分内容属于了解)关于线程的调度

    1.1、常见的线程调度模型有哪些?

        抢占式调度模型:
            那个线程的优先级比较高,抢到的CPU时间片的概率就高一些/多一些。
            java采用的就是抢占式调度模型。

        均分式调度模型:
            平均分配CPU时间片。每个线程占有的CPU时间片时间长度一样。
            平均分配,一切平等。
            有一些编程语言,线程调度模型采用的是这种方式。
    
    1.2、java中提供了哪些方法是和线程调度有关系的呢?

        实例方法:
            void setPriority(int newPriority) 设置线程的优先级
            int getPriority() 获取线程优先级
            最低优先级1
            默认优先级是5
            最高优先级10
            优先级比较高的获取CPU时间片可能会多一些。(但也不完全是,大概率是多的。)
        
        静态方法:
            static void yield()  让位方法
            暂停当前正在执行的线程对象,并执行其他线程
            yield()方法不是阻塞方法。让当前线程让位,让给其它线程使用。
            yield()方法的执行会让当前线程从“运行状态”回到“就绪状态”。
            注意:在回到就绪之后,有可能还会再次抢到。
        
        实例方法:
            void join()  
            合并线程
            class MyThread1 extends Thread {
                public void doSome(){
                    MyThread2 t = new MyThread2();
                    t.join(); // 当前线程进入阻塞,t线程执行,直到t线程结束。当前线程才可以继续。
                }
            }

            class MyThread2 extends Thread{
                
            }

2、关于多线程并发环境下,数据的安全问题。

    2.1、为什么这个是重点?
        以后在开发中,我们的项目都是运行在服务器当中,
        而服务器已经将线程的定义,线程对象的创建,线程
        的启动等,都已经实现完了。这些代码我们都不需要
        编写。

        最重要的是:你要知道,你编写的程序需要放到一个
        多线程的环境下运行,你更需要关注的是这些数据
        在多线程并发的环境下是否是安全的。(重点:*****)
    
    2.2、什么时候数据在多线程并发的环境下会存在安全问题呢?
        三个条件:
            条件1:多线程并发。
            条件2:有共享数据。
            条件3:共享数据有修改的行为。

        满足以上3个条件之后,就会存在线程安全问题。
    
    2.3、怎么解决线程安全问题呢?
        当多线程并发的环境下,有共享数据,并且这个数据还会被修改,此时就存在
        线程安全问题,怎么解决这个问题?
            线程排队执行。(不能并发)。
            用排队执行解决线程安全问题。
            这种机制被称为:线程同步机制。

            专业术语叫做:线程同步,实际上就是线程不能并发了,线程必须排队执行。
        
        怎么解决线程安全问题呀?
            使用“线程同步机制”。
        
        线程同步就是线程排队了,线程排队了就会牺牲一部分效率,没办法,数据安全
        第一位,只有数据安全了,我们才可以谈效率。数据不安全,没有效率的事儿。
    
    2.4、说到线程同步这块,涉及到这两个专业术语:

        异步编程模型:
            线程t1和线程t2,各自执行各自的,t1不管t2,t2不管t1,
            谁也不需要等谁,这种编程模型叫做:异步编程模型。
            其实就是:多线程并发(效率较高。)

            异步就是并发。

        同步编程模型:
            线程t1和线程t2,在线程t1执行的时候,必须等待t2线程执行
            结束,或者说在t2线程执行的时候,必须等待t1线程执行结束,
            两个线程之间发生了等待关系,这就是同步编程模型。
            效率较低。线程排队执行。

            同步就是排队。

3、Java中有三大变量?【重要的内容。】

    实例变量:在堆中。

    静态变量:在方法区。

    局部变量:在栈中。

    以上三大变量中:
        局部变量永远都不会存在线程安全问题。
        因为局部变量不共享。(一个线程一个栈。)
        局部变量在栈中。所以局部变量永远都不会共享。
    
    实例变量在堆中,堆只有1个。
    静态变量在方法区中,方法区只有1个。
    堆和方法区都是多线程共享的,所以可能存在线程安全问题。

    局部变量+常量:不会有线程安全问题。
    成员变量:可能会有线程安全问题。

4、如果使用局部变量的话:
    建议使用:StringBuilder。
    因为局部变量不存在线程安全问题。选择StringBuilder。
    StringBuffer效率比较低。

    ArrayList是非线程安全的。
    Vector是线程安全的。
    HashMap HashSet是非线程安全的。
    Hashtable是线程安全的。

5、总结:
    synchronized有三种写法:

        第一种:同步代码块
            灵活
            synchronized(线程共享对象){
                同步代码块;
            }

        第二种:在实例方法上使用synchronized
            表示共享对象一定是this
            并且同步代码块是整个方法体。
        
        第三种:在静态方法上使用synchronized
            表示找类锁。
            类锁永远只有1把。
            就算创建了100个对象,那类锁也只有一把。
        
        对象锁:1个对象1把锁,100个对象100把锁。
        类锁:100个对象,也可能只是1把类锁。

6、聊一聊,我们以后开发中应该怎么解决线程安全问题?

    是一上来就选择线程同步吗?synchronized
        不是,synchronized会让程序的执行效率降低,用户体验不好。
        系统的用户吞吐量降低。用户体验差。在不得已的情况下再选择
        线程同步机制。
    
    第一种方案:尽量使用局部变量代替“实例变量和静态变量”。

    第二种方案:如果必须是实例变量,那么可以考虑创建多个对象,这样
    实例变量的内存就不共享了。(一个线程对应1个对象,100个线程对应100个对象,
    对象不共享,就没有数据安全问题了。)

    第三种方案:如果不能使用局部变量,对象也不能创建多个,这个时候
    就只能选择synchronized了。线程同步机制。

7、线程这块还有那些内容呢?列举一下
    7.1、守护线程
    7.2、定时器
    7.3、实现线程的第三种方式:FutureTask方式,实现Callable接口。(JDK8新特性。)
    7.4、关于Object类中的wait和notify方法。(生产者和消费者模式!)

1、线程这块还有那些内容呢?列举一下

    1.1、守护线程

        java语言中线程分为两大类:
            一类是:用户线程
            一类是:守护线程(后台线程)
            其中具有代表性的就是:垃圾回收线程(守护线程)。

        守护线程的特点:
            一般守护线程是一个死循环,所有的用户线程只要结束,
            守护线程自动结束。
        
        注意:主线程main方法是一个用户线程。

        守护线程用在什么地方呢?
            每天00:00的时候系统数据自动备份。
            这个需要使用到定时器,并且我们可以将定时器设置为守护线程。
            一直在那里看着,没到00:00的时候就备份一次。所有的用户线程
            如果结束了,守护线程自动退出,没有必要进行数据备份了。

    1.2、定时器
        定时器的作用:
            间隔特定的时间,执行特定的程序。

            每周要进行银行账户的总账操作。
            每天要进行数据的备份操作。

            在实际的开发中,每隔多久执行一段特定的程序,这种需求是很常见的,
            那么在java中其实可以采用多种方式实现:
                
                可以使用sleep方法,睡眠,设置睡眠时间,没到这个时间点醒来,执行
                任务。这种方式是最原始的定时器。(比较low)

                在java的类库中已经写好了一个定时器:java.util.Timer,可以直接拿来用。
                不过,这种方式在目前的开发中也很少用,因为现在有很多高级框架都是支持
                定时任务的。

                在实际的开发中,目前使用较多的是Spring框架中提供的SpringTask框架,
                这个框架只要进行简单的配置,就可以完成定时器的任务。


    1.3、实现线程的第三种方式:实现Callable接口。(JDK8新特性。)
        这种方式实现的线程可以获取线程的返回值。
        之前讲解的那两种方式是无法获取线程返回值的,因为run方法返回void。

        思考:
            系统委派一个线程去执行一个任务,该线程执行完任务之后,可能
            会有一个执行结果,我们怎么能拿到这个执行结果呢?
                使用第三种方式:实现Callable接口方式。


    1.4、关于Object类中的wait和notify方法。(生产者和消费者模式!)

        第一:wait和notify方法不是线程对象的方法,是java中任何一个java对象
        都有的方法,因为这两个方式是Object类中自带的。
            wait方法和notify方法不是通过线程对象调用,
            不是这样的:t.wait(),也不是这样的:t.notify()..不对。
        
        第二:wait()方法作用?
            Object o = new Object();
            o.wait();

            表示:
                让正在o对象上活动的线程进入等待状态,无期限等待,
                直到被唤醒为止。
                o.wait();方法的调用,会让“当前线程(正在o对象上
                活动的线程)”进入等待状态。

        第三:notify()方法作用?
            Object o = new Object();
            o.notify();

            表示:
                唤醒正在o对象上等待的线程。
            
            还有一个notifyAll()方法:
                这个方法是唤醒o对象上处于等待的所有线程。


2、反射机制

(比较简单,因为只要会查帮助文档,就可以了。)
    
    2.1、反射机制有什么用?
        通过java语言中的反射机制可以操作字节码文件。
        优点类似于黑客。(可以读和修改字节码文件。)
        通过反射机制可以操作代码片段。(class文件。)
    
    2.2、反射机制的相关类在哪个包下?
        java.lang.reflect.*;
    
    2.3、反射机制相关的重要的类有哪些?

        java.lang.Class:代表整个字节码,代表一个类型,代表整个类。

        java.lang.reflect.Method:代表字节码中的方法字节码。代表类中的方法。

        java.lang.reflect.Constructor:代表字节码中的构造方法字节码。代表类中的构造方法

        java.lang.reflect.Field:代表字节码中的属性字节码。代表类中的成员变量(静态变量+实例变量)。

        java.lang.Class:
            public class User{
                // Field
                int no;

                // Constructor
                public User(){
                
                }
                public User(int no){
                    this.no = no;
                }

                // Method
                public void setNo(int no){
                    this.no = no;
                }
                public int getNo(){
                    return no;
                }
            }

3、关于JDK中自带的类加载器:(聊一聊,不需要掌握,知道当然最好!)
    3.1、什么是类加载器?
        专门负责加载类的命令/工具。
        ClassLoader
    
    3.2、JDK中自带了3个类加载器
        启动类加载器:rt.jar
        扩展类加载器:ext/*.jar
        应用类加载器:classpath
    
    3.3、假设有这样一段代码:
        String s = "abc";
        
        代码在开始执行之前,会将所需要类全部加载到JVM当中。
        通过类加载器加载,看到以上代码类加载器会找String.class
        文件,找到就加载,那么是怎么进行加载的呢?

            首先通过“启动类加载器”加载。
                注意:启动类加载器专门加载:C:\Program Files\Java\jdk1.8.0_101\jre\lib\rt.jar
                rt.jar中都是JDK最核心的类库。
            
            如果通过“启动类加载器”加载不到的时候,
            会通过"扩展类加载器"加载。
                注意:扩展类加载器专门加载:C:\Program Files\Java\jdk1.8.0_101\jre\lib\ext\*.jar

    
            如果“扩展类加载器”没有加载到,那么
            会通过“应用类加载器”加载。
                注意:应用类加载器专门加载:classpath中的类。
    
    3.4、java中为了保证类加载的安全,使用了双亲委派机制。
        优先从启动类加载器中加载,这个称为“父”
        “父”无法加载到,再从扩展类加载器中加载,
        这个称为“母”。双亲委派。如果都加载不到,
        才会考虑从应用类加载器中加载。直到加载
        到为止。
        
1、回顾反射机制

    1.1、什么是反射机制?反射机制有什么用?
        反射机制:可以操作字节码文件
        作用:可以让程序更加灵活。

    1.2、反射机制相关的类在哪个包下?
        java.lang.reflect.*;

    1.3、反射机制相关的主要的类?
        java.lang.Class
        java.lang.reflect.Method;
        java.lang.reflect.Constructor;
        java.lang.reflect.Field;

    1.4、在java中获取Class的三种方式?
        第一种:     
            Class c = Class.forName("完整类名");
        第二种:
            Class c = 对象.getClass();
        第三种:
            Class c = int.class;
            Class c = String.class;

    1.5、获取了Class之后,可以调用无参数构造方法来实例化对象

        //c代表的就是日期Date类型
        Class c = Class.forName("java.util.Date");

        //实例化一个Date日期类型的对象
        Object obj = c.newInstance();

        一定要注意:
            newInstance()底层调用的是该类型的无参数构造方法。
            如果没有这个无参数构造方法会出现"实例化"异常。
    
    1.6、如果你只想让一个类的“静态代码块”执行的话,你可以怎么做?
        Class.forName("该类的类名");
        这样类就加载,类加载的时候,静态代码块执行!!!!
        在这里,对该方法的返回值不感兴趣,主要是为了使用“类加载”这个动作。
    
    1.7、关于路径问题?

        String path = Thread.currentThread().getContextClassLoader()
                          .getResource("写相对路径,但是这个相对路径从src出发开始找").getPath();    

        String path = Thread.currentThread().getContextClassLoader()
                          .getResource("abc").getPath();    //必须保证src下有abc文件。

        String path = Thread.currentThread().getContextClassLoader()
                          .getResource("a/db").getPath();    //必须保证src下有a目录,a目录下有db文件。
        
        String path = Thread.currentThread().getContextClassLoader()
                          .getResource("com/bjpowernode/test.properties").getPath();    
                          //必须保证src下有com目录,com目录下有bjpowernode目录。
                          //bjpowernode目录下有test.properties文件。

        这种方式是为了获取一个文件的绝对路径。(通用方式,不会受到环境移植的影响。)
        但是该文件要求放在类路径下,换句话说:也就是放到src下面。
        src下是类的根路径。

        直接以流的形式返回:
        InputStream in = Thread.currentThread().getContextClassLoader()
                                .getResourceAsStream("com/bjpowernode/test.properties");

    1.8、IO + Properties,怎么快速绑定属性资源文件?

        //要求:第一这个文件必须在类路径下
        //第二这个文件必须是以.properties结尾。
        ResourceBundle bundle = ResourceBundle.getBundle("com/bjpowernode/test");
        String value = bundle.getString(key);
    

2、今日反射机制的重点内容
    2.1、通过反射机制访问对象的某个属性。
    2.2、通过反射机制调用对象的某个方法。
    2.3、通过反射机制调用某个构造方法实例化对象。
    2.4、通过反射机制获取父类以及父类型接口。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值