java学习笔记

java学习

Java的基础知识

Java的三大版本

  • JavaSE(java标准版)
  • javaEE(java企业版)
  • javaME(java微型版)
  • 其中javaSE是基础,以后主攻方向是javaEE方向

java的语言特性【开源,免费、纯面向对象、跨平台】

  • 简单性

    • 相对而言的,例如java中不再支持多继承,c++是支持多继承的,多继承比较复杂
    • c++中有指针,java中屏蔽了指针的概念,所以相比较而言,java是简单的。
    • java语言底层是c++实现的,不是C语言。
  • 面向对象

    • java是纯面向对象的。更符合人的思维模式。更容易理解。
  • 可移植性

    • java程序可以做到一次编译,到处运行也就是说java程序可以在Windows操作系统上运行,不做任何修改,同样的java程序可以直接放到Linux操作系统上运行。这个被称为是java程序的可移植性,或者说叫做跨平台。

      • Windows操作系统内核和Linux操作系统的内核是不同的,这两个操作系统执行指令的方式也是不一样的。结论:显然java程序不能直接和操作系统打交道,因为java程序只有一份,操作系统执行原理都不同。

      • 解决方式:sun团队让java程序运行在一台虚拟的计算机当中,这个虚拟的计算机叫做java虚拟机,简称JVM。java虚拟机再和底层的操作系统打交道。

  • 多线程

    • 更加支持企业级别的开发,多人开发。
  • 健壮性

    • 和自动垃圾回收机制有关,自动垃圾回收机制简称GC机制
    • java语言运行过程中产生的垃圾是自动回收的,不需要程序员关心。
  • 安全性

dos操作

  • 打开DOS命令窗口

    • 开始菜单—》运行----》输入cmd-----》回车【默认打开的是黑色的命令窗口,这就是命令窗
  • 常见的DOS命令操作

    • exit

      • 退出当前DOS命令窗口
    • cls

      • 清屏
    • 复制

      • 在DOS窗口任意位置,点击鼠标右键,然后选择标记。接下来选中要复制的内容,在DOS窗口的任意位置点击鼠标右键,此时被复制的内容已经被复制到剪切板了。在需要粘贴的位置粘贴既可。
    • dir

      • 列出当前目录下所有的子文件/子目录
    • cd命令 change directory【改变目录】

      • 绝对路径:表示该路径从某个磁盘的盘符下作为出发点的路径
      • 相对路径:表示该路径重当前所在的路径下作为出发点的路径
    • cd…

      • 回到上级目录
    • cd\

      • 直接回到根目录
    • 怎么切换盘符

      • c: 回车
      • d:回车
      • e:回车
      • f:回车

java的加载与运行

  • 编译

    • 编译阶段主要的任务是检查java源程序是否符合java语法

      • 符合java语法则能生成正常的字节码文件(xxx.class)

        • 一个java源文件可以编译生成多个.class文件。
      • 不符合java语法的则无法生成字节码文件

    • 编译阶段的过程

      • 程序员需要在硬盘的某个位置(位置随意)新建一个.java拓展名的文件,该文件被称为java源文件,源文件当中编写的java源代码/源程序。而这个源程序不能随意编写,必须符合java语法规则<java语法规则需要掌握>。

      • java程序员需要使用JDK当中自带的javac.exe命令进行java程序的编译。

        • javac是什么

          • javac是一个java编译器工具
        • javac在哪用:

          • 在DOS命令窗口中使用。
        • javac怎么使用:

          • 使用规则:javac java源文件的路径
    • 编译结束以后

      • 可以将class文件拷贝到其他操作系统当中运行【跨平台】
    • 字节码

      • 字节码文件不是纯粹的二进制,这种文件无法在操作系统当中直接执行。
      • 字节码文件/class文件是最终要执行的文件,所以说class文件生成以后,java源文件删除并不会影响java程序的执行。(一般情况下,不要删除,因为class文件最终执行效果可能不是我们想要的,那么这个时候需要回头再重新修改这个java源文件,然后将java源文件重新编译生成新的class文件,然后再重新运行这个class程序,生成新的效果。)
    • javac命令怎么用

      • java java源文件路径
      • 注意:路径包括相对路径和绝对路径,都可以。
  • 运行

    • JDK安装之后,除了自带一个javac.exe之外,还有另一个工具/命令,叫做java.exe。java.exe命令主要负责运行阶段。

      • java.exe

        • java.exe在哪用

          • 在DOS窗口中使用
        • 怎么用

          • java.exe命令会启动JVM

            • java 类名:

              • java A

                • 例如:硬盘上有一个A.class,那么那就这样用:java A
                • 硬盘上有一个B.class,那么那就这样用:java B
                • 硬盘上有一个C.class,那么那就这样用:java C
                • 千万注意:不要写成java A.class【这种方式是错误的】
          • JVM启动之后会启动类加载器ClassLoader

          • ClassLoader会在硬盘的某个位置搜索HelloWorld.class字节码文件

            • 找到该文件就立即执行
            • 找不到该文件则报错
    • 运行阶段过程

      • 打开DOS命令窗口
      • 输入java A
      • java.exe命令会启动java虚拟机(JVM),JVM会启动类加载器ClassLoader
      • ClassLoader会去硬盘上搜索A.class文件
      • JVM将A.class字节码文件解释成二进制10101010这样的数据。
      • 然后操作系统执行二进制和底层硬件平台进行交互。
    • java.exe的使用方式:

      • 首先你需要先将DOS窗口中的目录切换到HelloWorld.class文件所在目录

        • 切换方式:在目录地址直接输入cmd
      • 然后直接执行:java HelloWorld

        • java 类名
        • 硬盘上有HelloWorld.class,那么类名就是HelloWorld
        • java HelloWorld 一定要注意:java命令后面跟的不是文件路径,是一个类的名字。
  • 图解

java配置中的一些包

  • JDK

    • JDK是Java语言的软件开发工具包,主要用于移动设备,嵌入式设备上的java应用程序。JDK是整个Java开发的核心,它包含了JAVA的运行环境(JVM + Java系统类库)和JAVA工具。

      • 可以有单独的软件去安装
  • JRE

    • Java运行环境(Java Runtime Environment,简称JRE)是一个软件,由太阳微系统所研发,JRE可以让计算机系统运行Java应用程序(Java Application)。JRE的内部有一个Java虚拟机(Java Virtual Machine,JVM)以及一些标准的类别函数库(Class Library)。

      • 可以有单独的软件去安装
  • JVM

    • JVM是虚拟机的英文简称。它是java运行环境的一部分,是一个虚构出来的计算机,它是通过在实际的计算机上仿真模拟各种计算机功能来实现的。

      • java(虚拟机)主要包括三块内存空间,分别是:

        • 方法区内存
        • 堆内存
        • 栈内存
      • 堆内存和方法区内存各有一个,一个线程一个栈内存

      • 方法调用的时候,该方法所需要的内存空间在栈内存中分配,成为压栈,方法执行结束之后,该方法所属的空间释放,成为弹栈。

      • 栈中主要存储的是方法体当中的局部变量。

      • 方法的代码片段以及整个代码片段都被存储到方法区内存当中,在类加载的时候,这些代码片段会载入。

      • 在程序执行过程中使用new运算符创建的java对象,存储在栈内存当中,对象内部有实例变量,所以实例变量存储在堆内存当中。

      • 变量分类:

        • 局部变量【方法体中声明】

        • 成员变量【方法体外声明】

          • 实例变量【前面修饰符没有static】

          • 静态变量【前面修饰符有static】

            • 存储在方法区内存当中
      • 三块内存当中变化最频繁的是栈内存,最先有数据的是方法区内存,垃圾回收器主义针对的是堆内存。

      • 垃圾回收器【自动垃圾回收机制,GC机制】什么时候会考虑将某个java对象的内存回收呢?

        • 当堆内存当中的java对象成为垃圾数据的时候,会被垃圾回收器回收。

        • 什么时候堆内存中的java对象会变成垃圾呢?

          • 没有更多的引用指向它的时候。
          • 这个对象无法访问,因为访问对象只能通过引用的方式访问。
  • JDK目录解释

    • JDK/bin;该目录下存放了很多命令,例如javac.exe和java.exe

      • javac.exe

        • 负责编译
      • java.exe

        • 负责运行

配置环境变量

  • 如何解决javac不可用的问题

    • 打开DOS命令窗口,直接输入javac,然后回车,出现以下:

      • ‘javac’不是内部或外部命令,也不是可运行的程序或批处理文件

      • 出现以上的问题是因为:

        • Windows操作系统无法找到javac命令文件
    • Windows操作系统是如何搜索硬盘上的某个命令的

      • 首先从当前目录下去搜索
      • 当前目录搜索不到的话,会从环境变量path指定的路径当中搜索某个命令
      • 如果都搜索不到,则报以上的错误
  • 配置环境变量path

    • 注意:path环境变量和java语言没有关系,path环境变量是属于Windows操作系统的一个知识点。

    • path环境变量是专门给Windows操作系统指路的。

    • javac要想能随意使用,需要将javac所在的目录配置到环境变量path当中;

      • path=xxx;C:\java\jdk1.8.0_131\bin
  • Classpath环境变量

    • Classpath环境变量属于java语言中的环境变量,不属于Windows操作系统【PATH环境变量属于操作系统】

    • Classpath是给Classloader类加载器指路的。

      • 当Classpath环境变量没有配置的话,类加载器默认从当前路径下去找字节码文件。
      • 当Classpath环境变量配置为某个指定的路径之后,类加载器只去指定的路径当中价值字节码文件。

java的一些基本了解

  • 注释

    • 什么是注释

      • 出现在java的源程序当中,对java源代码的解释说明
      • 注释不会被编译到.class字节码文件当中
    • 注释的作用

      • “注释可以帮助其他人阅读程序,通常用于概括算法、确认变量的用途或者阐明难以理解的代码段。注释并不会增加可执行程序的大小,编译器会忽略所有注释。”
      • 应该多编写注释,这样程序的可读性比较强。
    • 注释怎么写

      • 单行注释

        • // 单行注释 只注释当前行
      • 多行注释

      • javadoc注释

        • 这种注释是比较专业的注释,可以利用javadoc.exe工具解析提取并生成帮助文档。
  • 程序入口

  • public class 和 class 的区别

    • 一个java源文件当中可以定义多个class

    • 一个java源文件当中public的class不是必须的

    • 一个class会定义生成一个xxx.class字节码文件

    • 一个java源文件当中定义公开的类的话,public的class只能有一个,并且该类名称必须和java源文件名称一致。

    • 每一个class当中都可以编写main方法,都可以设定程序的入口。例:想执行B.class中的main方法: java B

      • 注意:当在命令窗口中执行java Hello,那么要求Hello.class当中必须有主方法。没有主方法会出现运行阶段的错误:

关于java的集成开发环境【集成开发环境简称:IDE]

  • 什么是集成开发环境?

    • 集成开发集成环境讲究一站式开发,使用这个工具既可,有提示功能,有自动纠错功能。

    • 集成开发环境可以让软件开发变的更简单,更高效。

    • 没有IDE工具:

      • 需要安装JDK,需要配置环境变量,需要手动的将java源文件编译生成class字节码文件。
      • java源程序出错之后还没有提示。
      • 没有自动提示功能等。
    • 有IDE工具:

      • 不需要独立安装JDK【IDE中已经集成】
      • 不需要手动配置环境变量
      • 不需要使用javac命令对java源文件进行编译。
      • 并且java源文件编写语法错误马上有提示。
      • 使用IDE工具有很多代码不需要写,自动生成了。
  • 有哪些IDE

    • eclipse(myeclipse)【最多】
    • Intellij IDEA
    • NetBeans
    • JBuilder
  • 讲解myeclipse的使用:

    • workspace:工作区

        • 当myeclipse打开的时候,大多数都是会提示选择工作区
      • 这个工作区可以是已存在的工作区,也可以是新建的工作区
      • 选择工作区之后,将来编写的java代码,自动编译的class文件都会在工作区中找到
      • myeclipse可以开启两个甚至更多的会话,每一个会话对应不同的workspace
    • 在workspace工作区当中有一个文件夹:.metadata

      • 在该文件夹当中存储了当前myeclipse的工作状态

      • 将.metadata文件夹删除之后,下一次再次进入这个工作区的时候,是一个全新的开始。
        但是会发现这个IDE工具当中所有的项目丢失了,没关系,这里只是丢失的myeclipse的项目,
        硬盘上真实存储的项目不会丢失。

      • 子主题 3

package和import

  • 关于java语言中包的机制:

    • 包又被称为package,java中引入package这种语法机制主要是为了方便程序的管理。不同功能的类又被分门别类放到不同的软件包当中,查找比较方便,管理比较方便,易维护。

    • 怎么定义packag呢?

      • 在java源程序的第一行上编写package语句。

      • package只能编写一个语句。

      • 语法结构:

      • 包名的命名规范:

        • 公司域名倒序 + 项目名oa + 模块名 + 功能名;
        • 采用这种方式重名的几率较低,因为公司域名具有全球唯一性。
        • 包名要求全部小写,包名也是标识符,必须遵守标识符的命名规则。
        • 一个包对应的是一个目录。
    • 编译和运行:

      • 带有包名怎么编译

        • javac -d . xxx.java
      • 怎么运行

        • java 完整类名
    • 补充:以后说类名的时候,如果带着包名描述,表示完整类名。
      如果没有带包,描述的话,表示简类名。
      java.util.Scanner 完整类名。
      Scanner 简类名

  • import

    • import语句用来完成导入其他类,同一个包下的类不需要导入。【不在同一个包下需要手动导入】

    • java.lang.*;不需要手动导入,系统自动引入。【lang:language语言包,是java语言的核心类,不需要手动导入】

    • import语法格式:

    • 什么时候需要import:

      • 不是java.lang包下,并且不在同一个包下的时候,需要使用import进行引入。
    • 导入类的快捷键:Ctrl + shift + O

java编程语言基础

标识符

  • 什么是标识符

    • 在java源程序当中凡是程序员有权自己命名的单词都是标识符

    • 标识符在编辑器当中以黑色字体高亮显示

    • 标识符可以标识什么元素

      • 类名

      • 方法名

      • 变量名

      • 接口名

      • 常量名

  • 标识符的命名规则

    • 不按照规则来,编译器会报错,这是语法。
    • 一个合法的标识符只能有“数字、字母、下划线_、美元符号$"组成,不能含有其他符号。
    • 不能以数字开头
    • 严格区分大小写
    • 关键字不能当做标识符
    • 理论上无长度限制,但是一般不要太长。
  • 标识符的命名规范

    • 只是一种规范,不属于语法,不遵循规范编译器不会报错。

    • 最好见名知意

    • 遵守驼峰命名方式

      • SystemService
      • UserService
      • CustomerService
    • 类名、接口名:首字母大写,后面每个单词首字母大写。

    • 变量名、方法名:首字母小写,后面每个单词首字母大写

    • 常量名:全部大写

  • 合法和不合法的标识符

