备份一下java笔记

十进制(decimal)
二进制(binary)
十六进制(heaxdecimal)
八进制(octal)
发生及存在,存在及对象???

空格也是字符
注意:以后说类名的时候,如果带着包名描述,表示完整类名
注意:如果没有带包名描述的话,表示简类名
//重写equals是程序员的素养
对象在堆,方法在栈,字符串常量池在方法区
字符串常量池:所有字符串对象的所在地
垃圾回收器不会回收常量的
//类在强制类型转换过程中,如果类转换成接口类型,那么类和接口之间可以不需要继承关系
native关键字:表示调用JVM本地程序
    //底层调用c++代码,有方法,无方法体

//注意:java中允许子类中出现和父类一样的同名变量/同名属性
字符编码(ASCII):人为制定的二进制和文字的对照表,清楚地描述了二进制与文字的对照关系
    


编译软件的默认当前路径是当前模块的上一级
char类型在Java中占用了2个字节(可以将char类型看作一个字符)
字母“a”在windows中占用1个字节,汉字在windows占用2个字节
关于 Java注释
    /** 加上回车键(注意在方法之外):注释,且将方法内的关键字列出
除数为零会出现异常,除数不能为零 
关于配置文件:
    需要经常改变的数据,可以单独写到一个文件当中,使用程序动态获取,将来只需要修改这个文件的内容,java代码不需要改变,不需要重新编译,就可以拿到动态的信息
    这种机制的文件叫做配置文件。
    关于属性配置文件:
        文件的内容格式是:  key1=value
                key2=vallue
                key3=value
                (key重复了,value覆盖)
                (支持#号,#号是注释)
                (注意:等号左右最好不要有空格)
                (支持使用:冒号来代替=等号,但不建议)
        叫做属性配置文件
        属性配置文件的后缀为:.properties结尾,但这不是必须的(建议,java规范)
        其中properties是专门存放属性配置文件的一个类
注意:java.lang.*包下的类自动导入
注意:如果一个类的equals()方法重写了,那么该类的HashCode()方法必须重写。
    如果equals()方法返回的是true,那么HashCode()方法的返回值应该相同
注意:HashCode方法和equals方法使用工具“同时”生成
注意:放在HashMap集合key部分的,以及放在HashSet集合中的元素,需要同时重写hashCode方法和equals方法
关于序列化版本号:
    序列化版本号的实际作用:
        来区分 相同类名 的类,如果类名一样,java虚拟机将通过  序列化版本号 来区分
        只有实现了  Serializable接口   才拥有序列化版本号
        Serializable接口是为了IO流中的ObjectOutputStream类的使用
        实现Serializable接口,java虚拟机会自动生成序列化版本号
    序列化版本号的缺陷:
        这种自动生成的序列化版本号缺点是:代码一旦确定之后,不能进行后续修改,
        因为只要修改,就会重新编译,这样就会生成全新的序列化版本号,这个时候
        java虚拟机会认为这是一个全新的类
    注意:
        凡是一个类实现了Serializable接口,建议给该类提供一个固定不变的序列化版本号
        这样即使代码进行了修改,java虚拟机也能识别出这是同一个类
        关于序列化版本号手动设置:
            注意:数值随意,但请确保全球唯一性
            private   static   final  long   serialVersionUID=5313154687L;
            
    
关于java语言中采用什么机制来区分类:
    第一:先通过类名来进行对比,如果类名不一样,肯定不是同一个类
    第二:如果类名一样,靠“序列化版本号”来进行区分。
关于transient关键字:
    transient关键字:表示游离的,不参加序列化(序列化,ObjectInput(Output)StreamIO流中的概念)。
    例 :   public  transient  String   name;//这是一个属性

关于final关键字:最终的,不可改的
    final修饰的类无法被继承
    final修饰的方法无法被覆盖
    final修饰的变量只能被赋值一次
    final在修饰实例变量时,必须手动赋值,不能采用系统默认值(且赋值后无法更改)
    final修饰的引用指向一个对象时,无法在指向其他对象,且被指向的对象无法被垃圾回收器回收
    (但被指向的对象内部内存是可以被修改的,如里面的属性)
    
    final修饰的实例变量是不可变的,一般与static联合使用,被称为“常量”
    //常量的定义语法格式:public   static   final    类型  常量名 = 值;
    //java规范中要求常量的名字全部大写 ,每个单词之间用下划线连接

java文件中每个 类  都会生成各自的  .class  文件,而每个类中必须拥有  “主方法“( public  sattic void  main(String[]    args)  
),否则无法成功运行
java文件中只能定义一个公开的类,且公开的类名必须与java源文件的文件名“相同”。
//向控制台输出消息
System.out.println("  ");
    println:输出之后并换行
native2ascii命令:jdk自带的一个程序(可以将你输入的中文得出unicode码)(注:未找到)
字符型:单引号内只能包含单个字符,这是字符型(char)
字符串:双引号内可以包含多个字符(string)
Java类库字节码路径:
Java类库源码路径:C:\Program Files\Java\jdk-11\lib\src.zip
在java中main方法始终为栈底
递归:方法调用方法本身(尽量不用,因为会耗费大量栈内存,产生栈内存溢出错误)

方法(函数):代码片段,可以完成某个特定的功能,并且可以重复使用(定义在类体当中,方法体之外)
关于方法的返回值:(返回值的数据类型必须和“定义方法时声明的返回值数据类型一致”)
    (1):有返回值,返回值数据类型可以是java所有数据类型,包括基本数据类型和引用数据类型
    (2):无返回值,则必须使用“void”关键字(若没有使用void关键字,则该方法调用结束后必须有一个返回值)

在JVM内存划分上有三块主要的内存空间(除了这三块还有其他的内存空间)
    (1)方法内存:
        方法代码片段所在区域,方法代码片段属于.class字节码文件的一部分,字节码文件在类加载的时候,将其放到了方法区当中。所以JVM中的三块主要的内存空间中方法区内存最先有数据,存放了方法代码片段
        代码片段在方法区内存当中只有一份,但是可以重复调用
    (2)堆内存:存放的是对象
    (3)栈内存:(个人理解:三闭一开的容器,“先进后出,后进先出”,栈顶为最后进入的元素,栈帧永远指向栈顶)
        栈:stack,是一种数据结构
        局部变量在“方法体”中声明 ,局部变量运行时在栈中存储
        先调用的方法一定最后结束(main方法最先调用,位于栈底,栈??方法的调用??顺序??)
    对列:两头通(允许先进先出)

***方法参数传递的不是变量,而是变量所代表的的那个“值”,与变量没有关系,其变量所占得内存也不会有所变化    
    遇到大括号后,方法进行释放
数据结构:
    数据结构反映的是数据的存储形态
    数据结构是独立的学科,不属于任何编程语言的范畴,只不过大多数编程语言当中要使用数据结构
    数据结构  +  算法(很重要,计算机专业必修的一门课程)
    
    常见的数据结构:
        - 数组
        - 队列
        - 栈
        - 链表
        - 二叉树
        - 哈希表/散列表
        .....
方法案例:
    public  static    返回值数据类型  方法名 
    .... 
原码、反码和补码:(计算机采用补码的形式进行存储)(原码和补码,反码都有“符号位”和“数值位”)
    补码用二进制表示
    注意:补码的补码就是原码
    第一位皆为符号位(0代表正数,1代表负数)

    正数的反码和补码是它本身
    负数的反码:除了符号位,表示数值的二进制位全部相反。例:01000111  的反码00111000
    负数的补码:包括符号位,索取数的正数的 所有二进制位全部取反,之后+1     例:01000111  的补码   10111001
    
ASCII码:
    “a”  --》97       (注:“b”--》98)
    “A”  --》65    (注:“B”--》66)     以此类推
    “0”  --》48    (注:“1”--》49)
java中进制的表示方法
    十进制:不加任何表示
    八进制:前面加“0”的
    十六进制:前面加“0x”的
字面值:字面值就是数据,其中包含多个数据类型。
java中的整数字面值被当做int数据类型(默认为int类型)可以为整数型字面值添加后缀单位,例:L(long数据类型)
Java中的浮点数字面值默认为double数据类型,注意不会出现Java特殊机制(创建float变量方法一强制类型转换,方法二是为其添加“f或F”后缀)
自动类型转换机制:
    例:int  是小容量
          long  是大容量
        小容量可以自动转换成大容量,被称为自动类型转换机制。
强制类型转换:
    大容量转换成小容量,需要强制类型转换
    强制类型转换需要加“强制类型转换符”,但是可能会损失精度
    强制类型转换符:(要转换的数据类型)  字面值
    转换原理:先将数字转换为二进制数,然后砍掉左面的二进制数,使现在的二进制位数与你要转换的数据类型
    的二进制位数一样

当整数型字面值没有超出byte类型的取值范围,该字面值可以直接对byte类型变量赋值。(java特殊机制,方便编写)
而short(char)数据类型与上同理,赋值时只要不超过short(char)的取值范围,即可直接赋值。(注意:是整数型)

数据类型的作用:jvm在运行程序的时候给该数据类型分配多大的内存空间
数据类型包括两种:
    基本数据类型:包括四大类,八小种
        1)整数型:
            byte,short,int,long
        2)浮点型:
            float,double
        3)布尔型:
            boolean
        4)字符型    :
            char
        (字符串不属于基本数据类型,属于“引用数据类型”)

        基本数据类型占用的内存空间大小
          数据类型        字节    二进制数(1byte(字节)=8bit(二进制位))
        ————————————————    最大值(正数)和最小值(负数):
        | byte        1    8     |    字节转换成十进制  减   1
    整数型    | short        2    16   |
        | int        4    32   |
        | long        8    64   |
        ————————————————    
        ————————————————    在java中数据类型的正负数区分:
    浮点型      |  float           4    32   |    字节数最左方的二进制位为“符号位”
                     |  double       8    64   |    0为正数,1为负数
        ————————————————
        ————————————————
    布尔型    |  boolean       1    8     |
        ————————————————
        ————————————————    
    字符型      |  char        2    16   |
        ————————————————

    引用数据类型:
        类
        接口
        数组 
字符编码:ASCII码        二进制与字母的对照表(字典)(人为干涉的二进制与文字之间的对照关系)
    a--》01100001(解码)
    01100001--》a(编码)
-encoding
java运算符
    +
    -
    *    
    /
    %:取余
    ++:自增运算符
        自增前置:++变量(先加一),(变量先加1,再进行表达式运算)
        自增后置:变量++(后加一),(变量先进行表达式计算,再加1)
    --:自减运算符(与自增同理)
java关系运算符:(与python同理)
    ==
    >=
    <=
    >
    <
    !=
逻辑运算符:(逻辑运算符要去两边的算子都是布尔类型)    
    &:与          (两面的算子都为真,结果就为真)    
    |:或    (两面的算子只要有一个为真,结果就为真)
    !:非    (取反)                
    ^:异或    (两边的算子只要不一样,结果就为真,一样则为假)
                
    &&:短路与(结果与逻辑与一样,只不过有短路现象)    
    ||:短路或 (结果与逻辑或一样,只不过有短路现象)
    
    短路与和逻辑与的区别:(短路或同理)
        逻辑与:两面的表达式全部会执行(第二个表达式)
        短路与:如果经过第一个表达式后就可以得出结果,那么不会执行后面的表达式(第二个表达式)

        短路或:第一个表达式结果是true,后面的表达式不会执行
        
赋值运算符共两种:
    基本的赋值运算符: =
    扩展的赋值运算符: -=   +=   *=    /=   %=    等同于【变量 =(变量的数据类型)(表达式)运算符  数值】
        扩展的赋值运算符不会改变原变量的数据类型,其中含有强制类型转换
    赋值类的运算符优先级:先执行等号右边的表达式,将执行结果赋值给等号左边的变量

关于“+”的有两种作用:
    字符串连接符:当加号“+”两边有一个是字符串,就会把加号当做字符串连接符来使用,返回的是一个字符串
    求和:当加号“+”两边都是数值是,当做普通加号来使用,返回的是一个数值
    关于多个加号:当没有小括号的时候,表达式从左向右运算
关于String引用数据类型:
    String是字符串类型
控制语句:
    选择结构:
        if语句:
            if   (表达式){}
            if  else 
            if  () else if   ()   else
            if语句不加大括号时,会自动将后一条语句归纳到if语句(else同理)

        switch语句:(值之间的匹配)(只支持  int  或  String类型的数据)(支持ASCII码)
            switch 后小括号的“数据”和case后的“数据” 一一匹配,匹配成功,则执行其下java语句
            注:switch不支持java中关系运算符与逻辑运算符
            注意:如果不加break,则直接进入下一个分支执行,不进行匹配。这叫做case穿透现象
            switch  (支持  in  或  String类型的字面值或变量,char类型也可以)  {}
                //char类型也可以的原因:char类型会进行自动类型转换成int类型 
                //case支持合并,貌似利用了case穿透现象 
                //
                //例:switch  (1){ 
                //case 1  : case 2  :case  3 :case  4://1,2,3,4都会执行,这就是case合并
                    System.out.println("ww");}
                case    支持  in  或  String类型的字面值或变量  :
                    java语句;      
                    break;(注意:如果不加break,则直接进入下一个分支执行,不进行匹配)
                        
                case    支持  in  或  String类型的字面值或变量  :
                    java语句;.......      
                    break;
                default :(注:类似else)
                    java语句;
                    .....
                    
     循环结构:
        for语句:                  开始                 结束          开始到结束之间的变化规律
            格式:for  (初始化表达式;布尔表达式;更新表达式){循环体}(分号;,是必须的)
            
        while语句:java中的while循环条件结果只能是布尔值true或flase,不能是其他值
        do..while语句:
    控制循环的语句:
        break
        continue:继续,出现在循环语句当中,控制循环的执行,跳过本次循环,进行下一次循环

三元 运算符:(三元运算符不是一个完整的java语句)(可声明数据和变量,并将三元运算符的结果进行赋值)
    语法规则:
        布尔表达式 ? 表达式1 :表达式2  (布尔表达式为真,执行表达式1。  为假,则执行表达式2)

import 路径:导入类
java.util.Scanner
Scanner类:
    System.in:向控制台获得
    获取输入方法:
        next()
        nextLine()
        nextInt()
        nextFloat()
        nextDoule()
    从控制台“输入”例子:
        import java.util.Scanner;
        public class Tun{
            public static void main(String[] args){
                double   c;
                System.out.println("请输入一个数值");
                Scanner   num=new Scanner(System.in);
                c=num.nextDouble();
                System.out.println(c);
            }
        }
特殊注释:
    /**
    * 语句
    * 语句
    */
    该注释可以被javadoc.exe文件解释成doc文档
