type
status状态
tags标签
date
slug链接
summary简介
category分类
icon
password
第1章 Java 概述
1.1 什么是程序
程序:计算机执行某些操作或解决某个问题而编写的一系列有序指令的集合

1.2 java的诞生
- 1990 sun公司启动绿色计划
- 1992创建oak(橡树)语言->java
- 1994 gosling参加硅谷大会演示java功能,震惊世界。
- 1995 sun 正式发布java第1个版本。
- 2009年,甲骨文公司宣布收购Sun。2011,发布java7

1.3 java技术体系平台

1.4 java的重要特点
- Java 语言是面向对象的(oop)
- Java 语言是健壮的。Java 的强类型机制、异常处理、垃圾的自动收集等是 Java 程序健壮性的重要保证
- Java 语言是跨平台性的。[即: 一个编译好的.class 文件可以在多个系统下运行,这种特性称为跨平台

- Java 语言是解释型的[了解]
解释性语言:javascript,PHP,java
编译性语言: c / c++
区别是:解释性语言,编译后的代码,不能直接被机器执行,需要解释器来执行, 编译性语言, 编译后的代码, 可以直接被机器执行, c /c++
1.5 java的开发工具

- IDEA
- eclipse
- Sublime
- Notepad++等
1.5.1 工具的选择
- 如何选择
可以先使用文本编辑工具(Sublime,Notepad++),对 java 有一定了解后,再使用 IDEA 和 eclipse 开发工具
- 为什么
- 更深刻的理解 java 技术,培养代码感。【面试时,往往程序员手写代码】有利于公司面试。
idea的安装
官方下载地址
1.6 java的运行机制及运行过程
1.6.1 java语言的特点:跨平台性

1.6.2 核心机制-java虚拟机(JVM java virtual machine)
- 基本介绍
- JVM 是一个虚拟的计算机,具有指令集并使用不同的存储区域。负责执行指令,管理数据、内存、寄存器,包含在JDK 中.
- 对于不同的平台,有不同的虚拟机。
- Java 虚拟机机制屏蔽了底层运行平台的差别,实现了“一次编译,到处运行”

1.7 什么是JDK,JRE
1.7.1 JDK基本介绍
- JDK的全称(Java Development Kit Java 开发工具包)
JDK = JRE + java 的开发工具[java, javac,javadoc,javap 等]
- JDK是提供给 Java 开发人员使用的,其中包含了 java 的开发工具,也包括了 JRE。所以安装了JDK,就不用在单独安装 JRE 了。
1.7.2 JRE的基本介绍
- JRE(Java Runtime Environment Java 运行环境)
JRE = JVM + Java 的核心类库[类]
- 包括 Java 虚拟机(JVM Java Virtual Machine)和 Java程序所需的核心类库等,如果想要运行一个开发好的Java程序, 计算机中只需要安装 JRE 即可。
1.7.3 JDK,JRE,JVM的包含关系
- JDK = JRE + 开发工具集(例如 Javac,java 编译工具等)
- JRE = JVM + Java SE 标准类库(java 核心类库)
- 如果只想运行开发好的 .class 文件 只需要 JRE
1.8 下载和安装JDK
- 安装步骤:
傻瓜式安装,无脑下一步
- 细节说明:
安装路径不要有中文或者特殊符号如空格等。
当提示安装 JRE 时,可以选择不安装,也可以安装.
1.9 配置环境变量 path
- 我的电脑-属性--高级系统设置--环境变量
- 增加JAVA_HOME 环境变量,指向jdk的安装目录(注意:不要bin)

- 编辑 path 环境变量,增加%JAVA_HOME%\bin

- 打开DoS命令行,任意目录下敲入javac/java。如果出现javac的参数信息,配置成功。

1.10 我的第一个程序 HeloWorld
1.10.1 开发步骤
- 将 Java 代码编写到扩展名为 java 的文件中。[代码说明]
- 通过 javac 命令对该 java 文件进行编译,生成 .class 文件。
- 通过 java 命令对生成的 class 文件进行运行。
1.10.2 运行原理

1.10.3 如何编写
1.11 Java 开发注意事项和细节说明
- Java源文件以,java为扩展名。源文件的基本组成部分是类(class),如本类中的Hello类。
- Java应用程序的执行入口是main()方法。它有固定的书写格式: public static void main(String[] args) {...}
- Java语言严格区分大小写。
- Java方法由一条条语句构成,每个语句以“;”结束。
- 大括号都是成对出现的,缺一不可。[习惯,先写再写代码]
- 一个源文件中最多只能有一个public类。其它类的个数不限。
- 如果源文件包含一个public类,则文件名必须按该类名命名!
- 一个源文件中最多只能有一个public类。其它类的个数不限,也可以将main方法写在非public类中,然后指定运行非public类,这样入口方法就是非public的main方法
1.12 java 转义字符
2.12.1 常用转义字符
在控制台,输入 tab 键,可以实现命令补全
- \t :一个制表位,实现对齐的功能
- \n :换行符
- \\ :一个\
- \" :一个"
- \' :一个'
- \r :一个回车
1.13 初学java易犯错误


1.14 注释(comment)
1.14.1 介绍
用于注解说明解释程序的文字就是注释,注释提高了代码的阅读性(可读性);注释是一个程序员必须要具有的良好编程习惯。将自己的思想通过注释先整理出来,再用代码去体现。
1.14.2 Java 中的注释类型
- 单行注释 //注释内容
- 多行注释 /* 注释内容*/
- 文档注释 /** 注释内容 */
1.14.3 使用细节
- 被注释的文字,不会被 JVM(java 虚拟机)解释执行
- 多行注释里面不允许有多行注释嵌套
1.14.4 文档注释
注释内容可以被JDK提供的工具javadoc所解析,生成一套以网页文件形式体现的该程序的说明文档,一般写在类
1.15 代码规范

1.16 标识符
- Java 对各种变量、方法和类等命名时使用的字符序列称为标识符
- 凡是自己可以起名字的地方都叫标识符int num1=90;
1.16.1 标识符的命名规则(必须遵守)
- 由26个英文字母大小写,0-9,或$组成
- 数字不可以开头。int 3ab=1;//错误
- 不可以使用关键字和保留字,但能包含关键字和保留字。
- Java中严格区分大小写,长度无限制。int totalNum=10;int n=90;
- 标识符不能包含空格。int a b = 90;
1.16.2 标识符命名规范[更加专业]
- 包名:多单词组成时所有字母都小写:bbb.ccc //比如 com.hsp.crm
- 类名、接口名:多单词组成时,所有单词的首字母大写:XxxYyyZzz [大驼峰] 比如: TankShotGame
- 变量名、方法名:多单词组成时,第一个单词首字母小写,第二个单词开始每个单词首字母大写:xxxYyyZzz [小驼峰, 简称 驼峰法] 比如: tankShotGame
- 常量名:所有字母都大写。多单词时每个单词用下划线连接:XXX_YYY_ZZZ 比如 :定义一个所得税率 TAX_RATE
- 后面我们学习到 类,包,接口,等时,我们的命名规范要这样遵守,更加详细的看文档.
1.17 关键字
被 Java 语言赋予了特殊含义,用做专门用途的字符串(单词)
特点:关键字中所有字母都为小写


1.18 保留字
Java 保留字:现有 Java 版本尚未使用,但以后版本可能会作为关键字使用。自己命名标识符时要避免使用这些保留字 byValue、cast、future、 generic、 inner、 operator、 outer、 rest、 var 、 goto 、const
1.19 键盘输入语句Scanner
在编程中,需要接收用户输入的数据,就可以使用键盘输入语句来获取。Input.java , 需要一个 扫描器(对象), 就是Scanner
第2章 变量
2.1 变量的概念
变量相当于内存中一个数据存储空间的表示,你可以把变量看做是一个房间的门牌号,通过门牌号我们可以找到房间,而通过变量名可以访问到变量(值)。
2.2 变量的原理示意图

2.3 变量的使用步骤
- 声明变量
int a ;
- 赋值
a = 60 ; //应该这么说 : 把 60 赋给 a
3. 一步到位:
int a=60 ;
2.4 变量快速入门
2.5 变量使用注意事项
- 必须先声明后使用
- 变量在同一个作用域内不能重名
- 变量=变量名+值+数据类型,变量三要素
2.6 程序中 “+“的使用
- 当左右两边都是数值型时,则做加法运算
- 当左右两边有一方为字符串,则做拼接运算
2.7 数据类型
每一种数据都定义了明确的数据类型,在内存中分配了不同大小的内存空间(字节)。

2.8 整数类型
Java 的整数类型就是用于存放整数值的,比如 12 , 30, 3456 等等

2.8.1 整形的使用细节
- Java各整数类型有固定的范围和字段长度,不受具体OS[操作系统]的影响,以保证java程序的可移植性。
- Java的整型常量(具体值)默认为int型,声明long型常量须后加T'或‘L'
- java程序中变量常声明为int型,除非不足以表示大数,才使用long
- bit:计算机中的最小存储单位。byte:计算机中基本存储单元,1byte = 8 bit。
2.9 浮点类型
Java 的浮点类型可以表示一个小数,比如 123.4 ,7.8 ,0.12 等等

说明:
- 关于浮点数在机器中存放形式的简单说明,浮点数=符号位+指数位+尾数位
- 尾数部分可能丢失,造成精度损失(小数都是近似值)。
2.9.1 浮点型的使用细节
- 与整数类型类似,Java浮点类型也有固定的范围和字段长度,不受具体OS的影响。[float 4个字节 double是8个字节]
- Java的浮点型常量(具体值)默认为double型,声明float型常量,须后加‘f'或'F’
- 浮点型常量有两种表示形式 十进制数形式:如:5.12 512.0f .512(必须有小数点) 科学计数法形式:如:5.12e2[5.12*10的2次方] 5.12E-2[5.12/10的2次方]
- 通常情况下,应该使用double型,因为它比float型更精确。
2.10 字符类型
字符类型可以表示单个字符,字符类型是 char,char 是两个字节(可以存放汉字),多个字符我们用字符串 String
2.10.1 字符类型使用细节
- 字符常量是用单引号( ’ ‘ )括起来的单个字符。
- Java中还允许使用转义字符‘来将其后的字符转变为特殊字符型常量。例如:charc3= ‘\n';//'\n'表示换行符
- 在java中,char的本质是一个整数,在输出时,是unicode码对应的字符。 http://tool.chinaz.com/Tools/Unicode.aspx
- 可以直接给char赋一个整数,然后输出时,会按照对应 的unicode字符输出[97→a]
- char类型是可以进行运算的,相当于一个整数,因为它 都对应有Unicode码.
ASCII 码介绍(了解)
- ASC11码:上个世纪60年代,美国制定了一套字符编码(使用一个字节),对英语字符与二进制位之间的关系,做了统一规定,这被称为ASCII码。ASCII码一共规定了128个字符的编码,只占用了一个字节的后面7位,最前面的1位统一规定为0。特别提示:一个字节可以表示256个字符,ASCII码只用了128个字符.
- 缺点:不能表示所有的字符
Unicode 编码介绍(了解)
- Unicode的好处:一种编码,将世界上所有的符号都纳入其中。每一个符号都给予一个独一无二的编码,使用Unicode 没有乱码的问题。
- Unicode的缺点:一个英文字母和一个汉字都占用2个字节,这对于存储空间来说是浪费
- 2的16次方是65536,所以最多编码是65536个字符。
- 编码O-127的字符是与ASClI的编码一样.比如'a'在ASCII码是Ox61,在unicode码是ox0061,都对应97.因此 Unicode码兼容 ASCll码 … ….
UTF-8 编码介绍(了解)
- UTF-8 是在互联网上使用最广的一种 Unicode的实现方式(改进)
- UTF-8是一种变长的编码方式。它可以使用1-6个字节表示一个符号,根据不同的符号而变化字节长度。
- 使用大小可变的编码字母占1个字节,汉字占3个字节
2.11 布尔类型:boolean
- 布尔类型也叫boolean类型,booolean类型数据只允许取值true和false,无null
- boolean类型占1个字节。
- boolean 类型适于逻辑运算,一般用于程序流程控制
2.12 基本数据类型的转换
2.12.1 自动类型转换(隐式转换)
当java程序在进行赋值或者运算时,精度小的类型自动转换为精度大的数据类型,这个就是自动类型转换。

自动类型转换注意和细节
- 有多种类型的数据混合运算时,系统首先自动将所有数据 转换成容量最大的那种数据类型,然后再进行计算。
- 当我们把精度(容量)大的数据类型赋值给精度(容量)小的数据类型时,就会报错,反之就会进行自动类型转换。
- (byte,short)和char之间不会相互自动转换。
- byte,short,char 他们三者可以计算,在计算时首先转换为int类型。
- boolean不参与转换
- 自动提升原则:表达式结果的类型自动提升为操作数中最大的类型
2.12.2 强制类型转换(显示转换)
自动类型转换的逆过程,将容量大的数据类型转换为容量小的数据类型。使用时要加上强制转换符 ( ),但可能造成精度丢失
强制类型转换细节说明
- 当进行数据的大小从大—>小,就需要使用到强制转换
- 强转符号只针对于最近的操作数有效,往往会使用小括号提升优先级
- char类型可以保存 int的常量值,但不能保存int的变量值,需要强转
- byte和short,char 类型在进行运算时,当做int类型处理。
基本数据类型转换-练习题

2.13 基本数据类型和String 类型的转换
在程序开发中,我们经常需要将基本数据类型转成String类型。或者将String类型转成基本数据类型。
- 基本类型转String类型 语法:将基本类型的值+””即可
- String类型转基本数据类型 语法:通过基本类型的包装类调用parsexX方法即可
2.13.1 注意事项
- 在将 String 类型转成 基本数据类型时,要确保String类型能够转成有效的数据。比如 我们可以把 "123" , 转成一个整数,但是不能把 "hello" 转成一个整数
- 如果格式不正确,就会抛出异常,程序就会终止, 这个问题在异常处理章节中,会处理
第3章 运算符
运算符是一种特殊的符号,用以表示数据的运算、赋值和比较等。
- 算术运算符
- 赋值运算符
- 关系运算符 [比较运算符]
- 逻辑运算符
- 位运算符 [需要二进制基础]
- 三元运算符
3.1 算术运算符
算术运算符是对数值类型的变量进行运算的,在 Java 程序中使用的非常多。

细节:
- 对于除号”/”,它的整数除和小数除是有区别的:整数之间做除法时,只保留整数部分而舍弃小数部分。例如:int x=10/3,结果是3
- 当对一个数取模时,可以等价a%b=a-a/b*b,这样我们可以看到取模的一个本质运算。
- 当自增当做一个独立语言使用时,不管是++i;还是i++;都是一样的
面试题
答案
1
因为后++,先运算,后增1
答案
3.2 关系运算符(比较运算符)

细节说明
- 关系运算符的结果都是 boolean 型,也就是要么是 true,要么是 false。
- 关系运算符组成的表达式,我们称为关系表达式。 a > b
- 比较运算符"=="不能误写成"="
3.3 逻辑运算符
用于连接多个条件(多个关系表达式),最终的结果也是一个 boolean 值。
- && 短路与
- || 短路或
- ! 取反
- & 逻辑与
- | 逻辑或
- ^ 逻辑异或

说明逻辑运算符规则
- a&b : & 叫逻辑与:规则:当 a 和 b 同时为 true ,则结果为true, 否则为 false
- a&&b : && 叫短路与:规则:当 a 和 b 同时为 true ,则结果为 true,否则为 false
- a|b : | 叫逻辑或,规则:当 a 和 b ,有一个为 true ,则结果为 true,否则为 false
- a||b : || 叫短路或,规则:当 a 和 b ,有一个为 true ,则结果为 true,否则为 false
- !a : 叫取反,或者非运算。当 a 为 true, 则结果为 false, 当 a 为 false 是,结果为 true
- a^b : 叫逻辑异或,当 a 和 b 不同时,则结果为 true, 否则为 false
3.3.1 && || 和& | 的区别
- &&短路与:如果第一个条件为 false,则第二个条件不会判断,最终结果为 false,效率高
- & 逻辑与:不管第一个条件是否为 false,第二个条件都要判断,效率低
- ||短路或:如果第一个条件为 true,则第二个条件不会判断,最终结果为 true,效率高
- | 逻辑或:不管第一个条件是否为 true,第二个条件都要判断,效率低
3.4 赋值运算符
赋值运算符就是将某个运算后的值,赋给指定的变量。
- =
- +=
- -=
- *=
- /=
- %=
原理
a += b; [等价 a = a + b; ]
a -= b; [等价 a = a - b; ]
……
3.5 三元运算符
基本语法:
条件表达式 ? 表达式 1: 表达式 2;
运算规则:
- 如果条件表达式为 true,运算后的结果是表达式 1;
如果条件表达式为 false,运算后的结果是表达式 2;
三目运算符和if else 差不多
3.6 运算优先级
- 运算符有不同的优先级,所谓优先级就是表达式运算中的运算顺序。如下表,上一行运算符总优先于下一行。
- 只有单目运算符、赋值运算符是从右向左运算的。

第4章 程序流程控制
在程序中,程序运行的流程控制决定程序是如何执行的,是我们必须掌握的,主要有三大流程控制语句。
- 顺序控制
- 分支控制
- 循环控制
4.1 顺序控制

4.2 分支控制if-else
让程序有选择的的执行,分支控制有三种
- 单分支 if
- 双分支 if-else
- 多分支 if-else if -....-else
4.2.1 单分支
基本语法:
说明:当条件表达式为ture时,就会执行{}的代码。如果为false,就不执行.
特别说明:如果中只有一条语句,则可以不用,建议写上
单分支流程图

4.2.2 双分支
基本语法
说明:当条件表达式成立,即执行代码块1,否则执行代码块2。如果执行代码块只有一条语句,则可以省略,否则不能省略
双分支流程图

4.2.3 多分支
基本语法
多分支流程控制图

4.3 嵌套分支
在一个分支结构中又完整的嵌套了另一个完整的分支结构,里面的分支的结构称为内层分支外面的分支结构称为外层分支。建议: 不要超过 3 层 (可读性不好)
基本语法:

应用案例:

4.4 switch分支结构
基本语法:
流程图:

注意事项及细节:
- 表达式数据类型,应和case后的常量类型一致,或者是可以自动转成可以相互比较的类型,比如输入的是字符,而常量是int
- switch(表达式)中表达式的返回值必须是:(byte,short,int,char,enum[枚举],String)
- case子句中的值必须是常量,而不能是变量
- default子句是可选的,当没有匹配的case时,执行default
- break语句用来在执行完一个case分支后使程序跳出switch语句块;如果没有写break,程序会顺序执行到switch结尾,除非遇到break;
4.5switch和if的比较
- 如果判断的具体数值不多,而且符合 byte、 short 、int、 char, enum[枚举], String 这 6 种类型。虽然两个语句都可以使用,建议使用 swtich 语句。
- 其他情况:对区间判断,对结果为 boolean 类型判断,使用 if,if 的使用范围更广
4.6 for循环控制
基本语法:

说明:
- for 关键字,表示循环控制
- for 有四要素: (1)循环变量初始化(2)循环条件(3)循环操作(4)循环变量迭代
- 循环操作 , 这里可以有多条语句,也就是我们要循环执行的代码
- 如果 循环操作(语句) 只有一条语句,可以省略 {}, 建议不要省略
流程图:

注意事项及说明:
- 循环条件是返回一个布尔值的表达式
- for(;循环判断条件;) 中的初始化和变量迭代可以写到其它地方,但是两边的分号不能省略。
- 循环初始值可以有多条初始化语句,但要求类型一样,并且中间用逗号隔开,循环变量迭代也可以有多条变量迭代语句,中间用逗号隔开。
4.7 while循环控制
说明:
while循环也有四要素,只是位置和for循环不一样
流程图:

注意事项和细节:
- 循环条件是返回一个布尔值的表达式
- while 循环是先判断再执行语句
4.8 do…while循环
基本语法:
说明:
- do while 是关键字
- 也有循环四要素, 只是位置不一样
- 先执行,再判断,也就是说,一定会至少执行一次
- 最后 有一个 分号 ;
- while 和 .do…while 区别:
- while是根据循环条件执行的
- do…while会先执行一次再看循环条件
流程图:

4.9 多重循环控制(难点)
- 将一个循环放在另一个循环体内,就形成了嵌套循环。其中for ,while ,do…while 均可以作为外层循环和内层循环(建议一般使用两层,最多不要超过 3 层, 否则,代码的可读性很差)
- 实质上,嵌套循环就是把内层循环当成外层循环的循环体。当只有内层循环的循环条件为 false 时,才会完全跳出内层循环,才可结束外层的当次循环,开始下一次的循环
- 设外层循环次数为 m 次,内层为 n 次,则内层循环体实际上需要执行 m*n 次。

练习题:
九九乘法表

4.10 跳转控制语句 break
- 当某个条件满足时就停止循环
- 用于终止某个语句块的执行,一般使用在 switch 或者循环[for , while , do-while]中
使用细节:
在多层循环中,可以通过标签指定要终止循环的层
4.11 跳转控制语句 continue
- continue 语句用于结束本次循环,继续执行下一次循环。
- continue 语句出现在多层嵌套的循环语句体中时,可以通过标签指明要跳过的是哪一层循环 , 这个和前面的标签的使用的规则一样.
4.12 跳转控制语句 return
- 表示跳出所在的方法
第5章 数组、排序和查找
1. 创建数组
- 语法
数据类型 数组名[ ] = new 数据类型[大小]
数据类型 数组名[ ]={1,2,3,4};
- 动态数组
- 静态数组
2. 数组的使用事项和细节
- 数组是多个相同类型数据的组合,实现对这些数据的统一管理
- 数组中的元素可以是任何数据类型,包括基本类型和引用类型,但是不能混用。
- 数组创建后,如果没有赋值,有默认值
- 使用数组的步骤 声明数组并开辟空间 2 给数组各个元素赋值 3 使用数组
- 数组的下标是从 0 开始的。
- 数组下标必须在指定范围内使用,否则报:下标越界异常,比如 int [] arr=new int[5]; 则有效下标为 0-4
- 数组属引用类型,数组型数据是对象(object)
3. 数组的拷贝
4. 数组的反转
将数组的内容反转,{1,2,3,4,5}变成{5,4,3,2,1}
5. 反转拷贝/逆序赋值
注意:如果arr1=arr2,此时arr1 原来的数据空间就没有变量引用,arr1会被销毁
6. 数组的添加/扩容
7. 冒泡排序

8. 数组查找
- 顺序查找
- 二分查找
9. 多维数组—二维数组
1. 动态初始化
2. 静态初始化
3. 二维数组的内存图

第6章 面向对象
面向对象(基础)
6.1 创建类
访问修饰符+类+类名+{ }
6.2 创建属性
6.3 创建对象
- 先声明再创建
- 直接创建
6.4 如何访问属性
- 基本语法
对象名.属性名;
6.5 类和对象的内存分配机制
例如
定义一个人类(Person)(包括 名字,年龄)。
内存图:

6.6 成员方法
6.6.1 方法的定义
访问修饰符 返回数据类型 方法名(形参列表..) { //方法体语句; return 返回值; }
- 形参列表:表示成员方法输入 cal(int n) , getSum(int num1, int num2)
- 返回数据类型:表示成员方法输出, void 表示没有返回值
- 方法主体:表示为了实现某一功能代码块
- return 语句不是必须的。如果返回类型不是void,则需要return
- return也代表结束方法
6.6.2 方法调用的机制原理


6.6.3 成员方法的好处
- 提高代码的复用性
- 可以将实现的细节封装起来,然后供其他用户来调用即可
注意事项
- 方法不能嵌套定义
- 一个方法最多有一个返回值,如果要返回多个结果,可以返回数组
- 访问修饰符 (作用是控制 方法使用的范围)
如果不写默认访问,[有四种: public, protected, 默认, private]
返回数据类型
- 一个方法最多有一个返回值
- 返回类型可以为任意类型,包含基本类型或引用类型(数组,对象)
- 如果方法要求有返回数据类型,则方法体中最后的执行语句必须为 return 值; 而且要求返回值类型必须和 return 的值类型一致或兼容
- 如果方法是 void,则方法体中可以没有return语句,或者只写return
形参列表

方法体
里面写完成功能的具体的语句,可以为输入、输出、变量、运算、分支、循环、方法调用,但里面不能再定义方法!即:方法不能微套定义。
方法调用细节
- 同一个类中的方法调用,直接调用即可
- 跨类中的方法A类调用B类方法,需要通过对象名调用。比如:对象名.方法名(参数)
方法的值传递和引用传递
- 变量/基本类型 传值,不影响实参

- 引用类型 传内存地址,影响实参
因为引用类型共用地址,所以会影响main中指向的地址

- 如果置空方法,则不会影响main

6.6.4 方法递归
简单的说: 递归就是方法自己调用自己,每次调用时传入不同的变量.递归有助于编程者解决复杂问题,同时可以让代码变得简洁
6.6.5 递归能解决什么问题

6.6.6 递归举例

6.6.7 递归重要规则
- 执行一个方法时,就创建一个新的受保护的独立空间(栈空间)
- 方法的局部变量是独立的,不会相互影响,比如n变量
- 如果方法中使用的是引用类型变量(比如数组,对象),就会共享该引用类型的数据.
- 递归必须向退出递归的条件逼近,否则就是无限递归,出现 StackOverflowError,死龟了:)
- 当一个方法执行完毕,或者遇到return,就会返回,遵守谁调用,就将结果返回给谁,同时当方法执行完毕或者返回时,该方法也就执行完毕。
面向对象(进阶)
6.7 方法重载
在同一个类中,允许同时存在一个以上同名的方法的现象就叫做方法的重载,也就是说,两个或者两个以上的方法,具有相同的名称和不同的参数列表
6.7.1 重载的好处
- 减轻了起名的麻烦
- 减轻了记名的麻烦
6.7.2 写法
6.7.3 方法重载的规则
- 方法名称相同
- 形参列表:必须不同(形参类型或个数或顺序,至少有一样不同,参数名无要求)
- 方法的返回值类型可以相同,也可以不同
练习

6.8 可变参数
java 允许将同一个类中多个同名同功能但参数个数不同的方法,封装成一个方法。就可以通过可变参数实现
相当于可以传多个形参
6.8.1基本语法
访问修饰符 返回类型 方法名(数据类型... 形参名) { }
6.8.2 写法
6.8.3 使用事项和细节
- 可变参数的实参可以为0个或任意多个。
- 可变参数的实参可以为数组。

- 可变参数的本质就是数组.
- 可变参数可以和普通类型的参数一起放在形参列表,但必须保证可变参数在最后
- 一个形参列表中只能出现一个可变参数
6.9 作用域
- 在java编程中,主要的变量就是属性(成员变量)和局部变量。
我们说的局部变量一般是指在成员方法中定义的变量。【举例Cat类:cry】
6.9.1 java中作用域的分类
- 全局变量:也就是属性,作用域为整个类体Cat类:cry eat等方法使用属性
- 局部变量:也就是除了属性之外的其他变量,作用域为定义它的代码块中!
注意事项和使用细节
- 全局变量(属性)可以不赋值,直接使用,因为有默认值,局部变量必须赋值后,才能使用,因为没有默认值。
- 属性和局部变量可以重名,访问时遵循就近原则
- 在同一个作用域中,比如在同一个成员方法中,两个局部变量,不能重名。
- 属性生命周期较长,伴随着对象的创建而创建,伴随着对象的销毁而销毁。局部变量生命周期较短,伴随着它的代码块的执行而创建,伴随着代码块的结束而销毁。 即在一次方法调用过程中。
- 作用域范围不同 全局变量/属性:可以被本类使用,或其他类使用(通过对象调用) 局部变量:只能在本类中对应的方法中使用
- 修饰符不同 全局变量/属性可以加访问修饰符 局部变量不可以加访问修饰符
6.10 构造方法/构造器
构造方法又叫构造器(constructor),是类的一种特殊的方法,它的主要作用是完成对新对象的初始化。
相当于创建对象的时候指定对象的属性
6.10.1 基本语法
修饰符 方法名 (形参列表){ 方法体; }
6.10.2 写法
说明
- 构造器的修饰符可以默认, 也可以是 public protected private
- 构造器没有返回值
- 方法名 和类名必须一样
- 参数列表 和 成员方法一样的规则
- 构造器的调用, 由系统完成
注意事项和使用细节
- 一个类可以定义多个不同的构造器,即构造器重载 比如:我们可以再给Person类定义一个构造器,用来创建对象的时候,只指定人名,不需要指定年龄
- 构造器名和类名要相同
- 构造器没有返回值
- 构造器是完成对象的初始化,并不是创建对象
- 在创建对象时,系统自动的调用该类的构造方法
- 如果程序员没有定义构造器,系统会自动给类生成一个默认无参构造器(也叫默认构造器)
- 一旦定义了自己的构造器,默认的构造器就覆盖了,就不能再使用默认的无参构造器,除非显式的定义一下(就是自己写出来)
构造方法和普通方法的区别
- 作用不同 构造方法是为了创建一个类的实例。这个过程只可以在创建一个对象的时候用到。普通方法的作用是为了完成一段业务功能。
- 修饰符不同 和普通方法一样,构造方法可以有任何访问的修饰:public,protected,private或者没有修饰。不同于普通方法的是,构造方法不能有以下非访问性质的修饰:abstract,final, native,static或者synchronized。
- 返回值不同 返回类型也是非常重要的。普通方法能返回任何类型的值或者无返回值(void),构造方法没有返回值,也不需要void。
- 命名不同 构造方法使用和类相同的名字,而普通方法则不同。按照习惯,普通方法通常用小写字母开始,而构造方法通常用大写字母开始。构造方法通常是一个名词,因为它和类名相同;而方法通常更接近动词,因为它说明一个操作
6.11 this 关键字
简单来说,哪个对象调用,this就代表哪个对象
this的内存分析图

我们可以看到this指向的地址就是调用它的地址
注意事项和使用细节
- this 关键字可以用来访问本类的属性、方法、构造器
- this 用于区分当前类的属性和局部变量
- 访问成员方法的语法:方法名(参数列表);
- 访问构造器语法:this(参数列表); 注意只能在构造器中使用(即只能在构造器中访问另外一个构造器, 必须放在第一条语句)

- this 不能在类定义的外部使用,只能在类定义的方法中使用。
6.12 包
6.12.1 包的三大作用
- 区分相同名字的类
- 当类很多时,可以很好的管理类[看Java API文档]
- 控制访问范围
6.12.2 包的本质分析(原理)


6.12.3 包的命名
命名规则
只能包含数字、字母、下划线、小圆点.但不能用数字开头,不能是关键字或保留字
命名规范
一般是小写字母+小圆点一般是
com.公司名.项目名.业务模块名
举例:
com.sina.crm.user //用户模块
com.sina.crm.order //订单模块
com.sina.crm.utils //工具类
6.12.4 常用的包
一个包下,包含很多的类,java 中常用的包有:
- java.lang.* //lang 包是基本包,默认引入,不需要再引入.
- java.util.* //util 包,系统提供的工具包, 工具类,使用 Scanner
- java.net.* //网络包,网络开发
- java.awt.* //是做 java 的界面开发,GUI
6.12.5 如何引入包
我们引入一个包的主要目的是要使用该包下的类
语法:
import 包;
例如:
import java.util.Arrays ;
import java.util.Scanner ;
import java.util.*
*代表引入全部
建议:
我们需要使用到哪个类,就导入哪个类即可,不建议使用 *导入
注意事项和使用细节
1.package 的作用是声明当前类所在的包,需要放在类的最上面,一个类中最多只有一句package
2.import指令位置放在package的下面,在类定义前面,可以有多句且没有顺序要求。
6.13 访问修饰符
java 提供四种访问控制修饰符号,用于控制方法和属性(成员变量)的访问权限(范围)
- 公开级别:用 public 修饰,对外公开
- 受保护级别:用 protected 修饰,对子类和同一个包中的类公开
- 默认级别:没有修饰符号,向同一个包的类公开.
- 私有级别:用 private 修饰,只有类本身可以访问,不对外公开.
6.13.1 4种访问修饰符的访问范围
访问级别 | 访问控制修饰符 | 同类 | 同包 | 子类 | 不同包 |
公开 | public | √ | √ | √ | √ |
受保护 | protected | √ | √ | √ | × |
默认 | 没有修饰符 | √ | √ | × | × |
私有 | private | √ | × | × | × |
使用的注意事项
- 修饰符可以用来修饰类中的属性,成员方法以及类
- 只有默认的和public才能修饰类!,并且遵循上述访问权限的特点。
- 成员方法的访问规则和属性完全一样.
6.14 面向对象的三大特征
面向对象编程有三大特征:封装、继承和多态。
6.15 封装
封装(encapsulation)就是把抽象出的数据[属性]和对数据的操作[方法]封装在一起,数据被保护在内部,程序的其它部分只有通过被授权的操作[方法],才能对数据进行操作。
6.15.1 封装的理解和好处
- 隐藏实现细节:方法(连接数据库)<--调用(传入参数……)
- 可以对数据进行验证,保证安全合理
6.15.2 封装的实现步骤(三步)

快速入门案例
请大家看一个小程序,不能随便查看人的年龄,工资等隐私,并对设置的年龄进行合理的验证。年龄合理就设置,否则给默认年龄,必须在1-120,年龄,工资不能直接查看,name的长度在2-6字符之间
将构造器和setXXX结合
6.16 继承
6.16.1 为什么需要继承
我们编写了两个类,一个是Pupil 类(小学生),一个是Graduate类(大学毕业生).
问题:两个类的属性和方法有很多是相同的,怎么办?
这时候就需要继承来提高代码的复用性
6.16.2 继承基本介绍和示意图
介绍:
继承可以解决代码复用,让我们的编程更加靠近人类思维.当多个类存在相同的属性(变量)和方法时,可以从这些类中抽象出父类,在父类中定义这些相同的属性和方法,所有的子类不需要重新定义这些属性和方法,只需要通过 extends 来声明继承父类即可。
示意图:

6.16.3 继承的基本语法
- 子类就会自动拥有父类定义的属性和方法
- 父类又叫超类,基类。
- 子类又叫派生类。
6.16.4 继承的的好处
- 代码的复用性提高了
- 代码的扩展性和维护性提高了
6.16.5 继承的深入讨论/细节问题
- 子类继承了所有的属性和方法,非私有的属性和方法可以在子类直接访问, 但是私有属性和方法不能在子类直接访问,要通过父类提供公共的方法去访问
- 子类必须调用父类的构造器, 完成父类的初始化
- 当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器,如果父类没有提供无参构造器,则必须在子类的构造器中用 super 去指定使用父类的哪个构造器完成对父类的初始化工作,否则,编译不会通过
- 如果希望指定去调用父类的某个构造器,则显式的调用一下 : super(参数列表)
- super 在使用时,必须放在构造器第一行(super 只能在构造器中使用)
- super() 和 this() 都只能放在构造器第一行,因此这两个方法不能共存在一个构造器
- java 所有类都是 Object 类的子类, Object 是所有类的基类.
- 父类构造器的调用不限于直接父类!将一直往上追溯直到 Object 类(顶级父类)
- 子类最多只能继承一个父类(指直接继承),即 java 中是单继承机制。思考:如何让 A 类继承 B 类和 C 类? 【A 继承 B, B 继承 C】
- 不能滥用继承,子类和父类之间必须满足 is-a 的逻辑关系,比如:cat extends Animal //cat is a animal
6.16.6 继承内存分布图

案例

6.17 super关键字
super 代表父类的引用,用于访问父类的属性、方法、构造器
6.17.1 基本语法
- 访问父类的属性,但不能访问父类的private属性 super.属性名;
- 访问父类的方法,不能访问父类的private方法 super.方法名(参数列表);
- 访问父类的构造器(这点前面用过): super(参数列表);只能放在构造器的第一句,只能出现一句!
6.17.2 super 给编程带来的便利/细节
- 调用父类的构造器的好处(分工明确,父类属性由父类初始化,子类的属性由子类初始化)
- 当子类中有和父类中的成员(属性和方法)重名时,为了访问父类的成员,必须通过super。如果没有重名,使用super、this、直接访问是一样的效果!
- super的访问不限于直接父类,如果爷爷类和本类中有同名的成员,也可以使用super去访问爷爷类的成员;如果多个基类(上级类)中都有同名的成员,使用super访问遵循就近原则。A->B->C,当然也需要遵守访问权限的相关规则
super 和this的区别

练习

6.18 方法的重写/覆盖(override)
简单的说:方法覆盖(重写)就是子类有一个方法,和父类的某个方
法的名称、返回类型、参数一样,那么我们就说子类的这个方法
覆盖了父类的方法
6.18.1 注意事项和使用细节

6.18.2 方法重写和重载的区别

6.19 多态
方法或对象具有多种形态。是面向对象的第三大特征,多态是建立在封装和继承基础之上的。
6.19.1 多态的具体体现
方法的多态
重写和重载就体现多态
对象的多态
- 一个对象的编译类型和运行类型可以不一致
- 编译类型在定义对象时,就确定了,不能改变
- 运行类型是可以变化的.
- 编译类型看定义时=号的左边,运行类型看=号的右边
例如:
Animal animal = new Dog();【animal 编译类型是Animal,运行类型Dog】
animal=new Cat()【animal的运行类型变成了Cat,编译类型仍然是Animal】
6.19.2 注意事项
- 多态的前提是:两个对象(类)存在继承关系
6.19.3 向上转型
本质:父类的引用指向子类的对象
语法:父类类型 引用名=new 子类类型();
特点:编译类型看左边,运行类型看右边
- 可以调用父类中的所有成员(需遵守访问权限), 不能调用子类中特有成员; 最终运行效果看子类的具体实现!

6.19.4 向下转型
向下转型是建立在向上转型的基础上
语法:子类类型 引用名 = (子类类型)父类引用;
- 只能强转父类的引用,不能强转父类的对象 要求父类的引用必须指向的是当前目标类型的对象 当向下转型后,可以调用子类类型中所有的成员

练习


调用属性看编译类型,调用方法看运行类型,
Base b=s ;
b.count //调用属性,所以看编译类型Base b
b.display //调用方法,所以看运行类型s (new Sub())
6.19.5 细节
- 属性没有重写之说,属性的值看编译类型

6.19.6 instanceOf 比较操作符
用于判断对象的运行类型是否为 XX 类型或XX 类型的子类型
6.19.7 java的动态绑定机制


6.19.8 多态的应用
多态数组:

6.20 Object类
6.20.1 equals和==的对比(面试题)
- == 是一个比较运算符 == 既可以判断基本类型,又可以判断引用类型 == 如果判断基本类型,判断的是值是否相等。示例:int i=10;double d=10.0; == 如果判断引用类型,判断的是地址是否相等,即判定是不是同一个对象
- equals:是Object类中的方法,只能判断引用类型 默认判断的是地址是否相等,子类中往往重写该方类方法
6.20.2 如何重写equals方法
应用实例: 判断两个Person 对象的内容是否相等,如果两个 Person 对象的各个属性值都一样,则返回 true,反之 false
6.20.3 hashCode 方法
用于返回对象的哈希值
- 提高具有哈希结构的容器的效率!
- 两个引用,如果指向的是同一个对象,则哈希值肯定是一样的!
- 两个引用,如果指向的是不同对象,则哈希值是不一样的
- 哈希值主要根据地址号来的!, 不能完全将哈希值等价于地址。
6.20.4 toString 方法
默认返回:全类名+@+哈希值的十六进制,【查看 Object 的 toString 方法】子类往往重写 toString 方法,用于返回对象的属性信息
子类往往重写 toString 方法,用于返回对象的属性信息
如何重写toString方法:
右键生成toString方法,修改输出内容即可
注意:
若子类没有重写toString方法,则会调用父类的toString方法。若父类也没重写,则调用子类的未重写的toString方法(即地址)
6.20.5 断点调试(debug)
断点调试是指在程序的某一行设置一个断点,调试时,程序运行到这一行就会停住然后你可以一步一步往下调试,调试过程中可以看各个变量当前的值,出错的话,调试到出错的代码行即显示错误,停下。进行分析从而找到这个Bug断点调试是程序员必须掌握的技能。断点调试也能帮助我们查看java底层源代码的执行过程,提高程序员的Java水平
快捷键
F7(跳入) F8(跳过) shift+F8(跳出) F9(resume,执行到下一个断点)
F7:跳入方法内
F8: 逐行执行代码.
shift+F8: 跳出方法


面向对象(高级)
6.21 static 类变量和类方法(静态变量和静态方法)
使用static修饰的成员变量就是静态变量(或类变量、类属性)
类变量也叫静态变量/静态属性,是该类的所有对象共享的变量,任何一个该类的对象去访问它时,取到的都是相同的值,同样任何一个该类的对象去修改它时,修改的也是同一个变量。
类变量
1. 基本语法
访问修饰符 static 数据类型 变量名;[推荐]
static 访问修饰符 数据类型 变量名;
2. 静态变量的特点
- 静态变量的默认值规则和实例变量一样。
- 静态变量值是所有对象共享。
- 静态变量在本类中,可以在任意方法、代码块、构造器中直接使用。
- 如果权限修饰符允许,在其他类中可以通过“
类名.静态变量
”直接访问,也可以通过“对象.静态变量
”的方式访问(但是更推荐使用类名.静态变量的方式)。
- 静态变量的get/set方法也静态的,当局部变量与静态变量
重名时
,使用“类名.静态变量
”进行区分。
3. 如何访问类变量
类名.类变量名
或者对象名.类变量名
推荐使用:类名.类变量名;
【静态变量的访问修饰符的访问权限和范围和普通属性是一样的。】
4. 类变量的内存解析


5. 注意事项和细节
- 什么时候需要用类变量 当我们需要让某个类的所有对象都共享一个变量时,就可以考虑使用类变量(静态变量):比如:定义学生类,统计所有学生共交多少钱。Student(name,static fee)
- 类变量与实例变量(普通属性)区别类变量是该类的所有对象共享的,而实例变量是每个对象独享的。
- 加上static称为类变量或静态变量,否则称为实例变量/普通变量/非静态变量
- 类变量可以通过类名.类变量名或者对象名.类变量名来访问,但java设计者推荐 我们使用类名.类变量名方式访问。【前提是满足访问修饰符的访问权限和范围】
- 实例变量不能通过类名.类变量名方式访问。
- 类变量是在类加载时就初始化了,也就是说,即使你没有创建对象,只要类加载了,就可以使用类变量了。
- 类变量的生命周期是随类的加载开始,随着类消亡而销毁。
类方法
1. 基本语法
访问修饰符 static 数据返回类型 方法名(){ }
static 访问修饰符 数据返回类型 方法名(){ }
2. 类方法的调用
类名.类方法名.
或者 对象名.类方法名【前提是满足访问修饰符的权限】
3.类方法的使用场景
比如:工具类中的方法 utils、Math类、Arrays类、Collections 集合类……
在程序员实际开发,往往会将一些通用的方法,设计成静态方法,这样我们不需要创建对象就可以使用
了,比如打印一维数组,冒泡排序,完成某个计算任务等
4. 注意事项和细节
- 类方法和普通方法都是随着类的加载而加载,将结构信息存储在方法区: 类方法中无this的参数 普通方法中隐含着this的参数
- 类方法可以通过类名调用,也可以通过对象名调用。
- 普通方法和对象有关,需要通过对象名调用,比如对象名.方法名(参数),不能通过类名调 用。
- 类方法中不允许使用和对象有关的关键字,比如this和super。普通方法(成员方法)可以。
- 类方法(静态方法)中只能访问静态变量或静态方法。
- 管通成员方法,既可以访问 非静态成员,也可以访问静态成员。
小结:静态方法,只能访问静态的成员,非静态的方法,可以访问静态成员和非静态成员
(必须遵守访问权限)
类变量类方法练习

6.22 理解main方法
1. 解释main方法的形式
public static void main(String[ ] args){ }
- main方法时虚拟机调用
- java虚拟机需要调用类的main0方法,所以该方法的访问权限必须是public
- java虚拟机在执行mainO方法时不必创建对象,所以该方法必须是static
- 该方法接收String类型的数组参数,该数组中保存执行java命令时传递给所运行的类的参数,
- java 执行的程序参数1参数2参数3

6.23 代码块
1.介绍
代码化块又称为初始化块,属于类中的成员[即是类的一部分],类似于方法,将逻辑语句封装在方法体中,通过包围起来。
但和方法不同,没有方法名,没有返回,没有参数,只有方法体,而且不用通过对象或类显式调用,而是加载类时,或创建对象时隐式调用。
2. 语法
【修饰符】{
代码
};
3. 注意
- 修饰符可选,要写的话,也只能写static
- 代码块分为两类,使用static修饰的叫静态代码块,没有static修饰的,叫普通代码块/非静态代码块。
- 逻辑语句可以为任何逻辑语句(输入、输出、方法调用、循环、判断等)
- ;号可以写上,也可以省略。
4. 代码块的好处
- 相当于另外一种形式的构造器(对构造器的补充机制),可以做初始化的操作
- 场景:如果多个构造器中都有重复的语句,可以抽取到初始化块中,提高代码的重用性
5. 注意事项和细节讨论
- static代码块也叫静态代码块,作用就是对类进行初始化,而且它随着类的加载而执行,并且只会执行一次,如果是普通代码块,每创建一个 对象,就执行。
- 类什么时候被加载 ①创建对象实例时(new) ②创建子类对象实例,父类也会被加载 ③使用类的静态成员时(静态属性,静态方法)
- 普通的代码块,在创建对象实例时,会被隐式的调用。被创建一次,就会调用一次。 如果只是使用类的静态成员时,普通代码块并不会执行。
- 创建一个对象时,在一个类调用顺序是: ① 调用静态代码块和静态属性初始化(注意:静态代码块和静态属性初始化调用的优先级一样,如果有多个静态代码块和多个静态变量初始化,则按他们定义的顺序调用) ②调用普通代码块和普通属性的初始化(注意:普通代码块和普通属性初始化调用的优先级一样,如果有多个普通代码块和多个普通属性初始化,则按定义顺序调用) ③调用构造方法。 同类执行顺序:静态代码块—>代码块—>构造器(如果有多个静态/普通,则谁先声明就先调用谁,依旧按照执行顺序)
- 创建子类对象时,调用顺序 ①父类的静态代码块和静态属性(优先级一样,按定义顺序执行) ②子类的静态代码块和静态属性(优先级一样,按定义顺序执行) ③父类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行) ④父类的构造方法 ⑤子类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行) ⑥子类的构造方法//面试题
- 静态代码块只能直接调用静态成员(静态属性和静态方法),普通代码块可以调用任意成员。
6. 普通代码块和静态代码块的区别
普通代码块和静态代码块的执行:

静态代码块

如果只调用静态成员,普通代码块就不会执行

7. 代码块练习

6.24 单例设计模式
6.25 fina关键字
1. 介绍
final 可以修饰类、属性、方法和局部变量。
在某些情况下,程序员可能有以下需求,就会使用到final:
①当不希望类被继承时,可以用final修饰.
②当不希望父类的某个方法被子类覆盖/重写时,可以用final关键字修饰
③当不希望类的的某个属性的值被修改,可以用final修饰.
④当不希望某个局部变量被修改,可以使用final修饰
2. 注意事项和细节讨论
- final修饰的属性又叫常量,一般用XX_XX_XX来命名
- final修饰的属性在定义时,必须赋初值,并且以后不能再修改,赋值可以在如下位置之一【选择一个位置赋初值即可】: ①定义时:如 public final double TAX_RATE=0.08; ②在构造器中 ③在代码块中。
- 如果final修饰的属性是静态的,则初始化的位置只能是 ① 定义时② 在静态代码块 不能在构造器中赋值。
- final类不能继承,但是可以实例化对象。
- 如果类不是final类,但是含有final方法,则该方法虽然不能重写,但是可以被继承。
- 一般来说,如果一个类已经是final类了,就没有必要再将方法修饰成final方法。
- final不能修饰构造方法(即构造器)
- final 和static往往搭配使用,效率更高,不会导致类加载.底层编译器做了优化处理。
- 包装类(Integer,Double,Float,Boolean等都是final),String也是final类。
6.26 抽象类
当父类的某些方法,需要声明,但又不确定如何实现时,可以将其声明为抽象方法,那么这个类就是抽象类
1. 介绍
- 用abstract关键字来修饰一个类时,这个类就叫抽象类
访问修饰符 abstract 类名{ }
- 用abstract 关键字来修饰一个方法时,这个方法就是抽象方法
访问修饰符 abstract 返回类型 方法名(参数列表);//没有方法体
- 抽象类的价值更多作用是在于设计,是设计者设计好后,让子类继承并实现抽象类
- 抽象类,是考官比较爱问的知识点,在框架和设计模式使用较多
2. 注意事项和细节讨论
- 抽象类不能被实例化
- 抽象类不一定要包含abstract方法。也就是说,抽象类可以没有abstract方法
- 一旦类包含了abstract方法,则这个类必须声明为abstract
- abstract 只能修饰类和方法,不能修饰属性和其它的。
- 抽象类可以有任意成员(因为其本质还是一个类),比如:非抽象方法、构造器、静态属性等
- 抽象方法不能有主体,即不能实现