关键字

  • private 一种访问控制方式:私用模式
  • protected 一种访问控制方式:保护模式
  • public 一种访问控制方式:共用模式
  • abstract 表明类或者成员方法具有抽象属性
  • class 类
  • extends 表明一个类型是另一个类型的子类型,这里常见的类型有类和接口
  • final 用来说明最终属性,表明一个类不能派生出子类,或者成员方法不能被覆盖,或者成员域的值不能被改变
  • implements 表明一个类实现了给定的接口
  • interface 接口
  • native 用来声明一个方法是由与计算机相关的语言(如C/C++/FORTRAN语言)实现的
  • new 用来创建新实例对象
  • static 表明具有静态属性
  • strictfp 用来声明FP_strict(单精度或双精度浮点数)表达式遵循IEEE 754算术规范
  • synchronized 表明一段代码需要同步执行
  • transient 声明不用序列化的成员域
  • volatile 表明两个或者多个变量必须同步地发生变化
  • break 提前跳出一个块
  • continue 回到一个块的开始处
  • return 从成员方法中返回数据
  • do 用在do-while循环结构中
  • while 用在循环结构中
  • if 条件语句的引导词
  • else 用在条件语句中,表明当条件不成立时的分支
  • for 一种循环结构的引导词
  • instanceof 用来测试一个对象是否是指定类型的实例对象
  • switch 分支语句结构的引导词
  • case 用在switch语句之中,表示其中的一个分支
  • default 默认,例如,用在switch语句中,表明一个默认的分支
  • try 尝试一个可能抛出异常的程序块
  • catch 用在异常处理中,用来捕捉异常
  • throw 抛出一个异常
  • throws 声明在当前定义的成员方法中所有需要抛出的异常
  • import 表明要访问指定的类或包
  • package 包
  • boolean 基本数据类型之一,布尔类型
  • byte 基本数据类型之一,字节类型
  • char 基本数据类型之一,字符类型
  • double 基本数据类型之一,双精度浮点数类型
  • float 基本数据类型之一,单精度浮点数类型
  • int 基本数据类型之一,整数类型
  • long 基本数据类型之一,长整数类型
  • short 基本数据类型之一,短整数类型
  • null 空
  • true 正确
  • false 错误
  • super 表明当前对象的父类型的引用或者父类型的构造方法
  • this 指向当前实例对象的引用
  • void 声明当前成员方法没有返回值
  • goto 保留关键字,没有具体含义
  • const 保留关键字,没有具体含义

字面值

  • 字面值就是数据。

  • 字面值是java程序的组成成分之一,包括标识符和关键字他们都是java源程序的组成部分。

  • 注意:

    • java语言当中所有的字符串型字面值必须使用双引号括起来,双引号是半角。
    • java语言当中所有的字符型字面值必须使用单引号括起来,单引号是半角。

数据类型

  • 数据类型的作用:

    • 程序当中有很多数据,每一个数据都是有相关类型的,不同的数据类型占用空间大小不同。
    • 数据类型的作用是指导JVM在运行程序的时候给该数据分配多大的内存空间。
  • java中的数据类型包括两种:

    • 基本数据类型(包括四大类八小种)

      • 整数型

        • byte:(-128~127) byte变量赋值时不超范围就可以不写强制转换符

        • short:(-32768~32767)short变量赋值时不超范围就可以不写强制转换符

        • int:(-2147483648~2147483647)java语言中的“整数型字面值”被默认当初int类型来处理。

        • long:(-9223372036854775808~9223372036854775807) 要让这个“整数型字面值“被当成long类型来处理的话,需要在”整数型字面值“后面添加l/L,建议使用大写的L。

        • java语言当中整数型字面值有三种表示方式:

          • 第一种:十进制【是一种缺省的默认的方式】
          • 第二组:八进制【在编写八进制整数型字面值的时候需要以0开始】
          • 第三种:十六进制【在编写十六进制整数型字面值的时候需要以0x开始】
        • 转换机制:

          • 小容量可以自动转换成大容量,成为自动类型转换机制。比如:int->long

          • 强制类型转换:

            • 大容量转换成小容量,需要进行强制类型转换。
            • 强制类型转换需要加“强制类型转换符”
            • 加上强制类型转换符之后编译通过了,但是运行阶段可能损失精度。
            • 所以强制类型转换谨慎使用,因为损失精度之后可能损失很严重。
            • 强转原理:
          • 原码,反码,补码的基础概念和计算方法:

            • 原码:就是符号位加上真值的绝对值,即用第一位表示符号,其余位表示值,比方如果是八位二进制:

            • 反码的表示方式是:

              • 正数的反码是其本身
              • 负数的反码是在其原码的基础上,符号位不变,其余各个位取反
            • 补码的表示方式是:

              • 正数的补码就是其本身
              • 负数的反码是在其原码的基础上,符号位不变,其余各个位取反
            • 计算机在任何情况下底层表示和存储数据的时候采用了补码形式。

            • 子主题 5

      • 浮点型

        • float

        • double

        • float和double在计算机内部二进制存储的时候存储的都是近似值。

          • 在现实世界当中有一些数字是无限循环的,例如:3.33333333333
          • 计算机的资源是有限的,用有限的资源存储无限的数据只能存储近似值。
      • 布尔型

        • boolean:(true,false)在底层存储的时候boolean类型占用一个字节,因为实际存储的时候false底层是0,true底层是1。在实际开发当中,经常使用在逻辑运算和条件控制语句中。
      • 字符型

        • char:(0~65535)char变量赋值时不超范围就可以不写强制转换符

          • 一个中文占用2个字节,char类型正好是2个字节。所以java中的char类型变量可以存储一个中文字符。

          • 转义字符:\在java语言当中具有转义功能。

            • \n 换行
            • \t 制表符 就是tab键
            • \ 第一个\具有转义功能,将后面的\转义为普通的\字符。在java当中两个\代表一个普通的\字符。
            • 转义字符出现在特殊字符之前,会将特殊字符转换为普通字符。
            • \u 表示后面的一串数字是某个文字的Unicode编码。
      • 注意:short和char所表示的种类总数是一样的,只不过char可以表示更大的正整数,因为char没有负数。

      • 关于八种基本数据类型的默认值:

      • 关于基本数据类型之间的相互转换:转换规则

        • 八种基本数据类型当中除了布尔类型之外剩下的七种类型之间都可以相互转换。
        • 小容量向大容量转换,称为自动类型转换,容量从小到大排序: byte<short<int <long <float <double
          char < 注: 任何浮点类型不管占用多少个字节,都比整数型容量大。
          char和short可表示的种类数量相同,但是char可以取更大的正整数。
        • 大容量转换成小容量,叫做强制类型转换,需要加强制类型转换符,程序才能编译通过,但是在运行阶段可能会损失精度,所以谨慎使用。
        • 当整数字面值没有超过byte,short,char的取值范围,可以直接赋值给byte,short,char类型的变量。
        • byte,short,char混合运算的时候,各自先转换成int类型再做运算。
        • 多种数据类型混合运算,先转换成容量最大的那种类型再做运算。
    • 引用数据类型

      • 字符串“abc”不属于基本数据类型,属于“引用数据类型”,字符属于基本数据类型。

        • 字符串使用双引号 “abc“
        • 字符使用单引号 ‘a’
      • 接口

      • 数组

  • 字符编码

    • 起到一种转换的作用

      • 计算机只认识二进制,那么计算机是如何表示现实世界当中文字

        • 八种基本数据类型当中,byte,short,int,long,float,double,boolean这7种数据类型计算机在表示的时候比较容易,因为底层都是数字,十进制的数字和二进制之间存在一种固定的转换规则。

        • 但是八种基本数据类型当中char类型表示的是现实世界中的文字,文字和计算机二进制之间“默认”情况下是不存在任何转换关系的。

        • 为了让计算机可以表示现实世界当中的文字,我们需要进行人为的干涉,需要热负责提前制定好“文字”和“二进制”之间的对照关系,这种对照关系被称为:字符编码。

          • 计算机最初只支持英文,最先出现的字符编码是:ASCII码。
        • 后来出现了一种编码方式统一了全球所有的文字,容量较大,这种编码方式叫做:Unicode编码。Unicode编码方式有多种具体的实现(UTF-8、UTF-16、UTF-16)java语言源代码采用的是Unicode编码方式,所有“标识符”可以用中文。在实际开发中,一般使用UTF-8编码方式较多【统一编码方式】

进制转换

变量

  • 什么是变量:

    • 变量本质上说是内存中的一块空间,这块空间有“数据类型”、“有名字”、“有字面值”。
    • 变量包括三部分:数据类型,名称,字面值【数据】。
    • 变量是内存中存储数据的最基本的单元。
  • 数据类型的作用:

    • 不同的数据类型有不同的数据,不同的数据类型底层会分配不同大小的空间。
    • 数据类型是指导程序在运行阶段应该分配多大的内存空间。
  • 变量要求:变量中存储的具体的“数据”必须和变量的“数据类型”一致,当不一致的时候编译报错。

  • 声明/定义变量的语法格式:

    • 数据类型+空格+变量名
  • 变量声明之后怎么赋值:

    • 格式:

    • 其他形式:

    • 变量可以在一行上声明多个:

      • int a,b,c;
    • java中的变量必须先声明,再赋值,才能访问。

      • int i; 程序执行到这里,内存空间并没有开辟出来,变量i并没有初始化,所以没有赋值之前是无法访问的。
    • 在同一个“作用域”中,变量名不能重名,但是变量可以重新赋值。

  • 变量的作用域:

    • 变量的作用域,其实描述的就是变量的有效范围。在什么范围之内是可以被访问的,只要出了这个范围该变量就无法访问了。
    • 在不同的作用域当中,变量名是可以相同的。(相同的作用域内,变量名不可以相同)
  • 变量的分类:根据变量声明的位置来分类

    • 局部变量:在方法体当中声明的变量
    • 成员变量:在方法体外【类体之内】声明的变量
    • 变量还是遵守这个语法:必须先声明,再赋值,才能访问。成员变量没有手动赋值系统会默认赋值【局部变量不会】。

运算符

  • 算数运算符

      • 求和
      • 相减
      • 乘积
    • / 商

    • % 求余数【取模】

    • ++ 自加1

      • ++出现在变量后:先做赋值运算,再对变量中保存的值进行自加1.
      • ++出现在变量前:先做自加1运算,然后再进行赋值操作。
    • – 自减1

    • 注意:一个表达式当中有多个运算符,运算符有优先级,不确定的加小括号,优先级得到提升。

  • 关系运算符

    • 大于

    • = 大于等于

    • < 小于

    • <= 小于等于

    • == 等于

    • != 不等于

    • = 是赋值运算符
      == 是关系运算符 关系运算符的运算结果一定是布尔类型:true/false

    • 关系运算符的运算原理:

  • 逻辑运算符

    • & 逻辑与 (两边的算子都是true,结果才是true)

    • | 逻辑或(两边的算子只要有一个是true,结果就是true)

    • ! 逻辑非(取反,!false就是true,!true就是false,这是一个单目运算符)

    • ^ 逻辑异或(两边的算子只要不一样,结果就是true)

    • && 短路与

    • || 短路或

    • 逻辑运算符特点

      • 逻辑运算符要求两边的算子都是布尔类型,并且逻辑运算符最终的运算结果也是一个布尔类型。

      • 短路与和逻辑与最终的运算结果是相同的,只不过短路与存在短路现象。

      • 短路或和逻辑或最终的运算结果是相同的,只不过短路或存在短路现象。

      • 什么时候发生短路:

        • 发生短路与:第一个表达式执行结果是false,会发生短路与。
        • 发生短路或:第一个表达式执行结果是true,会发生短路与。
  • 赋值类运算符

    • 基本的赋值运算符

      • =
    • 扩展的赋值运算符

      • +=

        • 等同于:i = i + 数
        • 可以翻译为“追加/累加”
        • 强制转换,损失精度。
      • -=

        • 等同于:i = i - 数
      • *=

        • 等同于:i = i * 数
      • /=

        • 等同于:i = i / 数
      • %=

        • 等同于:i = i % 数
      • 扩展类的赋值运算符不改变运算结果类型,假设最初这个变量的类型是byte类型,无论怎么进行追加或追减,最终该变量的数据类型还是byte类型。

    • 赋值类的运算符优先级,先执行等号右边的表达式,将结果赋值给左边的变量。

  • 字符串连接运算符

    • +运算符在java语言中有两个作用:

      • 加法运算,求和

        • 当"+"运算符两边的数据都是数字的话,一定是进行加法运算。
        • 数据 + 数字----> 数字【求和】
      • 字符串的连接运算

        • 当”+“运算符两边的数据只要有一个数据是字符串,一定会进行字符串连接运算。并且,连接运算之后的结果还是一个字符串类型。
        • 数字 + ”字符串“----> “字符串” 【字符串连接】
      • 在一个表达式当中可以出现多个“+”,在没有添加小括号的前提下,遵循自左向右的顺序依次运算。

  • 三元运算符/三目运算符/条件运算符

    • 语法规则:布尔表达式 ?表达式1:表达式2

    • 三元运算符的执行原理

      • 当布尔表达式的结果是true的时候,选择表达式 1 作为整个表达式的执行结果。
      • 当布尔表达式的结果是false的时候,选择表达式 2 作为整个表达式的执行结果。

