传智播客毕向东 Java
- Java编程基础
- 基本概念
- 什么是计算机语言
计算机语言指用于人与计算机之间通讯的语言。计算机语言是人与计算机之间传递信息的媒介。为了使电子计算机进行各种工作,就需要有一套用于编写计算机程序的数字、字符和语法规划,由这些组成计算机指令就是计算机语言。
软件就是由若干条计算机语言所组成的。
- 计算机语言分类
机器语言:
机器语言是直接用二进制代码指令表达的计算机语言,指令是用0和1组成的一串代码,它们有一定的位数,并分成若干段,各段的编码表示不同的含义。
汇编语言:
汇编语言是使用一些特殊的符号来代替机器语言的二进制码,计算机不能直接识别,需要用一种软件将汇编语言翻译成机器语言。
高级语言:
使用普通英语进行编写源代码,通过编译器将源代码翻译成计算机直接识别的机器语言,之后再由计算机执行。
- 高级语言工作原理
- Java开发环境搭建
- JDK与JRE
JDK(Java Development Kit) Java开发工具,包含开发Java程序的所有组件,包含JRE
JRE(Java Runtime Environment) Java运行环境,如果要运行Java程序,就需要JRE的支持
常用组件:
src.zip Java是一门开源的语言,其源代码都在这个压缩包中
rt.jar Java的基础核心类库,我们编写Java程序时使用的class都在这个jar包中
javac.exe 编译器,将.java源代码编译为.class文件
java.exe 虚拟机,运行Java程序的工具
jar.exe 将class文件打成jar包的工具
javadoc.exe 生成帮助文档的工具
- 环境变量:环境变量是指在操作系统中用来指定操作系统运行环境的一些参数
path:
如果想在任意目录下运行一个程序,我们就需要将程序所在的路径配置在path环境变量中。
通常我们会将javac.exe所在目录配置到path中,因为我们需要在任意目录下都能编译Java源文件。
配置完成之后可以在命令行输入javac测试,如果显式帮助信息则是配置成功。
classpath:
Java虚拟机运行时加载类的路径。JDK5之后不配置默认为当前目录“.”。如使用JDK1.4或以下版本时需要人工配置。
暂时不需要配置,默认加载当前目录下的所有class文件。
配置方式:
- 命令行
点击屏幕左下角开始 – 运行 – 输入cmd – 在命令行中直接输入命令进行修改
查看变量值:set 变量名
设置变量值:set 变量名=变量值,多个值之间使用分号“;”分割,引用变量时使用“%变量名%”形式
注意:此种方式仅适用于当前窗口
- 我的电脑
鼠标右键点击我的电脑 – 属性 – 高级 – 环境变量
找到要修改的变量将其值修改,此种方式永久有效
注意:
配置环境变量之后可以查看编译器(javac.exe)和虚拟机(java.exe)版本,虚拟机版本不能低于编译器。
使用哪个版本的编译器和虚拟机取决于path环境变量,如果虚拟机版本过低,可以通过环境变量来修改。
编译器版本查看方式:javac –version
虚拟机版本查看方式:java –version
- 第一个Java程序
- 编写源代码
新建文本文档,扩展名改为.java,在文件中写入代码。
注意:
windows操作系统默认是隐藏已知文件扩展名的。
请测试新建一个文本文档,如果看到的文件名是“新建 文本文档”而不是“新建 文本文档.txt”,那么说明你的扩展名被隐藏了。
请选择菜单栏中的 工具 – 文件夹选项 – 查看 – 下拉滚动条找到“隐藏已知文件扩展名” – 取消掉这一项。
- 编译字节码文件
- 左键单机屏幕左下角开始 – 运行 – 输入cmd启动命令行窗口
- 使用DOS命令进入源代码所在目录
- 使用编译器(javac.exe)编译源代码,javac 文件名.java,编译后在该目录中会出现扩展名为class的字节码文件
常用DOS命令:
跳转到指定盘符: 盘符: 例:C: D: E:
跳转到指定目录: cd 目录 例:cd Itcast\day01 cd Tencent\QQ\Bin
显示当前目录下文件: dir
跳转到上级目录: cd..
跳转到根目录: cd\
清屏: cls
- 运行程序
使用虚拟机(java.exe)运行class文件,java 文件名,注意不要加扩展名,因为虚拟机只能运行class文件,扩展名省略不写,如写则报错。
- 进制
- 十进制
由0到9的数字组成,逢十进一
我们最常用的一种进制
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
- 二进制
由0和1组成,逢二进一
计算机中存储任何数据都是以二进制的形式进行存储的
0 1 10 11 100 101 110 111 1000
- 八进制
由0到7的数字组成,逢八进一
八进制在程序中以0开头
0 1 2 3 4 5 6 7 10 11 12 13 14 15 16 17 20
- 十六进制
由0到9的数字和A-F的字母组成,逢十六进一
十六进制在程序中以0x开头
0 1 2 3 4 5 6 7 8 9 A B C D E F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20
- 进制转换
- 十进制转二、八、十六进制
除法取余,将要转换的数除以进制数,记住余数,再除以进制数,记住余数,直到这个数等于0为止,将所有余数反转就是对应的二进制表现形式。
b.二、八、十六进制转十进制
乘法,将要转换的数编号,编号从低位开始,从0开始,将每一位上的数乘以进制数的编号次方,最后将所有乘得的结果相加就是十进制表现形式。
c.二进制和八进制互转
八进制的每一位对应二进制的三位。
- 二进制和十六进制互转
十六进制的每一位对应二进制的四位。
- 二进制负数
一个负数的二进制表现形式就是这个负数忽略符号的正数对应的二进制取反再加一。
计算机中存储的二进制数最高位是0则是正数,是1则是负数。
- 码表
ASCII:英文码表,每个字符占1个字节。A是65,a是97
GB2312:兼容ASCII,包含中文,每个英文占1个字节(正数),中文占2个字节(2个负数)。
GBK:兼容GB2312,包含更多中文,每个英文占1个字节(正数),中文占2个字节(第一个负数、第二个可正可负)。
Unicode:国际码表,每个字符占2个字节。Java中存储字符类型就是使用的Unicode编码。
UTF-8:国际码表,英文占1个字节,中文占3个字节。
- Java语法
- 基本格式
所有Java代码都应该在一个class中。
Java是严格区分大小写的。
Java是一种自由格式的语言。Java代码分为结构定义语句和功能执行语句,功能执行语句最后必须以分号结束。
- 注释
单行注释和多行注释是在程序用来标记一些特殊的文本,这些文本不参与编译运行。
文档注释是Java中特有的一种注释,它可以通过JDK中的工具(javadoc.exe)解析,生成帮助文档。
文档注释: /** 注释内容 */
- 标识符
- 什么是标识符
标识符可以理解为程序中我们自定义的一些名字,包括:包名、类名、函数名、变量名、常量名。
- 标识符的命名规则
由大小写字母、数字、下划线(_)和美元符号($)组成,开头不能是数字。不能使用关键字。推荐使用全英文。
- 标识符通用规范
类名、接口名:
所有单词首字母大写,驼峰式命名,例如:XxxYyyZzz
变量名、函数名:
第一个单词首字母小写,其他单词首字母大写,驼峰式命名,例如:xxxYyyZzz
常量名:
所有字母都大写,单词之间用下划线分割,例如:XXX_YYY_ZZZ
包名:
全部小写,例如:xxx.yyy.zzz
- 关键字
abstract |
boolean |
break |
byte |
case |
catch |
char |
class |
continue |
default |
do |
double |
else |
extends |
final |
finally |
float |
for |
if |
implements |
import |
instanceof |
int |
interface |
long |
native |
new |
package |
private |
protected |
public |
return |
short |
static |
super |
switch |
synchronized |
this |
throw |
throws |
transient |
try |
void |
volatile |
while |
注:java 无sizeof ,goto, const 关键字,但不能用goto const作为变量名
- 常量
- 整型
整数,4个字节。
- 长整型
整数,8个字节。以L结尾。
- 单精度浮点数
小数,4个字节。以F结尾。
- 双精度浮点数
小数,8个字节。
- 布尔
只有两个值,真(true)或假(false),1个字节。
- 字符
单个字符,2个字节。例如:'a', '中', '5', '\u0026' , '\u0027'
在字符常量中,斜杠(\)是一个特殊的字符,它的作用是用来转义后面一个字符,这些字符通常是不可见的或者有特殊意义的。
'\r' 回车,回到一行的开始
'\n' 换行,换到下一行
'\t' 制表符,键盘上的Tab
'\b' 类似退格,键盘上的Backspace
以上字符都不可见,无法直接表示,所以用斜杠加上另外一个字符来表示。
'\'' 单引号,Java代码中单引号表示字符的开始和结束,如果直接写程序会认为前两个是一对,报错。
'\"' 双引号,Java代码中双引号表示字符串的开始和结尾,如果要写一个包含双引号的字符串那么这个双引号也需要转义。
'\\' 斜杠,Java代码中的斜杠是转义字符,用来和后面一个字符配合使用,在真正需要用斜杠的时候那么就要用另一个斜杠来转义。
以上字符都有特殊意义,无法直接表示,所以用斜杠加上另外一个字符来表示。
- 字符串
由若干个字符组成的一串。可以是一个字符、多个字符、或者一个都没有。字符串没有固定大小。
- 空
null,只有这一个值,用来表示一个引用为空。
- 变量
int x = 5;
System.out.println(x);
x = 1 + 1;
System.out.println(x);
x = x + 1;
System.out.println(x);
上面的x就是一个变量,变量没有固定的值,是在内存中开辟的一片空间。
Java中的变量中只能存储同一种类型的值。
变量在被取值之前必须初始化(第一次给变量赋值)。
- 变量分类
a.基本数据类型: 8种
整数:
byte 1个字节,最小值:-128,最大值:127
short 2个字节,最小值:-32768,最大值:32767
int 4个字节,最小值:-2147483648,最大值:2147483647
long 8个字节,最小值:- 9223372036854775808,最大值:9223372036854775807
浮点数:
float 4个字节,最小值:1.4E-45,最大值:3.4028235E38
double 8个字节,最小值:4.9E-324,最大值:1.7976931348623157E308
字符:
char 2个字节,最小值:0,最大值:65535
布尔:
boolean 1个字节,true或false
b.引用数据类型:
类、接口、数组都是引用数据类型,除了8种基本数据类型,其他所有类型都是引用数据类型。
- 类型转化
- 自动类型转换
在byte、short、char参与运算的时候会自动提升为int,相当于将一个占空间较小的值放入了一个较大的空间。
- 强制类型转换
可以将一个占空间较大的值使用(类型)的形式强制放入一个较小的空间,有可能损失精度。
- 字符串转换
任何值和字符串相加都会得到字符串。
- 变量的作用域与生命周期
作用域:变量定义在哪一级大括号中,哪个大括号的范围就是这个变量的作用域。相同的作用域中不能定义两个同名变量。
生命周期:变量的生命周期从定义时开始,超出作用域后结束。变量生命周期以外不能使用。
- 函数
- 函数的定义
函数就是一段有名字的代码,可以完成某一特定功能。
如果有一段代码要使用多次,我们可以给它起个名字,每次使用时通过名字调用,这样就不用每次都写一大段代码了。
如果某个函数在执行的时候需要调用者传入数据,那么可以定义参数列表,用于接收数据。
如果函数运行之后需要返回给调用者数据,那么需要指定返回值类型,并且用关键字return返回。
定义函数的3个必要条件:函数名、参数列表、返回值类型。如果不需要参数也要写小括号,如果没有返回值类型要写void。
- 名词解释
形参:在定义函数时小括号中的参数,用来接收数据的参数。
实参:在调用函数时真正传入的参数,传递给函数的数据。
参数类型:函数的参数的类型,一旦定义传入时必须匹配。
返回值:函数运行结束后返回的值,使用return关键字返回。
返回值类型:函数运行结束后返回的值的类型,在类型非void情况下必须返回,而且必须类型匹配。
- 函数的重载
多个函数的函数名相同,参数列表不同(个数、顺序、类型),这就是函数的重载。在调用函数的时候通过传入的实参找到匹配的函数调用。
函数的重载和返回值类型无关。
- 运算符
- 算数运算符
加号:在操作数字、字符、字符串时是不同的,两个字符相加得到的是码表值,两个字符串相加是将字符串连接在一起。
除号:整数在使用除号操作时,得到的结果仍为整数(小数部分忽略)。
取模:模数的符号忽略不计,结果的正负取决于被模数。
自增:符号在前就是先运算后取值,符号在后则是先取值后运算。
习题:
a.System.out.println(3500 / 1000 * 1000);
b.某个培训中心要为新到的学员安排房间,假设共有x个学员,每个房间可以住6人,让你用一个公式来计算他们要住的房间数?
- 赋值运算符
等于:可以多个连用,例如:x = y = z = 5;
加等于:x += 5; 相当于 x = x + 5;
面试题:
以下代码正确的是? (多选)
- byte b = 1 + 1;
- byte b = 1; b = b + 1;
- byte b = 1; b += 1;
- byte b = 1; b = ++b;
- 比较运算
比较运算符运行结束之后返回的都是boolean值。
注意运算符==不要写成=
- 逻辑运算符
逻辑运算符运行结束之后返回的也是boolean值
& 两边都为true结果才为true,只要有一边是false,结果就是false
| 两边都为false结果才为false,只要有一边是true,结果就是true
^ 判断两边是否不同,不同则为true,相同则为false
! 取反,!true结果是false,!fasle结果是true
&& 和&结果相同,具有短路效果,如果前半是false,表达式结果一定为false,不运行后一半
|| 和||结果相同,具有短路效果,如果前半是true,表达式结果一定为true,不运行后一半
分析以下程序运行结果:
int x = 1;
int y = 2;
System.out.println(x++ == y & ++x > y++);
System.out.println(x);
System.out.println(y);
int x = 1;
int y = 2;
System.out.println(x++ == y && ++x > y++);
System.out.println(x);
System.out.println(y);
int x = 1;
int y = 2;
System.out.println(x++ == y | ++x > y++);
System.out.println(x);
System.out.println(y);
int x = 1;
int y = 2;
System.out.println(x++ == y || ++x > y++);
System.out.println(x);
System.out.println(y);
&& 在前半是false的时候短路
|| 在前半是true的时候短路
- 位运算符
任何信息在计算机中都是以二进制的形式保存的,&、|、^除了可以作为逻辑运算符,也可以做为位算符。
它们对两个操作数中的每一个二进制位都进行运算,0当做false,1当做true。
& 将两个二进制数每一位进行&运算,两边都为1结果才为1,只要有一边是0,结果就为0。
| 将两个二进制数每一位进行|运算,两边都为0结果才为0,只要有一边是1,结果就为1。
^ 将两个二进制数每一位进行^运算,只要两边不同结果就为1,相同则为0。
我们可以对数据按二进制位进行移位操作,java的移位运算符有三种:
<< 左移 将二进制的每一位向左移,低位补0。左移几位就相当于乘以2的几次方。
>> 右移 将二进制的每一位向右移,原来高位是0就补0,原来高位是1就补1。右移几位就相当于除以2的几次方。
>>> 无无符号右移 将二进制的每一位向右移,高位补0。正数移动没区别,负数移动后变为正数。
练习:
- 用&和>>来做十进制转十六进制
- 有两个int型变量a和b,在不使用第三个变量的情况下交换两个变量中的值
- 运算符优先级
思考一下代码运行结果:
System.out.println(1 + 2 * 3);
System.out.println(false && true || true);
System.out.println(true || true && false);
int a = 2;
int b = a + 3 * a++;
System.out.println(b);
int a = 2;
int b = a++ + 3 * a;
System.out.println(b);
int a = 1;
int b = 2;
System.out.println(a+++b);
尽量写简单的表达式,遇到运算符优先级的问题使用括号解决。
- 语句
- 顺序结构
顾名思义,就是程序从上到下一行一行执行的结构,中间没有判断和跳转,直到程序结束。
- 选择结构
程序具备多个分支,通过条件判断决定程序选择那一条分支执行
- if语句:
通过if...else if...else决定程序流程。
如果if中的条件满足则执行其中语句,if未满足则继续判断else if,如果满足则执行,不满足继续判断下一个else if,如果所有都不满足,则执行else。
练习:
用if else语句判断一个数是奇数还是偶数。
用户输入一个字符,用程序判断是否为小写字母,如果是,请输出“您输入的字符是小写字母”。
- switch语句:
通过switch...case...default语句控制程序流程。
根据switch后括号中的值判断运行哪一个case,这个值可以是byte、short、ch;ar、int。
default语句是可选的,如果所有case都不满足,则会执行default。
一旦匹配到一个case,程序就会从这个case向下执行,执行完一个case之后不会跳过其他的case,如需跳过请使用break。
- 三元运算符
语法:表达式 ? 结果1 : 结果2
如果表达式结尾为true取结果1,为false则取结果2。
注意三元运算符也是有短路的效果,根据表达式的结果,只运行冒号一边的,另外一边的不参与运行。
练习:
定义一个函数,接收两个int参数,返回较大的一个。
- 循环结构
通过循环语句让同一段代码反复执行多次,执行完毕程序才会继续往后运行
- while
先判断while中的表达式结果是否为true,true则执行循环体,执行结束之后再次判断,如果表达式结果为false则跳出循环。
练习:
打印出0-9
打印出a-z
- do...while
先执行一次循环体,然后判断while中的表达式,如果是true继续执行,如果是false则跳出循环。
练习:
编写一个程序,这个程序不断地读取键盘上输入的字符,直到读到字符’q’时,程序结束。
- for
for循环的括号中有三条语句,都是可选项。
语句1:这条语句会在整个循环开始之前执行,且仅运行一次,不参与循环。
语句2:必须是一个返回boolean值的表达式,如果写了这个语句那么每次循环开始之前会判断,true则执行循环,false则不执行。没写则直接执行。
语句3:这条语句在每次循环体运行结束之后执行。
练习:
使用星号打印如下图案
*****
*****
*****
*****
*****
i *
* 0 1
** 1 2
*** 2 3
**** 3 4
***** 4 5
i 空格 *
* 0 4 1
*** 1 3 3
***** 2 2 5
******* 3 1 7
********* 4 0 9
- continue、break、return
continue:跳过一次循环,继续执行下一次
break:结束循环
return:结束方法
- 数组
- 什么是数组
数组是一个类型一致,长度不可变的容器。可以通过索引操作容器中的每一个元素。
如果有多个类型相同的数据需要存储,我们就可以将其定义为一个数组,这样做省去了创建多个变量的麻烦。
- 如何定义数组
int[] arr = {1,2,3};
定义int数组arr,长度为3,其中3个元素分别为1、2、3。这种方式只能在定义数组的时候使用。
int[] arr = new int[]{1,2,3};
定义int数组arr,长度为3,其中3个元素分别为1、2、3。可以再任何情况使用。
int[] arr = new int[3];
定义int数组arr,长度为3。其中所有元素都为默认值0。
- 访问数组元素、遍历数组
存在数组中的数据是有索引的,从0开始递增,我们通过数组名和索引就可以操作其中每一个元素。例如:
System.out.println(arr[0]); // 打印数组中索引为0的元素
arr[1] = 100; // 给数组中索引为1的元素赋值为100
数组的长度
数组可以使用length属性获取其长度。
遍历数组
由于数组可以通过索引获取每一个元素,又可以通过length获取长度,那么我们就可以定义循环来遍历数组中的每一个元素了。
- 使用数组时的异常
如果访问数组时索引越界(小于0或者大于length-1),会抛出异常:ArrayIndexOutOfBoundsExcepion
如果访问数组的引用为空(null),会抛出空指针异常:NullPointerException
- 数组练习
- 定义一个函数,将数组中所有元素打印。要求打印成一行,每个元素之间以逗号分隔。
- 定义一个函数,交换数组中的两个元素。
- 定义一个函数,找出数组中的最大数。
- 定义一个函数,将数组中所有元素反转。例如:{1, 2, 3} 反转后为 {3, 2, 1}。
- 定义一个函数,对数组进行排序。
- 与数组操作相关函数
Arrays.toString() 查找帮助文档Arrays类,学习使用此方法将字符串转为字符串形式。
将一个数组转为字符串表示形式
System.arraycopy() 查找帮助文档System类,学习使用此方法拷贝数组中元素。
将一个数组中的某些元素拷贝到另一个数组的指定位置
- 多维数组
数组中的每一个元素都是数组,这样的数组就是多维数组。
int[][] arr = { { 1, 2, 3 }, { 4, 5 }, { 6, 7, 8, 9 } };
定义二维数组arr, 其中有三个元素都是数组, 第一个数组3个元素, 第二个2个元素, 第三个4个元素.
int[][] arr = new int[][] { { 1, 2, 3 }, { 4, 5 }, { 6, 7, 8, 9 } };
定义二维数组arr, 其中有三个元素都是数组, 第一个数组3个元素, 第二个2个元素, 第三个4个元素.
int[][] arr = new int[3][3];
定义二维数组arr, 其中有三个元素都是数组, 每个小数组都是3个元素.
int[][] arr = new int[3][];
定义二维数组arr, 其中有三个元素都是数组, 每个小数组元素个数不确定.
- 综合练习
- 编写一个程序,程序接收键盘上输入的三个数,并输出这三个数的最大数。
- 编写一个程序,它先将键盘上输入的一个字符串转换成十进制整数,然后打印出这个十进制整数对应的二进制形式。
- 使用移位方式将一个十进制数转换为十六进制。三种方式:
0-9之间的数值直接加上字符'0',9以上的数值减去10以后再加上字符'A'
定义一个数组,其中包含0-F这些字符,然后用要计算的数值作为数组的索引号,即可获得其对应的十六进制数据。
Character.forDigit静态方法可以将一个十六进制的数字转变成其对应的字符表示形式,例如,根据数值15返回字符'F'。
- 面向对象
- 面向对象概念
- 什么是面向对象 面向对象(Object Oriented)是一种思想,90年代以后软件开发的主流思想。
由于现实社会是由各种各样的事物所组成的,而我们编程又是在模拟现实社会,那么在程序也要用一些东西来表示现实社会中的事物,这些东西就是程序中的对象。我们在程序中使用这些对象,对其特征和行为进行操作进行编程,这就是面向对象编程。
在使用面向对象编程思想之前,我们通常用面向过程的思想编程,先分析出解决问题的步骤,然后按照步骤一步一步实现。
- 面向对象编程的优点
提高代码复用性。
使用者无需关心具体细节。
转变程序员角色,更加符合人的思维习惯。
- 类与对象
- 什么是类
类是用来描述对象的。由于对象是虚拟出来的东西,是看不见摸不着的,我们需要在程序中使用对象,就需要用一种方式来描述对象,然后根据这个描述来创建对象。
- 类和对象的关系
对象是类的实例,类是对象的抽象。
- 怎么定义类
将一系列特征相似的对象的共同特征及行为抽取出来进行描述,写在一个class中,用成员变量描述对象的特征,用成员方法来描述对象的行为。
class Person {
String name;
int age;
void speak(){
System.out.println("My name is " + name);
System.out.println("I am " + age + " years of age");
}
}
- 怎么使用类创建对象
使用new关键字和指定类名来创建一个对象。
- 对象的产生
Person p = new Person();
这句话先在堆内存中创建了一个对象,然后栈内存中创建一个变量引用了对象的地址。
- 成员变量初始化
当一个对象被创建时,会对其中各种类型的成员变量自动进行初始化赋值。基本数据类型初始化值为0,引用数据类型初始化值为null。
- 对象的使用
当我们创建对象之后可以使用点语法来访问对象的属性和方法。例如:
Person p = new Person();
p.name = "张三"; // 访问属性(成员变量)
p.age = 20;
p.speak(); // 访问方法
- 对象的生命周期
对象的生命周期从new关键字创建时开始,到没有任何引用到达对象时结束(成为垃圾)。
- 匿名对象
我们可以不定义变量引用对象,使用new关键字创建对象后直接使用,这样的对象没有名字,所以叫匿名对象。
匿名对象因为没有任何引用到达,在使用一次之后即成为垃圾。
通常我们需要使用一个对象且只使用一次的时候,就可以使用匿名对象。比如将对象作为一个参数传递给另外一个函数。
- 封装(Encapsulation)
- 什么是封装
封装是指隐藏对象的属性和一些实现细节,仅对外提供必须的访问方式。
- 怎么封装
将所有属性隐藏,提供公有方法对其访问。
将不需要对外提供的方法隐藏。
- 封装的优点
提高安全性:在访问对象的属性时候通过方法实现,在方法中可以进行校验。隐藏不必要提供的方法避免错误的调用。
简化编程:使用者无需关心对象内部具体实现细节,只要根据对象功能调用指定方法。
- 构造函数(Constructor)
- 什么是构造函数
构造函数(Constructor)是一个特殊的函数。
函数名和类名相同。
没有返回值类型。注意:没有返回值类型不等同于void,void也是一种返回值类型。不能使用return关键字返回任何值。
在使用new关键字创建对象之后自动调用。
- 构造函数的重载
构造函数的重载和普通函数相同,函数名相同,参数列表不同即可。
- 构造函数的调用
构造函数在new关键字创建对象时调用。
构造函数可以在该类其他构造函数的第一个语句使用this关键字调用。
- 所有类都有构造函数
每一个类都有构造函数,即使我们没有显式定义构造函数,也会生成一个默认无参的构造函数,其中没有任何内容。
注意:这个自动生成的构造函数只在未定义任何构造函数时生成,如果我们定义了一个有参的构造函数,那么就不会生成无参的了。
- 构造函数的访问权限
在定义构造函数时,如无特殊需要,应使用public关键字修饰构造函数。
在一些特定情况下,我们不想让别人创建该类对象,那么可以使用private修饰构造函数,例如单态设计模式。
- this关键字
this关键字除了在构造函数中调用其他构造函数以外,还可以当做一个引用使用。其用于方法中,哪个对象调用该方法,this就引用哪个对象。例如:
方法中局部变量和成员变量重名,我们想调用成员变量时就可以使用this.变量名形式访问成员变量。
在方法中要将调用该方法的对象作为参数传递给另一个方法时,可以将this作为实参传给该方法。
在内部类中访问外部类的成员时,需要使用外部类名.this.成员名形式访问。
- 函数的参数传递
基本数据类型的变量作为实参传入函数之后,在函数中将形参改变,调用处的实参不变。
因为基本数据类型的值是直接存在变量中,传入函数之后函数中的形参也同样存了一个值,这两个值是没有联系的,所以函数中将形参改变时修改的只是函数中的变量的值,和调用处的实参无关。
引用数据类型的变量作为实参传入函数之后,在函数中将形参改变,调用处的实参改变。
因为引用数据类型变量中存储的是地址,传入函数之后函数中的形参存储的也是同样一个地址,函数中将这个形参改变时改变的都是同一个地址上的对象,所以一边改变两边都变。
- static关键字
static关键字用来修饰类的成员,被这个关键字修饰的成员都和类加载有关。
JVM运行时不会将所有类加载到内存,因为无法确定程序中要使用哪些。类在第一次使用时加载,只加载一次。
- 静态变量
用static修饰的变量就是静态变量。
静态变量在类加载后就初始化。
静态变量被类的所有实例所共享。
静态变量可以使用 类名.变量名 形式访问。
如果在定义一个类的时候,发现一个成员变量需要被所有实例所共享,那么这个成员变量就需要定义为static的。
- 静态方法
用static修饰的方法就是静态方法。
静态方法在类加载后就可以使用。
静态方法可以使用 类名.方法名 形式访问。
静态方法不能直接访问外部非静态成员。
因为外部非静态成员必须在类创建对象之后才能使用,而静态方法可以在没创建对象时就使用。
如果要在静态方法内部访问外部非静态成员,需要先创建该类对象,通过对象访问。
静态方法中不能使用this关键字。
因为this是个引用,哪个对象调用方法就引用哪个对象。 而静态方法有可能不是被对象调用的,this无从引用。
如果一个方法不用访问对象的非静态成员,那么就可以定义为静态的,这样使用者就不需要创建对象,直接用类名调用。
静态方法通常是作为工具方法或者一个可以产生对象的方法被声明,目的是为了让调用者更方便的使用,不必创建对象。
- 静态代码块
用static修饰的代码块就是静态代码块。
静态代码块在类加载后执行。
静态代码块和静态方法相同,不能使用外部非静态成员。
静态代码块执行和静态变量的初始化顺序由代码从上到下顺序决定。
- 静态内部类
用static修饰的内部类就是静态内部类。
静态内部类在类加载后就可以创建对象,无需创建外部类对象。
具体内容详见3.18内部类
- 垃圾回收
对象在没有任何引用可以到达时,生命周期结束,成为垃圾。
所有对象在被回收之前都会自动调用finalize()方法。
一个对象在成为垃圾之后不会被马上回收,JVM会检测内存中的垃圾堆积到一定程度时才会回收,如果我们不想等到这个时候才回收,可以使用System.gc()方法来通知虚拟机回收垃圾。调用该方法之后JVM会开启新线程做处理垃圾的工作,这需要一定时间。
- 单态设计模式(SingletonPattern)
- 什么是设计模式
在编程过程中我们经常会遇到一些典型的问题或需要完成某种特定需求,而这些问题和需求前人也曾经遇到过,他们经过大量理论总结和实践验证之后优选出的代码结构、编程风格、以及解决问题的思考方式,这就是设计模式(Design pattern)。设计模式就像是经典的棋谱,不同的棋局,我们用不同的棋谱,免得我们自己再去思考和摸索。
- 单态(单例)设计模式
单态设计模式(Singleton pattern)就是要保证在整个程序中某个类只能存在一个对象,这个类不能再创建第二个对象。
- 单态设计模式的写法
私有化构造函数,阻止创建新对象。
由于需要返回一个对象,那么我们就需要在类内部自己创建一个对象,并使用成员变量记住它。
由于该类不能创建对象,所以这个成员变量不能是普通的成员变量,需要静态,这样在类加载之后就可以创建一个唯一的对象了。
我们不希望其他类修改这个成员变量,所以将其私有。
提供一个公有的方法用来获取唯一的一个对象。
这个方法由于需要在不创建对象的情况下使用,所以需要静态。
- 继承(Inherit)
- 什么是继承
在程序中,可以使用extends关键字可以让一个类继承另外一个类。
继承的类为子类(派生类),被继承的类为父类(超类, 基类)。
子类会自动继承父类所有的方法和属性。
- 为什么要使用继承
当我们发现一个类的功能不行,方法不够用时,就可以派生子类,增加方法。
当我们需要定义一个能实现某项特殊功能的类时,就可以使用继承。
最终还是为了一个目的,实现代码的复用性。
当我们定义一个类时,发现另一个类的功能这个类都需要,而这个类又要增加一些新功能时,就可以使用extends关键字继承那个类,这样那个被继承类的功能就都有了,不必重写编写代码。这时只要在新的类中编写新的功能即可,原有代码就被复用了。
- 继承的特点
Java只支持单继承,不支持多继承,但是可以多重继承
因为如果一个类继承多个类,多个类中有相同的方法,子类调用该方法时就不知道该调用哪一个类中的方法了。
子类中可以使用super调用父类成员
super用法和this类似,this是谁调用该方法就引用谁,super是调用该方法的对象的父类对象。
- 向上转型
把一个子类当做父类来用是可以的,因为父类有的子类都有
把一个父类当做子类来用就不可以了,因为子类有的父类不一定有
可以定义一个父类类型的变量来记住子类对象,这在程序中称之为向上转型
- 强制类型转换
把一个子类当做父类来用的时候,不能调用子类特有方法。
因为编译时编译器会做语法检查,看到变量是父类类型那么就会到父类中查找是否有该方法,没有则报错。
这种情况下,就需要强制类型转换,将父类类型强转成子类类型。
以(子类名)变量名形式进行强制类型转换
强制类型转换时,无论类型是否匹配编译都不会报错,但如果类型不匹配运行会报错,我们可以使用instanceof进行判断,编译时预知错误。
在子类当做父类来用时,不能调用特有方法,如果一定要调用,就需要强制类型转换回子类。在做转换时最好instanceof判断一下类型是否匹配。
- 子类覆盖(Override)父类方法
覆盖方法必须和被覆盖方法具有相同的方法名称、参数列表和返回值类型。
子类的方法返回值类型可以是父类方法返回值类型的子类。
如果在子类中想调用父类中的那个被覆盖的方法,我们可以用super.方法的格式。
如果直接调用方法,是在当前子类中先查找,如果子类有会调用子类的。使用super形式只在父类中查找,子类有没有都不调用。
覆盖方法时,不能使用比父类中被覆盖的方法更严格的访问权限。
因为有可能将子类对象当做父类对象来使用,那么能获取到的父类对象中的方法在子类中必须都能获取到。
覆盖方法时,不能比父类抛出更多的异常。
子类只能比父类强,不能比父类弱。
重载(Overload)和重写(Override)的区别:
重载是方法名相同,参数列表不同,和返回值类型无关。
重写是方法名、参数列表、返回值类型全相同。
@Override 注解,可以检查覆盖是否成功
- 子类当做父类使用时需要注意
当我们在调用某个类的一个方法时,此方法声明需要一个父类对象,这时我们可以将一个子类对象作为实参传递过去,注意此时方法定义的形参为父类,在方法中使用父类变量调用方法时,其实是调用子类的方法。
思考:上述情形下,在方法中用父类变量访问属性,访问的是子类还是父类的属性 ?
在把子类当做父类来用时,使用父类变量访问方法,访问的是子类的方法,因为虚拟机会找到变量引用的地址,根据这个地址来访问方法,这叫动态分配。
这种机制没有被使用到类的成员变量上,如果用父类变量访问属性,那么会直接找到父类的属性,不会看地址是哪个对象。
- 继承的应用细节
子类不继承父类私有成员
父类中私有成员对外不可见,子类对象中无法访问这些成员。
构造函数不被继承
构造函数通常用来初始化类的成员变量,父类和子类的成员变量不同,初始化方式也不同,构造函数的名字也不同。
为什么只支持单继承
如果一个类继承多个类,那么多个类中有相同的方法,调用时会引起歧义。
- 子类对象实例化过程
子类构造函数中可以使用super关键字调用父类构造函数。
在子类创建对象时一定会调用父类构造函数。即使没有显式调用,也会默认调用父类无参构造函数。
在子类中第一行用this关键字去调其他的构造方法,这时系统将不再自动调父类的。但其他构造函数中会调用父类构造函数。
在构造方法中this和super关键字只能出现一次,而且必须是第一个语句。
以后在设计类的时候,最好定义一个无参的构造方法,不然子类实例化的时候就容易出错。
- 对象的比较
在我们使用运算符“==”来比较两个对象时,其实比较的是两个对象的地址。如果运算符两边是同一个对象,地址相同则会等到true,只要是不同对象地址就会不同,返回false。
我们在编程过程中经常会比较两个对象的属性,这时我们就无法用“==”来比较了,因为即使两个对象所有属性都相同但不是同一个对象“==”号比较后也会得到false。这种情况下我们一般会定义一个equals()方法来进行比较。
- 文档注释
文档注释以“/**”开始,以“*/”标志结束,相应的信息和批注所对应的位置很重要! 类的说明应在类定义之前,方法的说明应在方法的定义之前。
使用文档注释修饰一个类的源代码之后可以通过javadoc.exe来生成帮助文档。
生成文档的命令:
javadoc -d (目录) -version –author (源文件)
批注参数来标记一些特殊的属性及其相应的说明 。
@author<作者姓名>
@version<版本信息>
@param<参数名称><参数说明>
@return<返回值说明>
- 组合设计模式(CompositePattern)
- 什么时候用组合
组合是一种实现代码复用的方式,当我们在定义一个类的时候需要用到另外一个类的方法时,就可以用组合。
- 怎么用组合
定义一个所需要的类类型的成员变量
通过构造函数进行装配,接收一个该类类型的对象,用成员变量引用
在需要使用另一个类的方法时通过成员变量访问
- 组合的优点
如果两个类没有父子关系,不合适用继承。
Java只支持单继承,组合不占用继承位置。
- 多态(Polymorphism)
- 什么是多态
多态字面上的意思就是多种形态。在面向对象语言中,我们可以将函数的形参定义为一个父类类型,而在真正调用该函数时这个父类类型的所有子类对象都可以传入,根据传入的子类对象不同函数可以运行处多种形态。
- 多态的特点
应用程序不必为每一个派生类(子类)编写功能调用,只需要对抽象基类进行处理即可。这一招叫“以不变应万变”,可以大大提高程序的可复用性。
派生类的功能可以被基类的引用变量引用,这叫向后兼容,可以提高程序的可扩充性和可维护性。现在写的程序可以调用将来写的程序不足为奇 。
- 抽象类
- 什么是抽象类
使用abstract关键字修饰的类就是抽象类,抽象类不能new对象,原因在于抽象类含有抽象方法,不能被调用。
没有方法体的方法为抽象方法,使用abstract关键字修饰。
有抽象方法的类必须声明为抽象类,抽象类不一定含有抽象方法。
- 为什么要定义抽象类
如果有多个类具有相同的方法声明,而方法的实现不一样,这时就可以抽象出父类,将方法在父类中声明
别人在学习我们的软件时,只需要学习父类就知道子类有什么方法
在设计软件时,要尽力抽象父类,继承关系以3~4层为宜
- final关键字
final标记的类不能被继承。
final标记的方法不能被子类重写。
final标记的变量即为常量,只能赋值一次。注意引用数据类型和基本数据类型的区别。
使用public static final共同修饰的常量就是全局常量。通常全部字母大写。
- 模板设计模式(TemplatePattern)
- 为什么要使用模板方法设计模式
在解决一些问题或者设计一个软件的时候,需要先定义一个模板,就相当于一种事先定义好的协议。
以后要做这系列的事情都按照这个模板来做。这样就实现统一化管理。
- 如何实现模板方法设计模式
定义一个抽象的父类做为模板,定义所有需要的方法
在父类中实现供外界调用的主方法,将方法声明为final
根据不同业务需求定义子类实现父类的抽象方法
- 内部类(InnerClass)
- 类中的内部类
在类里面定义的类称之为内部类(Inner Class),内部类是外部类的一个成员。
内部类必须创建外部类对象才能使用。
创建内部类对象时必须先创建一个外部类对象,通过一个外部类对象才能创建内部类对象。
外部类名.内部类名 变量名 = new 外部类名().new 内部类名();
内部类可以直接访问外部类的成员,而外部类不能直接访问内部类的成员。访问方式:外部类名.this.成员名
内部类可以访问外部类成员,因为在使用内部类时一定会有外部类对象,且只对应一个。
外部类不能访问内部类成员,因为在使用外部类时有可能还没有创建内部类对象。
如果一定要在外部类中使用内部类成员,那么需要创建内部类对象,通过对象来访问。
内部类中不能定义静态成员。
因为内部类需要创建外部类对象才能使用,static的本意是不创建对象就能使用,这是矛盾的。
内部类的class文件名为:外部类名.内部类名.class
- 方法中的内部类
一个类如果只在某个方法中使用,那么可以在方法中定义。
定义在方法中的类只能在方法中使用,而且使用的代码只能在声明的代码下面。
方法中的内部类只有在运行到类定义之后才能使用。
方法中定义的内部类不能访问方法中定义的局部变量,除非这个局部变量被声明为final的。
在方法中定义的局部变量在方法运行结束之后生命周期结束,不能再被访问。
方法中的内部类创建的对象有可能生命周期比这个局部变量长,例如这个对象被作为返回值返回,那么方法运行结束之后还可以访问这个对象。
这时变量被销毁了,对象还在,如果在对象的某个方法内访问这个变量就访问不到了。
我们需要使用final修饰这个变量,被final修饰的变量会一直存储在内存中,方法运行结束之后不被销毁。
方法中的内部类class文件名为:外部类名$.编号内部类名.class
- 匿名内部类
如果一个类只使用一次,那么可以定义为匿名内部类。
使用 new 父类名(){类定义} 形式声明,先创建一个指定类的子类,然后根据这个类创建一个对象。
匿名内部类的class文件名为:外部类名$编号.class
- 静态内部类
可以使用static修饰一个类中的内部类。
静态内部类不用创建外部类对象就可以直接创建对象。
外部类名.内部类名 变量名 = new 外部类名.内部类名();
静态内部类可以定义静态成员。
因为静态内部类可以直接使用,无需创建外部类对象。
静态内部类中不能访问外部非静态成员。
因为创建静态内部类不需要外部类对象,也就是有可能没有创建外部类对象,使用外部类成员必须有外部类对象。
- 接口
- 什么是接口
- 接口是一种特殊的抽象类,接口中声明的所有方法都是抽象的
- 使用interface关键字修饰一个接口
- 接口的用法
- 我们可以定义一个类来实现接口,使用implements关键字
- 实现一个接口需要实现接口中所有的方法,抽象类除外
- 通常使用匿名内部类来实现一个接口
- 接口可以继承接口,使用extends关键字。 接口不能继承抽象类,因为抽象类中可能有不抽象的方法。
- 一个类可以实现多个接口,为了实现多态
- 接口中的方法和变量
- 接口中定义的方法默认是公有的抽象的,被public abstract修饰
- 接口中定义的变量默认为全局常量,使用public static final修饰
- abstract class和interface的区别
- 抽象类中可以有不抽象的方法,接口中全是抽象的方法
- 抽象类用extends继承,接口用implements实现
- 抽象类中的变量和方法没有默认修饰符,接口中的变量默认为public static final的,接口中的方法默认为public abstract
- 一个类只能继承一个抽象类,一个类可以实现多个接口
- 什么时候用抽象类,什么时候用接口
- 如果能用接口,就不用抽象类,因为别人实现接口可以不占用继承的位置。
- 如果定义一个抽象的父类,其中所有方法都是抽象的,那么就定义为接口。
- 如果定义一个抽象的父类的时候,需要有不抽象的方法,那么只能定义为抽象类。
- 异常
- 什么是异常
- 异常就是Java程序在运行过程中出现的错误。如程序要打开一个不存的文件、网络连接中断、操作数组越界、装载一个不存在的类等。
- Throwable
- Throwable表示Java中可被抛出的对象,它是所有错误和异常的父类
- Throwable有两个子类:Error、Exception
- Error表示错误
- Exception表示异常
- RuntimeException表示运行时异常,是Exception的子类
Throwable |
Error |
Exception |
子类 |
子类 |
RuntimeException |
子类 |
Throwable |
Error |
Exception |
子类 |
子类 |
RuntimeException |
异常的分类
- Error(错误)
由Java虚拟机生成并抛出,包括动态链接失败、虚拟机错误等,程序对其不进行处理
- Exception(异常)
所有异常类的父类,子类定义了各种各样可能出现的异常事件,一般需要用户显式地声明向外抛出或捕获。
- Runtime Exception(运行时异常)
一类特殊的异常,如被0除、数组角标越界等。产生比较频繁,处理麻烦,如果每次都处理,会对程序可读性和运行效率影响比较大,因此由系统检测并将它们交给缺省的异常处理程序,用户不必对其进行处理。这类异常不处理,编译时不会报错,只是在运行时出现错误时才报告异常,所以我们称之为运行时异常,所有RuntimeException的子类都是运行时异常。我们也可以对运行时异常进行处理。
- 编译时异常
Exception中除了RuntimeException的子类,其他异常都是必须要处理的,如果不处理,编译时会报错,这些异常我们称之为编译时异常。
- 异常的用法
- 处理异常
在程序中可以在方法后面使用throws关键字声明向外抛出异常
对于编译时异常,通常我们需要使用try……catch语句进行捕获
finally可以结合try……catch使用,出现异常,finally里面的代码也会执行
- 异常的一些细节
如果父类方法中声明抛出多个异常,那么重写(覆盖)该方法只能抛出那些异常的一个子集,也就是说子类不能比父类抛出更多的异常。
如何处理多个异常
try语句与finally的嵌套使用
- 自定义异常
可以通过继承Exception类来自定义一个异常
如果要定义一个运行时异常则需要继承RuntimeException类
- 包
- Java中常用的包
- java.lang
包含一些Java语言的核心类,如String、Math、Integer、System和Thread,提供常用功能。
- java.awt
包含了构成抽象窗口工具集(abstract window toolkits)的多个类,这些类被用来构建和管理应用程序的图形用户界面(GUI)。
- java.net
包含执行与网络相关的操作的类。
- java.io
包含能提供多种输入/输出功能的类。
- java.util
包含一些实用工具类,如定义系统特性、使用与日期日历相关的函数。
- 定义带包类
- 使用package语句加上包名来定义类所属于的包,包名全部小写
- package语句为Java源文件的第一条语句
- 如果一个类中没有使用package语句,这个类为缺省无包名
- 一个类如果想被其他包中的类引用,必须使用public关键字修饰。构造函数也需要public
如果一个类被声明为public,那么必须和文件名同名
- 使用带包的类
- 在使用带包的类时需要使用全限定名(包名.类名)
- 在每次写类名时都使用全限定名很麻烦,我们可以使用import导入包,之后再使用就无需写包名了
星号*:导入一个包中所有类。优先匹配当前包中的类,如果当前包没有再匹配导入包中的类。
具体类名:导入指定一个类。无论当前包中是否有同名类,都直接匹配导入的类。
- 无包的类可以使用有包的类,有包的类不能使用无包的类。
- 编译运行带包的类
- 编译一个带包的源文件,在生成class文件的同时需要生成包文件
编译命令:javac –d <目录> 源文件名.java
- 运行有包的类时需要加上包名
运行命令:java 包名.类名
- jar文件
- 什么是jar文件
- jar文件是Java文件的一种压缩格式
- 一般来讲,我们会将一个软件系统的所有class文件打成一个jar文件以供别人使用
- 当我们用到jar包中的类时,需要将jar文件的绝对路径加到classpath当中
- 如何压缩jar文件
- 将编译好的带包的class文件压缩成一个jar文件称为打jar
- 打jar命令:jar cvf jar包名.jar 要打包的文件/文件夹
- 运行jar文件命令: java -jar jar文件名.jar
-
- 访问控制符
- 类的访问控制符有两种:
public关键字修饰:可以被所有的类访问
缺省为default:只能被同一包中的类访问
- 代码编写规范
- 标识符命名规则(驼峰式)
类名首字母大写:XxxYyyZzz
变量名、方法名首字母小写:xxxYyyZzz
包名全小写:xxx.yyy.zzz
常量名全大写:XXX_YYY_ZZZ
- 大括号的位置
大括号应成对出现,第一个大括号应在第一行语句后面
方法后面紧跟大括号,没有空格
关键字(while、for、if)后面应留一个空格
- 赋值语句之间用分号分隔,分号后面应空一格
- 代码折行应按照代码等级对齐,运算符写在下一行
- Java API String类
- 什么是API
- API全名:Application Programming Interface,API是应用程序编程接口,指一些预先定义好的类。
- 例如我们想要一台电脑,并不需要自己生产每个零件,只要从各个厂商买到组装电脑的零件就可以,然后根据说明书学会使用,将零件安装在一起就得到了电脑。电脑就像是我们要的程序,而零件就是API,说明书就是帮助文档。
- Java API
- Java API就是Sun公司提供给我们使用的类,这些类将底层的实现封装了起来,我们不需要关心这些类是如何实现的,只需要学习这些类如何使用。
- 我们可以通过查帮助文档来了解Java提供的API如何使用
- Java中常用API
- String类
对字符串进行操作通常我们使用String类,相关的还有StringBuffer和StringBuilder
- 集合类
集合是一种容器,用来存取对象(Collection、Map)
- 包装类
Java定义了一组包装类对基本数据类型进行了包装(Integer、Double、Boolean)
- 时间对象
Java定义了一些类方便用户对时间、日期进行处理(Date、Calendar)
- 系统类
Java定义了一些类针对系统进行操作(System、Runtime)
- IO流
Java定义了一些类对数据传输进行了封装(输入输出流、File文件对象)
- Socket
Java定义了一些类方便用户进行网络编程(Socket、DatagramSocket)
- String对象的存储
- 字符串是常量,一旦创建不能被修改。
- 字符串在程序中经常使用,虚拟机会将其缓存在String池中。
- 了解 String s = “abc” 和 String s = new String(“abc”) 的区别。
- String类的构造函数
- String(byte[] bytes)
通过指定字节数组构建字符串。
- String(byte[] bytes, int offset, int length)
通过指定字节数组、数组元素偏移量和元素个数构建字符串。
- String(byte[] bytes, String charsetName)
通过指定字节数组和指定码表构建字符串。
- String(byte[] bytes, int offset, int length, String charsetName)
通过指定字节数组、数组元素偏移量、元素个数和指定码表构建字符串。
- String(char[] value)
通过指定字符数组构建字符串。
- String(char[] value, int offset, int count)
通过指定字符数组、数组元素偏移量和元素个数构建字符串。
- String(StringBuffer buffer)
通过指定StringBuffer构建字符串。
- String(StringBuilder builder)
通过指定StringBuffer构建字符串。
- String类的常用方法
- char charAt(int index)
查找指定位置的字符
- int indexOf(String str)
判断字符串出现的位置
- int compareTo(String anotherString)
按字典顺序比较两个字符串
- String substring(int beginIndex, int endIndex)
截取子字符串
- String[] split(String regex)
字符分割
- String replace(CharSequence target, CharSequence replacement)
替换字符串
- 字符串练习
- 设计一个方法, 获取一个已知文件名的扩展名.
Person.java的扩展名是.java,Person.java.txt的扩展名是.txt
- 设计一个方法, 查找一个字符串中子字符串出现的所有位置.
“xxxabcxxxabcxxx”中abc出现了2次,索引位置是3和9
- 查找一个字符串中出现最多的字符.
“hello world”中L出现了3次
- 设计方法,使用System.in.read()读取一行.
循环读取一个字节,读取到\r\n结束。考虑中文问题
- 已知一个字符串. 设计一个方法, 可以从这个字符串中打印n个字节. 但不能打印出半个中文.
短信一次发送字节140个,如果超过140字节就会分为两条。这时如果第140个字节是中文的前半,那么第一条短信应该发送139字节。
- 查找两个字符串中最大相同子串.
“abc”和“bcd”的最大相同子串是”bc”
“xyzabcdefxyz”和“xxxabcdefooo”的最大相同子串是”abcdef”
- 集合类
- 集合概念
- 为什么出现集合类?
- 在面向对象的编程思想中,都是以对象的形式对事物进行描述的,为了保证对象的生命周期,我们需要持有对象
- 在很多情况下,我们不知道在程序中需要创建多少个对象,这时就不能依靠定义引用对象的变量来持有每一个对象
- 存储对象的容器就能帮我们解决这样的问题,而集合便是这样的容器
- 数组和集合类的区别
- 数组和集合类都是容器,都能存储对象
- 集合类的优势就在于长度可变
- 集合类的特点
- 集合类可用于存储对象
- 集合类的长度可变
- 一个集合可以存储多种类型的对象
- 集合接口
- Collection接口
- 一个独立的元素的序列,这些元素服从一条或多条规则
- Collection接口下主要分为List集合和Set集合
- List集合的特点是元素有序、允许有重复元素
- Set集合的特点是元素无存储顺序、不允许有重复元素
- Map接口
- 一组成对的”键值对”对象,允许根据键来查找值
- Map集合的键不允许有重复,所以Map的所有键构成了一个Set集合
- 主要学习HashMap和TreeMap
- Iterable接口
- JDK1.5新定义的接口作为Collection的父接口
- 主要为了实现增强for循环
- List
- List特点
- 元素有序,可重复。
- 我们主要学习三种:ArrayList、Vector、LinkedList
- 这三种都是List接口的实现类,使用上完全一样,只是实现原理不同,效率不同。
- ArrayList
- 底层数组实现
- 查找快,增删慢
- 线程不安全
- Vector
- 与ArrayList基本一样
- 线程安全(线程同步),效率低
- LinkedList
- 底层链表实现
- 增删块,查找慢
- 存取元素
- List集合元素存取方法一致
- 使用add()方法增加元素
- 由于List集合有序,可以使用get()方法获取元素
- 元素的迭代(Iterator)
通过集合对象的iterator()方法获得迭代器Iterator
通过Iterator迭代器的hasNext()方法判断是否存在下一个元素
通过Iterator迭代器的next()方法获取下一个元素
- 元素的迭代(Enumeration)
迭代Vector集合中的元素可以使用Enumeration
通过Enumeration的hasMoreElements()方法判断是否还有元素
通过Enumeration的nextElement()方法返回下一个元素
- JDK5新特性
- 泛型
- 由于集合可以存储不同类型的数据,所以取元素时有可能会导致类型转换错误
- JDK1.5增加了新特性泛型,为了减少操作集合时出错的几率
- 集合一旦声明了泛型,便只能存储同一类型的对象了
- 使用方法:ArrayList<Person> al = new ArrayList<Person>();
- 使用泛型的好处
提高了程序的安全性
将运行期遇到的问题转移到了编译期
省去了类型强转的麻烦
泛型类的出现优化了程序设计
- 增强for循环
- 新接口Iterable中定义了增强for循环
- 可以通过增强for循环对数组和集合进行遍历
- 语法:for(类型 变量名 : 要遍历的容器) { …… }
- 可变参数
- 有的时候在设计方法时无法确定将来别人会传入的参数个数
- JDK1.5增加了新特性可变参数,在函数中只声明参数类型,不规定个数
- 方法接受的参数实际上是一个数组,可以在方法中遍历数组
- 可变参数只能被定义为函数的最后一个形参
- 语法格式: 返回值 函数名(参数类型… 形参名)
- Set
- Set集合无序,不允许有重复元素
- Set集合通过存入对象的equals方法来保证集合中没有重复元素
- HashSet
- HashSet是Set的子类,因此也没有重复元素
- 底层使用哈希算法保证没有重复元素
- 存储对象时,先调用对象的hashCode()方法计算一个哈希值,在集合中查找是否有哈希值相同的对象。
如果没有哈希值相同的对象,直接存入。
如果有哈希值相同的对象,则和哈希值相同的对象进行equals()方法比较。
equals()方法比较结果相同则不存,不同就存入。
- 往HashSet集合里存储的对象必须正确重写hashCode和equals方法
- TreeSet
- TreeSet集合通过二叉树算法保证无重复元素,并对元素进行排序
- 在使用TreeSet时必须指定比较的算法,指定的方式有两种:
自然顺序:将要存储的类实现Comparable接口,重写compareTo方法,在方法中指定算法
比较器顺序:在创建TreeSet时,传入一个比较器Comparator,在比较器的compare方法中指定算法
- Map
- Map集合的特点
- Map存储了一系列键值的映射关系
- Map集合需要保证键的唯一性
- 可以通过键获得值,反之则不能
- Map集合存储元素使用put(key,value)方法
- Map集合的两种遍历方式
- 通过keySet方法返回由键组成的集合,迭代该集合的元素就拿到了所有的键,再调用get方法根据键拿到值
- 通过entrySet方法返回键值映射关系组成的集合,迭代该集合就拿到了一个个的键值映射关系,通过getKey方法拿到键,通过getValue方法拿到值。
- HashMap
- 线程不安全,存取速度快,允许存放null键,null值。
- 通过HashSet原理保证键唯一性
- Hashtable
- 线程安全,速度慢,不允许存放null键,null值,已被HashMap替代。
- TreeMap
- 通过二叉树算法保证键唯一性
- 对键进行排序,排序原理与TreeSet相同。
- Properties
- HashTable的子类,所以也是线程安全的
- 用于读写配置文件的,一般配置项等号两边都是String,所以该集合中的两列保存的都是String类型的数据
- 这个集合中只能存String,所以不需要定义泛型。
- 其他常用类
- 工具类
- Arrays
- 工具类,提供了对数组的常用操作
- 将数组转成List集合
- 对数组进行排序
- 对数组进行二分查找
- 将数组转为字符串显示形式
- Collections
- 工具类,提供了对集合的常用操作
- 对集合进行查找
- 取出集合中的最大值,最小值
- 对List集合进行排序
- 包装类
- JDK提供了对所有数据类型的包装类
- byte >>> Byte
- short >>> Short
- int >>> Integer
- long >>> Long
- double >>> Double
- float >>> Float
- char >>> Character
- boolean >>> Boolean
- 包装类的常用方法
- toString方法
- parseInt方法:Integer.parseInt(String s)
- valueOf方法:Double.valueOf(String s)
- 系统类
- System类
- 静态属性in为标准输入流,属于InputStream类型,read方法返回一个字节
- 静态属性out为标准打印流,属于PrintStream类型,print方法打印字符
- 可以用set方法修改属性in和out
- System.exit()方法退出Java虚拟机
- System.gc()垃圾回收
- System.getProperties()方法获得系统属性
- Runtime类
- 表示系统运行时状态
- exec方法执行命令
- 时间类
- Date类
- 使用new Date()创建时间对象代表当前系统时间
- 需要使用DateFormat类来进行格式化,才能显示想符合习惯的格式
- Calendar类
- 使用该类对时间进行操作比较方便
- 通过常量来表示时间的各种值,如一年中的某一天,一个月的某一天等
- 将对应的常量作为形参来调用相应的get、add、set方法来操作对象
- 练习
- 计算出某一年的二月份有多少天?
- 设计一个方法可以计算工作时间,接收一个参数(工作日),方法打印出哪天完工。
- IO(Input Output)
- IO流概念
- IO流用来处理设备之间的数据传输
- Java对数据的操作是通过流的方式
- Java用于操作流的对象都在IO包中
- 流按操作对象分为两种:字节流与字符流。 字节流可以操作任何数据,字符流只能操作纯字符数据比较方便。
- 流按流向分为:输入流,输出流。
- IO流常用基类
- 字节流的抽象基类:
- InputStream ,OutputStream
- 字符流的抽象基类:
- Reader , Writer
- 由这四个类派生出来的子类名称都是以其父类名作为子类名的后缀。
- 如:InputStream的子类FileInputStream。
- 如:Reader的子类FileReader。
- InputStreamReader是Reader的子类
- IO程序书写
- 使用前,导入IO包中的类
- 使用时,进行IO异常处理
- 使用后,释放资源
- 字符流读写文件
- 读取文件
- 定义字符流关联指定文件
FileReader reader = new FileReader("Test.txt");
- 读取一个字符,返回int,该字符的码表值
int ch = reader.read();
- 关闭流,释放资源
reader.close();
- 写出文件
- 定义字符输出流关联指定文件
FileWriter writer = new FileWriter("Test.txt");
- 写出一个字符,接收int码表值
writer.write(97);
- 关闭流,释放资源
writer.close();
- 注意事项
- 文件路径
定义文件路径时Windows中的目录符号为“\”,但这个符号在Java中是特殊字符,需要转义。
可以用“\\”或“/”表示。
- 读取文件
读取文件时必须保证文件存在,否则将抛出FileNotFoundException。
- 写出文件
写出时文件如不存在时程序会创建新文件,如文件已存在则会清空原文件内容重新写入。
如需追加内容可调用FileWriter构造函数FileWriter(String fileName, boolean append)
- 练习
拷贝一个文件
- 字符流缓冲区读写
- 自定义缓冲区读写
- 为什么定义缓冲区
由于单个字符读写需要频繁操作文件,所以效率非常低。
我们可以定义缓冲区将要读取或写出的数据缓存,减少操作文件次数。
- 缓冲区读取
先定义一个数组,然后调用FileReader读取一个数组的方法。
int read(char[] cbuf)
- 缓冲区写出
将要写出的数据存放在数组中,调用FileWriter方法,一次写出一个数组。
void write(char[] cbuf, int off, int len)
- 内置缓冲区的BufferedReader和BufferedWriter
- Java提供了带缓冲功能的Reader和Writer类:BufferedReader,BufferedWriter
- 这两个类都是提供包装功能,需要提供其他流来使用,给其他流增加缓冲功能
- 当我们调用BufferedReader读取数据时,程序会从文件中一次读取8192个字符用来缓冲
- 当我们调用BufferedWriter写出数据时,程序会先将数据写出到缓冲数组,直到写满8192个才一次性刷出到文件
- 装饰设计模式(Decorator)
- 什么情况下使用装饰设计模式
当我们需要对一个类的功能进行改进、增强的时候
- 装饰模式的基本格式。
含有被装饰类的引用
通过构造函数传入被装饰类对象
和被装饰类含有同样的方法,其中调用被装饰类的方法,对其进行改进、增强
和被装饰类继承同一个类或实现同一个接口,可以当做被装饰类来使用
- 了解BufferedReader、BufferedWriter的原理。
BufferedReader、BufferedWriter都是装饰类,他们可以装饰一个Reader或Writer,给被装饰的Reader和Writer提供缓冲的功能。
就像我们用BufferedReader、BufferedWriter装饰FileReader和FileWriter,使用的读写功能还是FileReader和FileWriter的,但给这两个类的读写添加了缓冲功能。
- 练习
- 模拟一个BufferedReader类。
- 模拟一个LineNumberReader类。
- 字节流
- 基本操作与字符流相同
- 字节流可以操作任意类型数据
- 练习:拷贝一个Jpg文件
- 字节流缓冲区读写
- 自定义缓冲区读写
- 原理和字符流相同,都是为了提高效率
- 定义数组缓冲数据,一次读取一个数组,一次写出一个数组,减少操作文件的次数
- BufferedInputStream、BufferedOutputStream
- 和BufferedReader、BufferedWriter原理相同,都是包装类
- BufferedInputStream、BufferedOutputStream包装InputStream和OutputStream提供缓冲功能
- 转换流
- 字符流与字节流之间的桥梁
- 方便了字符流与字节流之间的操作
- 字节流中的数据都是字符时,转成字符流操作更高效
- 练习:转换System.in
- 标准输入输出流
- System类中的成员变量:in,out。
- 它们各代表了系统标准的输入和输出设备。
- 默认输入设备是键盘,输出设备是显示器。
- System.in的类型是InputStream.
- System.out的类型是PrintStream是OutputStream的子类FilterOutputStream 的子类.
- 练习:通过修改标准输入输出流,使用System.in和System.out拷贝文件
- 流基本应用小节
- 流是用来处理数据的。
- 处理数据时,一定要先明确数据源,或者数据目的地
- 数据源可以是文件,可以是键盘或者其他设备。
- 数据目的地可以是文件、显示器或者其他设备。
- 而流只是在帮助数据进行传输,并对传输的数据进行处理,比如过滤处理、转换处理等。
- File类
- 用来将文件或者文件夹路径封装成对象
- 方便对文件与文件夹进行操作。
- File对象可以作为参数传递给流的构造函数。
- 了解File类中的常用方法。
- 递归
- 函数自己调用自己。
- 注意:递归时一定要明确结束条件。
- 应用场景:
当某一功能要重复使用时。
- 练习:
列出一个文件夹下所有的子文件夹以及子文件
- 思考:
删除一个目录的过程是如何进行的?
复制一个目录的过程呢?
- IO包中的其他类
- 序列流
SequenceInputStream
可以将多个字节输入流整合成一个流,在使用这个流读取的时候,读到第一个流的末尾时继续读第二个,第二个读到末尾则继续读第三个,以此类推,直到读到最后一个流的末尾返回-1
- 打印流
PrintStream 、PrintWriter
相比普通的OutputStream和Writer增加了print()和println()方法,这两个方法可以输出实参的toString()方法的返回值
这两个类还提供自动flush()的功能
- 操作对象
ObjectOutputStream
可以将实现了Serializable的接口的对象转成字节写出到流中
ObjectInputStream
可以从流中读取一个ObjectOutputStream流写出的对象
- 操作内存缓冲数组
ByteArrayOutputStream: 写出到字节数组(内存)中,可以获取写出的内容装入一个字节数组。通常我们用这个流来缓冲数据。
ByteArrayInputStream:可以从一个字节数组中读取字节。
CharArrayWriter:写出字符到字符数组(内存)中,可以获取写出的内容装入一个字符数组。
CharArrayReader:可以从一个字符数组中读取字符。
- 管道流
PipedInputStream:管道输入流,可以从管道输出流中读取数据
PipedOutputStream:管道输出流,可以向管道输入流中写出数据
- 操作基本数据类型
DataInputStream、DataOutputStream
可以按照基本数据类型占用空间大小读写数据
- 随机访问文件
RandomAccessFile
- 多线程
- 多线程概念
- 线程与进程
- 进程就是一个运行中的程序。
- 一个进程中可以有多个线程,线程是CPU调度和分派的基本单位。我们可以理解为线程就是程序运行中的一条路径。
- 多线程存在的意义
- 允许多个线程并发执行,提高程序运行效率。
- 例如:迅雷多线程下载,QQ多个人同时聊天,凌波多个人同时共享屏幕。
- 线程的使用
- 创建线程有两种方式
- 自定义一个类继承Thread类,将线程要做的事写在run()方法中,由于子类可以当父类来用,创建自定义子类对象就是创建了一个线程。
- 自定义一个类实现Runnable接口,将要做的事写在run()方法中。创建Thread对象时在构造函数中传入Runnable实现类对象。
- 线程的启动
- 两种创建方式都是调用Thread对象的start()方法。
- 当调用start()方法时,CPU会开启一条新线程,并在新线程上执行run()方法。
- 线程常用方法
- currentThread
静态方法,用来获取当前线程
- getName、setName
用来获取、设置当前线程的名字
- sleep
控制线程休眠,单位为毫秒
- setDeamon
将线程设置为守护线程。线程默认是非守护线程,守护线程不能单独执行。
- join
当前线程暂停,等待加入的线程运行结束,当前线程继续执行。
- 多线程同步
- 线程安全问题
- 多线程并发访问同一数据,有可能出现线程安全问题。
- 一条线程的访问还没有结束,CPU切换到另一条线程工作,导致数据访问出错。
- 使用同步解决线程安全问题
- 使用同步代码块synchronized(锁对象){需要同步的代码...}形式将访问数据的代码锁住,在同步代码块中的内容同一时间内只能一个线程执行。
- 使用同步方法,用synchronized修饰方法,整个方法的代码都是同步的,只能一个线程运行。同步方法使用this作为锁。
- 死锁
- 在多个线程并发执行使用多个锁来同步时,有可能互相冲突,导致程序无法继续执行。
- 同步的优点与缺点
- 同步可以解决多个线程同时访问一个共享数据的问题,只要加上同一个锁,在同一时间内只能有一条线程执行。
- 在执行同步代码时每次都会判断锁,非常消耗资源,效率较低。
- 多线程通信
- 在同步代码中可以使用锁对象的wait()方法让当前线程等待
- 使用锁对象的notify()方法可以将正在等待的线程唤醒
- 如果多个线程都在等待,notify()唤醒随机1个
- notifyAll()方法可以唤醒所有在等待的线程
- JDK5之后的线程同步与通信
- 同步
- 使用java.util.concurrent.locks.Lock接口的实现类对象来进行同步
- ReentrantLock就是Lock的实现类,可以实现synchronized的功能
- 在需要同步的代码块前后使用lock()和unlock()方法来完成同步
- unlock()最好放在finally中,因为如果上面代码抛出异常没有解锁的话,会导致其他线程无法运行,程序卡死。
- 通信
- 使用Lock对象的newCondition()方法获取一个Condition对象,Condition对象可以控制指定线程的等待与唤醒。
- await()方法可以控制线程等待。
- signal()方法可以唤醒等待的线程。
- signalAll()方法可以唤醒所有等待线程。
- GUI
- GUI概念
- 什么是GUI
- GUI是Graphical User Interface的缩写,图形化用户界面
- awt和swing
- Java为GUI提供的对象都存在java.awt,javax.swing两个包中
- awt依赖于本地系统平台,如颜色样式显示
- swing跨平台
- 组件与容器
- 组件 Component,是GUI图形界面的组成单元。
- 容器Container,可以存放组件,也可以存放容器。
- 布局管理
- FlowLayout(流式布局管理器)
- 从左到右的顺序排列。
- BorderLayout(边界布局管理器)
- 东,南,西,北,中
- GridLayout(网格布局管理器)
- 规则的矩阵
- CardLayout(卡片布局管理器)
- 选项卡
- GridBagLayout(网格包布局管理器)
- 非规则的矩阵
- 建立一个窗体
- 窗体中可以存放各种组件,所以窗体是容器Container。创建时我们使用的是它的子类
- Container的常用子类有两个,Window和Panel。Window是我们常用的窗体,Panel是用来布局的不可见的。
- Window也有两个常用子类,Frame和Dialog。Frame是我们常用的带有标题和边框的顶层窗口,Dialog是对话框。
- 所有AWT包中的类都会运行在AWT线程上
- 事件处理
- 事件处理机制
- 事件:用户对组件的一个操作。
- 事件源:发生事件的组件。
- 监听器:我们需要处理某个事件,就需要在发生事件的组件上添加监听器,也就是java.awt.event包中XxxListener接口的子类。
- 事件处理器:监听器中的方法。监听器被添加在组件上之后,组件上发生了对应事件就会执行指定方法。
- 常用事件分类
- 窗体事件,WindowEvent,窗体打开、关闭、正在关闭、激活、最小化等。
- 鼠标事件,MouseEvent,鼠标按下、抬起、进入、移出等。
- 键盘事件,KeyEvent,键盘按下、抬起等。
- 动作事件,ActionEvent,在某一组件上发生了定义好的动作,例如按钮上鼠标点击或按空格,菜单上鼠标点击或按回车等。
- Socket网络编程
- 网络编程概念
- IP地址
- 每台网络终端在网络中都有一个独立的地址,我们在网络中传输数据就是使用这个地址。
- ipconfig:查看本机IP
- ping:测试连接
- 本地回路地址:127.0.0.1
- IPv4:4个字节组成,4个0-255。大概42亿,30亿都在北美,亚洲4亿。已经用尽。
- IPv6:8组,每组4个16进制数。
1a2b:0000:aaaa:0000:0000:0000:aabb:1f2f
1a2b::aaaa:0000:0000:0000:aabb:1f2f
1a2b:0000:aaaa::aabb:1f2f
1a2b:0000:aaaa::0000:aabb:1f2f
1a2b:0000:aaaa:0000::aabb:1f2f
- 端口号
- 每个网络程序都需要绑定一个端口号,传输数据的时候除了确定发到哪台机器上,还要明确发到哪个程序。
- 端口号范围从0-65535
- 编写网络应用就需要绑定一个端口号,尽量使用1024以上的,1024以下的基本上都被系统程序占用了。
- 常用端口
mysql: 3306
oracle: 1521
web: 80
tomcat: 8080
QQ: 4000
feiQ: 2425
- 网络协议
- 为计算机网络中进行数据交换而建立的规则、标准或约定的集合。
- UDP
面向无连接,数据不安全,速度快。不区分客户端与服务端。
- TCP
面向连接(三次握手),数据安全,速度略低。分为客户端和服务端。
- Socket
- 通信的两端都有Socket。
- 网络通信其实就是Socket间的通信。
- 数据在两个Socket间通过IO传输。
- Socket在应用程序中创建,通过一种绑定机制与驱动程序建立关系,告诉自己所对应的IP和port。
- UDP传输
- 发送
- 创建DatagramSocket
- 创建DatagramPacket
- 使用DatagramSocket发送DatagramPacket
- 关闭DatagramSocket
- 接收
- 创建DatagramSocket
- 创建DatagramPacket
- 使用DatagramSocket接收DatagramPacket
- 关闭DatagramSocket
- TCP传输
- 客户端
- 创建Socket连接服务端
- 调用Socket的getInputStream()和getOutputStream()方法获取和服务端相连的管道流
- 输入流可以读取服务端输出流写出的数据
- 输出流可以写出数据到服务端的输入流
- 服务端
- 创建ServerSocket
- 调用ServerSocket的accept()方法接收一个客户端请求,得到一个Socket
- 调用Socket的getInputStream()和getOutputStream()方法获取和客户端相连的管道流
- 输入流可以读取客户端输出流写出的数据
- 输出流可以写出数据到客户端的输入流
传智播客毕向东 Java相关推荐
- 传智播客成都中心的Java课程设置
传智播客成都中心的Java课程设置 传智播客成都中心作为西南地区最大的高素质软件开发人才培训机构之一,以其强大的专业教学团队,科学的教学课程体系,以及孜孜不倦.踏实务实的教学精神,现已为中国IT产业培 ...
- python传智播客王铭东_传智播客Python学科的王铭东老师讲的怎么样 |
传智播客Python学科的王铭东老师讲的怎么样 | python高级编程 视频教程2020-09-20 16:40:21人已围观 python好学吗? Python相比于其程语言更容易学习,但是想学精 ...
- 2015年传智播客java_2015年的Java –重大事件
2015年传智播客java 2015年是Java的一年,语言,平台,生态系统和社区继续主导着软件领域,只有Javascript对整个行业产生了类似的影响. 如果您错过了2015年的亮点,这里是发生的一 ...
- Java中System类(传智播客毕老师视频讲解)
System:类中的方法和属性都是静态的. out:标准输出,默认是控制台. in:标准输入,默认是键盘. 描述系统一些信息. 获取系统属性信息:Properties getProperties(); ...
- Java中时间获取(传智播客毕老师视频讲解)
1.Date类 Date类中大多方法已经过时,且其打印的时间看不懂,可以调用DateFormat接口中的实现子类SimpleDateFormat进行格式调整: 代码如下: import java.ut ...
- Java中静态导入(传智播客毕老师视频讲解)
StaticImport 静态导入. 当类名重名时,需要指定具体的包名. 当方法重名是,指定具备所属的对象或者类. import java.util.*; import static java.ut ...
- Java中设计模式——装饰类(传智播客毕老师视频讲解)
装饰类设计模式: 当想要对已有的对象进行功能增强时,可以定义类,将已有的对象传入,基于已有的功能,并提供加强功能,则此自定义的该类称为装饰类. 装饰类通常会通过构造方法接收被装饰的对象,并基于被装饰的 ...
- Java多线程(6)——Thread类中的一些方法(传智播客毕老师视频讲解)
1.守护线程 代码如下: import java.util.concurrent.locks.*; public class StopTest implements Runnable {private ...
- Java中增强for循环(传智播客毕老师视频讲解)
高级for循环 格式: for(数据类型 变量名 : 被遍历的集合(Collection)或者数组) { } 如: String[] arr7={"abc","def&q ...
- 传智播客管家婆java答案_传智播客黑马19年Java全(IDEA) [230G]|百度云|天翼云|GD|OD...
目录:/黑马19年Java全(IDEA) [412.2M] ┣━━01-java语言入门 [0B] ┃ ┣━━01_Java基础语法 ┃ ┗━━02_面向对象与常用类 ┣━━02-Java语进阶 [0 ...
最新文章
- 深入理解ReactRedux
- angularJS学习笔记一
- before和after怎么区分_如何区分before和after~有时候觉得两者可以通用
- Kafka解惑之Old Producer(2)——Sync Analysis
- SAP S/4HANA OData Mock Service 介绍
- leetcode1299. 将每个元素替换为右侧最大元素
- 90-40-010-源码-CUBE-引擎为MR写入Habse的构建
- uni-app条件编译:#ifdef #ifndef #endif
- Verizon收购雅虎交易完成 硅谷第一美女梅耶尔辞职
- Hello!CDSN!
- linux设备驱动模型大剖析(1)-----底层阶级的程序猿
- windows安全事件id汇总
- 红米note5解锁教程_红米NOTE5解锁包
- g5500服务器装系统,联想G50笔记本U盘重装win10系统教程
- Ardunio开发实例-MLX90614红外测温仪
- Prometheus监控以及告警配置
- 刷题、OJ 1337: 运动员分组
- Java实现Nginx图片上传
- C语言三个整蛊程序,很强!!
- 学成在线 第9天 讲义-课程预览 Eureka Feign 四