- 如果一个类继承了抽象类,则它必须实现抽象类的所有抽象方法,除非它自己也声明为abstract类
- 抽象方法不能使用private、final和static来修饰,因为这些关键都是和重写相违背的
6.27 接口
1. 语法
2. 注意事项和使用细节
- 接口不能被实例化
- 接口中所有的方法是public方法,接口中的抽象方法可以不用abstract修饰
void aaa( );
实际上是 abstract void aa( ); //没有方法体{ }
- 一个普通类实现接口,就必需将该接口的所有方法都实现
- 抽象类实现接口,可以不用实现接口方法
- 一个类可以同时实现多个接口
- 接口中的属性,只能是final的,而且是public static final 修饰符.比如:
int a=1;
//实际上是 public static final int a=1;(必须初始化)
- 接口中属性的访问形式: 接口名 . 属性名
- 接口不能继承其它类,但是可以继承多个别的接口
- 接口的修饰符,只能是public 和默认,这点和类的修饰符是一样的
3. 接口和继承该怎么选?

接口和继承解决的问题不同
继承的价值主要在于:解决代码的复用性和可维护性。
接口的价值主要在于:设计,设计好各种规范(方法),让其它类去实现这些方法。即更加的灵活..
接口比继承更加灵活
接口比继承更加灵活,继承是满足is-a的关系,而接口只需满足like -a的关系。
接口在一定程度上实现代码解耦[即:接口规范性+动态绑定机制]
4. 接口的多态性
- 多态参数
- 多态数组
- 接口存在多态传递的现象
5. 接口练习