控制语句

  • 控制选择结构语句

    • if 语句 和 if esle 语句

      • 要点

        • 重点:对于java中的if语句来说,只要有一个分支执行,整个if语句全部结束。
        • 注意:以上的第二组编写方式和第四种编写方式都带有else分支,这两种方式都可以保证100%有分支执行。
        • 所有的控制语句都是可以嵌套使用的,只要合理嵌套就行。注意:嵌套使用的时候,代码格式要保证完美【该缩进的时候必须缩进,大部分情况下使用大括号包围的需要缩进】
        • if语句的分支中,只有一条java语句中,大括号可以省略不写。
    • switch

      • switch语句属于选择结构,也是分支语句。

      • switch语句的语法结构:

      • case可以合并:

      • switch语句的执行原理:

        • switch后面的小括号当中的“数据”和case后面的“数据”进行一一匹配,匹配成功的分支执行。按照自上而下的顺序依次匹配。

        • 匹配成功的分支执行,分支当中最后有“break;”语句的话,整个switch语句终止。

        • 匹配成功的分支执行,分支当中没有“break;”语句的话,直接进入下一个分支执行(不进行匹配),这种现象被称为case穿透现象。【提供break;语句可以避免穿透】

        • 所有分支都没有匹配成功,当有default的语句的话,会执行default分支当中的程序。

        • switch后面和case后面只能是int或者String类型的数据,不能是探测其他类型。

          • 当然byte,short,char也可以直接写到switch和case后面,因为他们可以进行自动类型转换。byte,short,char可以自动转换成int类型。
  • 控制循环结构语句

    • for

      • 语法结构:

      • 执行原理/过程:

        • 初始化表达式,布尔表达式,更新表达式都不是必须的!【但是两个分号是必须的。】

        • 初始化表达式最先执行,并且在整个for循环当中在那个只执行一次。

        • 布尔表达式必须是true/false,不能是其他值。

        • for的执行过程:

          • 先执行初始表达式,并且该表达式只执行一次。

          • 判断布尔表达式的结果是true还是false。

            • 布尔表达式true:

              • 执行循环体

              • 执行更新表达式

              • 判断布尔表达式的结果是true还是false。

                • 布尔表达式为true:

                  • 重复以上步骤
                • 布尔表达式为false:

                  • 循环结束
            • 布尔表达式false:

              • 循环结束
        • 死循环:Ctrl+C终止

        • i变量的作用域:

      • 嵌套

        • 循环体中可以编写其他的控制语句
        • 控制语句可以嵌套使用
        • 控制语句可以是:if、if…else、switch、for、while、do…while
        • 内层循环和外层循环的变量名不能重名。
      • 给for循环起名

    • while

      • while循环的语法结构:

      • while循环的执行原理

        • 先判断布尔表达式的结果:

          • true

            • 执行循环体

              • 判断布尔表达式的结果

                • true:重复执行以上语句
                • 循环结束
          • false

            • 循环结束
      • while循环的循环次数:

        • 0~N次
        • 注意:while循环的循环体可能执行次数为0次。
      • 死循环,不能直接写布尔值。

    • do while()

      • 语法结构

      • 执行原理

      • 执行次数

        • 1~N次【至少一次】
      • 注意事项

        • do…while循环语句最终有一个分号。
    • 在程序中总有一些需要反复的/重复的执行的代码,假设没有循环结构,那么这段需要执行的代码时需要重复编写的,代码无法得到重复使用。所以多数编程语言都是支持循环结构的,将来把需要反复执行的代码片段放到“循环体”,再联合“计数器”,共同控制这段需要反复执行的代码。

  • 改变控制语句顺序(控制循环语句)

    • break

      • break是java语言中的关键字,被翻译为“中断/折断”
      • break + ";"可以成为一个单独的完整的java语句:break;
      • break语句使用在switch语句当中,用来终止switch的语句执行。
      • break语句同样可以使用在循环语句中,用来终止循环的执行。
      • break;语句使用放在for,while,do…while循环语句当中,用来跳出循环,终止循环的执行。因为当程序循环到某个条件的时候,后续的循环没必要执行了,再执行也是消耗资源,所以可以终止循环,这样可以提高程序的执行效率。
    • continue

      • continue表示:继续/go on /下一个。
      • continue也是一个continue关键字加一个分号构成一个单独的完整的java语句,主要出现循环语句当中用来控制循环的执行。
      • continue也可以后面加控制语句名称,直接控制。
    • break和continue的区别?

      • break表示循环不执行了。
      • continue表示终止当前“本次”循环,直接进入下一次循环继续执行。

键盘接受数据

  • Scanner 变量名 = new Scanner(System.in); 数据类型 变量名1 = 变量名.next属性

    • 数据类型 新的变量名 = 变量.nestInt(); 这是int类型
    • 数据类型 新的变量名 = 变量.nest(); 这是字符类型
  • java.util.Scanner 变量名 = new java.util Scanner(System.in)

方法初步

  • 方法的基础语法:

    • 方法怎么定义,语法结构:

      • 对以上的语法结构进行解释说明:

        • 关于修饰符列表

          • 可选性,不是必须的

          • 先写出:public static

          • 方法的修饰符列表当中有”static“关键字的话,怎么调用这个方法

            • 类名.方法名(实际参数列表)
        • 什么是返回值?

          • 一个方法是可以完成某个特定功能的,这个功能结束之后大多数都是需要返回最终执行结果的,执行结果可能是一个具体存在的数据,而这个具体存在的数据就是返回值。

          • 返回值类型

            • 返回值是一个具体存在的数据,数据都是有类型的,此处需要指定的是返回值的具体类型。
            • 返回值类型:java任意一种类型都可以(byte,short,int,long,char,boolea,String,void…),包括基本数据类型和所有的引用数据类型。
          • 也可能这个方法执行结束不返回任何数据,java中规定,当一个方法执行结束之后不返回任何数据的话,返回值类型位置必须编写:void关键字。

          • 返回值是否为void

            • 返回值类型是void的时候,在方法体当中不能编写“return 值;”这样的语句。但是要注意,可以编写“return;”这样的语句。

              • “return;”语句出现在返回值为void的方法当中主要是为了用来结束当前方法。
            • 返回值类型若不是void,表示这个方法执行结束之后必须返回一个具体的数值,当方法执行结束的时候没有返回任何数据的话,编译器报错。怎么写返回值呢,代码怎么写呢?“return值;”,并且要求“值”的数据类型必须和“方法的返回值类型”一致,不然编译器报错。

              • 一个方法有返回值的时候,当我们调用了这个方法,方法返回了一个值,对于调用者来说,这个返回值可以选择接收,也可以选择不接收。一般情况下都是选择接收的。
          • 接收返回值

            • 采用变量接收
            • 变量的数据类型需要和返回值的数据类型相同,或者可以自动类型转换。
          • 深入return语句

            • 只要带有return关键字的语句执行,return语句所在的方法结束,【不是JVM结束,是return所在的方法结束】
            • 在“同一个作用域”当中,return语句下面不能编写任何代码,因为这些代码永远都执行不到,所以编译报错。
        • 方法名:

          • 只要是合法的标识符就行
          • 方法名最好见名知意
          • 方法名最好是动词
          • 方法名首字母要求小写,后面的每个单词首字母大写
        • 形式参数列表:简称形参

          • 形参是局部变量:int a;double b;float c; String s ;…
          • 形参的个数可以是:0~N个
          • 多个形参之间用“逗号”隔开
          • 形参中起决定性作用的是形参的数据类型,形参的名字就是局部变量的名字。
        • 实参:

          • 方法在调用的时候,必须给这个方法传递的真实数据被称为:实际参数,简称实参

          • 实参和形参列表必须满足:

            • 数量相同
            • 类型对应相同
        • 方法体必须由大括号括起来,方法体当中的代码有顺序,遵循自上而下的顺序依次执行,并且方法体由java语句构成,每一个java语句以“;”结尾。

  • 方法的本质:

    • 方法就是一段代码片段,并且这段代码片段可以完成某个特定的功能,并且可以被重复的使用。
    • 方法,对应的英语单词:Method
    • 方法在C语言中叫做函数/Function
  • 方法的定义

    • 方法定义在类体当中,在一个类中可以定义多个方法,方法编写的位置没有先后顺序,可以随意。
    • 方法体当中不能再定义方法
    • 方法体由java语句构成,方法体当中的代码遵循自上而下的顺序依次执行。
  • 方法的调用

    • 方法只定义不去调用时不会执行,只有在调用的时候才会执行

    • 语法规则:

      • 《方法的修饰列表当中有static》
        类名.方法名(实参列表);<这是一条java语句,表示调用某个类的某个方法,传递这样的实参>
      • 但是,有的时候“类名.”可以省略,在同一个类体中。
      • 建议一个java源文件中只定义一个class。
      • 调用的时候,先去调用的方法体中执行,此时调用的那一行java语句暂停,调用的方法体执行结束后,调用的那一行恢复活跃,继续往下执行。
    • 实例

  • 优点

    • 代码可以得到重复使用
    • 可以满足某个内容。
  • 方法在执行过程中,在JVM中的内存是如何分配的,内存是如何变化

    • 方法只定义,不调用,是不会执行的,并且在JVM中也不会给该方法分配“运行所属“的内存空间。职业在调用这个方法的时候,才会动态的给这个方法分配所属的内存空间。

    • 在JVM中内存划分上有这样三块主要的内存空间(当然除了这三块之外还有其他的内存空间)

      • 方法区内存

        • 在类加载的时候,class字节码代码被加载到该内存空间当中。
      • 堆内存(局部变量)

        • 方法代码片段在执行的时候,会给该方法分配内存空间,在栈内存中压栈。
      • 栈内存

        • 关于栈数据结构

          • 栈:stack,是一种数据结构

          • 数据结构反应的是数据结构的存储形态

          • 常见的数据结构

            • 数组
            • 队列
            • 链表
            • 二叉树
            • 哈希表/散列表
    • 方法代码片段存在哪里,方法执行的时候执行过程的内存在哪里分配?

      • 方法代码片段属于.class字节码文件的一部分,字节码文件在加载的时候,将其放到了方法区当中,所以JVM中的三块主要的内存空间中方法区内存最先有数据,存放了代码片段。

      • 代码片段虽然在方法区内存当中只有一份,但是可以被重复调用。每一次调用这个方法的时候,需要给该方法分配独立的活动场所,在栈内存中分配。【栈内存中分配方法运行的所属空间】

      • 方法在调用的瞬间,会给该方法分配内存空间,会在栈中发生压栈动作,方法执行结束之后,给该方法分配的内存空间全部释放,此时发生弹栈动作。

        • 压栈

          • 给方法分配内存
        • 弹栈

          • 释放该方法的内存空间
      • 局部变量在“方法体”中声明,局部变量阶段内存在栈中分配。

方法重载(overload)

  • 什么是方法重载?

    • 方法重载是指在一个类中定义多个同名的方法,但要求每个方法具有不同的参数的类型或参数的个数。调用重载方法时,Java编译器能通过检查调用的方法的参数类型和个数选择一个恰当的方法。(简单来说:方法重载就是方法名称重复,加载参数不同。)
  • 什么时候考虑使用方法重载?

    • 功能相似的时候,尽可能让方法名相同。【但是:功能不同/不相似的时候,尽可能让方法名不同。】
  • 什么条件满足之后构成了方法重载?

    • 在同一个类当中

    • 参数列表不同:

      • 数量不同
      • 顺序不同
      • 类型不同
  • 方法重载和什么有关系,和什么没关系?

    • 有关

      • 方法名和参数列表
    • 无关

      • 返回值类型
      • 修饰符列表
  • 方法重载的具体应用

    • 方法的封装

方法的递归问题

  • 什么是递归?

    • 方法自身调用自己
    • 执行过程
  • 递归是很耗费内存的,递归算法可以不用的时候尽量别用。

  • 运行的时候发生这样的一个错误,【不是异常,是错误Error】

    • java.lang.StackOverflowError
    • 栈内存溢出错误
    • 错误发生无法挽回,只有一个结果,就是jvm停止工作。
  • 递归必须有结束条件,没有结束条件一定会发生栈内存溢出错误。

  • 递归即使有了结束条件,即使结束条件是正确的,也可能发生栈内存溢出错误,因为递归的太深了。

  • 注意:

    • 递归可以不使用尽量别用。
    • 但是有些情况下该功能的实现必须依靠递归方式。例如:目录拷贝。

访问控制权限修饰符:

  • 访问控制权限来控制元素的访问范围。

  • 访问控制权限修饰符包括:

    • public

      • 表示公开的,在任何位置都能访问。
    • private

      • 表示私有的,只能在本类中访问。
    • protected

      • 同包,子类
    • 缺省【默认】

      • 同包,本类
  • 访问控制权限修饰符可以修饰类,变量,方法,接口。。。。。

    • 属性

      • 四个都可以用
    • 方法

      • 四个都可以用
      • public和缺省能用,其他不行
    • 接口

      • public和缺省能用,其他不行
  • 修饰符范围:

    • private < 缺省【默认】 < protected < public
  • 类只能采用public和缺省的修饰符进行修饰。【内部类除外】

面向对象

面对过程和面向对象的区别

  • 面向过程:主要关注点是:实现的具体过程,因果关系【集成显卡的开发思路】

    • 优点:对于业务逻辑比较简单的程序,可以达到快速开发,前期投入成本较低。
    • 缺点:采用面向过程的方式开发很难解决非常复杂的业务逻辑,另外面向过程的方式导致软件元素之间的“耦合性”非常高,只要其中一环出问题,整个系统受到影响,导致最终的软件拓展力差,另外,由于没有独立体的概念,所以无法达到组件复用。
  • 面向对象:主要关注点是:主要关注对象【独立体】能完成哪些功能。【独立显卡的开发思路】

    • 优点:耦合度低,拓展力强,更容易解决现实世界当中更复杂的业务逻辑,组件复用性强。
    • 缺点:前期投入成本较高,需要进行独立体的抽取,大量的系统分析与设计。
  • 编程语言的性质:

    • C语言纯面向过程
    • c++半面向对象
    • java纯面向对象
    • 现在出现的一些新的编程语言多数都是面向对象的,人在认识现实世界的时候以面向对象的方式。
    • 面向对象更符合人的思维方式。

三大特性(所有的面向对象的编程语言都有这三大特征)

  • 封装
  • 继承
  • 多态

采用面向对象的方式开发一个软件,生命周期当中:【整个生命周期中贯穿使用OO面向对象方式】

  • 面向对象的分析:OOA

  • 面向对象的设计:OOD

  • 面向对象的编程:OOP

  • 描述一下整个软件开发的过程:

    • 程序员先观察现实世界,从现实世界当中寻找对象
    • 寻找了N多个对象之后,发现所有的对象都有共同特征
    • 程序员在大脑中形成一个模板【类】
    • java程序员可以通过java代码来表述一个类
    • java程序中有了类的定义
    • 然后通过类就可以创建对象
    • 有了对象之后,可以让对象直接协作起来形成一个系统。

类和对象的概念

    • 类在现实世界当中是不存在的,是一个模板,是一个概念,是人类大脑思考抽象的结果。
    • 类代表了一类事物。
    • 在现实世界当中,对象A与对象B之间具有共同特征,进行抽象总结出一个模板,这个模板被称为类。
  • 对象

    • 对象是实际存在的个体,现实世界当中实际存在。
    • 对象又被称为实例/Instance
  • 相互转化:

    • 类—【实例化】–>对象
    • 对象—【抽象】—>类
  • 重点:

    • 类描述的是对象的共同特征,例如:身高特征。

    • 一个类主要描述什么信息?

      • 一个类主要描述的是 状态 + 动作

      • 状态信息: 名字、身高、性别、年龄

        • 状态---->一个类的属性
      • 动作信息: 吃、唱歌、跳舞、学习

        • 动作—>一个类的方法
  • 注意:

    • 状态和动作当具体到某个对象上之后,发现最终的结果可能会不一样。
    • 对象和对象之间有共同特征,但是具体到对象之后有数据的差异。

