基础语法
基础语法
Java是美国Sun公司于1995年推出的(面向对象)高级编程语言
Java是美国Sun公司于1995年推出的(面向对象)高级编程语言
Java是美国Sun公司于1995年推出的(面向对象)高级编程语言
Java是美国Sun公司于1995年推出的(面向对象)高级编程语言
JRE是Java运行环境,包含了JVM和运行Java程序所需的核心类库,是用来运行Java程序的JRE是Java运行环境,包含了JVM和运行Java程序所需的核心类库,是用来运行Java程序的JRE是Java运行环境,包含了JVM和运行Java程序所需的核心类库,是用来运行Java程序的
JRE是Java运行环JRE是Java运行环境,包含了JVM和运行Java程序所需的核心类库,是用来运行Java程序的JRE是Java运行环境,包含了JVM和运行Java程序所需的核心类库,是用来运行Java程序的JRE是Java运行环境,包含了JVM和运行Java程序所需的核心类库,是用来运行Java程序的境,包含了JVM和运行Java程序所需的核心类库,是用来运行Java程序的
Java、JDK、JRE、JVM
- Java是美国Sun公司于1995年推出的(面向对象)高级编程语言
- JDK是Java开发工具包,包含了JRE和Java开发工具,是用来编译和调试Java程序的
- JRE是Java运行环境,包含了JVM和运行Java程序所需的核心类库,是用来运行Java程序的
- JVM是Java虚拟机,一个可以运行Java代码的虚拟计算机
关键字、标识符、注释
- 关键字是程序中已经定义好的、具有特殊含义的单词
- 标识符是程序中我们自己定义的内容,如类名、方法名、变量名等
- 标识符可包含26个大小写字母、0-9数字、_以及$、不能以数字开头、不能是关键字
- 命名规则为:
- 项目名和包名全小写、常量名全大写且单词间用_连接
- 文件名和类名使用大驼峰、方法名和变量名使用小驼峰
- 注释是对代码的解释说明,被注释的代码不会被编译
- // 单行注释、 /* 多行注释 */、 /** 文档注释 */
变量、常量、直接量
- 变量是在程序运行过程中其值可以改变的数据
- 常量是在程序运行过程中其值固定不变的数据,通常使用final修饰
- 直接量是在程序中通过源码直接给出的值
- 定义变量的三要素:数据类型、变量名、数据值
数据类型
- Java中数据类型可分为基本数据类型和引用数据类型
- 基本数据类型可分为byte、short、int、long、float、double、char、boolean
- 引用数据类型可分为类、接口、枚举、数组等
- 整数直接量默认类型为int,浮点数直接量默认类型为double
- 若想表示long类型的直接量需在直接量后面加上L,float同理,加上F即可
- 浮点数类型数据在运算时可能会存在误差,float、double一般可以精确到7位、15位有效数字
- Java中char类型采用的是Unicode字符集编码,而Unicode中0~127是ASCII编码表
- 常用的ASCII有:10-换行、32-空格、48-0、65-A、97-a
- 常用的转义字符有:\n-换行、\t-横向制表、\"-双引号、\\-反斜杠
- 基本数据类型范围从小到大排序为:byte --> short/char --> int --> long --> float --> double
- 在数据范围从小到大进行赋值时会发生自动类型转换
- 在数据范围从大到小进行赋值时需进行强制类型转换,即在需要强转的数据前加上(数据类型)即可
- 强转可能会发生精度损失、数据溢出,需谨慎使用
- byte/short/char类型在运算时都会被提升为int类型再进行计算
- short s = 128; byte b = (byte) s; // 减1取反 -128
- short s = 128; s = s + 128; // error
- short s = 128; s += 128; // 等价于 s = (short) (s + 1024);
运算符
- 算术运算符
- 加法+、减法-、乘法*、除法/、求模%、自增++、自减--
- 在算数运算过程中如有不同类型的数据进行计算,那么运算结果的数据类型将是数据范围大的数据类型
- 两个整数相除只保留结果的整数部分,若希望保留小数部分可将其中一个整数强转为浮点数即可
- 在自增自减运算过程中如果是前自增就先加后用,后自增则先用后加,自减同理
- 运算符+既可作为数值类型的相加运算,也可作为字符串连接符
- 如果加号两边有一个数据是字符串类型,则加号就会被当作字符串连接符处理
- 赋值运算符
- 等于=、加等+=、减等-=、乘等*=、除等/=、模等%=
- 直接量不能进行赋值,在赋值运算中是隐含着类型转换的(编译器优化)
- 比较运算符
- 等等==、大于>、小于<、大等>=、小等<=、不等!=
- 比较运算的结果一定是一个布尔值,成立为true,反之为false
- 逻辑运算符
- 逻辑与&&、逻辑或||、逻辑非!
- &&全真为真、||全假为假、!非真即假,逻辑运算只能用于布尔值间
- &&和||存在短路特性,&&左边表达式为假时右边表达式不执行,||左边表达式为真时右边表达式不执行
- 三元运算符
- 表达式 ? 结果1 : 结果2;
- 三元运算符需保证所有表达式都符合左侧数据类型的要求,而且其结果必须使用
- 移位运算符
- 左移<<、右移>>、逻辑右移>>>
- 左移运算,将数据二进制位向左移动,右边补0
- 右移运算,将数据二进制位向右移动,左边补符号位
- 逻辑右移,将数据二进制位向右移动,左边补0
- 左移N位的结果为原值乘以2的N次方,右移N位的结果为原值除以2的N次方
- 按位运算符
- 按位与&、按位或|、按位取反~、按位异或^
- &全1为1、|全0为0、~非1即0、^相同为0、&和|不含短路特性
流程控制
- 顺序结构
- 顺序结构是最简单的程序结构,其执行顺序自上而下,依次执行
- 选择结构
- 选择结构可分为单分支if、双分支if else、多分支if else if else以及switch case
- switch()中支持的数据类型可以是byte、short、chár、int
- Java5开始支持枚举类型、Java7开始支持String类型
- 在switch结构中多个case后面的数据不可重复
- 循环结构
- 循环结构可分为for循环、while循环、do while循环等
- 如循环条件从未满足过,for循环体和while循环体一次都不会执行,do while循环体会至少执行一次
- 若在for循环和while循环后加个分号时:
- for循环的循环体在不报错的情况下只会执行一次
- while循环则会因为步进表达式的不存在而陷入死循环中
- 明确循环次数或范围确定的话多用for循环,明确循环条件多用while循环
- break、continue、标号
- break用于switch中的作用为终止switch,用于循环中的作用为终止循环
- continue用于循环中的作用为跳过本次循环而马上开始下次循环
- 在嵌套循环中break终止的是与其最近的循环,如需终止外层循环可标号解决,continue同理
数组
- 数组是一种可以同时存放多个相同数据类型元素的容器,数组的长度在程序运行过程中不可改变
- 如果不确定数组中的具体内容就动态初始化数组,即指定数组长度,否则就静态初始化数组,即指定数组内容
- 动态初始化创建的数组中元素会有默认值,0、0.0、false、null
- 静态初始化创建的数组其实也有默认值的过程,只不过系统马上将其默认值替换成了大括号内的具体内容
- 二维数组中的每个元素其实就是一个一维数组,而一维数组中的每个元素才是数据内容
面向对象
设计思想
- 面向对象是一种程序设计思想,对象泛指现实中的一切事物,每种事物都具备自己的属性和行为
- 也就是在编程时参照现实中的事物并将事物的属性特征和行为特征抽象出来描述成计算机事件的设计思想
- 其区别于面向过程思想强调的是通过调用对象来实现功能,而不是自己一步步去操作实现
- 面向对象是一种更符合我们思考习惯的思想,它可以将复杂的事情简单化,并将我们从执行者变成指挥者
- 面向对象的三大特征为:封装、继承、多态
类、对象、属性、行为
- 类可以看成是一类事物的描述,是抽象的,用事物的属性特征和行为特征来描述该类事物
- 对象则是一类事物的具体体现,是具体的,具备该类事物的属性和行为
- 万物皆对象,类是对象的模版,对象是类的实体
- 属性是该类事物的状态信息,也就是定义在类中的变量,也叫成员变量
- 对象创建后成员变量会自动拥有默认值,0、0.0、false、null
- 行为是该类事物能够做什么,也就是定义在类中的方法,也叫成员方法
- 方法的本质其实就是将通用的代码抽取出来形成一个单独的功能,需要使用时调用即可
- 这样既解决了代码的复用性,也解决了代码冗余的现象
- 方法定义的先后顺序无所谓,方法定义后需调用后才会执行
- 方法的声明包括返回值类型、方法名、形参列表等
- 一个方法的形参列表中最多只能声明一个可变参数,且可变参数需放在形参列表的末尾
- 当方法的参数列表数据类型已经确定,但参数列表的个数不确定,就可以使用可变参数
- 可变参数的底层其实就是一个数组,根据传参的个数来创建不同长度的数组来存储这些数据
构造方法、匿名对象
- 构造方法是专门用来创建对象的(实例化、引用)
- 当我们通过new关键字来创建对象时其实就是在调用构造方法来实现成员变量的初始化操作
- 在我们不手写构造方法的情况下默认隐含着一个无参构造方法
- 构造方法的名称必须与所在类的类名完全相同,且构造方法无需返回值
- 匿名对象就是只有等号右边的对象,没有左边的数据类型和引用变量名
- 如果确定一个对象只需使用唯一的一次,那么匿名对象就是个不错的选择
Overload、Override
- Overload方法重载
- 判断方法是否构成重载的核心就是调用方法时能否加以区分
- 方法的重载与形参的个数、类型、顺序有关,与形参变量名、返回值类型无关
- 方法重载的实际意义在于调用者只需记住一个方法名即可调用不同版本的方法来实现各种不同的功能
- Override方法重写
- 当父类继承下来的方法无法满足子类需求时,就可以在子类中对父类继承下来的方法进行覆盖重写
- 对方法重写时必须保证父子类之间方法名称相同、返回值以及参数列表也相同
- 重写时子类方法的返回值类型不能大于父类的返回值类型
- 重写时子类方法的访问权限修饰符范围不能小于父类的访问权限修饰符范围
- 重写时子类方法不能抛出大于父类方法所抛出的异常
访问权限修饰符、Package
- 访问权限修饰符可用来修饰类、成员方法、成员变量等,用于控制对其访问的权限
- public公共权限,可被任意类访问
- protected受保护权限,可被不同包子类访问
- default默认权限,可被同包访问
- private私有权限,可被同类访问
- 我们在定义类时需指定类的名称,但如果仅将类名作为类的唯一标识将不可避免地出现命名冲突的问题
- 在Java中可以用包的概念来解决该问题
- 定义包的规范多为公司域名反写.项目名.模块名.类名
- 使用package关键字来定义包,使用import关键字来导入包
- Java5开始也可直接导入包中的静态成员
封装、JavaBean
- 封装就是隐藏对象的属性和实现细节,仅对外公开接口,通过封装可以对对象属性进行合理化判断
- 实现封装需先私有化变量,然后提供getter/setter方法或再对属性数据进行合理化判断
- 对于boolean类型的成员变量来说,其getter方法需写成isXxx()的形式
- JavaBean是用Java编写的可重用组件,是Java编写类的一种规范
- JavaBean的本质其实就是符合某些标准的类
- 而最低标准为这个类必须是公共的、至少有一个无参构造器、类中属性都有对应的getter/setter方法
继承
- 继承是多态的前提,没有继承就没有多态,继承主要解决的问题就是共性抽取
- Java只能单继承,即一个类的直接父类只能有一个,但一个父类可以拥有多个子类
- Java可以多级继承,即父类还可以有父类
- 继承关系中,子类除了可以继承父类中所有可继承的内容,还可以拥有自己的专有内容
- “子类就是一个父类”,也就是说子类可以被当成父类看待
- 无论是访问成员变量还是成员方法,如果没有都是向上找父类,绝不会向下找子类
Static、Final
- 使用static关键字修饰的成员将不再属于对象,而是由对象层级提升为类层级
- 也就是整个类只有一份并被共享,随类加载,与是否创建对象无关
- 被static修饰的成员可使用引用.的方式访问,但推荐使用类名.的方式
- 在静态成员方法中只能访问静态成员而不能访问非静态成员,此时可能还没创建对象
- 在非静态成员中既能访问静态成员也能访问非静态成员,静态成员被所有对象共享
- 只有隶属于类层级并被所有对象共享的成员才可以使用static关键字修饰(不能滥用)
- 静态方法中不能使用this,因为this代表当前对象,而静态成员属于类,不属于某个对象
- 一旦使用final关键字进行修饰则说明不可改变
- final修饰成员变量后,必须立马赋值,否则编译报错
- final修饰基本数据类型后,其值为常量且不可修改
- final修饰引用数据类型后,其引用的地址值不可修改
- final修饰成员方法后,该方法将成为最终方法,可以被子类继承但无法重写此方法
- final修饰一个类后,该类将成为最终类,无法被继承,即“断子绝孙类”
This、Super
- this代表所在类的当前对象引用,是一个地址值,用于访问本类的内容
- 成员被哪个对象调用,成员中的this就代表哪个对象,即谁在调用,this就代表谁
- 在构造方法或成员方法中访问本类成员时,编译器会隐含地加上this.前缀
- 在本类的构造方法中访问本类的其它构造方法时,this()必须是第一条语句
- super是指向父类的引用,用于访问父类的内容
- 在子类的成员方法中可使用super.的方式访问父类的成员
- 在子类的构造方法中可以访问父类的构造方法
- 子类可以通过super()来调用父类的重载构造,super()必须是第一条语句
- 子类的构造方法中隐含着一个super()调用,所以一定是先调用父类的构造方法再执行子类的构造
- 子类必须调用父类构造方法,不手写则默认调用隐含着的super()
抽象类、抽象方法
- 抽象类就是用abstract关键字修饰的类,抽象类中可以没有抽象方法,但有抽象方法的类一定是抽象类
- 抽象方法就是用abstract关键字修饰且没有方法体的方法
- 抽象类不能传创建对象,可通过子类继承抽象父类的方式来创建
- 子类要么覆盖重写抽象父类中所有的抽象方法,要么该子类也必须是一个抽象类
- 对于类/方法来说,abstract和final不能同时使用
接口
- 接口(interface)是一种引用数据类型,最重要的内容就是其中的抽象方法
- 接口中的抽象方法默认也必须得使用public abstract修饰
- 接口不能直接使用,必须有一个实现类来实现该接口,接口的实现类必须覆盖重写接口中所有的抽象方法
- Java7开始接口可包含常量 public static final
- Java8开始接口可包含默认方法和静态方法
- 接口中的默认方法可以解决接口升级的问题,可通过接口实现类对象直接调用,可被接口实现类进行覆盖重写
- 接口中的静态方法不能通过接口实现类的对象来调用接口中的静态方法,可通过接口名称直接调用其静态方法
- Java9开始接口可包含私有方法
- 普通私有方法可以解决多个默认方法之间重复代码的问题
- 静态私有方法则可以解决多个静态方法之间重复代码的问题,私有方法只有接口自己才能调用
- 接口是没有静态代码块或者构造方法的
- 一个类的直接父类是唯一的,但是一个类可以同时实现多个接口
- 如果实现类所实现的多个接口中存在重复的抽象方法,那么只需要覆盖重写一次即可
- 如果实现类没有覆盖重写接口中所有的抽象方法,那么这个实现类自己就必须是抽象类
- 如果实现类实现的多个接口中存在重复的默认方法,那么实现类一定要对冲突的默认方法进行覆盖重写
- 如果一个类的直接父类的方法和接口中的默认方法产生了冲突,优先使用父类的方法
- 类与类之间是单继承的,直接父类只有一个
- 类与接口之间是多实现的,一个类可以实现多个接口
- 接口与接口之间是多继承的
- 多个父接口中的抽象方法如果重复是没关系的,如果多个父接口中的默认方法重复
- 那么子接口必须进行默认方法的覆盖重写,而且要带着default关键字
多态
- 继承或接口的实现是多态的前提,一句话就是父类引用指向子类对象
- 访问成员变量时编译运行都看左,访问成员方法时编译看左运行看右
- 对象的向上转型其实就是多态的写法,将子类对象当成父类看待使用
- 向上转型一定是安全的,从小范围转向了大范围,但对象一旦向上转型为父类,那么就无法调用子类原本特有的内容了
- 解决方法就是用对象的向下转型,也就是还原动作,就是将父类对象还原成为本来的子类对象
- 向下转型必须保证对象本来创建的时候就是这个对象,才能向下转型成功,否则就会抛出ClassCastException
- 如何才能知道一个父类引用的对象原本就是一个什么子类?使用(对象名 instanceof 类名称)
- 可得到一个boolean值结果,也就是判断前面的对象能不能做后面类型的实例
内部类
- 内部类就是在一个事物的内部包含另一个事物,即一个类的内部包含另一个类
- 成员内部类是和成员方法并排的类
- 使用时内用外可随意访问,外用内则需要内部类对象
- 使用成员内部类的方式可分为直接方式和间接方式
- 直接方式为:new 外部类名().new 内部类名();
- 间接方式为:外部类方法中使用内部类,然后调用外部类方法
- 局部内部类是定义在方法内部的类
- 只有当前所属的方法才能使用,局部内部类如果希望访问所在方法的局部变量,那么这个局部变量必须被final关键字修饰
- Java8开始只要局部变量事实不变,那么final关键字可省略
- 匿名内部类
- 若接口的实现类或继承自父类的子类只需使用唯一一次,那么使用匿名内部类就是个不错的选择
- 匿名内部类是省略了实现类/子类名称,匿名对象是省略了对象名称
new出来的对象在堆内存中,局部变量是跟着方法走的,在栈内存中,方法运行结束后会立刻出栈,局部变脸就会立刻消失,但new出来的对象会在堆中持续存在,直到被垃圾回收才会消失。
枚举
注解
- 注解是用来说明程序的,是给计算机看的,而注释是用来描述程序的,是给人看的
- 注解(Annotation)也叫元数据,是一种代码级别的说明
- 是Java5开始引入的新特性,与类、接口、枚举是在同一层次
- 注解可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明
- 注解可以用来编译检查、生成API文档以及代码分析(使用反射)
- 注解可以给编译器和解析程序使用,注解不是程序的一部分,可以理解为注解就是一个标签
- 注解本质其实就是一个接口,只不过该接口默认继承Annotation接口
- public interface XxxXxx extends java.lang.annotation.Annotation {}
- 预定义注解
- @Override 检测是否为有效的方法重写
- @Deprecated 将方法标注为已过时
- @SuppressWarnings("all") 压制警告
- 自定义注解
- @元注解 public @interface 注解名 { 属性列表; }
- 属性
- 注解中属性(接口中抽象方法)的返回值可以定义为基本数据类型、String、枚举、注解以及数组
- 注解中如果定义了属性的话,在使用该注解时就需要给属性赋值
- 在定义属性时使用default关键字给属性设置默认初始值,在使用该注解时可不进行属性的赋值
- 只有一个属性需要赋值且熟悉名称为value时,value可省略直接定义即可
- 数组在赋值时使用{}包裹,若数组中只有一个值,{}可省略
- 元注解
- 用于描述注解的注解
- @Target 注解的作用域
- @Retention 注解被保留的阶段
- @Documented 首付被抽取到AP文档
- @Inherited 是否被子类继承
- 解析注解
- 解析(使用)注解可获取注解中定义的属性值
- Class对象 Class、Method、Field
- Class对象名.getAnnotation(注解Class对象) 获取指定注解对象,注释接口子类的实现对象
```
#### 常用类库
- Java中数据类型可分为基本数据类型和引用数据类型
- 基本数据类型可分为byte、short、int、long、float、double、char、boolean
- 引用数据类型可分为类、接口、枚举、数组等
- 整数直接量默认类型为int,浮点数直接量默认类型为double
- 若想表示long类型的直接量需在直接量后面加上L,float同理,加上F即可
- 浮点数类型数据在运算时可能会存在误差,float、double一般可以精确到7位、15位有效数字
- Java中char类型采用的是Unicode字符集编码,而Unicode中0~127是ASCII编码表
- 常用的ASCII有:10-换行、32-空格、48-0、65-A、97-a
- 常用的转义字符有:\n-换行、\t-横向制表、\"-双引号、\\-反斜杠
- 基本数据类型范围从小到大排序为:byte --> short/char --> int --> long --> float --> double
- 在数据范围从小到大进行赋值时会发生自动类型转换
- 在数据范围从大到小进行赋值时需进行强制类型转换,即在需要强转的数据前加上(数据类型)即可
- 强转可能会发生精度损失、数据溢出,需谨慎使用
- byte/short/char类型在运算时都会被提升为int类型再进行计算
- short s = 128; byte b = (byte) s; // 减1取反 -128
- short s = 128; s = s + 128; // error
- short s = 128; s += 128; // 等价于 s = (short) (s + 1024);
##### Java、JDK、JRE、JVM
```
- Java是美国Sun公司于1995年推出的(面向对象)高级编程语言
- JDK是Java开发工具包,包含了JRE和Java开发工具,是用来编译和调试Java程序的
- JRE是Java运行环境,包含了JVM和Java程序所需的核心类库,是用来运行Java程序的
- JVM是Java虚拟机,一个可以运行Java代码的虚拟计算机
```
##### 关键字、标识符、注释
```
- 关键字是程序中已经定义好的、具有特殊含义的单词
- 标识符是程序中我们自己定义的内容,如类名、方法名、变量名等
- 标识符可包含26个大小写字母、0-9数字、_以及$、不能以数字开头、不能是关键字
- 命名规则为:
- 项目名和包名全小写、常量名全大写且单词间用_连接
- 文件名和类名使用大驼峰、方法名和变量名使用小驼峰
- 注释是对代码的解释说明,被注释的代码不会被编译
```
##### 变量、常量、直接量
```
- 变量是在程序运行过程中其值可以改变的数据
- 常量是在程序运行过程中其值固定不变的数据,通常使用final修饰
- 直接量是在程序中通过源码直接给出的值
- 定义变量的三要素:数据类型、变量名、数据值
```
##### 数据类型
```
- Java中数据类型可分为基本数据类型和引用数据类型
- 基本数据类型可分为byte、short、int、long、float、double、char、boolean
- 引用数据类型可分为类、接口、枚举、数组等
- 整数直接量默认类型为int,浮点数直接量默认类型为double
- 浮点数类型数据在运算时可能会存在误差,float、double一般可以精确到7位、15位有效数字
- Java中char类型采用的是Unicode字符集编码,而Unicode中0~127是ASCII编码表
- 常用的ASCII有:10-换行、32-空格、48-0、65-A、97-a
- 常用的转义字符有:\n-换行、\t-横向制表、\"-双引号、\\-反斜杠
- 基本数据类型范围从小到大排序为:byte --> short/char --> int --> long --> float --> double
- 在数据范围从小到大进行赋值时会发生自动类型转换
- 在数据范围从大到小进行赋值时需进行强制类型转换,即在需要强转的数据前加上(数据类型)即可
- 强转可能会发生精度损失、数据溢出,需谨慎使用
- byte/short/char类型在运算时都会被提升为int类型再进行计算
```
##### 运算符
```
- 算术运算符
- 加法+、减法-、乘法*、除法/、求模%、自增++、自减--
- 在算数运算过程中如果有不同类型的数据进行计算,那么运算结果的数据类型将是数据范围大的数据类型
两个整数相除只保留结果的整数部分,若希望保留小数部分只需将其中一个整数强转为浮点数类型就可以了,或者让其中一个整数乘以1.0也可以实现。
- 在自增自减运算过程中如果是前自增就先加后用,后自增就先用后加,自减同理
- 运算符+既可作为数值类型的相加运算,也可作为字符串连接符
- 如果加号两边有一个数据是字符串类型,则加号就会被当作字符串连接符处理
- 赋值运算符
- 等于=、加等+=、减等-=、乘等*=、除等/=、模等%=
- 直接量不能进行赋值,在赋值运算中是隐含着类型转换的(编译器优化)
- 比较运算符
- 等等==、大于>、小于<、大等>=、小等<=、不等!=
- 比较运算的结果一定是一个布尔值,成立为true,反之为false
- 逻辑运算符
- 逻辑与&&、逻辑或||、逻辑非!
- &&全真为真、||全假为假、!非真即假,逻辑运算只能用于布尔值间
- &&和||存在短路特性,&&左边表达式为假时右边表达式不执行,||左边表达式为真时右边表达式不执行
- 三元运算符
- 表达式 ? 结果1 : 结果2;
- 三元运算符需保证所有表达式都符合左侧数据类型的要求,而且其结果必须使用
- 移位运算符
- 左移<<、右移>>、逻辑右移>>>
- 左移运算,将数据二进制位向左移动,右边补0
- 右移运算,将数据二进制位向右移动,左边补符号位
- 逻辑右移,将数据二进制位向右移动,左边补0
- 左移N位的结果为原值乘以2的N次方,右移N位的结果为原值除以2的N次方
- 按位运算符
- 按位与&、按位或|、按位取反~、按位异或^
- &全1为1、|全0为0、~非1即0、^相同为0
```
##### 流程控制
```
- 顺序结构
- 顺序结构是最简单的程序结构,其执行顺序自上而下,依次执行
- 选择结构
- 选择结构可分为单分支if、双分支if else、多分支if else if else以及switch case
- switch()中支持的数据类型可以是byte、short、chár、int
- Java5开始支持枚举类型、Java7开始支持String类型
- 在switch结构中多个case后面的数据不可重复
- 循环结构
- 循环结构可分为for循环、while循环、do while循环等
- 如循环条件从未满足过,for循环和while循环一次都不会执行,do while循环会至少执行一次
- 若在for循环和while循环后加个分号时:
- for循环的循环体在不报错的情况下只会执行一次
- while循环则会因为步进表达式的不存在而陷入死循环中
- 明确循环次数或范围确定的话多用for循环,明确循环条件多用while循环
- break、continue、标号
- break用于switch中的作用为终止switch,用于循环中的作用为终止循环
- continue用于循环中的作用为跳过本次循环而马上开始下次循环
- 在嵌套循环中break终止的是与其最近的循环,如需终止外层循环可使用标号的方式解决,continue同理
```
##### 数组
```
- 数组是一种可以同时存放多个相同数据类型元素的容器,数组的长度在程序运行过程中不可改变
- 如果不确定数组中的具体内容就动态初始化数组,即指定数组长度,否则就静态初始化数组,即指定数组内容
- 动态初始化创建的数组中元素会有默认值,0、0.0、false、null
- 静态初始化创建的数组其实也有默认值的过程,只不过系统马上将其默认值替换成了大括号内的具体内容
- 二维数组中的每个元素其实就是一个一维数组,而一维数组中的每个元素才是数据内容
```
#### 面向对象
##### 设计思想
```
- 面向对象是一种程序设计思想,对象泛指现实中的一切事物,每种事物都具备自己的属性和行为
- 就是在编程时参照现实中的事物并将事物的属性特征和行为特征抽象出来描述成计算机事件的设计思想
- 其区别于面向过程思想强调的是通过调用对象来实现功能,而不是自己一步步去操作实现
- 面向对象是一种更符合我们思考习惯的思想,它可以将复杂的事情简单化,并将我们从执行者变成指挥者
- 面向对象的三大特征为:封装、继承、多态
```
##### 类、对象、属性、行为
```
- 类可以看成是一类事物的描述,是抽象的,用事物的属性特征和行为特征来描述该类事物
- 对象则是一类事物的具体体现,是具体的,具备该类事物的属性和行为
- 万物皆对象,类是对象的模版,对象是类的实体
- 属性是该类事物的状态信息,也就是定义在类中的变量,也叫成员变量
- 对象创建后成员变量会自动拥有默认值,0、0.0、false、null
- 行为是该类事物能够做什么,也就是定义在类中的方法,也叫成员方法
- 方法的本质其实就是将通用的代码抽取出来形成一个单独的功能,需要使用时调用即可
- 这样既解决了代码的复用性,也解决了代码冗余的现象
- 方法定义的先后顺序无所谓,方法定义后需调用后才会执行
- 方法的声明包括返回值类型、方法名、形参列表等
- 一个方法的形参列表中最多只能声明一个可变参数,且可变参数需放在形参列表的末尾
当方法的参数列表数据类型已经确定,但参数列表的个数不确定,就可以使用可变参数。可变参数的底层其实就是一个数组,根据传递参数的个数不同,会创建不同长度的数组来存储这些数据,传递参数的个数可以是0个或多个。可变参数可在定义方法时使用,一个方法的参数列表只能有一个可变参数,如果方法的参数有多个,那么可变参数就必须写在参数列表的末尾,可变参数的终极写法为(Object...object)。
```
##### 构造方法、匿名对象
```
- 构造方法是专门用来创建对象的(实例化、引用)
- 当我们通过new关键字来创建对象时其实就是在调用构造方法来实现成员变量的初始化操作
- 在我们不手写构造方法的情况下默认隐含着一个无参构造方法
- 构造方法的名称必须与所在类的类名完全相同,且构造方法无需返回值
- 匿名对象就是只有等号右边的对象,没有左边的数据类型和引用变量名
- 如果确定一个对象只需使用唯一的一次,那么匿名对象就是个不错的选择
```
##### Overload、Override
```
- Overload方法重载
- 判断方法是否构成重载的核心就是调用方法时能否加以区分
- 方法的重载与形参的个数、类型、顺序有关,与形参变量名、返回值类型无关
- 方法重载的实际意义在于调用者只需记住一个方法名即可调用不同的版本来实现各种不同的功能
- Override方法重写
- 当父类继承下来的方法无法满足子类需求时,就可以在子类中对父类继承下来的方法进行覆盖重写
- 对方法重写时必须保证父子类之间方法名称相同、返回值以及参数列表也相同
- 重写时子类方法的返回值类型不能大于父类的返回值类型
- 重写时子类方法的访问权限修饰符范围不能小于父类的访问权限修饰符范围
- 重写时子类方法不能抛出大于父类方法所抛出的异常
```
##### 访问权限修饰符、Package
```
- 访问权限修饰符可用来修饰类、成员方法、成员变量等,用于控制对其访问的权限
- public公共权限,可被任意类访问
- protected受保护权限,可被不同包子类访问
- default默认权限,可被同包访问
- private私有权限,可被本类访问
- 我们在定义类时需指定类的名称,但如果仅将类名作为类的唯一标识将不可避免地出现命名冲突的问题
- 在Java中可以用包的概念来解决该问题
- 定义包的规范多为公司域名反写.项目名.模块名.类名
- 使用package关键字来定义包,使用import关键字来导入包
- Java5开始也可直接导入包中的静态成员
```
##### 封装、JavaBean
```
- 封装就是隐藏对象的属性和实现细节,仅对外公开接口,通过封装可以对对象属性进行合理化判断
- 实现封装需先私有化变量,然后提供getter/setter方法或再对属性数据进行合理化判断
- 对于boolean类型的成员变量来说,其getter方法需写成isXxx()的形式
- JavaBean是Java编写的可重用组件,是Java编写类的一种规范
- JavaBean的本质其实就是符合某些标准的类
- 而最低标准为这个类必须是公共的、至少有一个无参构造器、类中属性都有对应的getter/setter方法
```
##### 继承
```
- 继承是多态的前提,没有继承就没有多态,继承主要解决的问题就是共性抽取
- Java只能单继承,即一个类的直接父类只能有一个,但一个父类可以拥有多个子类
- Java可以多级继承,即父类还可以有父类
- 继承关系中,子类除了可以继承父类中所有可继承的内容,还可以拥有自己的专有内容
- “子类就是一个父类”,也就是说子类可以被当成父类看待
- 无论是访问成员变量还是成员方法,如果没有都是向上找父类,绝不会向下找子类
```
##### Static、Final
```
- 使用static关键字修饰的成员将不再属于对象,而是由对象层级提升为类层级
- 也就是整个类只有一份并被共享,随类加载,与是否创建对象无关
- 被static修饰的成员可使用引用.的方式访问,推荐使用类名.的方式
- 在静态成员方法中只能访问静态成员而不能访问非静态成员,此时可能还没创建对象
- 在非静态成员中既能访问静态成员也能访问非静态成员,静态成员被所有对象共享
- 只有隶属于类层级并被所有对象共享的成员才可以使用static关键字修饰(不能滥用)
- 静态方法中不能使用this,因为this代表当前对象,而静态成员属于类,不属于某个对象
- 一旦使用final关键字进行修饰则说明不可改变
- final修饰基本数据类型后,其值为常量且不可修改
- final修饰引用数据类型后,其引用的地址值不可修改
- final修饰成员变量后,必须立马赋值,否则编译报错
- final修饰成员方法后,该方法将成为最终方法,可以被子类继承但无法重写此方法
- final修饰一个类后,该类将成为最终类,无法被继承,即“断子绝孙类”
```
##### This、Super
```
- this代表所在类的当前对象引用,是一个地址值,用于访问本类的内容
- 成员被哪个对象调用,成员中的this就代表哪个对象,即谁在调用,this就代表谁
- 在本类的成员方法中可以访问本类的成员
- 在本类的构造方法中可以访问本类的其它构造方法,且this()必须是第一条语句
- super是指向父类的引用,用于访问父类的内容
- 在子类的成员方法中可以访问父类的成员
- 在子类的构造方法中可以访问父类的构造方法
- 子类的构造方法中默认隐含着一个super()调用,所以一定是先调用父类的构造方法再执行子类的构造
- 子类可以通过super关键字来调用父类重载构造,子类必须调用父类构造方法,不写则赠送super()
- 写了则调用自己写的调用,super()只能有一个,且必须是第一条语句
<font color="#80F">this关键字的使用</font>,this代表所在类当前对象的引用,用于访问本类的内容。this在构造方法中代表正在构造的对象、在成员方法中代表正在调用的对象,调用的对象不同,结果也随之不同。在构造方法或成员方法中访问成员变量时,编译器会隐含地加上this.前缀;当局部变量和成员变量同名时,若希望调用成员变量只需加上this.前缀即可。this关键字可以在本类的成员方法中访问本类的成员变量和成员方法、在构造方法中的第一行使用this()的方式可以访问本类的构造方法、也可以作为方法的返回值使用。
<font color="#80F">super关键字的使用</font>,super代表指向父类的引用,用于访问父类可访问的内容。super关键字可以在子类的成员方法中访问父类的成员变量和成员方法、在子类构造方法中的第一行使用super()的方式可以访问父类的构造方法。子类的构造方法中默认隐含着super()调用,子类必须调用父类构造方法,所以一定是先调用父类的构造方法而后执行子类的构造方法。
```
##### 抽象类、抽象方法
```
- 如果父类中的方法不确定如何进行{}方法体实现,那么这就应该是一个抽象方法。抽象方法就是在权限修饰符后加上abstract关键字,然后去掉大括号,直接分号结束的方法;抽象方法所在的类必须是抽象类才行,在class前加上abstract关键字即可。一个抽象类不一定含有抽象方法,只要保证抽象方法所在的类是抽象类即可。这样没有抽象方法的抽象类也不能直接创建对象,但在一些特殊场景下有用途。
抽象类的使用,抽象类不能直接创建new抽象类对象;必须用一个子类来继承抽象方法,且子类必须覆盖重写抽象父类中所有的抽象方法。对于类、方法来说,abstract和关键字final不能同时使用,因为矛盾。
```
##### 接口
```
在我们的日常生活中,接口就是一种公共的规范标准,只要符合规范标准,就可以大家通用,而在java程序中,接口是一种引用数据类型,最重要的内容就是其中的抽象方法。定义接口的格式其实就是将类关键字class替换成为interface接口,替换成interface后,仍是将.java源文件编译生成为.class字节码文件。
* 在任何版本的JDK中,接口都能定义抽象方法。
接口中的抽象方法,修饰符必须是两个固定的关键字 : public abstract,这两个关键字修饰符可以选择性的省略;方法的三要素也可以随意定义。
接口的使用,接口不能直接使用,必须有一个实现类来实现该接口;接口的实现类必须覆盖重写(实现)接口中所有的抽象方法。
* 在JDK7中,接口可以包含常量。
在接口中其实也可以定义“成员变量”,但是必须使用public static final三个关键字进行修饰,从效果上看,这其实就是接口中的常量。接口中的常量必须得进行赋值,且可以省略public static final关键字。
* 在JDK8中,接口可以包含默认方法和静态方法;
接口中的默认方法可以解决接口升级的问题;可通过接口实现类对象直接调用;可被接口实现类进行覆盖重写。
接口中的静态方法不能通过接口实现类的对象来调用接口中的静态方法,可通过接口名称直接调用其静态方法。
* 在JDK9中,接口可以包含私有方法。
普通私有方法可以解决多个默认方法之间重复代码的问题,而静态私有方法则可以解决多个静态方法之间重复代码的问题。私有方法只有接口自己才能调用,不能被实现类或别人使用。
* 接口是没有静态代码块或者构造方法的。
* 一个类的直接父类是唯一的,但是一个类可以同时实现多个接口。
* 如果实现类所实现的多个接口中存在重复的抽象方法,那么只需要覆盖一次即可。
* 如果实现类没有覆盖重写接口中所有的抽象方法,那么这个实现类自己就必须是抽象类。
* 如果实现类实现的多个接口中存在重复的默认方法,那么实现类一定要对冲突的默认方法进行覆盖重写。
* 如果一个类的直接父类的方法和接口中的默认方法产生了冲突,优先使用父类的方法。
* 类与类之间是单继承的,直接父类只有一个。
* 类与接口之间是多实现的,一个类可以实现多个接口。
* 接口与接口之间是多继承的。
* 多个父接口中的抽象方法如果重复是没关系的,如果多个父接口中的默认方法重复,那么子接口必须进行默认方法的覆盖重写,而且要带着default关键字。
```
##### 多态
```
继承或接口的实现是多态的前提,代码中体现多态性,其实就是一句话 : 父类引用指向子类对象。访问成员变量,编译看左边,运行还看左;访问成员方法,编译看左边,运行看右边。
对象的向上转型,其实就是多态的写法,将子类对象当成父类看待使用。向上转型一定是安全的,从小范围转向了大范围,但也有一个弊端,就是对象一旦向上转型为父类,那么就无法调用子类原本特有的内容了。解决方法就是用对象的向下转型,也就是还原动作,就是将父类对象还原成为本来的子类对象。向下转型必须保证对象本来创建的时候就是这个对象,才能向下转型成功,否则就会抛出ClassCastException类转换异常。
如何才能知道一个父类引用的对象原本就是一个什么子类?使用(对象名 instanceof 类名称)即可得到一个boolean值结果,也就是判断前面的对象能不能做后面类型的实例。
```
##### 内部类
```
内部类就是在一个事物的内部包含另一个事物,即一个类的内部包含另一个类。
* 成员内部类
成员内部类就是跟成员方法并排的类,使用时内用外可以随意访问,外用内则需要内部类对象。使用成员内部类的方式可分为直接方式和间接方式。直接方式为new 外部类名().new 内部类名();间接方式为在外部类的方法中使用内部类,然后main方法调用外部类的方法。
* 局部内部类
如果一个类定义在一个方法的内部,那么这就是一个局部内部类,包含匿名内部类。只有当前所属的方法才能使用,出了这个方法外面就不能用了。局部内部类如果希望访问所在方法的局部变量,那么这个局部变量必须是有效final的。
从JDK8开始,只要局部变量事实不变,那么final关键字就可以省略。因为new出来的对象在堆内存中,局部变量是跟着方法走的,在栈内存中,方法运行结束后会立刻出栈,局部变脸就会立刻消失,但new出来的对象会在堆中持续存在,直到被垃圾回收才会消失。
如果接口的实现类,或继承自父类的子类只需要使用唯一的一次,那么这种情况下就可以省略掉该类的定义而改为使用匿名内部类。定义匿名内部类时(new 接口名称() {···}),new代表创建对象的动作,接口名称就是匿名内部类需要实现哪个接口,{···}才是匿名内部类的内容。
定义一个类时,外部类可以使用public/(default);成员内部类四个权限修饰符都可以用;局部内部类什么都不能写。
匿名内部类在创建对象的时候,只能使用唯一的一次,如果希望多次创建对象,而且类的内容一样的话,那就需要单独定义实现类了;匿名对象在调用方法时,只能调用唯一的一次,如果希望同一个对象调用多次方法,那就必须给对象取个名字了;匿名内部类是省略了实现类/子类名称,而匿名对象是省略了对象名称,匿名内部类和匿名对象不是一回事!
```
##### 枚举
```
```
##### 注解
注解是用来说明程序的,是给计算机看的;而注释是用来描述程序的,是给人看的。注解(Annotation)也叫元数据,是一种代码级别的说明,是JDK5后引入的新特性,与类、接口、枚举是在同一层次。注解可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明。注解可以用来编译检查、生成API文档以及代码分析(使用反射)。
以后大多数时候,我们会使用注解,而不是自定义注解。注解可以给编译器和解析程序使用;注解不是程序的一部分,可以理解为注解就是一个标签。
预定义注解
- @Override;检测是否为有效的方法重写。
- @Deprecated;将方法标注为已过时。
- @SuppressWarnings(“all”);压制警告。
自定义注解
自定义注解的格式为
@元注解
public @interface 注解名 {
属性列表;
}
注解的本质其实就是一个接口,只不过该接口默认继承Annotation接口。
public interface CustomAnnotation extends java.lang.annotation.Annotation {}
属性
注解中属性(接口中的抽象方法)的返回值可以定义为基本数据类型、String、枚举、注解以及数组。注解中如果定义了属性的话,那么在使用注解的时候需要给属性赋值。
- 如果在定义属性时使用default关键字给属性默认初始化值,则在使用注解的时候可以不进行属性的赋值。
- 如果只有一个属性需要赋值,并且属性的名称是value,则value可以省略,直接定义即可。
- 数组在赋值时,使用{}包裹,如果数组中只有一个值,则{}可以省略。
元注解
元注解是用于描述注解的注解。
- @Target;描述注解能够作用的位置,ElementType枚举的取值有TYPE(作用于类上)、METHOD(作用于方法上)、FIELD(作用于成员变量上)。
- @Retention;描述注解被保留的阶段,RetentionPolicy枚举的取值有SOURCE(不会保留到.class字节码文件中)、CLASS(保留到.class字节码文件中,不会被JVM读取到)、RUNTIME(保留到字节码文件中并被JVM读取到)。
- @Documented;描述注解是否被抽取到API文档中。
- @Inherited;描述注解是否被子类继承。
解析注解
在程序中解析(使用)注解,获取注解中定义的属性值。步骤为先获取注解定义的位置(Class, Method, Field)的Class对象;再获取定义的注解对象;再通过注解对象调用其属性(抽象方法)来获取属性值。
- Class对象名.getAnnotation(注解Class对象);获取指定的注解对象,其实就是在内存中生成了一个该注释接口的子类实现对象。