访问接口的属性就用接口.属性名
访问父类的属性就用super.属性名
6.28 内部类
1. 内部类的分类
定义在外部类局部位置上(比如方法内):
①局部内部类(有类名)
②匿名内部类(没有类名)
定义在外部类的成员位置上:
①成员内部类(没用static修饰)
②静态内部类(用static修饰)
2. 局部内部类
说明:局部内部类是定义在外部类的局部位置,比如方法中,并且有类名。
- 可以直接访问外部类的所有成员,包含私有的
- 不能添加访问修饰符,因为它的地位就是一个局部变量。局部变量是不能使用修饰符的。但是可以使用final修饰,因为局部变量也可以使用final。如果不想让其他类继承局部内部类,就可以用final。
- 作用域:仅仅在定义它的方法或代码块中。
- 局部内部类---访问---->外部类的成员[访问方式:直接访问]
- 外部类---访问---->局部内部类的成员 访问方式:创建对象,再访问(注意:必须在作用域内)
- 外部其他类---不能访问--->局部内部类(因为局部内部类地位是一个局部变量)
- 如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问【演示】 System.out.println(“外部类的n2="+外部类名.this.n2);
记住:(1)局部内部类定义在方法中/代码块
(2)作用域在方法体或者代码块中
(3)本质仍然是一个类
3. 匿名内部类
- 基本语法
- 创建


- 匿名内部类的使用 1. 只创建一次,用完就删了。这样可以简化代码,就不用再去创建一个类
2.当对象使用
- 细节
- 本质还是一个类,是内部类,类没有名字,并且还是一个对象
- 匿名内部类是定义在外部类的局部位置,比如方法中或者代码块中
- 匿名内部类的语法比较奇特,因为匿名内部类既是一个类的定义,同时它本身也是一个对象,因此从语法上看,它既有定义类的特征,也有创建对象的特征,对前面代码分析可以看出这个特点,因此可以调用匿名内部类方法。
- 可以直接方问外部类的所有成员,包含私有的[案例演示]
- 不能添加访问修饰符,因为它的地位就是一个局部变量。
- 作用域:仅仅在定义它的方法或代码块中。
- 匿名内部类…-访问-->外部类成员[访问方式:直接访问]
- 外部其他类…不能访问-…->匿名内部类(因为匿名内部类地位是一个局部变量)
- 如果外部类和匿名内部类的成员重名时,匿名内部类访问的话,默认遵循就近原则,
- 如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问
第7章 枚举和注解
第8章 异常
1. 异常的分类
- 编译时异常,是编译器要求必须处置的异常。
- 运行时异常,编译器检查不出来。一般是指编程时的逻辑错误,是程序员应该避免其出现的异常。java.lang.RuntimeException类及它的子类都是运行时异常 对于运行时异常,可以不作处理,因为这类异常很普遍, 若全处理可能会对程序的可读性和运行效率产生影响
2.体系图

- SQLException//操作数据库时,查询表可能发生异常
- IOException//操作文件时,发生的异常
- FileNotFoundException //当操作一个不存在的文时,发生异常
- ClassNotFoundException//加载类,而该类不存在时,异常
- EOFException//操作文件,到文件末尾,发生异常 IllegalArguementException //参数异常
4. 常见的运行时异常
- NullPointerException 空指针异常
- ArithmeticException 数学运算异常
- ArrayIndexOutOfBoundsException 数组下标越界异常
- ClassCastException 类型转换异常
- NumberFormatException 数字格式不正确异常[]
5. 异常处理
1. try-catch-finally
语法:
注意事项
- 如果异常发生了,则异常发生后面的代码不会执行,直接进入到catch块.
- 如果异常没有发生,则顺序执行try的代码块,不会进入到catch. 3)如果希望不管是否发生异常,都执行某段代码(比如关闭连接,释放资源等) 则使用如下代码-finally{ }
- 可以有多个catch语句,捕获不同的异常(进行不同的业务处理),要求父类异 常在后,子类异常在前,比如(Exception 在后,NullPointerException 在前),如果发生异常,只会匹配一个catch
- 可以进行try-finally配合使用,这种用法相当于没有捕获异常,因此程序会直接崩掉/退出。应用场景,就是执行一段代码,不管是否发生异常,都必须执行某个业务逻辑
- finally语句会在return语句之前执行,除非finally里有return语句,则不执行try里的return.
2. throws