类的定义

  • 语法结构:

  • 属性

    • 重点:属性通常是采用一个变量的形式类完成定义的。

      • 例如

        • int no;
        • String name;
        • boolean sex;
        • String address;
    • 属性【描述的是对象的状态信息】【存储数据采用变量的形式】

    • 在类体中,方法体之外定义的变量被称为“成员变量”

    • 成员变量没有赋值,系统赋默认值:一切向0看起。

对象的创建和使用

  • 实例化的语法:

  • 什么是对象?

    • new运算符在堆内存中开辟的内存空间称为对象。
  • 什么是引用?

    • 引用是一个变量,只不过这个变量中保存了另一个java对象的内存地址。
  • 如何访问实例变量。

    • java语言中,程序员不能直接操作堆内存,java中没有指针,不像C语言。

    • java语言中,程序员只能通过“引用”去访问堆内存当中的对象内部的实例变量。

    • 访问实例变量的语法格式:

      • 读取数据:

        • 引用 . 变量名
      • 修改数据:

        • 引用 . 变量名 = 值
      • 引用是一个变量。变量包括:

        • 局部变量
        • 成员变量
    • 注意变量存储的位置:

      • 局部变量在栈内存中存储
      • 成员变量中的实例化变量在堆内存的java对象内部存储。
      • 实例变量是一个对象一份。n个对象有n份。
  • 空指针异常

    • 运行过程中出现空指针异常
    • 空引用访问“实例”相关的数据一定会出现空指针异常
    • “实例”相关的数据表示:这个数据=访问的时候必须有对象的参与,这种数据就是实例相关的数据。

面向对象的封装性

  • 封装的好处

    • 封装之后,对于那个食物来说,看不到这个事物比较复杂的一面,只能看到该事物简单的那一面。复杂性封装,对外提供简单的操作入口。对于使用者来说不需要关心内部的实现原理,只需要会操作就行。
    • 封装之后才会形成真正的“对象”,真正的“独立体”
    • 封装就意味着以后的程序可以重复使用。并且这个事物应该适应性比较强,在任何场合都可以使用。
    • 封装之后,对于事物本身,提高了安全性【安全级别高】
  • 封装的步骤:

    • 所有属性私有化,使用private关键字进行修饰,private表示私有的,修饰的所有数据只能在本类中访问。

    • 对外提供简单的操作入口,也就是说以后外部程序要想访问属性,必须通过简单的入口进行访问。

      • 对外提供两个公开的方法,分别是set方法和get方法:

        • 想修改age属性,调用set方法
        • 想读取age属性,调用get方法
    • set方法的命名规范:

      • public void set +属性名首字母大写(形参){}
    • get方法命名规范:

      • public 数据类型 get+属性首字母大写(){}
    • 调用规则:

      • setter and getter方法没有static关键字

      • 有static关键字修饰的方法怎么调用:

        • 类名.方法名(实参);
      • 没有static关键字修饰的方法怎么调用:

        • 引用.方法名(实参);

方法的构造

  • 关于java类中的构造方法:

    • 构造方法又被称为构造函数/构造器/Constructor

    • 构造方法语法结构:

      • 【修饰符列表】 构造方法名(形式参数列表){ 构造方法体;}
    • 普通方法的语法结构:

    • 对于构造方法来说,“返回值”不需要指定,并且也不能写void,只要写上void,那么这个方法就成为普通方法了。

    • 对于构造方法来说,构造方法的方法名必须和类名保持一致。

    • 构造方法的作用?

      • 构造方法存在的意义是,通过构造方法的调用,可以创建对象。
    • 构造方法应该怎么调用?

      • 普通方法调用:

        • 有static关键字修饰的方法怎么调用:

          • 类名.方法名(实参列表);

            • static的方法调用不需要对象,直接使用类名,所以执行过程中没有当前对象,所以不能使用this。
        • 没有static关键字修饰的方法怎么调用:

          • 引用.方法名(实参列表);
      • 构造方法调用:

        • new 构造方法名(实参列表);
    • 构造方法调用执行之后,有返回值吗?

      • 每一个构造方法实际上执行结束之后都有返回值,但是这个“return 值;”这样的语句不需要写,构造方法结束的时候java程序自动返回值。
      • 并且返回值类型是构造方法所在类的类型,由于构造方法的返回值类型就是类本身,所以返回值类型不需要编写。
    • 当一个类中没有定义任何构造方法的话,系统默认给该类提供一个无参数的构造方法,这个构造方法称为缺省构造器。

    • 当一个类显示的将构造方法定义出来了,那么系统则不再默认为这个类提供缺省构造器。建议开发中手动的为当前类提供无参数构造方法,因为无参数构造方法太常用了。

    • 构造方法支持重载机制。在一个类当中编写多个构造方法,这多个构造方法显然已经构成方法重载机制。

    • 构造方法的作用;

      • 创建对象

      • 创建对象的同时,初始化实例变量的内存空间。

        • 成员变量之实例变量,属于对象级别的变量,这种变量必须先有对象才能用实例变量。

        • 实例变量没有手动赋值的时候,系统默认赋值,那么这个系统默认赋值时什么时候完成的?

          • 不是在类加载的时候,因为类加载的时候只加载了代码片段,还没来得及创建对象,所以此时实例变量并没有初始化。
          • 实际上,实例变量的内存空间是在构造方法执行过程当中完成开辟的,完成初始化的。
          • 系统在默认赋值的时候,也是在构造方法执行过程中完成赋值的。
          • 实例变量默认值:
          • 实例变量是存储在JVM的堆内存java对象内部的。

对象和引用

  • 对象和引用的概念:

    • 对象:

      • 目前在使用new运算符在堆内存中开辟的内存空间称为对象。
    • 引用:

      • 是一个变量,不一定是局部变量,还可能是成员变量。引用保存了内存地址,指向了堆内存当中的对象。
      • 所有访问实例相关的数据,都需要通过“引用.”的方式访问,因为只有通过引用才能找到对象。
      • 只有一个空的引用,访问对象的实例相关的数据会出现空指针异常。
  • 参数的传递:

    • java语言中方法调用的时候涉及到参数传递的问题,参数传递实际上传递的是变量中保存的具体值。
    • 方法调用的时候,涉及到参数传递的问题,传递的时候,java中值遵循一种语法机制,就是将变量中保存的“值"传递过去了,只不过有的时候这个值是一个字面值10,有的时候这个值是另一个java对象的内存地址 例如0x1234

this关键字

  • this是一个关键字,翻译为:这个。

  • this是一个引用,this是一个变量,this变量中保存了内存地址指向自身,this存储在JVM堆内存java对象内部。

  • 创建100个java对象,每一个对象都有this,也就是说有100不同的this。

  • this可以出现在实例方法当中,this指向当前正在执行这个动作的对象。(this 代表当前对象)

  • this在多数情况下都是可以省略不写的。

  • 用来区分局部变量和实例变量的时候,“this.”不能省略。

  • static的最终结论:

    • 在带有static的方法当中不能“直接”访问实例变量和实例方法。

    • 因为实例变量和实例方法都需要对象的存在。

    • 而static的方法当中是没有this的,也就是说当前对象是不存在的。

    • 自然也是无法访问当前对象的实例变量和实例方法。

    • 必须通过创建对象的方式来调用。

    • 带有static的方法,其实可既可以采用类名的方式访问,也可以采用引用的方法访问。

      • 但是即使采用引用的方式去访问,实际上执行的时候和引用指向的对象无关。
      • 在eclipse开发的时候,使用引用的方法访问带有static的方法,程序会出现警告。
      • 所以带有static的方法还是建议使用“类名.”的方式访问。
  • this可以用在哪里?

    • 可以使用在实例方法当中,代表当前对象【语法格式: this.]
    • 可以使用在构造方法当中,通过当前的构造方法调用其他的构造方法【语法格式:this(实参);】
    • 重点【记忆】:this()这种语法只能出现在构造函数的第一行。通过当前的构造方法区调用“本类”中其他的构造方法,目的是:代码复用。

super关键字

  • super是一个关键字,全部小写。

  • super能出现在实例方法和构造方法中。

  • super的语法是:“super”、“super()”

  • super不能使用在静态方法中。

  • super.

    • 大部分情况下是可以省略的。

    • 父类中有,子类型中又有,如果想要在子类中访问“父类的特征”,super. 不能省略。

    • java是如何区分子类和父类中的同名属性的:

      • this. :当前对象的属性
      • super. :当前父类型特征中的属性。
  • super()

    • 只能出现在构造方法的第一行,通过当前的构造方法去调用“父类”中的构造方法。目的是:创建子类对象的时候,先初始化父类型的特征。

    • 表示通过子类的构造方法去调用父类的构造方法。【模拟现实世界中的这种场景,目的:创建子类对象的时候,先初始化父类型的特征。】

    • 当一个构造方法第一行:

      • 既没有this();有没有super();的话,默认会有一个super();
      • 表示通过当前子类的构造方法调用父类的无参数构造方法。
      • 所以必须保证父类的无参数构造方法是存在的。
    • super(实参)的作用:

      • 初始化当前对象的父类型特征。并不是创建新对象。
    • this()和super()不能共存,因为他们都是只能出现在构造方法的第一行。

    • 无论如何,父类的构造方法是一定会执行的。【绝对的】

  • super 不是引用。super也不保存内存地址,super也不指向任何对象。super 只是代表当前对象内部的那一块父类型的特征。

  • super调用父类的方法:

    • super. 不仅可以访问属性,也可以访问方法。
    • 在父类中子类中有同名的属性,或者是同名的方法,如果想在子类中访问父类中的数据,必须使用“super"区分。
    • super. + 父类中的方法名(实参);

static关键字

  • static英文单词翻译为静态的。

  • static修饰的方法是静态方法。

  • static修饰的变量是静态变量。

  • 所有static修饰的元素都称为静态的,都可以使用类名.的方式访问,当然也可以使用引用.的方式访问【但不建议】

  • static修饰的所有元素都是类级别的特征,和具体的对象无关。

  • 可以使用static关键字来定义代码块。

    • 语法格式:

    • 静态代码块在类加载时执行,并且只执行一次。

    • 静态代码块在一个类中可以编写多个,并且遵循自上而下的顺序依次执行。

    • 静态代码块的作用是什么?怎么用?用在哪儿?有什么时候用?

      • 这当然和具体的需求有关,例如项目中要求在类加载的时刻/时机执行代码完成日志的记录。
      • 静态代码时java为程序员准备的一个特殊的时刻,这个特殊的时刻被称为类加载时刻,若希望在此刻执行一段特殊的程序,这段程序可以直接放到静态代码块当中。
      • 通常是静态代码块当中完成预备工作,先完成数据的准备工具,例如:初始化连接池,解析XML配置文件…
  • 在变量前添加static关键字修饰后,成为静态变量。

    • 静态变量,静态变量在类加载的时候初始化,不需要创建对象,内存就开辟了。
    • 静态变量存储在方法区内存当中。
  • 什么时候成员变量声明为实例变量呢?

    • 所有对象都有这个属性,但是这个属性的值会随着对象的变化而改变。【不同的对象的这个属性具体的值不同】
  • 什么时候成员变量声明为静态变量呢?

    • 所有对象都有这个属性,并且所有对象的这个属性的值是一样的,建议定义为静态变量,节省内存的开销。
    • 所有静态的数据都是可以采用类名.,也可以采用引用.,但是建议采用类名.的方式访问。
    • 采用引用.的方式访问的时候,即使引用是null,也不会出现空指针异常。因为访问静态的数据不需要对象的存在。
  • 实例代码块/语句块【了解内容】

    • 实例代码块可以编写多个,也是遵循自上而下的顺序依次执行。
    • 实例代码块在构造方法执行之前执行,构造方法依次执行,实例代码块对应执行一次。
    • 实例代码块也是java语言为程序员准备的一个特殊时机,这个特殊时机被称为:对象初始化时机。

继承

  • 继承是面向对象三个特征之一,三大特征分别是:封装,继承,多态。

  • 继承“基本”的作用是:代码复用,但是继承最“重要”的作用是:有了继承才有了以后“方法的覆盖”和“多态机制”。

  • 继承语法格式:

  • java语言中的继承只支持单继承,一个类不能同时继承很多类,只能继承一个类。

  • 关于继承中的一些术语:

    • B类继承A类,其中:

      • A类称为:父类,基类,超类,superclass
      • B类称为:子类,派生类,subclass
  • 在java语言中子类继承父类都继承哪些数据:

    • 私有的不支持继承
    • 构造方法不支持继承
    • 其他数据都可以被继承
  • 虽然java语言只支持单继承,但是一个类也可以间接继承其他类,比如:

  • java语言中假设一个类没有显示继承任何类,该类默认继承JavaSE库当中提供的java.lang.Object类。【java语言中任何一个类中都有Object类的特征。】

方法覆盖

  • 回顾方法重载

    • 方法重载又被称为Overload

    • 什么条件满足之后构成方法重载?

      • 在同一个类中
      • 方法名相同
      • 参数列表不同:类型,顺序,个数
    • 方法重载和什么无关?

      • 和方法的返回值类型无关。
      • 和方法的修饰符列表无关。
  • 方法覆盖又被称为方法重写,英文单词:override【官方的】/overwrite

  • 什么时候使用方法重写?

    • 当父类中的方法无法满足当前子类的业务需求。
    • 子类有必要将父类中继承的方法进行重新编写。
    • 这个重新编写的过程称为方法重写/方法覆盖。
  • 什么条件满足之后会发生重写呢?【代码满足什么条件之后,就构成方法的覆盖呢?】

    • 方法重写发生在具有继承关系的的父子类之间。
    • 返回值类型相同,方法名相同,形参列表相同。
    • 访问权限不能更低,可以更高。
    • 抛出异常不能更多,可以更少。
  • 建议方法重写的时候尽量复制粘贴。编写时,认真仔细,避免出错(没有产生覆盖)。

  • 注意:

    • 私有方法不能继承,所以不能覆盖。
    • 构造方法不能继承,所以不能覆盖。
    • 静态方法不存在覆盖。
    • 覆盖只针对方法,不针对属性。