java转义字符:(这是字符,属于char数据类型),反斜杠“\”在具有转义功能
    转义字符出现在特殊字符前,会把特殊字符转义成普通字符
    \n:换行符
    \t:制表符(就是一个tab键),制表符和空格不一样,ASCII码不相同
    \\:代表一个普通的反斜杠“\”字符,(第一个反斜杠为转义字符,将后面的反斜杠转义成普通的反斜杠字符)
    \':代表一个普通的单引号(  '  ),
    \u ???:unicode编码对应的字符
变量分为:(注意,出了大括号就不认识)
    成员变量:类体之内,方法体之外
        实例变量:未赋值,系统自动赋值为null
        静态变量:类似全局变量,在java内声明成员变量必须加“static“关键字

        成员变量声明后,如果没有手动赋值,系统会自动赋值
        八大数据类型的默认值都为0
    局部变量:方法体之内(局部变量不会被系统自动赋值)


关于方法重载机制:
    功能相似,可使用方法重载
    特点:在同一个类当中,方法名相同,参数列表不同,使用时像是在使用一个方法一样
        //注意:方法重载和返回值类型无关


关于方法覆盖机制(又称:override/overwrite):(重写时尽量 复制粘贴原方法)
    父类中的方法无法满足子类的业务需求,这时需要进行方法覆盖/方法重写
    方法覆盖后,会调用重写之后的方法
    条件:
        1.方法覆盖发生在拥有继承关系的父子类之间
        2.返回值类型相同,方法名相同,形参列表相同
        3.访问权限不能更低,只能更高
        4.抛出异常不能更多,可以更少
    注意:
        1.私有方法不能继承,不能覆盖
        2.构造方法不能继承,不能覆盖
        3.静态方法不能覆盖
        4.覆盖只针对方法,不针对属性

多态:
          多态的产生条件:存在继承关系
    //父类型引用可以指向子类型对象,
    //注意,java分为编译阶段和运行阶段,在父类型引用指向子类型对象时,只能调用父类型的方法,但底层运行的却是子类型对象    
    java.lang.ClassCastException   //类型 转换异常,只在强制类型时会发生,也就是“向下转型”

    向上转型:子类转向父类型(自动类型转换)
    向下转型:父类转换成子类型(需要进行强制类型转换)
    避免向下转型的异常:    
        instanceof:用法  (   对象1 或引用   instanceof   对象2或数据类型   )
        两个对象之间数据类型的判断
        //返回值类型为布尔类型

关于访问控制权限修饰符:
    public :表公开的,任何位置都可以访问
    protected:同包以及子类可以访问
    缺省:不写修饰符  ,   只在同一个包下可以访问
    private:表示私有的,只能在本类中访问
    修饰符范围:
        private>缺省>protected>public
    //注意:类只能采用public和“缺省”修饰符修饰【内部类除外】
    //修饰类,变量,方法

关于this关键字:
    this能出现在实例方法和构造方法中
    this不能使用在静态方法中
    this()只能出现在构造方法第一行,通过当前的构造方法去调用“本类”中其他的构造方法
    //this()和super()不能共存

关于super关键字:super.可调用父类的属性和方法,super()可调用父类的构造方法
    super能出现在实例方法和构造方法中
    super不能使用在静态方法中
    语法:super.    和   super()
    super()只能出现在构造方法第一行,通过当前的构造方法去调用“父类”中的构造方法
    //子类构造方法第一行默认super()
    super()子类的构造方法调用父类的构造方法


关于抽象类(abstract):类和类之间有共同特征,将具有共同特征的类进一步抽象,形成 抽象类
    //确切的说的 就是   类的再次抽象
    //抽象类无法实例化,无法创建对象,所以抽象类是用来被子类继承的
    //抽象类有构造方法,供子类使用
    //抽象类属于引用数据类型,且支持多态
    
    语法:
        修饰符列表   abstract   class  类名{
            类体;
        }
    //final和abstract无法同时修饰类,因为fanal修饰的类无法被继承,abstract抽象类就是用来被继承的,出现冲突
    //抽象类可以继承抽象类
    //抽象类中不一定有抽象方法,抽象方法一定出现在抽象类中,抽象类中也可以有非抽象方法
    //非抽象子类从抽象类中继承过来的抽象方法必须得重写/覆盖/实现,归根结底抽象方法只能出现在抽象类
    关于抽象方法:
        //没有实现的方法,没有方法体的方法
        例:public   abstract   void  doSome();
        
关于接口(interface):作用“解耦合”
    //接口也是一种引用数据类型,接口的祖先类也是Object
    //接口是完全抽象的,(抽象类是半抽象的)
    //接口一般都是对“行为”的抽象    
    语法:
        修饰符列表    interface    接口名{

        }
    //接口可以继承接口,且接口支持多继承 (一个接口继承多个接口)
    //一个类可以实现多个接口(弥补了java中类与类单继承的缺陷)
    //接口中只有“常量”和“抽象方法”
    //接口中所有的元素都是public (公开的),且public  abstract可以省略
    //类实现接口可以使用implements关键字完成
    //注意:接口与接口之间在进行强制类型转换时,没有继承关系也可以强转(接口稍稍有点特殊)
        //但是运行时可能会出现ClassCastException异常
    //面向抽象编程,降低程序的耦合度,提升程序的扩展力(接口的使用离不开多态)
异常处理:
    try{  }
    catch(){}
    finally{}(一定会执行)
java.util.Date  : 日期时间类
java.text.SimpleDateFormat : 简单格式化类
    (已知)有参构造:参数 为输出格式 例("yyyy年MM月dd日  HH:mm:ss")
        输出:
            对象.format(输出格式)
            对象.parse(“日期”):返回一个该日期的date对象
java.util.Random:随机数类
Java中”equals“和“==”的区别
    java中“==”比较的是变量所保存的值是否相等,例:str1==str2,当前比较的是两个对象的内存地址是否相等