语法:
注意事项和使用细节:
- 对于编译异常,必须显示处理,比如try-catch或者throws

- 对于运行时异常,程序中没有显示处理的话,则默认就是throws处理

- 子类重写父类的方法时,对抛出的异常规定: 子类重写的方法,所抛出的异常类型要么和父类抛出的异常一致,要么为父类抛出异常的类型的子类型(和重写时访问修饰符的规则类似)
- 在throws过程中,如果方法try-catch,就相当于处理异常,就可不必throws
3. 自定义异常
当程序中出现了某些“错误”,但该错误信息并没有在Throwable子类中描述处理,这个时候可以自己设计异常类,用于描述该错误信息。
- 语法
4. throws和throw的区别
ㅤ | 意义 | 位置 | 后面跟的东西 |
throws | 异常处理的一种方式 | 方法声明处 | 异常类型 |
throw | 手动生成异常对象的关键字 | 方法体中 | 异常对象 |
第9章 常用类
1.包装类
- 针对八种基本数据类型相应的引用类型—包装类
- 有了类的特点,就可以调用类中的方法。


1.包装类和基本数据的转换
JDK5以前是手动

自动,底层还是手动//调用valueOf

2. 包装类和String类型的相互转换
3. Integer 类和Character 类的常用方法
可以通过图查询到其含有的字段和方法,跳转到源 可以查看到源码。