多态

  • 关于多态中涉及的几个概念:

    • 向上转型【upcasting】

      • 子类型---->父类型【java中允许这种语法:父类型引用指向子类型对象】
      • 又被称为:自动类型转换。
      • 向上转型只要编译通过,运行一定不会出问题。 Animal a2 = new Cat();
    • 向下转型【downcasting】

      • 父类型-----> 子类型

      • 又被称为:强制类型转换。【需要加强制类型转换符】

      • 什么时候需要使用向下转型呢?

        • 当调用的方法是子类中特有的,在父类型当中不存在,必须进行向下转型。
    • 注意:无论是向上转型,还是向上转型。两种类型之间必须要有继承关系。没有继承关系,程序是无法编译通过的。

  • 多态运行机制:

    • java程序永远都分为编译阶段和运行阶段。
    • 先分析编译阶段,再分析运行阶段,编译无法通过,根本是无法运行的。
    • 编译阶段编译器检查a2这个引用的数据类型是Animal,由于Animal.class字节码中只有move()方法,所以编译通过了。这个过程我们称为静态绑定,编译阶段绑定。只有静态绑定成功之后才有后续的运行。
    • 在程序运行阶段,JVM堆内存当中真实创建的对象是Cat对象,那么以下程序在运行阶段一定会调用Cat对象的move()方法,此时发生了程序的动态绑定,运行阶段绑定。
    • 无论Cat类有没有重写move()方法,运行阶段一定调用的是Cat对象的move()方法,因为底层真实对象就是Cat对象。
    • 父类型引用指向子类对象这种机制导致程序存在编译阶段绑定和运行阶段绑定两种不同形态/状态,这种机制可以后成为一种多态语法机制。
  • 类型转换异常

    • 以下程序编译是没有问题的,因为编译器检查到a3的数据类型是Animal。Animal和Cat之间存在继承关系,并且Animal是父类型,Cat是子类型,父类型转换成子类型叫向下转型,语法合格。

    • 程序虽然编译通过了,但是程序在运行阶段会出现异常,因为JVM堆内存当中真实存在的对象是Bird类型,Bird对象无法转换成Cat对象,因为两种类型之间不存在任何继承关系,此时出现了著名的异常:

      • java.lang.ClassCastException
      • 类型转换异常,这种异常总是在“向下转型”的时候发生。
      • 异常只有在强制类型转换的时候会发生。所以“向下转型”存在隐患【编译通过,运行不通过】
    • 怎么避免向下转型出现的ClassCastException呢?

      • 使用instanceof运算符可以避免出现以上的异常。

      • instanceof运算符怎么用?

        • 语法格式:(引用 instanceof 数据类型名);

        • 以上运算符的执行结果类型是布尔类型,结果可能是true/false.

        • 关于运算结果true/false: 【假设:(a instanceof Animal)】

          • true表示:a这个引用指向的是一个Animal类型。
          • false表示:a这个引用指向的不是一个Animal类型。
        • java规范中要求:在进行强制类型转换之前,建议采用instanceof运算符进行判断,避免ClassCastException异常的发生。

  • 多态的作用是:

    • 降低程序的耦合度,提高程序的拓展力。
    • 能使用多态尽量使用多态。
    • 父类型引用指向子类型对象。
    • 核心:面向抽象编程,尽量不要使用面向具体编程。

final关键字:

  • final是一个关键字,表示最终的,不可变的。

  • final修饰的类无法被继承。

  • final修饰的方法无法被覆盖。被重写。

  • final修饰的变量一旦赋值之后,不可重新赋值。

  • final修饰的实例变量

    • 成员变量之实例变量

    • 实例变量有默认值 + final修饰的变量一旦赋值不能重新赋值

    • 综合考虑,java语言最终规定实例变量使用final修饰之后,必须手动赋值,不能采用系统赋值。

    • final int i; //编译错误

    • 必须手动赋值,不能采用系统默认值。

    • final修饰的实例变量是不可变的,这种变量一般和static联合使用,被称为:常量。

      • 常量的定义语法格式:public static final 类型 常量名 = 值;

      • java规范中要求所有常量的名字全部大写,每个单词之间使用下划线连接。

      • 常量:实际上常量和静态变量一样,区别在于:

        • 常量的值不能变。
        • 常量和静态变量,都是存储在方法区,并且都是在类加载时初始化。
  • final修饰的引用

    • final修饰的引用,一旦指向某个对象之后,不能再指向其他对象,那么被指向的对象无法被垃圾回收器回收。直到当前方法结束,才会释放空间。
    • final修饰的引用虽然指向某个对象之后不能再指向其他对象,但是所指向对象的内存是可以被修改的。【final的引用指向对象A后,不能再重新指向对象B,但是对象A内部的数据可以被修改。】

抽象类,接口

  • 抽象类【abstract】

    • 什么是抽象类

      • 类和类之间有共同特征,将这些具有共同特征的类再进一步抽象形成了抽象类。由于类本身是不存在的,所以抽象类无法创建对象。【无法实例化】
      • 抽象类和抽象类实际上可能还会有共同特征,还可以进一步再抽象。
    • 抽象类属于什么类型

      • 引用数据类型
    • 抽象类怎么定义

      • 语法:【修饰符列表】 abstract class 类名{类体;}
    • 抽象类是无法实例化的,无法创建对象的,所以抽象类是用来被子类继承的。

      • final和abstract不能联合使用,是非法的修饰符组合。
      • 抽象类的子类也可以是抽象类。也可以不是抽象类。
      • 抽象类虽然无法实例化,但是抽象类有构造方法,这个构造方法是供子类使用的。
    • 抽象类关联到一个概念:抽象方法。

      • 抽象方法表示没有实现的方法,没有方法体的方法。例如【public abstract void dosome();】

        • 没有方法体,以分号结尾。
        • 前面修饰符列表中有abstract关键字。
      • 抽象类中不一定有抽象方法。抽象方法必须出现在抽象类中。

      • 一个非抽象的类继承抽象类,必须将抽象类中的抽象方法实现了。这是java语法上强行规定的,不然编译器就报错了。【实现可以叫做:覆盖或重写(对抽象的实现)】

  • 接口

    • 接口的基础语法:

      • 接口也是一种“引用数据类型”。 编译之后也是一个class字节码文件。

      • 接口是完全抽象的,【抽象类是半抽象的】,或者也可以说接口是特殊的抽象类。

      • 接口的语法: 【修饰符列表】 interface 接口名{}

      • 接口支持多继承,一个接口可以继承多个接口。

      • 接口中只包含两部分内容,一部分是:常量,一部分是:抽象方法。

        • 接口中的抽象方法定义时:public abstract修饰符可以省略。
        • 接口中的常量的public static final 可以省略。
      • 接口中所以的元素都是public修饰的。【都是公开的】

      • 接口中方法都是抽象方法,所以接口中的方法没有方法体。

      • 类和类之间叫做继承【接口和接口之间支持多继承】,类和接口之间叫做实现。【特殊的抽象类,完全抽象的,叫做接口】可以将“实现”看做“继承”。

        • 继承使用extends关键字完成。
        • 实现使用implements关键字完成。
        • 同时存在,extends在前,implements在后。
      • 当一个非抽象的类实现接口的话,必须将接口中所有的抽象方法全部实现(覆盖,重写)。

      • 一个类中可以同时实现多个接口。

        • java中类和类只支持单继承,实际上单继承是为了简单而出现的,现实世界中存在多继承,java中的接口弥补了单继承带来的缺陷。
      • 接口和接口之间在进行强制类型转换的时候,没有继承关系,也可以强制转换,但是一定要注意,运行是可能会出现ClassCastException异常。

      • 使用接口,写代码的时候,可以使用多态(父类型引用指向子类型对象)

    • 接口在开发中的作用:

      • 注意:接口在开发中的作用,类似于多态在开发中的作用。

        • 多态:面向抽象编程,不要面向具体编程,降低程序的耦合度,提高程序的拓展力。
      • 接口可以解耦合,解开的是什么之间的耦合:

        • 任何一个接口都有调用者和实现者。
        • 接口可以将调用者和实现者解耦合。
        • 调用者面向接口调用。
        • 实现者面向接口编写实现。
  • 抽象类和接口有什么区别:

    • 抽象程度:

      • 抽象类是半抽象的。
      • 接口是完全抽象的。【接口一般都是对“行为”的抽象】
    • 有无构造方法:

      • 抽象类中有构造方法。
      • 接口中没有构造方法。
    • 继承关系:

      • 一个类可以同时实现多个接口。
      • 一个抽象类只能继承一个类。【单继承】
    • 接口中只允许出现常量和抽象方法。

  • 类型和类型之间的关系:【is
    a,has a, like a】

    • is a【继承】

      • Cat is a Animal (猫是一个动物)
      • 凡是能够满足is a的表示“继承关系”
      • A extens B
    • has a【关联】

      • I has a Pen(我有一支笔)
      • 凡是能够满足has a 关系的表示”关联关系“
      • 关联关系通常以”属性“的形式存在。
      • A{
        B b;
        }
    • like a【实现】

      • Cook like a FoodMenu(厨师像一个菜单一样)
      • 凡是能够满足like a关系的表示”实现关系“
      • 实现关系通常是:类实现接口。
      • A implements B

进阶:

object类

  • 任何一个类默认继承object,就算没有直接继承,最终也会间接继承。

  • 常用的几个方法:

    • protected object clone()

      • 负责对象克隆。
    • int hashCode()

      • 获取对象哈希值的一个方法。
    • boolean equals(object obj)

      • 判断两个对象是否相等。

      • 以后所有类的equals方法也需要重写,因为Object中的equals方法比较的是两个对象的内存地址,我们应该比较内容,所以需要重写。

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

      • 基本数据类型比较实用:==

      • 对象和对象比较:调用equals方法【不能使用“”,因为“”比较的是两个对象的内存地址。】

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

      • 注意:重写equals方法的时候要彻底。

    • String toString()

      • 将对象转换成字符串的形式。
      • 以后所有类的toString()方法是需要重写的。
      • 重写规则,越简单越明了就好。
      • System.out.println(引用); 这里会自动调用“引用”的toString()方法。
      • String类是SUN写的,toString方法已经重写了。
    • protected void finalize()

      • 垃圾回收器负责调用的方法。
      • 这个方法是protected修饰的,在Object类中这个方法的源代码
        protected void finalize() throws Throwable { }
  • 匿名内部类

    • 内部类:在类的内部又定义了一个新的类,被称为内部类。

    • 内部类的分类:

      • 静态内部类:

        • 类似于静态变量。
      • 实例内部类:

        • 类似于实例变量。
      • 局部内部类:

        • 类似于局部变量。
    • 使用内部类编写的代码,可读性很差,能不用尽量不用。

    • 匿名内部类是局部内部类的一种。【因为这个类没有名字而得名,叫做匿名内部类】

    • 缺点:

      • 因为一个类没有名字,没有办法重复使用。
      • 另外代码太乱,可读性太差。
  • 总结:

    • String类已经重写了equals方法,比较两个字符串不能使用==,必须使用equals。equals是通用的。
    • String类已经重写了toString方法。
    • java中基本数据类型比较是否相等,使用==。
    • java中所有的引用数据类型统一使用equals方法来判断是否相等。

API

【Application Program Interface】

  • 应用程序编程接口。
  • 整个JDK的类库就是一个javase的API。
  • 每一个API都会配置一套API帮助文档。
  • sun公司提前写好的这套类库就是API。(一般每一份API都对应一份API帮助文档。)

数组

  • 含义(解释):

    • java语言中的数组是一种引用数据类型,不属于基本数据类型,数组的父类是Object。

    • 数组实际上是一个容器,可以同时容纳多个元素。【数组是一个数据的集合。】数组:字面意思是“一维数组”。

    • 数组当中可以存储“基本数据类型”,也可以存储“引用数据类型”的数据。

    • 数组因为是引用数据类型,所以数组对象是堆内存当中。(数组是存储在堆当中的)

    • 数组当中如果存储的是“java对象”的话,实际上存储的是对象的“引用(内存地址)“。java中不能直接存储java对象。

    • 数组一旦创建,在java中规定,长度不可变。(数组长度不可变)

    • 数组的分类:(一维数组较多,二维数组偶尔使用!)

      • 一维数组
      • 二维数组
      • 三维数组
      • 多维数组。。。
    • 所有的数组对象都有length属性(java自带的),用来获取数组中元素的个数。

    • java中数组要求数组中的元素的类型统一【数组中存储的元素类型统一】。比如int类型的数组只能存储int类型,Person类型的数组只能存储Person类型的。

    • 数组在内存方面存储的时候,数组中的元素内存地址(存储的每一个元素都是有规则的挨着排列的)是连续的,内存地址连续。这是数组存储元素的特点(特色)。数组实际上是一种简单的数据结构。

    • 所有的数组都是拿“第一个小方框的内存地址”作为整个数组对象的内存地址。(数组中首元素的内存地址作为整个数组对象的内存地址。)

    • 数组中每一个元素都是有下标的,下标从0开始,以1递增。最后一个元素的下标是(length-1)。

  • 数组这种数据结构的优缺点:

    • 优点:

      • 查询/查找/检索某个下标上的元素时效率极高,可以说是查询效率最高的一个数据结构。

      • 为什么查询/检索效率高:

        • 每一个元素的内存地址在空间上存储上是连续的。
        • 每一个元素类型相同,所以占用空间大小一样。
        • 知道第一个元素的内存地址,知道每一个元素占用空间的大小,又知道下标,所以通过一个数学表达式就可以计算出某一个下标上元素的内存地址,直接通过内存地址定位元素,所以数组的检索效率是最高的。
        • 数组中存储100个元素,或者存储100万个元素,在元素查询/检索方面,效率是相同的,因为数组中的元素查找时不会一个一个找,是通过数学表达式计算出来的。(算出一个内存地址,直接定位的。)
    • 优点:

      • 由于为了保证数组中每个元素的内存地址连续,所以在数组上随机删除或者添加元素的时候,效率较低,因为随机增删元素会涉及到后面元素统一向前或者向后位移的操作。

        • 注意:对于数组最后一个元素的增删,是没有效率影响的。
      • 数组不能存储大数据量

        • 因为很难在内存空间上找到一块特别大的连续的内存空间。【比如网吧五黑,很难找到五个连在一起的位置。】
  • main方法的String数组

    • jvm负责调用。

      • JVM调用main方法的时候,会自动传一个String数组过来。
    • JVM默认传递过来的这个数组对象的长度为0。

      • 通过测试:args不是null。
    • 这个数组什么时候里面会有值:

      • 其实这个数组是留给用户的,用户可以在控制台上传入参数,这个参数会自动被转换成“String[ ] args"

      • 例如这样运行程序:

        • java test abc def xyz
        • 这个时候JVM会自动将”abc def xyz“通过空格的方式进行分离,分离完成之后,自动放到”String[ ] args"数组中。
        • 所以main方法上面的String[ ] args 数组主要是用来接收用户输入参数的。
        • 把abc def xyz 转换成字符串数组:{”abc”,“def”,“xyz”}
  • 一维数组:

    • 数组的语法格式:

      • 声明/定义一个一维数组:

        • int [ ] array1;
        • double[ ] array2;
        • boolean [ ] array2;
        • String [ ] array4;
        • Object [ ] array5;
      • 初始化一个一维数组:

        • 静态初始化一维数组:

          • int [ ] array = { 100,200,300,399,…};
          • 当创建数组时,确定数组中存储哪些具体的元素时,采用静态初始化方式。
        • 动态初始化一维数组:

          • int [ ] array = new int [5] ;

            • 这里的5表示数组的元素个数。
            • 初始化一个5个长度的int类型数组,每个元素默认值0。
          • String [ ] array = new String [6];

            • 初始化1个6个长度的String类型数组,每个元素默认值为null。
          • 当创建数组时,不确定将来数组中存储哪些数据,可以采用动态初始化方式,预先分配内存空间。

    • 数组中存储引用数据类型

      • 数组中存储的类型为:引用数据类型。
      • 对于数组来说,实际上只能存储java对象的“内存地址”。数组中存储的每个元素是“引用”。
    • 一维数组的扩容:

      • 在java开发中,数组长度一旦确定不可变。数组满了,需要扩容。

      • java中对数组的扩容是:

        • 先新建一个大容量的数组,然后将小容量数组中的数据一个一个拷贝到大数组当中。
      • 结论: 数组扩容效率较低,因为涉及到拷贝的问题。所以在以后的开发中请注意:尽可能的少的进行数组的拷贝,。可以在创建数组对象的时候预估一下多长合适,最后预估准确,这样可以减少数组的扩容次数,提供效率。

      • 数组的拷贝:

        • System.arraycopy(源【从这个数组中拷贝】,起始位置,目标数组【拷贝到这个数组中上】,目标数组的起始位置,长度【源数组的长度】);
    • 一维数组的遍历:

      • for(int i = 0; i < arr.length; i++){
        System.out.println(arr[i]);
        }
  • 二维数组:

    • 二维数组其实是一个特殊的一维数组,特殊在这个一维数组当中的每一个元素是一个一维数组。

    • 三维数组:

      • 三维数组是一个特殊的二维数组,特殊在这个二维数组中每一个元素是一个一维数组。
    • 二维数组静态初始化:

      • 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()}
        };
    • 二维数组中元素的读和写:

      • a[二维数组中的一维数组的下标][一维数组的下标]
    • 二维数组的遍历

      • 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();
        }
  • 常见的算法:

    • 排序算法:

      • 冒泡排序算法

        • 每一次循环结束之后,都要找出最大的数据,放到参与比较的这堆数据的最右边。(冒出最大的那个气泡)
        • 核心:拿着左边的数字和右边的数字比对,当左边 > 右边的时候,交换位置。
      • 选择排序算法

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

        • 选择排序比冒泡排序的效率高。

          • 高在交换位置的次数上。
          • 选择排序的交换位置是有意义的。
    • 查找算法:

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

        • 二分法查找建立在排序的基础之上。
        • 二分法查找的效率要高于“一个挨着一个”的这种查找方式。
    • 算法实际上不需要精通,因为java中已经封装好了,要排序调用方法就好。例如:java中提供了一个数字工具类:

      • java.util.Arrays

      • Arrays是一个工具类。

        • 所有方法都是静态的,直接用类名调用
      • 其中有一个sort()方法,可以排序。静态方法,直接使用类名调用就行。