而不是比较两个对象是否相等
    equals是重写方法
    public boolean equals (Object obj) {
        if(obj == null 1 ! (obj instanceof Address) ) return false;
        if( this -=obj)return true;
        Address a-|(Adldress) obj;
        if(城市相同'&&街道相同&&邮编相同){ //属性的判断
        return true ;
        }
        return false ;
object类内的方法:
    equals方法:比较的是两个对象是否相等,尽量重写(还有toString方法)
    toString方法:将对象以字符串的形式表达出来
    finalize方法:不需要人为手动调用,jvm的垃圾回收器负责调用。(可以重写)(遗言方法)
        只需要重写,在对象销毁时,由jvm自动调用。
    hashCode方法:实际上就是一个对象的内存地址,经过哈希算法,得出的一个值。等同于对象的内存地址。
        


instanceof:用法  (   对象1   instanceof   对象2   )
    两个对象之间数据类型的判断

注意:垃圾回收器存在着  垃圾太少,不启动的可能性
System.gc()方法:建议启动垃圾回收机制,但是还是存在着不启动的可能性(提高启动垃圾回收机智的成功几率)

带有native关键字的方法,底层调用的是c++算法
匿名内部类:(可读性偏差,尽量不用)
    内部类:在类的内部又定义了一个新的类
        内部类的分类:
            静态内部类:类似于静态变量(在类中且声明时前面加static)
            实例内部类:类似于实例变量 (类内定义)
            局部内部类:类似于局部变量(在方法内部声明其类,且只能在该方法中使用)
        //匿名内部类是局部内部类的一种
        匿名内部类:创建一次性的对象,//可使用在方法之中
            new       父类或接口名             ()                     {  }
            创建   其父类下的一个对象       构造方法的声明    里面含抽象方法的实现
    


数组(array):数组是一种引用数据类型,父类是Object
    数组是一种容器,可以同时容纳多个元素。(数组是一个数据的集合)
    数组当中可以存储基本数据类型的数据,也可以存储引用数据类型的数据
    数组因为是引用数据类型,所以数组对象是堆内存当中。(数组存储在堆内存当中)
    数组当中如果存储的是 Java对象 的话,实际上存储的是对象的内存地址
    数组一但创建,Java中规定,长度不可变
    数组分为:一维数组,二维数组,多维数组。
    所有数组对象都有“length属性”,用来获得数组中元素的个数
    Java中数组要求数组中的元素的类型统一。
    数组中每个元素所在空间都是有规则的,连续的,有规律的。(索引??)
    数组实际上是一种简单的数据结构
    所有的数组中第一个元素所在空间的内存地址,是整个数组对象的内存地址。
    为什么第一个元素是整个数组的内存地址???
        因为可以通过第一个元素的内存地址来推算出其他元素的内存地址。
        数组中的每个元素都是有下标的,由0开始,最后一个下标是 length - 1 。(存取是依靠下标类完成的)

    语法格式:         引用数据类型      
    数组的声明:   int[]    变量名;
    初始化数组:
        静态初始化: int[]  变量名 = {值。。。。。}
        动态初始化: 变量名 = new  int[数值];
    数组的优缺点:
        优点:查询/查找/检索某个下标上的元素时效率极高。可以说是查询效率最高的一个数据结构。
            为什么检索效率高?
            第一:每一个元素的内存地址在空间存储上是连续的。
            第二:每一个元素类型相同,所以占用空间大小一样。
            第三:知道第一个元素内存地址,知道每一个元素占用空间的大小,又知道下标,所以通过一个数学表达式就可以计算出某个下标上元素的内存地址。直接通过内存地址定位元素,所以数组的检索效率是最高的。
            (数组中查找的方式是通过数学表达式计算出来的,所以不管数组内的元素有多少,查找的效率都一样)
        缺点:
            第一:在插入或删除元素时,会牵扯到该元素后的所有元素发生变动。             
            第二:数组存储大数据量时,很难找到很大一块连续的内存空间
直接传递静态数组:
    方法名(new  int【】{值,值,值})
jvm虚拟机去调用  main 方法,并传递一个数组参数

在cmd中  Java  文件名    asd  da  dad
(注意,在文件名之后的字母,jvm会 将其转换为字符串格式,放进main方法中的参数数组)
public static  void  main(String[] args){}
                 用来接收用户输入的数据的

字符串.equals(字符串对象)  (这种方法可以避免空指针异常)
abc.equals(abc)
数组是支持多态的,
    例:   animal   a  = {new  cat(),new bird()};
    animal是cat,bird的父类(这是多态)
关于数组的扩容:
    (数组扩容效率较低)最好在创建数组时,预估一下数组的长度,减少数组的扩容次数
    创建一个大容量数组,将小容量数组内的 数据拷贝进去。
    扩容方法:数组拷贝(拷贝的是对象的内存地址)
        System.arraycopy(源头,int  源的起点,目标,int  目标的起点,int 长度);
                        //被拷贝                     //拷贝到该目标
关于二维数组: 二维数组其实是一个特殊的一维数组,只不过一维数组中的每个元素都是一个一维数组
    声明格式:  例  int[][]   a;
    二维数组静态初始化:int[][]  b = { {0,1 },{0,1 },{0,1 } };

三维数组与二维数组的规律相似
数组中每个元素的内存空间的长度都是4

数组之算法:
    排序算法:
        冒泡排序算法:
            相邻的两个数进行比较,最大的放后面,用到两个循环,外循环用来得到参与比较的数据中最大的数字放在最后,内循环:相邻的两个数字进行比较,交换位置,大的那位放在后面,
        选择排序算法:每一次从这堆参与比较的数据中找出最小值,拿着这个最小值和最前面的元素交换位置(每一次的交换位置都是有意义的,比冒泡排序更有效率)
    查找算法:
        二分法查找算法:将数组从中间分成两个部分(建立在从小到大排序之后)
            二分法查找只适合从小到大排序的数组,因为该查找方法是得到中间元素来和被查找元素进行对比,然后得到被查找元素在中间元素的左右方(该方法效率高于“一个挨着一个的查找方法”)
            二分法终止条件:直到中间元素正好是被查找元素
            (首下标 + 尾下标)/2
    Java中已经封装好了,是数组工具类Arrays类
    java.util.Arrays
        方法:
             Arrays.sort(数据类型[]   array);:数组排序方法,静态方法用于排序
        //工具类中的方法大部分都是静态的

Java常用类
    string类:不可变,字符串存储在“方法区”的“字符串常量池”当中,因为string使用的太过频繁,所以为了效率,放在了“字符串常量池”当中(注意:凡是双引号括起来的,在字符串常量池中一定有一份,)
    string类中的构造方法:
        string(bytes【】):将byte数组内的数字用解码的方式表现出来
        string(bytes【】,元素起始下标,长度):将byte数组内的一部分元素转换成字符串
        string(char【】):将char数组转换成字符串
        string(char【】,元素起始下标,长度):将char数组内的一部分元素转换成字符串
        string(string)
        string    a = “adad”;
    常用方法:
        char    charAt(int   index):截取一个char字符
        boolean  contains(string) :判断前面的字符串是否包含后面的字符串
        boolean  endsWith(string):判断当前字符串是否以某个字符串结尾
        boolean  startsWith(string):判断当前字符串是否以某个字符串开始的
        boolean  equals(string):比较两个字符串是否相等
        boolean  equalsIgnoreCase(string):判断两个字符串,忽略大小写
        int   compareTo(string):比较两个字符串的大小  
        byte【】    getBytes(string):将字符串转换成byte数组
        int   indexOf(string):判断某个子字符串在当前字符串的第一次出现出的索引
        int   lastIndexOf(string):判断某个字符串在当前字符串最后出现的索引
        boolean isEmpty():判断某个字符串是否为空(为“”返回true,字符串长度为0)
        int   length():返回字符串长度(注意数组的是length属性,字符串是length()方法)
        string  replace(被替换(旧的),替换(新的)):替换掉旧的字符串
        string【】 split(string  界限):以“界限”拆分字符串
        string    substring(int   index):从下标开始截取字符串(可在参数内设置结束下标)
        char【】  toCharArray():将一个字符串转换为一个char数组
        string    toLowerCase():将当前字符串全部转换为小写
        string     toUpperCase():将当前字符串全部转换为大写
        string    trim():去除字符串前后空白
        string中的唯一静态方法
            static  string    valueOf(非字符串):将非字符串转换为字符串


关于对字符串的频繁拼接问题:因为java中的字符串是不可改的,每一次拼接都会产生新字符串。这样会占用大量的方法去内存。造成内存空间的浪费。(所以出现了StringBuffer类 )

        StringBuffer:需要进行大量字符串进行拼接的操作,建议使用该类。(字符串缓冲区对象)
            在创建StringBuffre时最后创建一个初始化容量,减少扩容次数,预估一下容量。
            构造方法:StringBuffer()默认构造方法,默认创建一个byte【】容量为16的数组
            
            方法:
                append():在末尾追加字符串,容量不够自动进行扩容。
        StrignBuilder:与StringBuffer相似
    StringBuffer和StringBuilder的区别:
        StringBuffer中的方法都有:synchronized关键字修饰。表示StringBuffer在多线程环境下运行时安全的
        StringBuilder中的方法没有:synchronized关键字修饰。表示StringBuilder在多线程环境下运行时不安全的


八大包装类:用于将八大基本数据类型转换为引用数据类型(有时方法参数为objate,由于基本数据类型无法利用多态传入参数,所以为了方便开发,出现了八大包装类)
    装箱:将基本数据类型转换为引用数据类型
    拆箱:运用从父类继承的方法将引用数据类型转换为基本数据类型
    自动装箱机制:可以自动转换为  integer   (八大包裝类)   
            例:integer    t = 100;
    自动拆箱机制:可以自动转换为  基本数据类型类型  
            例:int   a = t;
    八大包装类的构造方法:
        都支持“参数为   int   或    String  类型”
    character:char的包装类
    integer:
        构造方法:integer(int)  
            integer(String)

        方法:
            MAX_VALUE:最大值(包装类通用,常量)
            MIN_VALUE:最小值(包装类通用,常量)
            static    paseInt:将字符串(双引号内是数字)转换为数字,static静态方法,返回值int
                         paseDouble:Double包装类中的静态方法
                         paseFloat:Float包装类中的静态方法
            static  valueof():数据类型转换   ,静态方法(各大基本数据类型应该都具有该方法)

Java中为了提高效率,将【-128    -    127】之间所有的包装对象提前创建好,并放到了方法区的“整数型常量池”当中,只要是在这个区间的数据不需要再new了,且创建该区间之间的对象会自动指向整数型常量池之间的对象
缓存机制尤为重要,
java关于对日期的类
    java.util.Date
    其中无参数构造方法获取的是当前系统的准确时间,精确到毫秒
    Date类的toString方法已经重写,返回的是一个字符串日期
    
    有参构造
        参数是long类型,从1970年1月1日 00:00:00 的毫秒数来计算
        (由于是地区差异,北京时间,所以可能会出现差异)
java中关于对日期的格式化
    java.text.SimpleDateFormat(将该类当成 “对日期的加工封装即可”)
    构造方法    参数类型String    
        yyyy    年
        MM     月
        dd       日
        HH      时
        mm    分
        ss       秒
        SSS    毫秒
        yyyy-MM-dd     HH:mm:ss    SSS
        年     月    日     时    分   秒   毫秒
        以上字母不可随便定义,其他符号可随意
    1秒==1000毫秒
    SimpleDateFormat类内的方法
        format方法的返回值类型为String类型
        对象.format(Date对象);
        
        对象.parse(“日期”):返回一个该日期的date对象
    将format方法的返回值再转换成Date类型
        SimpleDateFormat的构造方法参数必须与日期字符串格式相同(如果不同则会抛出异常)
        调用SimpleDateFormat中的parse(字符串)方法(注意该方法不是静态方法)
        方法不通过,可以尝试抛出异常   throws    Exception
System类
    获取从1970年1月1日  00:00:00  到系统当前的总毫秒数
    System.currentTimeMillis();返回值类型为long类型
    作用:可以统计该程序所运行的时间

    System.out.println()   out是PrintStream类的对象
    System.gc()   :建议启动垃圾回收器
    System.exit() :退出jvm虚拟机
Java中数字格式化
    java.text.DecimalFormat
    DecimalFormat类
    构造方法:new  DecimalFormat(“数字格式”)
        #代表任意数字
        ,代表千分位
        .   代表小数点
        0   代表不够时补零
        例: ###,###.##

Java中BigDecimal类
    属于大数据,精度极高,不属于基本数据类型,属于Java对象(引用数据类型)
    专门用于财务软件中
    Java.math.BigDecimal
    构造方法:new  BigDecimal(数字)
    方法: 
        add:求和方法,两个BigDecimal对象的相加,返回值为BigDecimal类型

Java中关于随机数Random类
    Java.util.Random
    构造方法为无参
    方法:
        nextInt(可设置参数):返回一个int类型范围内的随机数(如果设置参数,则0-参数范围之内,不包含参数)
Java中关于枚举类型:高版本jdk中switch也支持枚举
    作用:在Java开发中,有时方法的运行结果拥有两种情况以上 ,这时就需要用到枚举类型。
    true和false就是枚举的两个值
    一枚一枚可以例举出来的,才建议使用枚举
    枚举编译后可以生成class文件
    枚举是一种引用数据类型
    枚举的每一个值可以看做是常量
    (枚举是一个类,里面的枚举值可以看做常量,且注意该值不需要赋值,建议单词尽量大写)
    枚举的创建语法:
        enum   类名{//大写字母   例:
            SUCCESS,FAIL   //枚举值}
    枚举的调用:
        类名.枚举值
        例:enum   Test{SUCCESS,FAIL}
        Test.SUCCESS //枚举的调用
Java中对异常的回顾
    程序在执行过程中发生了不正常的情况,这种情况叫做:异常
    Java提供了异常处理机制,发生异常后会在控制台打印出异常信息,供编译人员参考,让程序更加的健壮。
    **异常作用:增加程序的健壮性。
    
    Java中异常是以“异常类”的形式存在,每一个类都可以创建对象
    **通过“异常类”可以创建“异常对象”

    //**运行时关于异常,jvm虚拟机检测到异常,会自发的创建一个对象的异常对象,并抛出,让控制台去接收
    
    两大可抛出类:
        exception和error的父类是  Throwable类(可抛出的)
        Throwable的父类是Object
        异常exception:
              ***注意:编译时异常和运行时异常都是在运行阶段发生的,只有在程序运行阶段才可以new异常对象,并让控制台接收消息
            exception又分为两类:
                ExceptionSubClass:Exception的直接继承子类及其子类都被叫做编译时异常
                    编译时异常,编译阶段前预先处理该异常,如果不处理编译器报错
                    发生概率较高,可以进行预处理
                    编译时异常又叫受检异常,受控异常
                RuntimeException:所有的RuntimeException类及子类都被称为运行时异常
                    运行时异常:编译通过,运行时发生报错,视为运行时异常
                    发生概率较低,没必要预处理
                    运行时异常又叫未受检异常和未受控异常
        错误error:发生后终止程序执行,立即退出jvm,错误不可处理
    对异常的处理方式:
        第一种:在方法声明的位置上,使用throws关键字,抛给上一级
        第二种:使用try..catch语句进行对异常的捕捉
    注意:Java中如果将异常一直上抛,抛给了jvm,这是jvm退出,终止程序。    
        使用throws关键字的使用案例:
            public   void     方法名()  throws 异常类名{  }
    关于catch:
        catch支持使用多态
        catch可以写多个,建议catch的时候,精确到一个一个,这样有利于程序的调试
        注意:catch多个的时候,异常必须按照从上到下,从小到大的顺序
    关于jdk8的更新:
        从jdk8开始,catch后的参数类型允许采用“或”的形式,
        例:  catch(异常 |  异常 | 异常  e){}
    关于对于异常的处理方式(throws或try,catch):
        如果希望调用者来处理,使用throws    
        其他情况采用try  {}  catch(){}
        不建议在main方法上使用throws
    所有异常常用方法:
        返回值String       getMessage():获取异常简单的描述信息
        常用    对象.printStackTrace():打印异常追踪的堆栈信息(采用了异步线程掉的方式 ,多线程)
                在实际开发中建议多使用
                关于对异常的追踪信息:
                    括号内为灰色是sun公司人员编写,不需要看。
                    观看信息从上往下一行一行看(区分,也可以选择看 包名 来区分)
    关于finally字句:
        在finally字句中的代码是最后执行的,且一定会执行,即使try语句内出现了异常
        finally的运行权限高于return,但是要低于System.exit()(退出jvm虚拟机)
        finally不可以单独编写,必须有try语句,finally必须放在最try,catch后面(可以没有catch语句)
        finally常用场合:
            通常在finally语句块中完成资源的释放和关闭
            关于流的关闭
    关于自定义异常:
        1,编写一个类继承Exception或者RuntimeException
        2,提供两个构造方法:无参,有参
            皆可调用父类构造方法
        例:class   类名    extends    Exception{
            public  类名(){super()}
            public 类名(String  str){super(str)}    
        }
    关于方法覆盖遗漏的异常问题:
        重写后的方法不能比重写之前的方法抛出更多(更广泛)的异常,可以更少。

关于final、finally、finalize的区别:
    final是一个关键字。  常量    :最终的,不变的
    finally也是一个关键字,和try联用。使用在异常处理机制中
    finalize()是Object类中的一个方法,作为方法名出现。(遗嘱方法???)
        finalize是一个标识符 。
        由垃圾回收器gc负责调用的
        System.gc()方法:增加垃圾回收器的启动几率
在打印信息和return;的时候    
    养成手动抛异常的习惯

关于集合:(集合里面可以嵌套集合)
    注意:所有有的集合类和集合接口都在  java.util.*  包下
    注意:所有集合继承Iterable接口的含义是,所有集合都是可迭代的
    1.什么是集合?集合有什么用?
    数组就是一个集合,集合其实就是一个容器。可以容纳其他数据类型的数据
    集合是一个容器,是一个载体,可以容纳多个数据对象
    2.集合中存储什么?
    集合不能直接存储基本数据类型,也不能直接存储Java对象,集合中存储的是Java对象的内存地址,
    或者说是“引用”,集合任何时候存储的都是引用
    3.不同的集合区别。
    在Java中每一个不同的集合,底层会对应不同的数据结构。
    往不同的集合中存储元素,等于将数据放到了不同的数据结构当中。
    4.什么是数据结构?
    数据存储的结构就是数据结构。不同的数据结构,数据存储的方式不同
    常见数据结构  例如:
        数组、二叉树、链表、哈希表.....等等。
    5.本章主要是掌握如何用集合类,再什么情况下选择哪种数据结构即可。
    常用集合类:
        new   ArrayList();   //创建一个集合,底层是数组数据结构
        new   LinkedList();  //创建一个集合对象,底层是链表
        new   TreeSet();  //创建一个集合对象,底层是二叉树。
    6.集合在Java中分为两大类:
        一类是单个方式存储元素:
        单个方式存储元素,这一类集合中超级父接口是:Java.util.Collection;
        collection继承了Iterable接口:
            Iterable接口内置方法iterator:
                返回值为Iterator     对象.iterator()
                作用:返回一个迭代器对象。
        (常用)继承了collection的子接口:
            List接口:特点是有序可重复,存储的元素有下标(就是列表)
                常用的list接口的实现类:
                    ArrayList:该集合底层采用了数组的数据结构(非线程安全)(最常用)
                    LinkedList:底层采用了双向链表数据结构
                    Vector:该集合底层采用了数组的数据结构(线程安全,该集合效率较低,使用很少)
            
            Set接口:特点无序不可重复没有下标,与list相反,且set集合中没有下标,元素不可重复
                常用的Set接口实现类:
                    HashSet:实际上该集合底层new了一个HashMap集合
                    TreeSet:该集合实现了Set的子接口“SortedSet”,底层的数据结构实际上是TreeMap(自定义类型如果没有定义比较规则,放入集合后无法遍历,会出现异常)

TreeSet和TreeMap的排序的两种方式:
    第一:可排序集合必须得继承Comparable接口,并实现该接口中的方法compareTo,在其中定义比较规则,compareTo方法的返回值是数字(treemap)。(适合比较规则不会发生改变的)
    第二:另一种方法,在创建集合时传递一个比较器,比较器必须实现java.lang包下得Comparator接口,并实现里面的比较方法(适合多个比较规则切换的,可以采用匿名内部类的方式)
            

        一类是以键值对的方式存储元素:
        以键值对的方式存储元素,这一类集合中超级父接口:java.util.Map;
        Map接口:
            1.Map集合和Collection集合没有任何关系,只是同样在集合和框架当中
            2.Map集合以key和value的方式存储数据:键值对
            key和value都是引用数据类型
            key和value都是存储对象的内存地址
            key起到主导的地位,value是key的附属品
            特点:Map集合以key和value的这种键值对的方式存储元素
                       key和value都是存储java对象的内存地址
                        所有Map集合的特点都是无序,不可重复的,与Set集合存储元素的特点相同
            Map接口的实现类:
                HashMap:该集合底层是哈希表数据结构,是非线程安全的,底层是一个哈希表数据结构(扩容是原容量的2倍)
                    //HashMap的默认初始化容量是16
                    注意:放在HashMap集合key部分的,以及放在HashSet集合中的元素,需要同时重写hashCode方法和equals方法
                    (如果单向链表>8个节点时数据结构会变成红黑树(二叉树)数据结构,如果红黑树节点<6,那么会重新将红黑树转换成单向链表)
                    关于hashMap内的默认加载因子:
                        hashMap内的数组的默认加载因子是0.75
                        这表示数组在达到   75%   时进行扩容
                    注意:*** HashMap集合初始化容量必须是2的倍数,这也是官方推荐的,因为达到散列均匀,为了提高HashMap集合的存取效率,所必需的
                    hashMap的key部分可以为空(null),但是只能有一个

                                

                Hashtable:该集合底层也是哈希表数据结构,是线程安全的(不过效率较低,使用较少)
                    //Hashtable的初始化容量是11,加载因子是0.75。扩容是原容量*2+1
                    //Hashtable的key和value不支持null
                    
                    Hashtable子类Properties:继承peroperties,存储元素的时候采用键值对方式,但
                               key和value只支持“String”类型,不支持其他类型,Properties被称为“属性类”

                TreeMap:该集合实现了Map的子接口SortedMap,该集合底层是一个二叉树数据结构,
                    SortedMap接口:key的特点,无序不可重复,且集合key部分的元素会自动按照大小顺序排序,称为可排序集合
                    
                    //放到TreeSet或者TreeMap集合key部分的元素要想做到排序,包括两种方式:
                        第一种:放在集合中的元素实现java.lang.Comparable接口
                            当比较规则不会发生改变,是固定的时候,推荐使用Comparable接口
                        第二种:在构造TreeSet或者TreeMap集合的时候给它传一个比较器对象(Comparator)
                            当比较规则有多个,需要频繁切换比较规则时,建议使用比较器,实现Comparator接口
                    //按照字典顺序升序            
        Collection常用方法:
            (放在集合内的元素,尽量都要从写equals方法)
            注意:没有使用泛型之前,Collection可以存储Object的所有子类型
                       使用了泛型之后,Collection只能存储某个具体的类型
                       集合中不可以直接存储基本数据类型,也不能直接存储java对象,只是存储java对象的存储地址
            返回值boolean   add(object   e): 向集合内添加元素(注意:对象.add(数字)会用到自动装箱机制)
            返回值int   size():该方法会返回集合内部的元素个数(注意:不是获取集合的容量)
            无返回值void    clear():清空集合
            返回值boolean   contains(object   e):如果该集合内包含指定元素,则返回true(注意:底层调用了equals方法,放在集合里面的元素要重写equals方法)
            无返回值void      remove(object   e):删除集合中指定元素(底层调用了equals方法)
                例:s1和s2两个不同的对象里面都是hello,集合添加s1,remove删除s2会导致s1被删除                boolean      isEmpty():判断集合是否为空,为空则返回true
            返回值iterator     iterator():返回一个迭代器   
            返回值object【】   toArray(): 返回一个拥有该集合所有元素的数组
            boolean    addAll(coollection   e):集合合并,将指定集合内的所有元素添加到该集合当中
        Map集合中不支持iterator方法,iterator是所有collection通用的一种方式
        关于iterator对象(迭代器对象)的方法:
            (注意:集合结构只要发生改变,迭代器一定要重新获取)
            boolean     hasNext():如果仍有元素可以迭代,则返回true
            object      next():获得迭代的下一个元素
            void    remove():删除迭代器内的当前元素,同时会更新集合内的元素,集合内的元素也会删除(迭代器内的元素和集合内的元素都会删除,而集合对象.remove()不推荐在迭代时使用)
        list特有常用方法:
            void    add(int index,object  element):在指定下标位置添加元素(没有下标参数,则在列表末尾添加元素)
            object    set(int   index,object   element):修改指定下标位置的元素
            int      indexof(object   o):获取指定对象第一次出现处的索引
            int     lastindexof(object  o):获取指定对象最后一次出现处的索引
            object    remove(int   index ):删除指定下标处的元素
            object   get(int   index):根据下标来获取元素
        Arraylist的构造方法:(Arraylist是非线程安全的)
            Arraylist():关于扩容,每次扩容后的大小是未扩容前的1.5倍
                无参构造,初始化默认为零,添加第一个元素时,初始化容量是10
                           (指定容量):初始化Arraylist集合的容量
                           (cllection集合):构造一个包含指定collection的元素的列表,按照collection的迭代器返回他们的顺序排列
                //建议在创建数组时预估计一下数组元素的个数,初始化数组,减少扩容
                //扩容会影响效率
        LinkedList:采用了双向链表,LinedList集合没有初始化容量,最初什么元素都没有
        Vector:
            底层的数据结构是数组,Vector是线程同步的,是线程安全的。效率较低,使用较少。
            扩容之后是原容量的二倍
            Vector的构造方法:
                Vector():无参构造,默认初始化容量是10
        
        Map接口中常用的方法:Map<K,V>
            (注意:contains方法底层调用的是equals方法,自定义类型需要重写equals方法)
            void  clear():清空Map集合
            boolean   containsKey(object  key):查询Map集合内是否有指定元素
            boolean    containsValue(object   valu):查询Map集合中是否有指定值
            v  get(object   key):通过键来返回该建所对应的值
            Boolean   isEmpty():判断集合是否为空
            v   put(K   key,V  value):向Map集合内添加键值对
            v   remove(object  key):删除键(键删除后,所对应的值也会被删除)
            int   size():返回该集合的元素长度
            Set<k>  keySet():获取Map集合所有的key,返回一个Set集合
            Collection<v>  value():获取Map集合所有value,返回一个Collection
            Set<Map.Entry<K,V>>  entrySet():将Map集合转换成Set集合
                    (其中Map元素的key和value通过某种方式变成了Set集合中的一个元素,转换后Set单个元素呈现格式:key=value)。单个元素的数据类型是Map.Entry<K,V>,其中Map.Entry是一个类,Entry是静态内部类,Map是外部类(内部类支持泛型)。转换为set集合,set集合中的每一个元素都是一个对象,对象内包含一个key和value
                Map.Entry内的方法:
                    getKey():获取该对象的键属性
                    getValue():获取该对象的值属性

继承关系又叫“泛化关系”。
关于哈希表(散列表)结构:
    哈希表又叫散列表,是一个一维数组,这个数组中的每一个元素都是一个单向链表(有点像珠子门帘)
    所以哈希表是数组和单向链表的结合体
    数组:在查询方面效率较高,随机增删效率较低
    单向链表:在随机增删方面效率较高,查询方面效率较低
    哈希表将以上的两种数据结构融合在一起,充分发挥它们各自的优点。
    map.put(k,v)实现原理:
        1.先将k,v封装到Node对象当中
        2.底层会调用k的hashCode()方法得出hash值,然后通过哈希函数/哈希算法,将hash值转换成数组的下标,该数组下标位置上如果没有任何元素,就将Node添加到这个位置上了。如果说下标对应的位置上有链表,此时会拿着k和链表上每一个节点中的k进行equals,若果所有的equals方法返回都是false,那么这个新节点将会被添加到链表的末尾,如果其中有一个equals返回了true,那就说明该建在链表中存在,只会将该键的value进行覆盖
    v = map.get(k)的实现原理:
        1.先调用k的hashCode()方法得出哈希值,通过哈希算法转换成数组下标,通过数组下标快速定位到某个位置,如果这个位置上什么也没有,返回Null。如果这个位置上有单向链表,那么会拿着参数k和单向链表上的每一个节点中的k进行equals,如果所有equals方法返回false,那么get方法返回null,只要其中有一个节点的k和参数k  equals的时候放回true,那么此时这个节点的value就是我们要找的value,get方法最终返回这个要找的value
    重点:
        需要注意,使用哈希表是key需要频繁地使用hashCode方法和equals方法,所以这两个方法都需要重写
        注意:同一个单向链表上所有的hash相同,因为他们的数组下标是一样的。
        当同一个链表上k和k的equals方法肯定返回false,都不相等
        hashCode不可以设置一个默认值,因为这样所有的k都会是同一个下标,这样与有一个纯粹的单向链表没有区别。这种情况我们称为:散列分布不均匀。
        什么是散列分布不均匀:
            数组内每个元素(单向链表)都是一个单向链表,而当前单向链表与数组内的其他单向链表数量差异过大是,属于散列分布不均匀(这样会影响整个哈希表的效率)
        散列分布均匀需要重写hashCode()方法时有一定的技巧
        
关于链表数据结构:
    对于链表数据结构来说:基本的单元是节点Node。
    对于单向链表来说,任何一个节点Node中都有两个属性:
        第一:存储的数据
        第二:下一个节点的内存地址
        链表的空间存储上内存地址是不连续的
        优点:因为链表的空间存储上内存地址是不连续的,随机增删元素效率较高(因为增删元素不会涉及到大量元素位移)
        缺点:查询效率较低,每一次查找某个元素的时候都需要从头节点开始往下遍历(因为不能通过数学表达式计算 被查找元素的内存地址)
        Node是一个类,有两个属性,分别是数据和下一个节点(Node)的内存地址
    关于双向链表:
        双向链表的的基本单元还是节点Node
        只不过节点(Node)内有三个属性
            第一:上一个节点的内存地址
            第二:数据
            第三:下一个节点的内存地址
        源码中,创建第一个节点后,first(首节点)和last(末尾节点)都为第一节点的内存地址


关于二叉树数据结构:
    Java二叉树内拥有五个属性:
        k,v,left(左子节点),right(右子节点),父节点


    自平衡二叉树(TreeSet、TreeMap):(以第一个数字作为“根”)
        特点:遵循左小右大原则存放
    
    遍历二叉树的三种方式:(注意:前中后说的是‘根’的位置,以根的位置为标准)
        前序遍历:根左右
        中序遍历:左根右
        后序遍历:左右根

集合类之间的转换:
    通过集合的构造方法来进行转换,构造方法的参数可以传递另一个集合,来进行集合之间的转换

collection集合工具箱    :
    java.util.collections;包下的的collection集合工具箱
    排序:(集合之间支持互相包装)
        Collections.sort(list);     //注意比较对象需要实现  比较接口(Comparable)并实现比较方法    
        Collections.sort(list,比较器对象); //也可以传入比较器对象(Comparator)
        
        List<String>   list = new Array<>(set);  //(集合之间支持互相包装),将set集合转换成了ArrayList集和    
        Collections.sort(list)        
    关于如何将一个线程非安全的ArrayList集合转换成线程安全的:
        collections.synchronizedList(集合对象):将非线程安全的集合转换为线程安全的

Hashtable子类Properties的常用方法:
    setProperty(key,value):存储键对值
    getProperty(key):通过建获取对象
    load(输入流):将硬盘文件加载到properties对象上
关于泛型:(感觉起到了一个过滤的作用)
    泛型是程序编译阶段起的作用,只给编译器参考
    用泛型来指定集合中存储的数据类型,这样集合中元素的数据类型变得更加统一了,如果存储非指定元素,编译器会报错
    优点:
        第一:集合中存储的元素类型统一了
        第二:从集合中取出的元素类型示泛型指定的类型,不需要进行大量的“向下转型”!
    缺点:
        使集合存储的元素缺乏了多样性

    例:list<Animal> 变量 = new Animal<Animal>();
        list<Animal>:使用泛型之后,表示List集合中只允许存储Animal类型的数据。
    jdk8之后泛型进行了优化,右侧的Animal<>尖括号内可以不写,这是自动类型推断,又叫钻石表达式。
    
    关于自定义泛型:创建类时可以自定义泛型
        //定义了自定义泛型,却不用,将默认为Object
        例://使用时该类可以使用泛型    
            public   class   类名<标识符>{    

                public     void   方法名(标识符    参数名){
                        
                }
                public     标识符    方法名(){
                
                }
            }

关于foreach(增强for):
    //缺点:没有下标
    for(元素类型     变量名  :   数组或集合){
        语句块;
        System.out.println(变量名);
    }        

关于位运算:
    >> 数字:位运算符,二进制右移 指定位数  例,>>2,二进制右移二位,00000010变成了00000001(规律:除以2的指定位数的次方)
    << 数字:位运算符,二进制左移  指定的位数 (乘以2的指定位数的次方)


关于IO流:通过IO可以完成硬盘文件的读和写
    注意:能用记事本打开的都是文本文件
    输出流最后一定要刷新flush()
    编译软件的默认当前路径是当前模块的上一级(project)
    所有的流都在java.io包下
    (很重要)流使用完一定要关闭,不然会一直占用资源
    注意:在java中只要“类名”以Stream结尾的是字节流,以reader和writer结尾的是字符流。
    通过IO来完成对文件的读和写
    节点流和包装流:
        节点流:当一个流的构造方法中需要一个流的时候,这个被传进来的流叫做:节点流
        包装流:外部负责包装的这个流,叫做:包装流,还叫做:处理流。
            注意:对于包装流来说,只需要关闭最外部流,节点流会自动关闭
    流的分类:
        输入流,输出流
        字节流,字符流
    按照流的方向进行分类:
        以内存为参照物:
            将文件从硬盘导入内存的过程叫做“输入(input)”(输入流InputStream)
            将文件从内存写入硬盘的过程叫做“输出(Output)”(输出流OutputStream)
    还有一种方式是按照读取数据方式不同进行分类:
        按照字节的方式读取数据:
            每次读取1个字节,等同于一次读取8个二进制位这种流是万能的,包括:文本,图片,声音文件,以及视频
        按照字符的方式读取数据,一次读取一个字符,这种只是为了方便读取普通文本文件而存在,仅限于文本文件(限制颇多,但对文本文件非常友好)
    Java IO流的四大抽象类:
        Java.io.InputStream        字节输入流
        java.ioOutputStream    字节输出流
        java.io.Reader        字符输入流
        java.io.Writer        字符输出流
    都实现了Closeable接口,其中方法close()作用是--关闭流
        注意:使用完流后一定要使用close()方法关闭流,不然会一直占用内存资源

    所有输出流都实现了Flushable接口,且都有flush()方法(可刷新的),作用是--清空管道,将管道内的残存数据强行清出管道
        注意:用完输出流后一定要使用flush()方法刷新一下,以防丢失数据

    Java.io包下需要掌握的流有16个:
        文件流:
        java. io.FileInputstream
        java.io.Fileoutputstrean
        java.io.FileReader
        java.io.Filewriter
        转换流:将字节流转换成字符流
        java.io . InputStreamReader
        java .io.OutputStreanWriter
        缓冲流:
        java .io.BufferedReader
        java .io. Buffereclwriter
        java. io.BufferedInputstream
        java.io.Bufferedoutputstream
        数据流:
        java.io. DataInputstream
        java. io.Dataoutputstrean
        对象专属流:
        java.io. ObjectInputstrean
        java.io.objectoutputstrean
        标准输出流:
        java . io . Printwriter
        java.io.Printstream
    FileInputstream详解:文件字节输入流(万能流)任何类型文件都可以采用这个流来读(硬盘-->内存)
        构造方法:Fileinputstream(文件路径)(注意:路径中/可以代替\\)
        
        方法:
        read():返回值为int(读取到的是字节本身,如果读到文件末尾且无任何数据则返回-1)  读取文件的一个字节
            缺陷:一次只读取一个字节,效率较低
        read(byte[] b):返回值是int类型,是读取到的字节数量。一次读取b.length个字节,去往byte[]数组当中读取(可以读取多个字节,提升效率,如果没有读到字节则返回-1)
            参数b:byte数组需要初始化容量,注意,读的时候数组已满则从数组头部进行覆盖
            数组转换为字符串:
                new String(byte数组,0,读取到的字节数量)
        close():关闭流
        available():返回流当中剩余的没有读到的字节数量,返回值为int,
            //创建数组是可以直接new byte[对象.available()]创建于文件相同字节数的数组,只适合小文件,不适合大文件(因为byte数组不能太大)
        skip(long n):返回值是long类型,以当前读取到的字符串位置为标准,跳过n个字节不读  
    FileOutputStream详解:从内存向硬盘写入的过程
        构造方法:
            new FileOutputStream(“路径文件”):若文件不存在则新建,若有文件,写入时会对源文件进行覆盖
            new FileOutputStream(“路径文件”,true):以追加的方式写入字节
        方法:    
        write(byte[] b,0,可选参数 读取到的字节数):写入于byte数组.length等量的字节(默认将源文件覆盖掉)
        write(byte[] b):将byte数组的内容写入(默认将源文件覆盖掉)
        write():写入单个字节
        
    FileReader:与FileInputStream类大致一样,不过构造方法底层调用的是char数组(文件字符输入流,仅限普通文本文件,word文件不可以)
        方法大致一样
        //普通文本文件:可以用记事本打开正常编辑的    
    FileWriter:与FileOutputStream类相似度极高,方法也大致一样(文件字符输出流,仅限普通文本文件,word文件不行)    
        write(String  str):写入字符串    
        write(char[]   char,索引下标,字符长度):写入字符串    
        write(char[]   char):写入char数组    
    BufferedReader:缓冲输入流,带有缓冲区的字符输入流,不需要自定义“char数组”
        /**感觉有点类似包装类**/
        构造方法:
            new    BufferedReader(reader  n)   // reader  是一个流,抽象类,该构造方法可以传进去一个字符流
                                  //InputStreamReader转换流  可以将字节流转换成字符流
        方法:
            String    readLine():读取一个文本行,但是不带有换行符。返回值是一个字符串,当没有读取到字符时,返回null
            read():读取一个字节
    BufferedWriter:(缓冲输出流),带有缓冲的字符输出流
    节点流和包装流:
        节点流:当一个流的构造方法中需要一个流的时候,这个被传进来的流叫做:节点流
        包装流:外部负责包装的这个流,叫做:包装流,还叫做:处理流。
            注意:对于包装流来说,只需要关闭最外部流,节点流会自动关闭
    InputStreamReader:(转换流)可以将字节流转换成字符流,通过构造方法
        构造方法:
            new   InputStreamReader(字节流  InputStream);
    OutputStreamWriter:(转换流)可以将字节流转换成字符流,构造方法参数传递节点流
    
    DataOutputStream:(仅了解,使用较少)数据专属流,DataOutputStream写的文件只能使用DataInputStream去读,且需要知道写入的顺序
            //作用:可以将数据连同数据的类型一并写入文件。
            //注意:这个文件不是普通文本文档(记事本打不开)
        构造方法:
            DataOutputStream(outputStream   n):参数是    字节输出流(这是节点流,外面的是包装流)
        方法:
            .writeByte(byte  n):把数据以及数据的类型一并写入到文件当中
            .write数据类型(数据类型  n):写入方法含多个,与数据类型的数量相同
    DataInputStream:(仅了解)
            注意:读的顺序必须和写入的顺序一样,才可以正常取出数据
        方法:
            .read数据类型():读取数据及数据类型
    PrintStream:(标准输出流)标准的字节输出流,默认输出到控制台
        PrintStream   ps = System.out   (system.out其实是PrintStream,而println是PrintStream中的方法)
        注意:标准输出流不需要手动close()关闭
        构造方法:
            PrintStream(outputStream   n):OutputStream是一个节点流

        System.setOut(PrintStream  n):修改输出方向,将输出方向改为一个PrintStream文件
        
    ObjectInputStream:(反序列化)将硬盘中的多个java对象数据块组合起来,并重新恢复到内存中。

        构造方法:
            ObjectInputStream  (InputStream):包装流,参数是节点流
        方法:
            readObject():读取对象
        关于一次性序列化多个对象:
            将对象放入集合当中,序列化集合    

    ObjectOutputStream:(序列化)将内存中的java对象数据信息以切割多块并且有编号的形式(拆分对象)放到硬盘当中,叫做序列化。(这是一个包装流,节点流必须是OutputStream)

    **注意:可序列化对象必须实现“Serializable”接口(该接口内无方法,只是一个标志接口,起到一个标志的作用)
    注意:**********
        凡是一个类实现了Serializable接口,建议给该类提供一个固定不变的序列化版本号
        这样即使代码进行了修改,java虚拟机也能识别出这是同一个类
        关于序列化版本号手动设置:
            注意:数值随意,但请确保全球唯一性
            private   static   final  long   serialVersionUID=5313154687L;

    注意:存取多个对象时,需要用到集合,不然存到第二个对象时会报错。
    注意:如果要某一个属性不参加序列化,需要用到   transient   关键字,
                 “transient”关键字:表示游离的,不参加序列化。
            例:例 :   public  transient  String   name;//这是一个属性

        方法:
            writeobject(Object  obj):写入硬盘当中
            writeobject(arraylist集合):支持参数是Arraylist集合,序列化集合
            注意:Arraylist集合实现了Serializable接口


    关于File类:
        流的构造方法支持传递File类
        File类与流没有任何关系,所以File类不能完成文件的读和写
        File是一个文件和目录路径名的抽象表示形式
        一个File对象可能对应的是目录路径,也可能是文件
        构造方法:
            File(String  路径)
        

        方法:
            .exists():判断该文件是否存在    
            .createNewFile():以文件形式新建该文件
            .mkdir():以目录形式新建该文件
            .mkdirs():以多重目录的形式新建
            .getParent():获取该文件的父路径
            .getAbsolutePath():获取绝对路径
                .endswith(“参数”):是否以该参数结尾,返回值为boolean
            .getName():获取文件名
            .isDirectory():判断是否是个目录
            .isFile():判断是否是个文件
            .lastModified():获取文件最后一次的修改时间(返回值long,返回的是从1970年到现在的毫秒数)
            .length():获取文件大小(返回的是文件字节长度)
            .listFile():返回值是File[ ]数组,获取当前目录下的所有子文件
关于接口的两种表现方式:
    普通接口:
    标志接口:
        java虚拟机看到标志接口可能会进行特殊待遇
        例:Serializable标志接口,java虚拟机看到后,会对  对象自动生成序列版本号
关于多线程:
    扩:
        单核CPU表示只有一个大脑,不能够做到真正的多线程并发,只是在多个线程之间频繁切换
    多线程机制是为了提高程序的处理效率
    有时候栈的数量就代表了线程的多少
    主线程=主栈,分支线程=支栈
    主栈结束不代表分栈结束
    线程优先级较高的抢到的cpu时间片相对多一些(处于运行状态的时间多一些)
    注意:run()方法中的异常不能throw,只能try/catch,因为run方法在父类中并没有抛出异常,子类不能比父类抛出更多异常
    关于进程:一个应用程序(可以理解为一个软件)
        进程与进程:
            进程与进程之间是独立的,不共享资源
    关于线程:一个进程的执行场景/执行单元。
        一个进程可以启动多个线程
        线程与线程的关系:
            **********堆内存与方法区内存共享,但栈内存独立,一个线程一个栈
        多线程并发:
            如:十个线程有十个栈空间,每个栈之间,互不干扰
    实现线程的两种方式:
        #第一种方式
        编写一个类,直接继承java.lang.Thread(线程类),重写run方法
        run方法中的方法体运行在分支线程中(分支线)
        线程启动方法:
            new  一个线程对象
        *********  threadObject(线程对象).start():启动一个分支线程,在jvm开辟一个新的栈空间(任务完成之后就会结束,作用仅开辟一个新的栈空间)
            启动线程成功之后会自动调用run方法,并且run方法在分支栈的栈底部。(run和main是平级的)
            注意:如果直接调用run方法,main和run方法在同一个栈,没有开辟新的栈空间

        #第二种方式
        编写一个类,实现java.lang.Runnable接口。并实现run方法   //创建一个可运行的类
        实际上是将实现java.lang.Runnable接口的类实例化,并将其作为参数传递给
        Thread类的构造方法,在调用Thread类中的“start()”方法。
        (建议使用接口方式,在实现接口的同时,还可以继承其他类)
        //也可以采用匿名内部类的形式创建一个可运行的类
            

        #实现线程的第三种方式:(效率较低)
            #实现Callable接口
            这种方式实现的线程可以获取线程的返回值(这也是该方式的特点)
            public  Object  call(){}   //相当于run方法
            如何使用:
                第一步:需要创建一个“未来任务类对象”,FutureTask对象,构造方法参数是Callable才有返回值
                第二步:实现Callable中的call方法(call方法相当于run方法)
                第三:创建一个Thread对象,将FutureTask对象作为参数传递进去,然后启动线程
                在主线程获取线程的返回结果
                    “未来任务”对象.get():另一线程的执行结果
                    注意:get()方法可能会导致当前线程的堵塞,因为get()方法的获取结果需要等待另一个线程的结束并且返回执行结果

    线程的生命周期:
        新建,就绪,运行,堵塞,死亡
        抢夺执行权(cpu时间片)

        新建状态,刚创建的一个线程对象
        就绪状态又叫做可运行状态,表示当前线程具有抢夺CPU时间片的权利(CPU时间片就是执行权),当一个线程抢夺到CPU时间片之后,就会开始执行run方法,run方法开始执行标志着线程进入运行状态
        运行状态,当之前战友的CPU时间片用完之后,会重现回到就绪状态继续抢夺CPU时间片 ,当再次抢到CPU时间之后,会重新进入run方法接着上一次的代码继续往下执行
        阻塞状态,遇到阻塞事件(例如:用户的输入),当一个线程遇到阻塞事件,会进入到阻塞状态,阻塞状态的线程会放弃之前占有的CPU时间片
        死亡状态,run方法结束

    
    
    方法:
        线程对象.setName:设置线程名字
        线程对象.getName:获取线程名字
        Thread.currentThread():该方法获取当前执行线程对象并返回,返回值是当前线程线程对象  Thread类型,该方法是静态方法

        Thread.sleep(数值):(静态方法),让当前线程进入休眠,参数以毫秒数为单位,实际上是进入堵塞状态,放弃占有CPU时间片,让给其他线程
            注意:该方法需要抛出异常
        线程对象.interrupt():终止该线程对象的睡眠(sleep),
                在另一个线程调用,使沉睡线程苏醒
        线程对象.stop():强行结束该线程的执行(不建议使用,容易丢失数据)
    合理的终止线程的执行:
        在线程对象内放入一个boolean标记,如果为false,返回return;
        在其他线程直接修改布尔标记就可以终止线程

    关于线程线程的调度:
        常见的线程调度模型:
            抢占式调度模型:
                那个线程的优先级比较高,抢到的CPU时间片的概率就高一些/多一些
                //CPU时间片多一些就是运行状态的时间多一些
                java采用的就是抢占式调度模型
            均分式调度模型:
                平均分配CPU时间片。每个线程占有的CPU的时间片时间长度一样。

    关于线程调度的方法:都是实例方法(最低优先级1,最高是10,默认5,有优先级常量属性)
        //优先级比较高的,抢到的CPU时间片的概率就高一些/多一些,
        //CPU时间片多一些就是运行状态的时间多一些
        .getPriority():返回线程的优先级,返回值int
        .setPriority(int  newpriority):设置线程优先级(实例方法)
        .yield():让位方法(静态方法),暂停当前正在执行的线程对象,并执行其他线程,不是堵塞,只是返回就绪状态
        .join():(实例方法),合并线程,当前线程停止(阻塞),让位给该实例线程
            (实例线程合并到当前线程,当前线程受阻,实例线程执行)
            注意:不是栈的合并,而是栈之间发生了等待关系
    *****关于多线程并发环境下,数据的安全问题:
        安全问题发生的三个条件:
            一:多线程并发
            二:有共享数据
            三:共享数据有修改的行为
            (只有满足以上三个条件之后,才会存在线程安全问题)

        解决线程安全问题:
            线程排队执行(不能并发)
            线程同步机制:用排队执行解决线程安全问题
            (线程同步就是线程排队,这样会牺牲一部分效率)
    线程同步机制的语法:(在不得已的情况下再使用线程同步机制)
        解释:线程t1和线程t2,在线程t1执行的时候,必须等待t1线程执行结束,或者说在t2执行的时候,必须等待t1线程执行。
        //这门拦截的是共享数据(共享对象??)
        //有点像  将门变窄了,只能通过一个人(线程),其他人(线程)只能在后面排队
        synchronized(线程共享对象){
            线程同步代码块;
            //()填入需要排队的共享对象
            //示例:t1线程,t2线程需要同步,所以填入t1和t2的共享对象(共享对象:多个线程都拥有的对象,共享数据)        
        }


    
java中有三大变量:
    实例变量:在堆中
    静态变量:在方法区中
    局部变量:在栈中
    局部变量和常量不会出现线程安全问题,因为局部变量不共享(一个线程一个栈),局部变量在栈中
    线程之间  堆和方法区都是共享的    ,所以实例变量和静态变量可能存在线程安全问题
synchronized关键字的用法:

    //每个Java对象都有一把锁(标记),当对象锁被一个线程所占有,另一个线程是无法再次占有,当当前线程的同步代码块结束,这把锁才会被释放
    //线程进入锁池寻找共享对象的对象锁,会释放之前占有的CPU时间片,没找到在锁池等待,找到了会进入就绪状态继续抢夺CPU时间片

    注意:synchronzied最好不要嵌套使用,容易造成死锁现象()
    一:偏灵活
        synchronized(线程共享对象){
            线程同步代码块;
            //()填入需要排队的共享对象,不可以为“null”
            //示例:t1线程,t2线程需要同步,所以填入t1和t2的共享对象(共享对象:多个线程都拥有的对象,共享数据)        
        }
    二:在实例方法中使用(缺点:共享对象固定为this,且整个方法都会同步,影响效率)
        例: 
            public   synchronized  void  方法名(参数)
            {
                代码块是整个方法体
            }
        //当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。
    三:类锁(保证静态变量的安全,静态的且synchronized的方法也是类锁)
        在静态方法上使用Synchronized,表示找类锁    

    如何设置守护线程:
        线程对象.setDaemon(true):将该线程设置为守护线程

线程部分-关于Object中的wait和notify方法:(生产者和消费者)
    注意:以上两种方法不是线程对象的方法,是Java对象都有的方法
    调用方法时,是通过Java对象调用的
    注意:*****wait方法和notify方法建立在synchronized线程同步的基础之上
    wait():
        Object  o=new Object()
        o.wait();
        表示(作用):让正在o对象上活动的线程进入等待状态,无期限等待,知道被唤醒为止。
            *****调用方法后,会让“当前线程”(正在o对象上活动的线程)进入等待状态
                    直到最终调用o.notify方法()
            *****进入等待状态是,会释放之前占有的o对象的锁
        o.notify():
            将正在进行o对象等待的线程唤醒(该方法不会释放o对象的锁)
        o.notifyAll():
            唤醒o对象上处于等待的所有线程        
    扩:
        生产者和消费者模式
            一个线程负责生产,一个线程负责消费,最终达到生产和消费的均衡
关于线程分类:
    线程分为“用户线程”和“守护线程”
    用户线程:平时常用的,例:main方法,
    守护线程:在后台默默运行的线程(后台线程),例如Java中的垃圾回收机制    
    守护线程的特点:
        一般守护线程是一个死循环,所有的用户线程只要结束,守护线程自动结束
        即使是死循环,也会随着用户线程的结束而结束
        如何设置守护线程:
            线程对象.setDaemon(true):将该线程设置为守护线程
关于死锁:
      线程死锁是只两个或多个线程互相持有对方所需要的资源,导致这些线程处于等待状态,互相等待对方释放资源,如果线程都不主动释放锁占有资源,将会导致死锁。

如何使用其他方法来解决线程安全问题:
    //用户吞吐量就是并发量
    1.尽量使用局部变量代替“实力变量和静态变量”
    2.如果必须是实例变量,那么可以考虑创建多个对象,这样实例变量的内存就不共享了(对象不共享,没有数据安全问题)    
    3.使用synchronized关键字
关于常用的线程调度模型(仅了解):
    抢占式调度模型:
        那个线程的优先级比较高,抢到的cpu时间片长的概率就高一些/多一些
        java采用的就是抢占式调度模型
    均分式调度模型:
        平均分配cpu时间片。每个线程占有的cpu时间长度一样。
        有一些编程语言,线程调度模型是采用的这种方式
关于线程同步和异步编程模型(仅了解):
    异步编程模型(并发):
        线程t1和线程t2,各自执行各自的,t1不管t2,t2不管t1
        谁也不需要等谁,其实就是:多线程并发。
    同步编程模型(排队):
        线程t1和线程t2,在线程t1执行的时候,必须等待t1线程执行结束,或者说在t2执行的时候,必须等待t1线程执行。
关于定时器:(可以将定时器当做一个线程)
    java类库中的Java.util.Timer
    定时器的作用:间隔特定的时间,执行特定的程序
    构造方法:
        无参构造
        Tiemr():创建一个定时器
        Tiemr(String  name):可以给定时器设置一个名字
        Timer(true):以守护线程的方式出现
        Timer(true,String  name):以守护线程的方式出现,并设置一个名字
        
    方法:
        schedule(TimerTask  任务,Date   第一次执行的时间,Long  间隔的时间):安排指定的任务在指定的时间开始进行重复的,固定延迟执行
            //TimerTask实现了Runnable接口,算是一个线程,TimerTask是一个抽象类

    
关于Java中的反射机制:(Class对象相当于“数据类型”)(SSM框架底层运用到了反射机制)
    作用:通过Java中的字节码可以操作字节码文件(可以读和修改字节码文件,也就是class文件)
    //可以让程序变得更加灵活
    反射机制的相关类所在位置:
        Java.lang.reflect.*;
    反射机制相关类有哪些:
        java.lang.Class;//代表字节码文件,代表一个类型,代表整个类
        Java.lang.reflect.Method;//代表字节码中的方法字节码,代表类中的方法
        Java.lang.reflect.Constructor;//代表字节码中的构造方法字节码,代表类中的构造方法
        Java.lang.reflect.Field;//代表字节码中的属性字节码,代表类中的成员变量(静态变量和实例变量)
    获取Class的三种方式:需要先获取到Class文件实例
        (第一种方式)
        static forName(String className):返回一个与字符串名的类或者接口相关联的Class对象
            (这个方法的执行会导致类加载,而类加载会执行该类的静态代码块)
                //类加载:将class文件加载到方法区
                classname:需要一个完整类名,完整类名必须带有包名。(java.lang包也不能省略)
            示例:
                Class c1=Class.forName(“java.lang.String”)
                //现在c1代表String文件(代表String.class文件,字节码文件)
        (第二种方式)
        Object中有一个方法(所有对象都有):该方法属于反射机制获取Class的第二种方式
            .getClass():返回一个Class,作用:返回该对象类型所代表的的字节码文件(.class)内存地址
        (第三种方式)
        任何类型(包括基本数据类型)都有.class属性,返回的是其字节码文件地址
            示例:
                Class  c1=String.class        //c1指向“java.lang.String”class文件
    Class类方法:
        static forName(String className):返回一个与字符串名的类或者接口相关联的Class对象
            示例:
                Class c1=Class.forName(“java.lang.String”)
                //现在c1代表String文件(代表String.class文件,字节码文件)
        .newInstance():(实例方法)通过Class文件创建对象实例(该方法内部调用了无参构造,该类型必须有无参构造方法)
        .getName():返回值String类型,返回该Class对象的完整类名(带有包名)
        .getSimpleName():返回值String类型,返回该Class对象的简类名(不带有包名)
        
    
        .getFields():(实例方法)返回值是Fields数组,获取类中所有public修饰的属性
        .getDeclaredFields():(实例方法)返回值是Fields数组,获取类中所有的属性
        .getDeclareField(String  name):(实例方法)返回值是Field,参数是属性的名字,通过属性名获取指定属性
        .getDeclaredMethods():(实例方法)返回一个Method数组,获取所有的方法        
        .getDeclaredConstructors():(实例方法)返回一个Constructor数组,获取该类所有的构造方法
        .getDeclaredConstructor(Class... parameter【int.class等等】):(实例方法),返回一个指定的构造方法对象Constructor
        .getSuperclass():返回值是一个Class对象,获取当前对象的父类
        .getInterfaces():返回值是一个Class数组,获取当前对象的所有接口
        
        .isAnnotationPresent(Class  注解名.class):判断该类上面是否有该注解
        .getAnnotation(Class   注解名.class):获取该类上的指定注解

    Field方法(属性):
        .getName():(实例方法)获取该属性对象的名字
        .getType():(实例方法)返回一个Class对象,返回该属性所对应的类型 
        .getModifiers():(实例方法)返回一个int类型,获取该属性所对应的修饰符列表(public...)
            Modifier.toString(int  mod):(Modifier静态方法)将所对应的数字转换为修饰符,返回值是String
            //可与Field的实例方法.getModifiers()联合使用

        .set(指定对象,值):(实例方法)给指定对象 赋该实例属性的属性值
        .get(指定对象):(实例方法)获取指定对象 该实例属性的属性值            
        .getAccessibleField(true):打破封装,设置为true后,可以通过方法直接访问或者设置私有属性
            //如果没有打破封装,私有属性是无法进行设置或访问的

    Method方法(方法):
        .getName():(实例方法)返回值是String,获取该方法的方法名
        .getReturnType():(实例方法)返回值是Class,获取该方法的返回值数据类型
        .getModifiers():(实例方法)返回值是int,获取修饰符列表
            可以与Modifier.toString()方法连用
        .getParameterTypes():(实例方法)返回值是一个Class数组,获取所有的参数类型
        .getParameterType(String   name,Class...  parameter):返回值是一个Method对象,获取指定方法
            //第一参数,要获取方法的方法名
            //第二参数,要获取方法的参数列表,采用了可变长度参数,参数之间用逗号隔开,类型是Class

        .invoe(指定对象,实参...):通过反射机制,指定对象调用方法
    Constructor方法(构造方法):
        .getModifiers():(实例方法)返回一个int类型,获取该属性所对应的修饰符列表(public...)
            Modifier.toString(int  mod):(Modifier静态方法)将所对应的数字转换为修饰符,返回值是String
            //可与Field的实例方法.getModifiers()联合使用
        getParameterTypes():(实例方法)返回值是一个Class数组,获取所有的参数类型
        .newInstance(构造方法实参):根据构造方法创建一个对象
        
    反射机制的灵活性:反射机制与属性配置文件搭配使用
        Java代码写一遍,在不需要改变原代码的基础上,通过改变属性配置文件的内容可以完成不同对象的实例化
        
关于“可变长度参数”:
    //注意1:可变长度参数要求的参数个数是:0~N个
    //注意2:可变长度参数必须在参数列表的最后一个,且只能有一个
    //注意3:可变长度参数可以当做一个数组看待,有下标,有length属性,也可以直接传递一个数组

    语法:类型...      //注意:一定是3个点
    示例:
        public    static  void  m(int...  args){语句块;}  

关于注解(annotation):注解在程序中等同于一种标记,程序的注释
    注解是一种引用数据类型,编译之后也会生成.class文件
    注解语法:
        【修饰符列表】 @interface  注解类型名{

        }
    注解使用时的语法格式:
        @注解类型名
        //注意:注解可以出现在类上、属性上、方法上、变量上、参数列表上....(注解可以出现在任意位置)
        //注解还可以出现在注解类型上
    注解中定义属性:
        //属性可以使用default指定默认值
        //注意:如果一个注解当中有属性,那么必须给属性赋值,除非该属性使用default指定了默认值
        //注意:如果属性名是“value”,并且只有一个属性的时候,使用注解时,该属性名可以省略
        //*****注解中属性的类型可以是(八大基本类型,String ,Class,枚举类型 ),支持数组
        【修饰符列表】 @interface  注解类型名{
            类型   属性名();
        }
        例:public    @interface   test{
            String  name();
            String  color();
            int    age  default  25();//为age设置默认值25,使用时可以忽略age属性
            String[]   email();//使用了数组,在使用注解时,该属性值需要在大括号{}内
                    //数组当中如果只有一个元素,大括号是可以省略的
        }
        使用时:    
            @test(name=“zhangsan”,color=“blue”,email={“aaa”,“bbb”});
    JDK内置注解:    
        java.lang包下
        Deprecated 用@Deprecated注释的程序元素,

        @Override:意思是重写父类的方法
            //只能注解方法,且只是给编译器参考,跟运行阶段没有关系
            //带有该注解,编译器会自动检查

        @Deprecated:表示“已过时”
            (since:9)//自JDK9之后已过时
    元注解:
        用来标注“注解类型”的注解,叫做元注解
        
        常用的元注解:
            @Target:用来标注“被注解的注解”可以出现在哪些位置上
                例:@Target(ElementType.METHOD)//表示“被标注的注解”只能出现在方法上
                @Rarget(value={CONSTRUCTOR,FIELD,LOCAL,VARIABLE,METHOD,PACKAGE,MODULE...})
                    //表示该注解可以出现在:
                        构造方法上
                        字段上
                        局部变量上
                        方法上
                        ...
                        类上...
            @Retention:用来标注“被注解的注解”最终保存到哪里
                @Retention(RetentionPolicy.SOURCE)//表示该注解只被保存在java源文件中
                @Retention(RetentionPolicy.CLASS)//表示该注解被保存在Class文件中
                @Retention(RetentionPolicy.RUNTIME)//表示该注解被保存在Class文件中,并且可以被反射机制所读取
            
        通过反射机制获取注解:注意@Retention注解属性需要设置为RUNTIME,才可以被反射机制读取到
            注解对象的方法:
                .value():获取该类上注解中的属性
OCP开闭原则:
    对扩展开发,对修改关闭
关于路径的通用型:(*****支持跨操作系统,适合各操作系统,各个环境)
    前提是在 ‘类路径’下
    什么是“类路径”:在src下的都是类路径(src是类的根路径),但是因为jvm调用的是.class文件,严格意义上来说类路径其实是所有java文件运行之后生成的一个拥有.class文件的目录
    *****必须在类的根路径下src
    Thread.currentThread().getContextClassLoader().getResource(“从类的根路径下作为起点/文件名.后缀”).getPath()
    以上方法获取 “该文件的绝对路径”
    Thread.currentThread():返回当前线程对象
    getContextClassLoader():线程对象的方法,获取当前线程的类加载器对象
    getResource(“从类的根路径下作为起点/文件名.后缀”):类加载器的方法,当前线程的类加载器默认从“类的根路径下”加载资源
    getPath():获取路径(获得的是绝对路径)
    
    Thread.currentThread().getContextClassLoader().getResourceAsStream(“从类的根路径下作为起点/文件名.后缀”)
    //返回值是一个流,直接以流的形式返回

关于资源绑定器:
    //便于获取从“类路径(src)”下作为起点获取.properties文件(属性配置文件)
    //注意:只能获取属性配置文件(properties)
    //在写路径的时候  文件的扩展名不用写
    例:ResourceBundle bundle = ResourceBundle.getBundle("test");
    .getBundle(“文件名”):静态方法,参数不可以加文件扩展名,返回一个ResourceBundle对象
    .getString(“keyName”):实例方法,参数为属性配置文件key名,返回一个String对象
    
关于类加载器:
    专门负责加载类的命令/工具(ClassLoader)
    JDK自带的三个类加载器:    
        启动类加载器(父加载器):专门加载jdk/jre/lib/rt.jar(rt.jar中都是JDK最核心的类库)
        扩展类加载器(母加载器):专门加载jdk/jre/lib/ext/*.jar
        应用类加载器:专门加载classpath中的类
    //代码开始执行之前,会将所需类加载到JVM中,通过类加载器加载
    //首先通过“启动类加载器”,如果找不到会通过“扩展类加载器”加载,再次未找到,最后通过“应用类加载器”加载
        
    java中为了保证类加载的安全,使用了双亲委派机制
    关于双亲委派机制:
        优先从启动类加载器(父)中加载,“父”无法加载到,再从扩展类加载器(母)中加载。双亲委派,如果都加载不到,才会考虑从应用类加载器中加载,直到加载到为止。
关于静态代码块:
    在类的成员位置,用static{} 只有在类加载的时候,才会执行,且只执行一次,且由于是在类加载时才会执行,所以甚至先于main方法前执行
    static{

    }
    如果只执行一个类的静态代码块,其他代码一律不执行,可以使用:
        Class.forName(“完整类名”)
Java中三大变量:
    实例变量:在堆中
    静态变量:在方法区中
    局部变量:在栈中
    (因为线程安全问题的特点是共享数据,而局部变量也就是栈并不共享,所以局部变量不存在线程安全问题)

java根源规则(很重要):
    方法体内的代码必须自上而下
    return语句一旦执行,方法必须结束
关于反编译工具(重要):很有可能会用到
    将class文件反向编译为Java文件,找不到bug时,可以尝试使用反编译工具尝试一下
番外:UML
    UML是一种统一建模语言,一种图标式语言。应用于面向对象的语言
    常用人员:软件架构师或者系统分析师,软件设计人员。
    作用:可以描述类与类之间的关系,程序的执行流程,对象的状态等
    UML软件工具
IDEA快捷键:
    ctrl+alt+l  :代码格式化
    alt+left(right):前往左右编辑页
    ctrl+d:向下复制一行
    ctrl+shift+z:反撤销
    alt+F12:查看类的结构
    shift+F6:修改变量名或方法名
    alt+insert:生成构造器
    ctrl+  “+”(“-”):展开或折叠当前方法
    ctrl+  shift+“+”(“-”):展开或折叠全部方法
    ctrl+alt+F12:打开代码所在硬盘文件夹
    ctrl+f:查看当前
    ctrl+r:查找/替换
    ctrl+h:查看类的继承结构
    shift+shift:查找文件
    alt+shift+insert:选中指定区域进行操作(批量编辑)
    alt+回车键:纠错
IDEA内置模板:
    soutv:生成打印语句并输出变量
    fori:生成for循环
    iter:增强for循环
    list.for:生成集合list的for循环
    psfs:public  static  final  String

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值