4. Integer 类面试题

解析


2. 字符串类
1. String 类的理解和创建对象
- String对象用于保存字符串,也就是一组字符序列
- 字符串常量对象是用双引号括起的字符序列。例如:“你好”、“12.97”、“boy”等
- 字符串的字符使用Unicode字符编码,一个字符(不区分字母还是汉字)占两个字节
- String类较常用构造器(其它看手册);
字符串 s1 =新字符串();
字符串 s2 = 新字符串(原始字符串);
字符串 s3 = 新字符串(字符[] a);
字符串 s4 = new String(char[] a, int startIndex, int count)
实现Serializable,说明可以串行化,即可以在网络上传输。
实现接口Comparable [String 对象可以比较大小]


2. 创建string对象的两种方式
两种方式的区别
- 常量池有

- 常量池没有

3. 测试题

解析
T
T //因为判断的是 .name 的地址,也就是hspedu在常量池的地址,所以为Ture
T
F

3. 字符串的特性
- String是一个final类,代表不可变的字符序列
- 字符串是不可变的。一个字符串对象一旦被分配,其内容是不可变的.
面试题

解析
2个


解析
1个
1.编译器不傻,会做一个优化,判断创建的常量池对象,是否有引用指向
2. String a = "hello"+"abc"; → String a = "helloabc";