String类

  • 关于String类中的构造方法:

    • String s = new String(" ");
    • String s = " ";
    • String s = new String(char 数组);
    • String s = new String(char数组,起始下标,长度);
    • String s = new String(byte数组);
    • String s = new String(byte数组,起始下标,长度);
  • String的一些方法:

    • 字符串之间比较大小不能直接使用 > <,需要使用compareto方法。
      .int compareTo(String anotherString)

      • 前后一致 0
      • 前小后大 -1
      • 前大后下 1
    • .boolean contains(CharSequence s)
      判断前面的字符串是否包含后面的子字符串。

      • Syetem.out.println(“helloworld”.contains(“hello”));
    • .boolean endWith(String suffix)
      判断当前字符串是否以某个字符串结尾。

      • System.out.println(“test.txt”.enWith(“.txt”));
    • .boolean equalsIgnoreCase(String anotherString)
      判断两个字符串是否相等,并且同时忽略大小写。

      • System.out.println(“ABc”.equalsIgnoreCase(“abC”));
    • 判断子字符串在当前字符串中的位置(索引)

      • .int indexOf(String str)
        判断某个子字符串在当前字符串中第一次出现处的索引(下标)。
      • .int lastIndexOf(String str)
        判断某个子字符串在当前字符串中最后一次出现的索引(下标)
    • .byte[ ] getBytes()
      将字符串对象转换成字节数组。

    • .boolean isEmpty()
      判断某个字符串是否为空。

      • String s = “”;
        System.out.println(s.isEmpty); //true
    • 判断数组长度是length属性,判断字符串长度是length()方法。

    • .String replace(CharSequencetarget,CharSequence replacement) 替换
      String的父接口就是:CharSequence

    • .String [ ] split(String regex)
      拆分字符串

    • .boolean startsWith(String prefix)
      判断某个字符串是否以某个子字符串开始。

    • 截取字符串:

      • String substring(int beginIndex)
        截取字符串//参数是起始下标
      • String substring(int beginIndex,int endIndex);//起始位置(包括) 结束位置(不包括)
    • char[ ] toCharArray( )
      将字符串转换成char数组

      • char[ ] chars = "周杰伦,林俊杰“.toCharArray();
    • 转换大小写

      • String toLowerCase();
        转换为小写
      • String toUpperCase();
        转换为大写
    • .String trim();
      去除字符串前后空白

      • System.out.println(" hello world ".trim());// hello world
    • String中只有一个方法是静态的,不需要new对象【valueOf】
      作用:将“非字符串”转换成“字符串”

  • StringBuffer和StringBuilder

    • StringBuffer

      • StringBuffer底层实际上是一个byte[ ] 数组。【字符串缓冲区对象】

        • 往StringBuffer中放字符串,实际上是放到byte数组当中了。
        • StringBuffer的初始化容量是16.
      • append()

        • append是追加的意思。拼接字符串时使用。
        • append方法底层在进行追加的时候,如果byte数组满了,会自动扩容。
      • 如何优化StringBuffer的性能

        • 在创建StringBuffer的时候尽可能给定一个初始化容量。
        • 最好减少底层数组的扩容次数,预估一下,给一个大一些初始化容量。
        • 关键点:给一个合适的初始化容量。
    • StringBuilder

      • StringBuilder也可以完成字符串的拼接。
    • 区别:

      • StringBuffer中的方法都有:synchronized关键字修饰。表示StringBuffer在多线程环境下运行是安全的。
      • StringBuilder中的方法都没有synchronized关键字修饰,表示StringBuilder在多线程环境下运行是不安全的。
      • StringBuffer是线程安全的。
      • StringBuilder是非线程安全的。

包装类

  • java中为8种基本数据类型又对应准备了8种包装类型。8种包装类属于引用数据类型,父类是Object。

  • 为什么要再提供8种包装类:

    • 因为8种基本数据类型不够用
    • SUN又提供了对应的8种包装类型。
  • 8中基本数据类型对应的包装类型:

    • 基本数据类型

      • 包装类型
    • byte

      • java.lang.Byte(父类Number)
    • short

      • java.lang.Short(父类Number)
    • int

      • java.lang.Integer(父类Number)
    • long

      • java.lang.Long(父类Number)
    • float

      • java.lang.Float(父类Number)
    • double

      • java.lang.Double(父类Number)
    • boolean

      • java.lang.Boolean(父类Object)
    • char

      • java.lang.Character(父类Object)
  • 8种包装类中其中6个都是数字对应的包装类,它们的父类都是Number:

    • Number是一个抽象类,无法实例化对象。

    • Number类中有这样的方法:

      • byteValue()
        返回指定号码作为值 byte ,这可能涉及舍入或截断。
        abstract double doubleValue()
        返回指定数字的值为 double ,可能涉及四舍五入。
        abstract float floatValue()
        返回指定数字的值为 float ,可能涉及四舍五入。
        abstract int intValue()
        返回指定号码作为值 int ,这可能涉及舍入或截断。
        abstract long longValue()
        返回指定数字的值为 long ,可能涉及四舍五入或截断。
        short shortValue()
        返回指定号码作为值 short ,这可能涉及舍入或截断。

日期类:

  • 获取系统当前时间

    • Date d = new Date();
  • 日期格式化: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());
  • String --> Date

    • SimpleDateFormat sdf = new SimpleDate(“yyyy-MM-dd HH:mm:ss”);
      Date d = sdf.parse(“2008-08-08 08:08:08”);
  • 获取毫秒数

    • long begin = System.currentTimeMillis();
      Date d = new Date(begin - 1000 * 60 * 60 * 24);

数字类:

  • DecimalFormat数字格式化

    • ###,###.## 表示加入千分位,保留两个小数。
      ###,###.0000 表示加入千分位,保留4个小数,不够补0
  • BigDecimal

    • 财务软件中通常使用BigDecimal

随机数

  • 怎么产生int类型随机数。

    • Random r = new Random();
      int i = r.nextInt();
  • 怎么产生某个范围之内的int类型随机数。

    • Random r = new Random();
      int i = r.nextInt(101); // 产生[0-100]的随机数。

枚举:

  • 枚举是一种引用数据类型。

  • 枚举编译之后也是class文件。

  • 枚举类型怎么定义?

    • enum 枚举类型名{
      枚举值,枚举值2,枚举值3
      }
  • 当一个方法执行结果超过两种情况,并且是一枚一枚可以列举出来的时候,建议返回值类型设计为枚举类型。

异常

  • 什么是异常:

    • 程序执行过程中的不正常情况。
  • java提供异常处理机制的作用:

    • 增强程序的健壮性
  • java语言中异常是以什么形式存在的;

    • 异常在java中以类的形式存在,每一个异常类都可以创建异常对象。
  • 编译时异常:

    • 因为编译时异常必须在编译(编写)阶段预先处理,如果不处理编译器报错,因此得名。
      所有异常都是在运行阶段发生的。因为只有程序运行阶段才可以new对象。
      因为异常的发生就是new异常对象。
  • 编译时异常和运行时异常的区别?

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

    • 运行时异常一般发生的概率比较低。

  • 强调:

    • 所有异常都是发生在运行阶段的。
  • Java语言中对异常的处理包括两种方式:

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

      • 注意:Java中异常发生之后如果一直上抛,最终抛给了main方法,main方法继续向上抛,抛给了调用者JVM,JVM知道这个异常发生,只有一个结果。终止java程序的执行。
    • 使用try…catch语句进行异常的捕捉。
      这件事发生了,谁也不知道,因为我给抓住了。

      • catch后的异常名称可以写确切的异常,也可以写父类的异常【多态】

      • catch可以写多个,建议写catch的时候,精确的一个一个处理,这样有利于程序的调试。

      • catch写多个的时候,从上到下,必须遵守从小到大。

      • 关于try…catch中的finally字句:

        • 在finally字句中的代码时最后执行的,并且是一定执行的,即使try语句块中的代码出现了异常。

        • finally语句通常使用在哪些情况下:

          • 通常在finally语块中完成资源的释放/关闭。
          • 因为finally中的代码比较有保障。
          • 即使try语句块中的代码出现异常,finally中代码也会正常执行。
        • final finally finalize 区别:

          • final

            • final是一个关键字。表表示最终的。不变的。
            • final修饰的类无法继承
            • final修饰的方法无法覆盖
            • final修饰的常量不能重新赋值
          • finally

            • finally也是一个关键字,和try联合使用,使用在异常处理机制当中。
            • 在finally语句块中的代码时一定会执行的。
          • finalize()

            • finalize()是Object类中的一个方法。作为方法名出现。
            • finalize是标识符。
            • finalize()方法是JVM的GC垃圾回收器负责调用。
    • 如果希望调用者处理就是用throws上抛。

  • 异常对象的两个非常重要的方法:

    • 获取异常简单的描述信息:

      • String msg = exception.getMessage();
    • 打印异常追踪的堆栈信息:

      • exception.printStackTrace();

      • 查看异常的追踪信息,应该怎么看,可以快速调试程序:

        • 异常信息追踪信息,从上往下一行一行看。
        • 但是需要注意的是:SUN写的代码就不需要看(看包名),主要的问题是出现在自己编写的代码上。
  • java中自定义异常:

    • 编写一个类继承Exception【编译时异常】或者RuntimeException【运行时异常】。
    • 提供两个构造方法,一个无参数的,一个带有String参数的。
  • 总结异常中的关键字:

    • 异常捕捉:

      • try
      • catch
      • finally
    • throws

      • 在方法声明位置上使用,表示上报异常信息给调用者。
    • throw

      • 手动抛出异常。