解析
3个
1.先创建一个 StringBuilder sb =StringBuilder()
2.执行 sb.append("hello");
3. sb.append("abc");
4. String c= sb.toString()
最后其实是 c指向堆中的对象(String)value[]→池中"helloabc"

重要规则
String c1="ab"+"cd"; 常量相加,看的是池。
String c1=a+b;变量相加,是在堆中
综合练习

解析
hsp and have

每次调用方法就会产生对应的新栈
3. String 类的常见方法
第10章 集合
1. 集合对比数组
数组
1)长度开始时必须指定,而且一旦指定,不能更改
2)保存的必须为同一类型的元素
3)使用数组进行增加/删除元素的示意代码-比较麻烦
集合
1)可以动态保存任意多个对象,使用比较方便!
2) 提供了一系列方便的操作对象的方法:add、remove、set、get等
3)使用集合添加,删除新元素的示意代码-简洁了
2. 集合的框架体系
主要分为两大类:
1. Collection

2. map

- 集合主要是两组(单列集合, 双列集合)
- Collection 接口有两个重要的子接口List Set , 他们的实现子类都是单列集合 (单列数据)
- Map 接口的实现子类是双列集合,存放的K-V (双列数据)
3. Collection 接口和常用方法
1. Collection 接口实现类的特点
- collection实现子类可以存放多个元素,每个元素可以是Object
- 有些Collection的实现类,可以存放重复的元素,有些不可以
- Collection的实现类,有些是有序的(List),有些不是有序(Set)
- Collection接口没有直接的实现子类,是通过它的子接口Set和List来实现的…
2. Collection 接口常用方法
- add:添加单个元素
- remove:删除指定元素
- contains:查找元素是否存在
- size:获取元素个数
- isEmpty:判断是否为空
- clear:清空
- addAll:添加多个元素
- removeAll:删除多个元素
以实现子类 ArrayList 来演示:
3. Collection 接口遍历元素方式
1. 使用Iterator(迭代器)
- Iterator对象称为迭代器,主要用于遍历Collection集合中的元素。
- 所有实现了Collection接口的集合类都有一个iterator()方法,用以返回一个实现了lterator接口的对象,即可以返回一个迭代器。
- Iterator的结构