集合:

  • 什么是集合?有什么用?

    • 数组其实就是一个集合。集合实际上就是一个容器。可以来容纳其它类型的数据。
  • 集合为什么说在开发中使用较多?

    • 集合是一个容器,是一个载体,可以一次容纳多个对象。在实际开发中,假设连接数据库,数据库当中有10条记录,那么假设把这10条记录查询出来,在java程序中会将10条数据封装成10个java对象,然后将10个java对象放到某一个集合当中,将集合传到前端,然后遍历集合,将一个数据一个数据展现出来。
  • 集合不能直接存储基本数据类型,另外集合也不能直接存储java对象,集合当中存储的都是java对象的内存地址。(或者说集合中存储的是引用。)

    • 注意:集合在java中本身是一个容器,是一个对象。集合中任何时候存储的都是“引用”。
  • 在java中每一个不同的集合,底层会对应不同的数据结构。往不同的集合中存储元素,等于将数据放到了不同的数据结构当中。什么是数据结构?数据存储的结构就是数据结构。不同的数据结构,数据存储方式不同。

  • 集合在java JDK中哪个包下;

    • java.util.*;
      所有的集合类和集合接口都在java.util包下。
  • 在java中集合分为两大类:

    • 单个方式存储元素:

      • 单个方式存储元素,这一类集合中超级父接口:java.util.Collection;
    • 键值对儿的方式存储元素:

      • 以键值对的方式存储元素,这一类集合中超级父接口:java.util.Map;
  • List集合存储元素特点:

    • 有序可重复,存储的元素有下标。

    • 有序实际上是说存进去是这个顺序,取出来还是这个顺序。这里的顺序不是说按照大小排序。有序是因为List集合都有下标,下标从0开始,以1递增。

    • List中特有的方法:

      • void add(int index,E,element)

        • 将指定的元素插入此列表中的指定位置(可选操作)。
      • E get(int index)

        • 返回此列表中指定位置的元素。
      • int indexOf(Object o)

        • 返回此列表中指定元素的第一次出现的索引,如果此列表不包含元素,则返回-1。
      • int lastIndexOf(Object o)

        • 返回此列表中指定元素的最后一次出现的索引,如果此列表不包含元素,则返回-1。
      • E remove(int index)

        • 删除该列表中指定位置的元素(可选操作)。
      • E set(int index, E element)

        • 用指定的元素(可选操作)替换此列表中指定位置的元素。
    • ArrayList:

      • ArrayList集合底层采用了数组这种数据结构。

      • ArrayList集合是享线程安全的。

      • 默认初始化容量10(底层先创建了一个长度为0的数组,当添加第一个元素的时候,初始化容量10).

      • 集合底层是一个Object[ ] 数组。

      • 构造方法:

        • new ArrayList();
        • new ArrayList( 20 ); [指定初始化容量]
      • ArrayList集合的扩容:

        • 扩容到原容量的1.5倍。

        • ArrayList集合底层是数组,怎么优化?

          • 尽可能少的扩容,因为数组扩容效率比较低,建议在使用ArrayList集合的时候预估计元素的个数,给定一个初始化容量。
    • LinkedList:

      • LinkedList集合底层采用了双向链表数据结构。
    • Vector:

      • Vector集合底层采用了数组这种数据结构。

      • Vector集合是线程安全的。

      • Vector所有的方法都有synchronized关键字修饰,所以线程安全,但是效率较低。

      • 底层也是一个数组。

      • 初始化容量:10.

      • 怎么扩容:

        • 扩容后是原容量的2倍。
          10---->20---->40---->80
  • Set集合存储元素的特点:

    • 无序不可重复。

    • 无序表示存进去是这个顺序,取出来就不一定是这个顺序了,另外Set集合中元素没有下标。Set集合中的元素还不能重复。

    • HashSet:

      • 实际上HashSet集合在new的时候,底层实际上new了一个HashMap集合。向HashSet集合中存储数据,实际上是存储到HashMap集合的key中。HashMap集合是一个哈希表数据结构。
    • TreeSet:

      • TreeSet集合底层实际上是TreeMap,new TreeSet集合的时候,底层实际上new了一个TreeMap集合。

      • 往TreeSet集合中放数据的时候,实际上是将数据放到TreeMap集合中了。

      • TreeMap集合底层采用了二叉树数据结构。

      • TreeSet集合中的元素:无序不可重复,但是可以按照元素的大小顺序自动排序。称为:可排序集合。

      • 二叉树:

        • 白平衡二叉树,遵循左小右大原则存放。

        • 遍历二叉树的时候有三种方式:

          • 前序遍历:根左右

          • 中序遍历:左根右

          • 后序遍历:左右根

          • 注意:

            • 前中后说的是“根”的位置。
            • 根在前面是前序,根在后面是后序,根在中间是中序。
      • TreeSet集合/TreeMap集合采用的是:

        • 中序遍历方法
        • Inerator迭代器采用的是中序遍历的方式。
        • 左根右
      • 结论:

        • 放到TreeSet或者TreeMap集合key部分的元素要想做到排序,包括两种方式:

          • 放在集合中的元素实现java.lang.Comparable接口。
          • 在构造TreeSet或者TreeMap集合的时候给它传一个比较器对象。
        • Comparable和Comparator怎么选择:

          • 当比较规则不会发生改变的时候,或者说当比较规则只有一个的时候,建议实现Comparable接口。
          • 如果比较规则有多个,并且需要多个比较规则之间频繁切换,建议使用Comparator接口。
          • Comparator接口的设计符合OCP原则。
  • Map:

    • Map集合和Collection集合没有关系。

    • Map集合以key和value的这种键值队的方式存储元素。

      • key起到主导的地位,value是key的一个附属品。
    • key和value都是存储java对象的内存地址。

    • 所有Map集合的key特点:无序不可重复。Map集合的key和set集合存储元素特点相同。

    • 常用方法:

      • V put(K key, V value)

        • 将指定的值与该映射中的指定键相关联(可选操作)。
        • 向Map集合中添加键值对
      • V get(Object key)

        • 返回到指定键所映射的值,或 null如果此映射包含该键的映射。
        • 通过key获取value
      • void clear()

        • 从该地图中删除所有的映射(可选操作)。
        • 清空Map集合
      • boolean containsKey(Object key)

        • 如果此映射包含指定键的映射,则返回 true 。
        • 判断Map中是否包含某个key
      • boolean containsValue(Object value)

        • 如果此地图将一个或多个键映射到指定的值,则返回 true 。
        • 判断Map中是否包含某个value
      • boolean isEmpty()

        • 如果此地图不包含键值映射,则返回 true 。
        • 判断Map集合中元素个数是否为0
      • Set keySet()

        • 返回此地图中包含的键的Set视图。
        • 获取Map集合所有的key(所有的键是一个set集合)
      • V remove(Object key)

        • 如果存在(从可选的操作),从该地图中删除一个键的映射。
        • 通过key删除键值对
      • Collection values()

        • 返回此地图中包含的值的Collection视图。
        • 获取Map集合中所有的value,返回一个Collection。
      • int size()

        • 返回此地图中键值映射的数量。
        • 获取Map集合中键值对的个数。
      • Set<Map.Entry<K,V>> entrySet()

        • 返回此地图中包含的映射的Set视图。
        • 将Map集合转换成Set集合。
    • HashMap:

      • HashMap集合底层是哈希表/散列表的数据结构,是非线程安全的。

        • 哈希表是一个数组和单向链表的结合体。

        • 一维数组,这个数组中每一个元素是一个单向链表。(数组和链表的结合体)

        • HashMap集合key部分特点【无序,不可重复】:

          • 无序:因为不一定挂到哪个单向链表上。
          • 不可重复:equals方法来保证HashMap集合的key不可重复,如果key重复了,value会覆盖。
          • 放在HashMap集合key部分的元素其实就是放在HashSet集合中了。所以HashSet集合中的元素也需要同时重写hashCode() + equals()方法。
        • 向Map集合中存,以及从Map集合中取,都是先调用key的hashCode方法,然后再调用equals方法。【equals方法有可能调用,也有可能不调用。】

      • HashMap集合的key可以是null,但是只能有一个。

      • 重点:

        • 放在HashMap集合key部分的元素,以及放在HashSet集合中的元素,需要同时重写hashCode()和equals()方法。
        • HashMap集合的默认初始化容量是16,默认加载因子是0.75.【这个默认加载因子是当HashMap集合底层数组的容量达到75%的时候,数组开始扩容。】
        • HashMap集合初始化容量必须是2的倍数,这是因为达到散列均匀,为了提高HashMap集合的存取效率,所必须的。
    • Hashtable:

      • Hashtable集合底层也是哈希表数据结构,是线程安全的,其中所有的方法都带有syndronized关键字,效率较低。

      • Hashtable集合的key不能为null,会出现空指针异常。

      • Hashtable集合初始化容量11

      • Hashtable集合扩容是:原容量*2+1

      • Properties:

        • Properties是一个Map集合,继承Hashtable,Properties的key和value都是String类型。

        • Properties被称为属性类对象。

        • Properties是线程安全的。

        • 两个方法:

          • 存:

            • setProperty
          • 取:

            • getProperty
  • Collection:

    • Collection中能存放什么元素:

      • 没有使用“泛型”之前,Collection中可以存储Object的所有子类型。
      • 使用了“泛型”之后,Collection中只能存储某个具体的类型。
      • Collection中什么都能存,只要是Object的子类型就行。(集合中不能直接存储基本数据类型,也不能存java对象,只是存储java对象的内存地址。)
    • Collection中常用方法:

      • boolean add(Object e)向集合中添加元素
      • int size() 获取集合中元素的个数
      • void clear() 清空集合
      • boolean contains(Object 0) 判断当前集合中是否包含元素0
        包含返回true,不包含返回false
      • boolean remove(Object o) 删除集合中的某个元素
      • boolean isEmpty() 判断该集合中元素的个数是否为0
      • Object[ ] toArray() 调用这个方法可以把集合转换成数组。
    • 迭代:

      • boolean hasNext()如果仍有元素可以迭代,则返回true。

      • Object next() 返回迭代的下一个元素。

      • 注意:

        • 集合结构只要发生改变,迭代器必须重新获取。
        • 在迭代集合元素的过程中,不能调用集合对象的remove方法,删除元素。
        • 在迭代元素的过程中,一定要使用迭代器Iterator的remove方法,删除元素,不要使用集合自带的remove方法删除元素。
  • 链表:

    • 对于链表结构来说,基本单元是节点Node。

    • 对于单向链表来说,任何一个节点Node中都有两个属性:

      • 存储的数据。
      • 下一个节点的内存地址。
    • 链表优点:

      • 由于链表上的元素在空间存储上内存地址不连续。随机增删元素效率较高。(因为增删元素不涉及到大量元素的位移。)
    • 链表缺点:

      • 不能通过数学表达式计算被查找元素的内存地址。查询效率较低,每一个查找某一个元素的时候都需要从头节点开始往下遍历。
  • 泛型:

    • 用泛型来指定集合中存储的数据类型。

    • 泛型这种语法机制,只在程序编译阶段起作用,只是给编译器参考的。(运行阶段泛型没用!)

    • 泛型优点:

      • 集合存储的元素类型统一了。
      • 从集合中取出的元素类型是泛型指定的类型,不需要进行大量的“向下朱那行
    • JDK之后引入了:自动类型推断机制。(又称钻石表达式)

      • ArrayList<这里的类型自动推断>
    • 自定义泛型:

      • 自定义泛型的时候,<>尖括号中的是一个标识符,随便写。

      • java源代码中经常出现的是:

          • E是Element单词的首字母。
          • T是Type单词的首字母。

IO流:

  • I: Input
    O: Output

    • 通过IO可以完成硬盘文件的读和写。
  • 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个字节。)
    • 综上所述:流的分类

      • 输入流、输出流
        字节流、字符流
  • 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”结尾的都是字符流。

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

    • 文件专属:

      • java.io.FileInputStream(掌握)

        • 文件字节输入流,万能的,任何类型的文件都可以采用这个流来读。

        • 字节的方式,完成输入的操作,完成读的操作(硬盘—>内存)

        • 一些基本方法:

          • int read(byte[ ] b)
            一次最多读取b.length 个字节
            减少硬盘和内存的交互,提高程序的执行效率
            往byte[]数组中读。
          • int available() :返回流当中的剩余的没有读到的字节数量
          • long skip(long n): 跳过几个字节不读。
      • java.io.FileOutputStream(掌握)

        • 文件字节输出流,负责写
          从内存到硬盘
      • java.io.FileReader

        • 文件字符输入流,只能读取普通文本。
          读取文本内容时,比较方便,快捷。
      • java.io.FileWriter

        • 文件字符输出流,写。
          只能输出普通文本。
    • 转换流:(将字节流转换成字符流)

      • java.io.InputStreamReader

        • 当一个流的构造方法中需要一个流的时候,这个被传进来的流叫做:节点流
          外部负责包装的这个流,叫做:包装流,还有一个名字叫做:处理流
        • 通过转换流转换(InputStreamReader将字节流转换成字符流。)
        • 这个构造方法只能传一个字符流,不能传字节流
      • java.io.OutputStreamWriter

    • 缓冲流专属:

      • java.io.BufferedReader

        • 带有缓冲区的字符输入流
          使用这个流的时候不需要自定义char数组,或者说不需要自定义byte数组,自带缓冲
      • java.io.BufferedWriter

        • 带有缓存的字符输出流
      • java.io.BufferedInputStream

      • java.io.BufferedOutputStream

    • 数据流专属:

      • java.io.DataInputStream

        • 数据字节输入流
          DataOutputStream写的文件,只能使用DataInputStream去读,并且读的时候需要提前知道写入的顺序。
          读的顺序需要和写的顺序一致,才可以正常取出数据。
      • java.io.DataOutputStream

        • 数据专属的流。
          这个流可以将数据连同数据的类型一并写入文件
          注意:这个文件不是普通的文件(这个文件使用记事本打不开)
    • 标准输出流:

      • java.io.PrintWriter

      • java.io.PrintStream(掌握)

        • 标准的字节输出流,默认输出到控制台

        • 标准输出流不需要手动close()关闭

        • //标准输出流不再指向控制台,指向指定文件
          PrintStream printStream = new PrintStream(new FileOutputStream(“log”));

          //修改输出方向,将输出的方向修改为“指定文件”
          System.setOut(printStream);

    • 对象专属流:

      • java.io.ObjectInputStream(掌握)

        • 序列化【Serialize】
      • java.io.ObjectOutputStream(掌握)

        • 反序列化【DeSerialize】
  • 序列化与反序列化:

    • 序列化【Serialize】:

      • java对象存储到文件中,将java对象的状态保存下来的过程。
      • 拆分对象。
      • java.io.ObjectOutputStream(掌握)
    • 反序列化【DeSerialize】:

      • 将硬盘上的数据重新恢复到内存当中,恢复成java对象。
      • 组装对象。
      • java.io.ObjectInputStream(掌握)
    • 参与序列化和反序列化的对象,必须实现Serializable接口。

    • 注意:

      • Serializable接口只是一个标志接口:
        public interface Serializable {
        }

        • 这个接口当中什么代码都没有。

        • 起到标识的作用,标志的作用,java虚拟机看到这个类实现了这个接口,可能会对这个类进行特殊待遇。

        • Serializable这个标志接口是给java虚拟机参考的,java虚拟机看到这个接口后,会为该类自动生成一个序列化版本号。

        • 结论:

          • 凡是一个类实现了Serializable接口,建议给该类提供一个固定不变的序列化版本号。这样,以后这个类即使代码修改了,但是版本号不变,java虚拟机会认为是同一个类。
      • 源代码改动之后,需要重新编译,编译之后生成了全新的字节码文件。并且class文件再次运行的时候,java虚拟机生成的序列号版本号也会发生相应的改变。

        • 这种自动生成的序列化版本号的缺点是:

          • 一旦代码确定之后,不能进行后续的修改,因为只要修改,必然会重新编译,此时会生成全新的序列化版本号,这个时候java虚拟机会认为这是一个全新的类。
    • 可以一次序列多个对象,将对象放到集合当中。

    • transient关键字表示游离的,不参与序列化

    • java语言中采用什么机制来区分类:

      • 首先通过类名进行比对,如果类名不一样,肯定不是同一个类。
      • 如果类名一样,再靠序列化版本号进行区分。