迭代器的执行原理
lterator接口的方法
在调用iterator.next()方法之前必须要调用iterator.hasNext()进行检测。若不调用,且下一条记录无效,直接调用iterator.next()会抛出NoSuchElementException 异常

迭代器使用方法
Iterator 仅用于遍历集合,Iterator 本身并不存放对象。
2. 使用增强for
增强for循环,可以代替iterator迭代器,特点:增强for就是简化版的iterator,本质一样。只能用于遍历集合或数组。
基本语法:
实例:
4. List接口和常用方法
1. 基本介绍
List 接口是 Collection接口的子接口
- List集合类中元素有序(即添加顺序和取出顺序一致)、且可重复
- List集合中的每个元素都有其对应的顺序索引,即支持索引。
- List容器中的元素都对应一个整数型的序号记载其在容器中的位置,可以根据序号存取容器中的元素。
- JDK API中List接口的实现类有很多:

2. List 接口的常用方法
这部分方法是List独有的,set用不了。
- void add(int index, Object ele):在index位置插入ele元素
- boolean addAll(int index, Collection eles):从index位置开始将eles中的所有元素添加进来
- Object get(int index):获取指定index位置的元素
- int indexOf(Object obj):返回obj在集合中首次出现的位置
- int lastIndexOf(Object obj):返回obj在当前集合中末次出现的位置
- Object remove(int index):移除指定index位置的元素,并返回此元素
- Object set(int index, Object ele):设置指定index位置的元素为ele , 相当于是替换.
- List subList(int fromIndex, int toIndex):返回从fromIndex到toIndex位置的子集合。(fromIndex <= subList < toIndexdai
3. List 的三种遍历方式 [ArrayList, LinkedList,Vector]

4. 练习题

4.1 ArrayList 底层结构和源码分析
1)ArrayList 可以加入nul,井且可以多个null
2)ArrayList 是由数组来实现数据存储的
3)ArrayList 基本等同于Vector,除了ArrayList是线程不安全(执行效率高) 看源码.
在多线程情况下,不建议使用ArrayList,因为没有synchronized
ArrayList 的底层操作机制源码分析(重点,难点.)
- ArrayList中维护了一个Object类型的数组elementData. transient Objectf] elementData;//transient表示瞬间,短暂的,表示该属性不会被序列化
- 当创建ArrayList对象时,如果使用的是无参构造器,则初始elementData容量为0,第1次添加,则扩容elementData为10,如需要再次扩容,则扩容elementData为1.5倍。
- 如果使用的是指定大小的构造器,则初始elementData容量为指定大小,如果需要扩容,则直接扩容elementData为1.5倍。


个人理解:
- 调用无参时(不指定大小):先创建空数组(elementDate数组),然后默认扩容空间为10,每次添加元素的时候都判断一下会不会超出空间范围,当超过10的时候,就调用扩容机制,扩容空间大小为10的1.5倍,即10+10/2=15; 后面空间不够的时候也是如此扩容,大小均为原来的1.5倍
- 调用有参时(指定大小):直接创建指定大小的数组,然后就判断添加元素的数量会不会超过空间的大小,超过就调用扩容机制,扩容大小也是1.5倍
4.2 Vector 底层结构和源码剖析


4.3 LinkedList 底层结构
1. LinkedList 的说明
- LinkedList底层实现了双向链表和双端队列特点
- 可以添加任意元素(元素可以重复),包括null
- 线程不安全,没有实现同步
2. LinkedList 的底层操作机制
- LinkedList底层维护了一个双向链表.
- LinkedList中维护了两个属性first和last分别指向首节点和尾节点
- 每个节点(Node对象),里面又维护了prev、next、item三个属性,其中通过prev指向前一个,通过next指向后一个节点。最终实现双向链表.
- 所以LinkedList的元素的添加和删除,不是通过数组完成的,相对来说效率较高。

///////////待完善
5. ArrayList 和 LinkedList 比较

注意:如果涉及到并发多线程,则不推荐使用这两个;这俩只适合单线程
6. Set接口
特点:⽆序、⽆下标、元素不可重复。
⽅法:全部继承⾃Collection中的⽅法。
6.1 HashSet
- 实现了Set了接口
- HashSet实际上是HashMap

- 可以存放null值,但只能有一个null
- 不能有重复的元素/对象
- HashSet不保证元素是有序的,取决于hash后,在确定索引的结果(即不保证存放元素的顺序和取出的顺序一致)
底层原理


个人理解:
先得到元素的Hash值,然后把值变成索引(相当于先确定数组位置),位置为空就添加进去,要是不为空就对比equals,要是equals相同就放弃添加,不同就跟在这个位置的元素的后面(链在后面)
源码剖析
///////待补充
6.2 LinkedHashSet
- LinkedHashSet是HashSet的子类
- LinkedHashSet 底层是一个LinkedHashMap,底层维护了一个数组+双向链表
- LinkedHashSet 根据元素的 hashCode 值来决定元素的存储位置,同时使用链表维护元素的次序(图),这使得元素看起来是以插入顺序保存的。
- LinkedHashSet不允许添重复元素
底层原理

个人理解:
和HashSet有点像,但是区别在于它第一次添加的元素之间就有链,这样就能让遍历顺序和添加顺序一致.和HashSet一样,如果添加的元素的hash值相同就调用equals,然后就判断是否能链在此元素后面(相当于链中链)
7. 重写equals和hashCode方法
相同属性的对象如何只添加一个
例如:
这俩属性是一样的,但因为是new的,hash值就不一样,就会导致这俩都能添加进去,这时候就要用到重写equals和hashCode方法


返回true就代表不添加
两个√可以根据不同的情况自行勾选
比如我只添加年龄相同的人,就可以不勾选年龄
8. Map接口
特点:
JDK8:
- Map与Collection并列存在。用于保存具有映射关系的数据:Key-Value
- Map 中的key和value可以是任何引用类型的数据,会封装到HashMap$Node对象中
- Map 中的 key 不允许重复,原因和HashSet一样;如果key相同,则后者会将其覆盖
- Map中的value 可以重复
- Map 的key可以为null,value 也可以为null,注意key为null,只能有一个,value 为null 可以多个.
- 通常用String类作为Map的key [别的类型也可以作为key]
- key 和 value 之间存在单向一对一关系,即通过指定的key总能找到对应的 value
常用方法:
put | 添加 |
remove | 根据key删除映射 |
get | 根据key获取值 |
size | 获取元素个数 |
isEmpty | 判断个数是否为0 |
clear | 清除 |
containsKey | 查找Key是否存在 |
遍历方法:

可以先使用第一组的第一种方式 , 根据后续的需求来选择别的方式
- 作者:小林
- 链接: /article/java
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。