多线程:

  • 什么是进程、什么是线程:

    • 进程是一个应用程序(一个进程就是一个软件)。
    • 线程是一个进程中的执行场景/执行单元。
  • 进程和线程的关系:

    • 进程可以看做是现实生活中的公司。

    • 线程可以看做公司当中的某个员工。

    • 注意:

      • 进程A和进程B的内存独立不共享。

      • 线程A和线程B【在java语言中:】

        • 线程A和线程B,堆内存和方法区内存共享。
        • 但是栈内存独立,一个线程一个栈。
  • 实现线程有两种方式:

    • 编写一个类,直接继承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();

    • 注意:

      • 第二种方式实现接口比较常用,因为一个类实现了接口,它还可以去继承其它的类,更灵活。
  • 关于线程对象:

    • 怎么创建线程对象:

      • new
    • 怎么获取当前线程对象?

      • Thread t = Thread.currentThread();【static Thread currentThread();】
        返回值t就是当前线程。
    • 获取线程对象的名字?

      • String name = 线程对象.getName();
    • 修改线程对象的名字?

      • 线程对象.setName(“线程名字”);
    • 当线程没有设置名的时候,默认名字:

      • Thread-0
        Thread-1
        Thread-2
        Thread-3
  • 怎么启动线程:

    • 调用线程对象的start()方法。

      • start()方法的作用是:启动一个分支线程,在JVM中开辟一个新的栈空间,这段代码任务完成之后,瞬间就结束了。
      • 这段代码的任务只是为了开启一个新的栈空间,只要新的栈空间开出来,start()方法就结束了,线程就启动成功了。
      • 启动成功的线程会自动调用run方法,并且run方法在分支栈的底部(压栈)。
      • run方法在分支栈的底部,main方法在主栈的底部,run和main 是平级的。
  • 线程的生命周期:

    • 新建状态

      • 刚new出来的线程对象。
    • 就绪状态

      • 就绪状态的线程又叫可运行状态,表示当前的线程具有抢夺CPU时间片的权利(CPU时间片就是执行权)。当一个线程抢夺到CPU时间片之后,就开始执行run方法,run方法的开始执行标志着线程进入运行状态。
    • 运行状态

      • run方法的开始执行标志着这个线程进入运行状态,当之前占有的CPU时间片用完之后,会重新回到就绪状态继续抢夺CPU时间片,当再次抢夺到CPU时间之后,会重新进入run方法接着上一次的代码继续往下执行。
    • 阻塞状态

      • 当一个线程遇到阻塞事件,例如接收用户键盘输入,或者sleep方法等,此时线程会进入阻塞状态,阻塞状态的线程会放弃之前占有的CPU时间片。
      • 之前的时间片没了,需要再次回到就绪状态,抢夺CPU时间片。
    • 死亡状态

      • run方法执行结束。
  • 关于线程的sleep方法:static void sleep(long millis)

    • 静态方法:Thread sleep(long millis)

    • 参数是毫秒

    • 作用:让当前线程进入休眠,进入“阻塞状态”,放弃占有CPU时间片,让给其他线程使用
      这行代码出现在A线程中,A线程就会进入休眠。
      这行代码出现在B线程中,B线程就会进入休眠。

    • Thread.sleep()方法,可以做到这样的效果
      间隔特定的时间,去执行一段特定的代码,每隔多久执行一次。

  • 终止线程的睡眠:

    • 线程对象.interrupt();
    • 这种中断睡眠的方式依靠了java的异常处理机制。
  • 关于线程的调度:

    • 常见的线程调度模型

      • 抢占式调度模型:

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

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

      • 实例方法:

        • void setPriority(int newPriority) 设置线程的优先级
          int getPriority() 获取线程优先级
          最低优先级1
          默认优先级是5
          最高优先级10
          优先级比较高的获取CPU时间片可能会多一些。(但也不完全是,大概率是多的。)
        • void join()
          合并线程
          class MyThread1 extends Thread {
          public void doSome(){
          MyThread2 t = new MyThread2();
          t.join(); // 当前线程进入阻塞,t线程执行,直到t线程结束。当前线程才可以继续。
          }
          }

        class MyThread2 extends Thread{

        }

      • 静态方法:

        • static void yield() 让位方法
          暂停当前正在执行的线程对象,并执行其他线程
          yield()方法不是阻塞方法。让当前线程让位,让给其它线程使用。
          yield()方法的执行会让当前线程从“运行状态”回到“就绪状态”。
          注意:在回到就绪之后,有可能还会再次抢到。
  • 线程安全:

    • 什么时候数据在多线程并发的环境下会存在安全问题

      • 条件1;

        • 多线程并发。
      • 条件2:

        • 有共享数据。
      • 条件3:

        • 共享数据有修改的行为。
      • 满足以上3个条件之后,就会存在线程安全问题。

    • 怎么解决线程安全问题【当多线程并发的环境下,有共享数据,并且这个数据还会被修改,此时就存在线程安全问题,怎么解决这个问题】

      • 线程排队执行。(不能并发)。

      • 用排队执行解决线程安全问题。

      • 这种机制被称为:线程同步机制。【专业术语叫做:线程同步,实际上就是线程不能并发了,线程必须排队行。】

      • 线程同步就是线程排队了,线程排队了就会牺牲一部分效率,没办法,数据安全第一位,只有数据安全了,我们才可以谈效率。数据不安全,没有效率的事儿。

        • 异步编程模型:

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

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

      • 线程同步机制的语法是:

        • 第一种:同步代码块
          灵活
          synchronized(线程共享对象){
          同步代码块;
          }
        • 第二种:在实例方法上使用synchronized
          表示共享对象一定是this
          并且同步代码块是整个方法体。
        • 第三种:在静态方法上使用synchronized
          表示找类锁。
          类锁永远只有1把。
          就算创建了100个对象,那类锁也只有一把。
        • 对象锁:1个对象1把锁,100个对象100把锁。
          类锁:100个对象,也可能只是1把类锁。
      • synchronized(){
        //线程同步代码块
        }
        synchronized()传的数据是多线程共享的数据,才能达到多线程排队

      • 遇到synchronized关键字时,找共享对象的对象锁线程进入锁池找共享对象的对象锁的时候,会释放之前占有的CPU时间片,有可能找到了,有可能没找到,入股饿哦找到了会进入就绪状态继续抢夺CPU时间片。

    • java中的三大变量:

      • 实例变量:在堆内存中

        • 堆只有一个。
      • 静态变量:在方法区中

        • 方法区只有一个。
      • 局部变量:在栈内存中

      • 以上三大变量中:

        • 局部变量永远都不会存在线程安全问题。
        • 因为局部变量不共享(一个线程一个栈)。
        • 局部变量在栈中,所以局部变量永远都不会共享。
        • 堆和方法区都是多线程共享的,所以可能存在线程安全问题。
        • 局部变量+常量:不会有线程安全问题。
          成员变量:可能会有线程安全问题。
      • 如果使用局部变量的话:

        • 建议使用:StringBuilder。
          因为局部变量不存在线程安全问题。选择StringBuilder。
          StringBuffer效率比较低。
        • ArrayList是非线程安全的。
          Vector是线程安全的。
          HashMap HashSet是非线程安全的。
          Hashtable是线程安全的。
    • 以后开发中怎么解决线程安全问题:

      • 是一上来就选择线程同步吗?synchronized

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

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

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

  • 守护线程:

    • java语言中线程分为两大类:

      • 用户线程
      • 守护线程(后台线程)
      • 其中具有代表性的就是:垃圾回收线程(守护线程)。
    • 守护线程的特点:

      • 一般守护线程是一个死循环,所有的用户线程只要结束,守护线程自动结束。
    • 守护线程用在什么地方:

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

      • 主线程main方法是一个用户线程。
    • 语法格式:

      • 线程对象.setDaemon(true);
  • 定时器:

    • 作用:

      • 间隔特定的时间,执行特定的程序。
    • 在实际的开发中,每隔多久执行一段特定的程序,这种需求是很常见的,那么在java中其实可以采用多种方式实现:

      • 可以使用sleep方法,睡眠,设置睡眠时间,没到这个时间点醒来,执行任务。这种方式是最原始的定时器。(比较low)
      • 在java的类库中已经写好了一个定时器:java.util.Timer,可以直接拿来用。不过,这种方式在目前的开发中也很少用,因为现在有很多高级框架都是支持定时任务的。
      • 在实际的开发中,目前使用较多的是Spring框架中提供的SpringTask框架,这个框架只要进行简单的配置,就可以完成定时器的任务。
  • 实现线程的第三种方式:FutureTask方法,实现Callable接口。

    • 这种方式实现的线程可以获取线程的返回值。
      之前讲解的那两种方式是无法获取线程返回值的,因为run方法返回void。
    • 优点:可以获取到线程的执行结果。
    • 缺点:效率比较低,在获取t线程执行结果的时候,当前线程受阻塞,效率较低。
  • 关于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对象上处于等待的所有线程。
    • wait和notify方法建立在synchronized线程同步的基础之上的。

      • 重点:

        • o.wait()方法会让正在o对象上活动的当前线程进入等待状态,并且释放之前占有的o对象的锁。
        • o.notify()方法只会通知,不会释放之前占有的o对象的锁。

反射机制:

  • 反射机制的作用:

    • 通过java语言中的反射机制可以操作字节码文件。
      优点类似于黑客。(可以读和修改字节码文件。)
      通过反射机制可以操作代码片段。(class文件。)
    • 打破封装(反射机制的缺点:打破封装,可能会受到攻击)
      Field 变量名 = 设置类的变量名.getDeclaredField(“属性名”);
      变量名 .setAccessible(true);
  • 反射机制的相关类在哪个包:

    • java.lang.reflect.*;
  • 反射机制相关的重要的类:

    • java.lang.Class:

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

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

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

      • 代表字节码中的属性字节码。代表类中的成员变量(静态变量+实例变量)。
  • 在java中获取Class的三种方式:

    • Class c = Class.forName(“完整类名”);
    • Class c = 对象.getClass();
    • Class c = int.class;
      Class c = String.class;
  • 获取了Class之后,可以调用无参数构造方法来实例化对象

    • //c代表的就是日期Date类型
      Class c = Class.forName(“java.util.Date”);
    • //实例化一个Date日期类型的对象
      Object obj = c.newInstance();
    • 一定要注意:
      newInstance()底层调用的是该类型的无参数构造方法。
      如果没有这个无参数构造方法会出现"实例化"异常。
  • 如果你只想让一个类的“静态代码块”执行的话:

    • Class.forName(“该类的类名”);
      这样类就加载,类加载的时候,静态代码块执行!!!!
    • 在这里,对该方法的返回值不感兴趣,主要是为了使用“类加载”这个动作。
  • 关于JDK自带的类加载器:

    • 什么是类加载器:

      • 专门负责加载类的命令/工具。
        ClassLoadder
    • JDK中自带的三个类加载器:

      • 启动类加载器:rt.jar
      • 扩展类加载器:ext/*.jar
      • 应用类加载器:classpath
    • 代码在开始执行之前,会将所需要类全部加载到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中的类。
    • java中为了保证类加载的安全,使用了双亲委派机制。

      • 优先从启动类加载器中加载,这个称为“父”
        “父”无法加载到,再从扩展类加载器中加载,这个称为“母”。双亲委派。如果都加载不到,才会考虑从应用类加载器中加载。直到加载到为止。

关于路径问题:

  • 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”);

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

  • IO+Properties

    • 以后经常改变的数据,可以单独写到一个文件内,使用程序动态读取。将来只需要修改这个文件的内容,java代码不需要改动,不需要重新编译,服务器也不需要重启,就可以拿到动态的信息。

    • 当配置文件中的内容格式是:
      key1 = value
      key2 = value
      的时候,我们把这种配置文件叫做属性配置文件。

    • java规范中有要求:

      • 属性配置文件建议以.properties 结尾,但是不是必须的。
  • ResourceBundle bundle = ResourceBundle.getBundle(“com/…文件路径”);
    String value = bundle.getString(key);

  • 要求:

    • 第一这个文件必须在类路径下
    • 第二这个文件必须是以.properties结尾。

注解:

  • 注解,或者叫做注释类型,英文单词是:Annotation

  • 注解Annotation是一种引用数据类型。编译之后也是生成xxx.class文件。

  • 怎么自定义注解呢?语法格式?

    • [修饰符列表] @interface 注解类型名{

      }

  • 注解怎么使用,用在什么地方?

    • 第一:注解使用时的语法格式是:
      @注解类型名
    • 第二:注解可以出现在类上、属性上、方法上、变量上等…
      注解还可以出现在注解类型上。
  • JDK内置了哪些注解

    • java.lang包下的注释类型:

      • 掌握:

        • Deprecated 用 @Deprecated 注释的程序元素,不鼓励程序员使用这样的元素,通常是因为它很危险或存在更好的选择。

          • Deprecated这个注解标注的元素已过时。
          • 这个注解主要是向其它程序员传达一个信息,告知已过时,有更好的解决方案存在。
        • Override 表示一个方法声明打算重写超类中的另一个方法声明。

          • @Override这个注解只能注解方法。
          • @Override这个注解是给编泽器参考的,和运行阶段没有关系。
          • 凡是java中的方法带有这个注解的,编译器都会进行编译检查,如果这个方法不是重写父类的方法,编译器报错。
      • 不需要掌握:

        • SuppressWarnings 指示应该在注释元素(以及包含在该注释元素中的所有程序元素)中取消显示指定的编译器警告。
  • 元注解

    • 什么是元注解

      • 用来标注“注解类型”的“注解”,称为元注解。
    • 常见的元注解有哪些

      • Target
      • Retention
    • 关于Target注解:

      • 这是一个元注解,用来标注“注解类型”的“注解”
        这个Target注解用来标注“被标注的注解”可以出现在哪些位置上。
      • @Target(ElementType.METHOD):表示“被标注的注解”只能出现在方法上。
      • @Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, MODULE, PARAMETER, TYPE})
        表示该注解可以出现在:
        构造方法上
        字段上
        局部变量上
        方法上

        类上…
    • 关于Retention注解:

      • 这是一个元注解,用来标注“注解类型”的“注解”
        这个Retention注解用来标注“被标注的注解”最终保存在哪里。

      • @Retention(RetentionPolicy.SOURCE):表示该注解只被保留在java源文件中。

      • @Retention(RetentionPolicy.CLASS):表示该注解被保存在class文件中。

      • @Retention(RetentionPolicy.RUNTIME):表示该注解被保存在class文件中,并且可以被反射机制所读取。

      • Retention的源代码

        • //元注解
          public @interface Retention {
          //属性
          RetentionPolicy value();
          }

      RetentionPolicy的源代码:
      public enum RetentionPolicy {
      SOURCE,
      CLASS,
      RUNTIME
      }

      //@Retention(value=RetentionPolicy.RUNTIME)
      @Retention(RetentionPolicy.RUNTIME)
      public @interface MyAnnotation{}
      
  • 我们通常在注解当中可以定义属性。

    • 语法:

      • 属性类型 属性名( );
    • 如果一个注解当中有属性,那么必须给属性赋值。

      • @自定义注解名(属性名=属性值,属性名 = 属性值,属性名 = 属性值…)
      • 除非该属性使用default指定了默认值。
    • 如果一个注解的属性的名字是value的话,在使用的时候,该属性名可以省略。

    • 注解当中的属性是哪些类型:

      • byte short int long float double boolean char String Class 枚举类型 以及以上每一种的数组形式。
  • 注解在开发中的作用:

    • 需求:
      假设有这样一个注解,叫做:@Id
      这个注解只能出现在类上面,当这个类上有这个注解的时候,要求这个类中必须有一个int类型的id属性。如果没有这个属性就报异常。如果有这个属性则正常执行!
    • 注解在程序当中等同于一种标记。
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值