一. 计算机语言发展史java
• 机器语言 • 汇编语言 • 高级语言 • 面向对象语言
二. Java版本发展程序员
1. 版本更新web
时间 描述
1991~1995 Sun为了占领智能消费电子产品市场,由james gosling负责该项目,来开发Oak语言
1995 将Oak更名为Java
1996 发布JDK1.0
1997 发布JDK1.1
1998 发布JDK1.2,将该版本命名为J2SDK,将Java改名为Java 2
1999 将Java分为三大块:J2SE(Java标准版)、J2EE(Java企业版)、J2ME(Java微型版本)
2000 发布J2SE1.3
2002 发布J2SE1.4
2004 此时再也不叫J2SE1.5,叫5.0
2005 2005 Java 10周年,将J2SE改成 Java SE、将J2EE改成 Java EE、将J2ME改成 Java ME
2006 发布 Java SE 6
2011 Oracle 发布 Java SE 7
2014 Oracle 发布 Java SE 8
2017 Oracle 发布 Java SE 9算法
2. Java三大致系express
Java SE编程
Java SE(JavaPlatform,Standard Edition)。Java SE之前称为J2SE。它容许开发和部署在桌面、服务器、嵌入式环境和实时环境中使用的Java应用程序。Java SE 包含了支持Java
Web服务开发的类,并为Java EE提供基础。windows
Java EE设计模式
Java EE(Java Platform,Enterprise
Edition)。企业版本帮助开发和部署可移植、健壮、可伸缩且安全的服务器端Java应用程序。Java EE是在Java
SE的基础上构建的,它提供Web 服务、组件模型、管理和通讯API,能够用来实现企业级的面向服务体系结构和Web 2.0应用程序。 Java
EE既是一个框架又是一种规范,说它是框架是由于它包含了不少咱们开发时用到的组件,例如:Servlet,EJB,JSP,JSTL等。说它是规范又如咱们开发web应用常会用到的一些规范模式,Java
EE提供了不少规范的接口却不实现,将这些接口的具体实现细节转移到厂商身上,这样各家厂商推出的Java
EE产品虽然名称实现不一样,但展示给外部使用的倒是统一规范的接口。api
Java ME数组
Java ME(Java Platform,Micro Edition)。Java
ME为在移动设备和嵌入式设备(好比手机、PDA、电视机顶盒和打印机)上运行的应用程序提供一个健壮且灵活的环境。Java
ME包括灵活的用户界面、健壮的安全模型、许多内置的网络协议以及对能够动态下载的连网和离线应用程序的丰富支持。基于Java
ME规范的应用程序只需编写一次,就能够用于许多设备,并且能够利用每一个设备的本机功能。
如图所示
3. Java特性
语言特色
简单易学、面向对象 、平台无关性
4. Java环境搭建
4.1 环境配置
安装JDK
JDK是整个Java开发的核心,它包含了Java的运行环境(JVM+Java系统类库)和JAVA工具。
从官网下载JDK,根据不一样系统选择须要的版本。 官网下载地址以下:http://www.oracle.com/technetwork/java/javase/downloads,下载后直接点击下一步安装便可。
配置环境变量(以windows系统为例)
第一步:
配置JAVA_HOME环境变量右击个人电脑–>点击属性–>左侧的高级系统设置–>点击右下方的环境变量–>点击新建或者编辑系统变量中的JAVA_HOME–>输入JDK的安装目录
第二步:配置Path环境变量右击个人电脑–>点击属性–>左侧的高级系统设置–>点击右下方的环境变量–>双击系统变量中Path属性–>添加%JAVA_HOME%/bin值至尾部 【注意】: “;”来分隔
第三步:配置CLASSPATH环境变量右击个人电脑–>点击属性–>左侧的高级系统设置–>点击右下方的环境变量–>双击系统变量中classpath属性或新建classpath–>添加%JAVA_HOME%/lib值至尾部
【注意】: “.”添加至最前边,并用”;”与后边的隔开
环境变量简介
(1) JAVA_HOME:指定JDK的安装路径,做为全局变量用做后面配置的变量。 (2) Path:windows系统根据Path环境变量来查找命令。Path环境的值是一系列的路径,若是能经过Path找到这个命令,则该命令是可执行。不然报“XXX命令不是内部或外部命令,也不是可运行的执行程序或批处理文件”。 %JAVA_HOME%\bin;%JAVA_HOME%\jre\bin; (3) CLASSPATH:指定了运行Java程序时,查找Java程序文件的路径。 .;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar;
验证环境变量
按键win+r->输入cmd->进入window命令行界面->输入javac -version->验证版本是否正确。
【注意】:设置环境后要新打开cmd窗口才能生效
按键win+r->输入cmd->进入window命令行界面->输入java -version验证版本和输出是否正确。
4.2 Eclipse安装使用
• 下载和安装
下载地址:官网下载! 安装:绿色版免安装 • 基本使用 • 使用Eclipse建立一个HelloWorld工程,并实现打印 “HelloWorld”到控制台
5. Java编码规范
• 严格区分大小写 • 源文件以”.java”为后缀,基本组成单元为class • 一个Java源文件只能有一个public类,其它非public不限。当存在public类时,源文件名称必须与该类同名,区分大小写。 • 程序主入口为main方法,标准格式为:public static void main(String[] args){} • 类内部的方法代码以语句为最小单位,每一个语句以”;”为分号结束
1、介绍
本章节主要学习程序基础,主要涉及的知识点分为三大块:变量、流程控制、方法。
那么在开始本章内容以前,咱们先思考几个问题: 1. 咱们常常看到一个项目成千上万行代码,这些代码都是造成的呢? 2. 一条语句又是怎么造成的呢? 3. 若是在项目中某一段功能代码须要被重复使用几遍,怎么办?咱们就一遍遍地写么? 【答案】: 这些成千上万行的代码都是由最简单的一个个语句按照某种流程堆积而成的; 一条语句通常由关键字、变量和运算符等组成。 Java中方法能够解决代码复用问题。
1.标识符
1.1释义 标识符就是用于给程序中的变量、类、方法命名的符号。标识符能够有编程人员自由定义,但须要遵循必定的命名规则。 1.2命名规则 能够由字母、数字、下划线(_)、美圆符号($)组成。 必须以字母、下划线或美圆符号开头,不能以数字开头。 不能指定为关键字。 长度没有限制,但定义时通常以见名知义为原则。 使用驼峰命名,类名首名字均大写,常量所有字母大写;方法名、属性名的单词首字母小写中间的单词首字母大写。
2.关键字
2.1释义 Java语言中用以特殊用途而预占用的单词或标识符称之为关键字,Java中的关键字均为小写。
2.2关键字
除了上面表格中,goto和const为Java语言中的两个保留字。保留字是指预留的还未被使用的关键字,但可能在未来的版本中使用。
常量
常量也可称为字面值,即字面显示的值,其自己不会发生变化。
【样例】
数值型 1234 , 3.14 字符常量 'c' 逻辑常量值 true , false 字符串常量 "Hello"
一种final修饰下的变量也称为常量。 【格式】 final 数据类型 常量名称[=值]
【常量与变量区别】
常量在程序运行过程当中其值不能改变。变量是用于存储可变数据的容器,存储必定格式的可变数据。 命名规范不同。默认常量为全大写,而变量为驼峰。 修饰符不一样。通常常量都会用final修饰。变量不会。并且,为了节省内存,常量都会同时使用static修饰。
变量
变量是程序中最基本的存储单元,由做用域、变量类型、变量名组成。
1.1变量的声明
Java是强声明式语言,每一个变量在使用前均要先声明。 【声明格式】数据类型 变量名称[=值]; 【代码示例一】 int age; //只声明 【代码示例二】 int age = 18; //直接初始化
1.2变量分类
变量分为局部变量、成员变量、类变量。
1.2.1局部变量 (本地变量)
方法的形式参数以及在方法中定义的变量。 【格式】 (type name = value) 【做用范围】 形参:在方法体中任何位置均可以访问。 方法中定义变量:从定义处开始,直到所在代码块结束。 【生命周期】 出生:运行到建立变量语句时。 死亡:超过其做用范围。
1.2.2成员变量 (实例变量,属性)
成员变量就是类中的属性。当new对象的时候,每一个对象都有一份属性。一个对象中的属性就是成员变量。 【格式】 (访问修饰符 type name = value) 【做用范围】 在类内部,任何地方均可以访问成员变量。 【生命周期】 出生:new对象的时候,开辟内存空间。 死亡:堆内存地址没有引用,变成垃圾,被垃圾回收器回收后。
1.2.3类变量 (静态属性)
被static修饰的属性。 【格式】 (访问修饰符 static type name = value) 【做用范围】 在类变量定义以后。 【生命周期】 出生:类加载时,类变量就分配内存空间。 死亡:JVM退出。
1.释义
数据类型是为了把数据分红所需内存大小不一样的数据,编程的时候须要用大的数 据才申请大内存,这样能够充分利用内存。 Java语言是一种强类型语言,要求全部变量先声明后使用。目的就是为了保证变量或者表达式在编译时就可以肯定其类型, 并为其分配相应的内存。
2.分类
2.1整型
2.1.1 Java整型
byte/short/int/long
2.1.2整型取值范围
Java语言整数型默认为int类型,若是要声明成long类型在变量值后加入L,如:long l = 123L
类型 | 占用存储空间字节数 | 数值范围 |
---|---|---|
byte | 1 | -128~127 |
short | 2 | -2的15次方2的15次方-1(-3276832767) |
int | 4 | -2的31次方~2的31次方-1 |
long | 8 | -2的63次方~2的63次方-1 |
2.1.3 Java整型常量的三种表示方法
十进制:如123=1*100+2*10+3*1=123 八进制,八进制0开头:如:013=1*8+3*1=11 十六进制,十六进制0x开头:如:0x23=2*16+3*1=35
【进制转换】
10进制到二进制
示例:求十进制数10的二进制
6/2=3 余 0
3/2=1 余 1
1/2=0 余 1
将余数逆序输出就是6的二进制表示:110,位数不够补零
二进制到十进制
示例:求二进制110的十进制
规则:取出最后一位,从2的0次方开始乘,将获得的结果相加便可
0*2的0次方=0
1*2的1次方=2
1*2的2次方=4
110的十进制为:0+2+4=6
八进制与二进制、十进制转换类同
2.2浮点型
2.2.1 Java浮点型
float/double
2.2.2两种表示形式
十进制形式:例如:123.456 0.314 科学计数法:例如:1.23456E2 3.14E-1
2.2.3 Java浮点型取值范围
浮点声明默认是double类型,若要是float,请在尾部添加f或是F。如:float myFloat=1.23
类型 | 占用存储空间字节数 | 数值范围 |
---|---|---|
float | 4 | -3.4E38 ~ 3.4E38 |
double | 8 | -1.7E308~ 1.7E308 |
2.3布尔型
适用于逻辑运算,用于程序流程控制 只容许取值为true,false,不能够任何其它形式代替
[示例]
boolean real=true; //正确
boolean notReal=false; //正确
boolean read2=1; //错误
boolean notReal2=0; //错误
2.4字符型
2.4.1 Java字符型
一般意义上的字符,用单个引号括起来的单个字符
如'1','a','b'等等
Java采用Unicode编码(即为全球统一语言编码),都可以用十六进制表示编码值
char c = '\u0012';
转义字符,用’\n’来表示,即为转变以前的意义,但依然是个字符
char c='\n'; //表示换行符
3.基本类型转换
布尔类型不能与其它类型作任何转换 数值型、字符型能够相互转换,规则以下: 容量小的自动转换成表数范围容量大的,但byte,short,char不能相互转换,均转化成int作计算 容量大小排序为:byte,char,short<int<long<float<double 容量大转换为容量小的,要增强制转换符,此时容易丢失精度 多类型混合运算时,系统会自动转换成统一类型(大容量数据)后再进行计算,即先类型转换后计算
1.运算符
释义
用于表示数据的运算、赋值和比较的一系列符号咱们称之为运算符。
分类
运算符按功能划分以下:
运算符类型 | 运算符 |
---|---|
算术运算符 | +,-,*,/,++,–,% |
关系运算符 | <,<=,>,>=,==,!= |
布尔运算符 | &&, |
位运算符 | &, |
赋值类运算符 | =, +=, -=, *=, /=, %= |
字符串链接运算符 | + |
条件运算符(三目运算符) | ? : |
其余运算符 | instanceof,new |
1.1算术运算符
类型 | 描述 | 示例 |
---|---|---|
++(自加运算符) | ++在变量前面时,先作运算后赋值++在变量后面时,先作赋值后运算 | i = 1, j; j = ++i; 则j=2;i = 1, j; j = i++; 则 j = 1 |
–(自减运算符) | 同上 | i = 1, j; j = - -i; 则 j = 0;i = 1, j; j = i- -; 则 j = 1; |
1.2关系运算符
注意 ‘==’关系运算,其意义为全等,基本数据类型比较值,引用数据类型比较地址
1.3逻辑运算符
与 &:两个操做数相与,若是都为true,则为true 或 |:两个操做数相或,有一个为true,则为true 异或 ^:相异为true,两个操做数不同就为true,相同为false
短路&& 和 逻辑& 区别?
1.短路与,从第一个操做数推断结果,只要有一个为fase,再也不计算第二个操做数 2.逻辑与,两个操做数都计算
短路|| 和 逻辑| 区别?
1.短路或,从第一个操做数推断结果,只要有一个为true,再也不计算第二个操做数 2.逻辑或,两个操做数都计算
1.4赋值运算符
注意
1)当 "=" 两侧数据类型不一致时,适用默认转换或强制转换处理,如long num=20;int i=(int)num; 2)特殊状况为:当byte,char,short被整赋值时,不须要进行强制类型转换,不超过取值范围便可。即一个自动装载的过程。 char c=100;byte b=20; //正确 char c2=-99999;byte b2=128; //类型越界错误
运算符 | 用法 | c |
---|---|---|
+= | a+=b | a=a+b |
-= | a-=b | a=a-b |
*= | a*=b | a=a*b |
/= | a/=b | a=a/b |
%= | a%=b | a=a%b |
1.5字符串链接运算符
"+" 可用于数值计算,当有一方是字符时,则为将左右两个数据转化成字符串连在一块儿。如int i=10+20;String j="10"+"20"。 当" +" 任意一侧为字符串时,系统将自动将两侧转化成字符串,作字符串连接操做。 当进行System.out.println(var)打印操做的时候,均自动转化为字符串进行输出。
1.6运算优先级
优先级 | 运算符分类 | 结合顺序 | 运算符 |
---|---|---|---|
由高到低 | 分隔符 | 左结合 | . [] ( ) ; , |
一元运算符 | 右结合 | ! ++ – - ~ | |
算术运算符 | 左结合 | * / % + - | |
移位运算符 | << >> >>> | ||
关系运算符 | 左结合 | < > <= >= instanceof == != | |
逻辑运算符 | 左结合 | ! && | |
三目运算符 | 右结合 | 布尔表达式?表达式1:表达式2 | |
赋值运算符 | 右结合 | = *= /= %= += -= <<= >>= >>>= &= *= |
【问】:作一道综合性强点的练习题,感觉感觉运算符优先级怎么样? int a = 5; int b = 4; int c = a++ - --b * ++a / b-- >> 2 % a--; c的值是多少?
2.表达式
表达式是指由(常量、变量、操做数)与运算符所组合而成的语句。 符合语法规则的运算符+操做数,即为表达式,如:5+3,2.0+3.0,a+b,3%2 表达式最终运行结果即为表达式的值,值的类型就是表达式的类型 运算符优先级,决定表达式的运算顺序 三目运算符: 形如:x?y:z 释义:计算x的值,若为true,则表达式的值为y;若为false,则表达式的值为z
程序控制结构是指以某种顺序执行的一系列动做,用于解决某个问题。程序能够经过控制语句来对程序实现选择、循环、转向和返回等流程控制。
程序控制结构包括:顺序结构、分支结构、循环结构。
1. 顺序结构
顺序结构程序就是按语句出现的前后顺序执行的程序结构。计算机按顺序逐条执行语句,当一条语句执行完毕, 自动转到下一条语句。
如图:
示例:
int a = 11; //第一步
int b = 2; //第二步
int c = a+b; //第三步
System.out.println(“a+b的结果为:”+c); //第四步
2. 分支结构
1)分支结构又称为选择结构。当程序执行到控制分支语句时,首先判断条件,根据条件表达式的值选择相应的语句执行(放弃另外一部分语句的执行)。
2)分支结构包括单分支、双分支和多分支三种形式。
如图:
2.1单分支
【语法格式】
if(布尔表达式){语句块;}
说明:当语句块为一条语句时,大括号能够省略。只有布尔表达式为true时,才进入if语句中。
【示例】
int age = 20; if(age >= 18){ System.out.println("成年人"); }
2.2双分支
【语法格式】
if(布尔表达式){ 语句块;//if分支 }else{ 语句块;//else分支 }
【示例】
int age = 20; if(age >= 18){ System.out.println("成年人"); }else{ System.out.println("未成年人"); }
2.3多分支-1
【语法格式】
if(布尔表达式){ 语句块; }else if(布尔表达式){ 语句块; }else{ 语句块; }
【示例】
int age = 20; if(age >0 && age <=18){ System.out.println("未成年"); }else if(age > 18 && age <=40) { System.out.println("青年"); }else if(age > 40&& age<=50) { System.out.println("中年"); }else if(age > 50) { System.out.println("老年"); }else{ System.out.println("见鬼了"); }
2.4多分支-2
【语法格式】
switch (表达式) { case 值1: 语句; break; case 值2: 语句; break; default: 语句; break; }
说明:
表达式的值只能为:char、byte、short、int类型、String、enum类型,其它类型均非法 break语句能够省略,但会出现switch穿透 default语句也能够省略,通常不建议省略,而且放置在最后
【示例】
public static void main(String[] args) { String type = "dog"; switch(type) { case "cat": System.out.println("喵"); break;//注意break case "dog": System.out.println("旺"); break; case "sheep": System.out.println("咩"); break; default: System.out.println("哇!"); } System.out.println("switch执行结束!"); }
3. 循环结构
当程序执行到循环控制语句时,根据循环断定条件对一组语句重复执行屡次。 循环结构的三个要素:循环变量、循环体和循环终止条件。 while、do…while、for三种循环。
如图:
3.1 while语句
【语法格式】
while(布尔表达式){ 循环体; //一条或多条语句 }
【示例】
int i = 1; while(i<=5) { System.out.println(i); i++; }
3.2 do…while语句
【语法格式】
do { 循环体; }while(条件判断表达式);
【示例】
int i = 1; do{ System.out.println(i); i++; }while(i<=0); //注意分号
3.3 for语句
【语法格式】
for(表达式1;表达式2;表达式3) { 循环体; //一条或多条语句 }
【示例】
for (int i=1; i<=5; i++) { System.out.println(i); }
3.4 break语句
强制退出某个循环体,结束循环语句的执行
【示例】
public static void main(String[] args) { for(int i=1; i<=10; i++) { System.out.println(i); if(i == 5){ break; //会跳出当前循环 } } //break跳到这里 }
3.5 continue语句
终止某次循环过程,跳过continue语下方未执行的代码,开始下一步循环过程
【示例】
public static void main(String[] args) { for (int i=1; i<=10; i++) { if (i == 5) { continue; //会跳该次循环,跳到i++代码处 } System.out.println(i); } }
3.6 流程控制语句总结
条件判断语句:if语句、switch语句。 循环执行语句:do while语句、while语句、for语句。 跳转语句:break语句、continue语句、return语句。
控制语句类型 | 关键字 | 做用 |
---|---|---|
选择结构语句 | if、if else、else if、switch | 经过开关机制,选择要执行的代码 |
循环结构语句 | for、while、do while | 经过循序机制,反复执行相同的代码段 |
改变语句执行序 | break、continue | 经过打断或继续机制,改变当前工码的执行顺序 |
三种循环结构的异同点:
用while和do…while循环时,循环变量在循环体以前初始化,而for循环通常在语句1进行初始化。 while 循环和for循环都是先判断表达式,后执行循环体;而do…while循环是先执行循环体后判断表达式。 也就是说do…while的循环体最少被执行一次,而while循环和for就可能一次都不执行。 这三种循环均可以用break语句跳出循环,用continue语句结束本次循环。
1.释义
方法是组合在一块儿来执行操做语句的集合。
2.方法做用
1) 使程序变得更简短更清晰 2) 有利于程序维护 3) 提升程序开发效率 4) 提升代码重用性
3.方法建立与使用
【语法格式】
访问修饰符 返回值类型 方法名(参数列表){ 方法体 ; }
【方法分类】
根据方法是否带参、是否带返回值,可将方法分为四类 1) 无参无返回值方法 2) 无参带返回值方法 3) 带参无返回值方法 4) 带参带返回值方法
3.1无参无返回值方法
public void print(){ System.out.println("你们好,我是我是papi酱"); System.out.println("一个集美貌和才华与一身的女子"); }
3.2无参带返回值方法
public int callForYou(){ System.out.println("老铁,双击666!"); return 666; }
3.3带参无返回值方法
public void printResult(int a, int b){ int c = a + b; System.out.println("我只是打印结果而已,两数相加结果:"+c); }
3.4带参带返回值方法
public String ifAdult(int age){ if(age >= 18){ return "成年人"; }else{ return "未成年人"; } }
3.5递归方法
释义
程序自身调用自身的编程技巧称为递归
递归四个特性
1.必须有可最终达到的终止条件,不然程序将陷入无穷循环; 2.子问题在规模上比原问题小,或更接近终止条件; 3.子问题可经过再次递归调用求解或因知足终止条件而直接求解; 4.子问题的解应能组合为整个问题的解。
技巧
找到递归实现的递归部分和终止部分
斐波那契数列
Fibonacci: 1 , 1 , 2 , 3 , 5 , 8 , 13 , 21 ... ... 终止部分:F1=1,F2=1; 递归部分为:F(n)=F(n-1)+F(n-2),其中n>2
图解斐波那契递归过程
Fibonacci递归实现代码
public class Test { public static long fibonacci(int n) { if(n==0||n==1) return 1; else { return fibonacci(n-1)+fibonacci(n-2); } } public static void main(String[] args) { for(int i=0;i<10;i++) { long num = fibonacci(i); System.out.print(num+" "); } } }
释义
数组是在程序设计中,为了处理方便, 把具备相同类型的若干元素按无序的形式组织起来的一种形式。这些无序排列的同类数据元素的集合称为数组。
数组有一维数组和多维数组。
1. 一维数组介绍
把int类型的四个数字1,2,3,4组织起来。
一维数组声明
两种声明格式
元素类型[] 变量名称 示例:int[] intArray; 元素类型 变量名称[] 示例:int intArray[]; 一行中容许声明多个数组 int[] array1,array2,array3;
一维数组初始化
数组初始化的过程就是为数据分配内存空间的过程。
静态初始化
声明数组时,对数组初始化,数组的大小会根据初始值的个数肯定长度。
【示例】
public static void main(String[] args) { String[] nameArray={"one","two","three"}; for(int i=0;i<nameArray.length;i++){ System.out.println(nameArray[i]); } }
动态初始化
声明数组时,指定数组的长度便可。
【示例】
public static void main(String[] args) { int[] girlFriendArray=new int[10]; for(int i=0;i<10;i++){ girlFriendArray[i]=i; } for(int i=0;i<10;i++){ System.out.println(girlFriendArray[i]); } }
2. 一维数组的使用
2.1长度属性:length
int arr = new int[5]; //数组arr的长度属性,即arr.length=5
2.2下标访问数组元素
int arr = {12,23,5,34,7}; System.out.println("取出arr的第一个元素的值:"+arr[0]);
2.3数组遍历
下标循环
for(int 下标变量值=0;下标变量值<遍历对象的长度值;下标变量值++){ 循环体 }
【示例】
int[] arr = new int[5]; for(int i=0;i<arr.length;i++){ 循环体 }
加强循环
for(元素类型t 元素变量x : 遍历对象obj){ 语句; }
【示例】
int[] arr = {2,5,8,12,51}; for(int i : arr){ 循环体 }
1. 二维数组介绍
二维数组本质上是以数组做为数组元素的数组,即“数组的数组”。
int[][] a = {{1,3,5,7},{9,11,13,15},{17,19,21,23}};
2. 二维数组的声明
【语法格式】
类型说明符 数组名[常量表达式][常量表达式]
【常见二维数组声明问题】
二维数组的声明和初始化,严格按从高维到低维的顺序进行
int tempArray[][]=new int[][3]; //错误 int tempArray[][]=new int[3][]; //正确 int tempArray[][]=new int[3][4]; //正确
3.二维数组的使用
静态初始化
public static void main(String[] args) { int[][] myArr={{1,2},{3,4},{5,6}}; }
动态初始化
public static void main(String[] args) { int[][] myArr=new int[10][10]; for(int i=0;i<10;i++){ for(int j=0;j<10;j++){ myArr[i][j] = (i+1)*j; } } }
数组是一种引用数据类型
数组是一组类型相同的数据集合
数组元素的类型能够是基本类型或引用类型,但全部元素类型要一致
数组长度固定
数组元素可经过下标访问,下标从0开始
1. 本身写算法排序
冒泡排序(Bubble Sort),是一种计算机科学领域的较简单的排序算法。
它重复地走访过要排序的数列,一次比较两个元素,若是他们的顺序错误就把他们交换过来。走访数列的工做是重复地进行直到没有 再须要交换,也就是说该数列已经排序完成。这个算法的名字由来是由于越大的元素会经由交换慢慢 “浮”到数列的顶端, 故名 “冒泡”。
【算法原理】
冒泡排序算法的运做以下:(从后往前)
1. 比较相邻的元素。若是第一个比第二个大,就交换他们两个。 2. 对每一对相邻元素做一样的工做,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。 3. 针对全部的元素重复以上的步骤,除了最后一个。 4. 持续每次对愈来愈少的元素重复上面的步骤,直到没有任何一对数字须要比较。
【算法描述】
public static void bubbleSort(int[] arr) { int temp = 0; int size = arr.length; for(int i = 0 ; i < size-1; i ++) { for(int j = 0 ;j < size-1-i ; j++) { if(arr[j] > arr[j+1]) //交换两数位置 { temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp; } } } }
选择排序(Selection Sort)是一种简单直观的排序算法。它每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到所有待排序的数据元素排完。
【算法思想】
1. 在未排序序列中找到最小元素,存放到排序序列的起始位置 2. 再从剩余未排序元素中继续寻找最小元素,而后放到排序序列末尾。 3. 以此类推,直到全部元素均排序完毕。
【算法描述】
public static void selectSort(int[] numbers) { int size = numbers.length; //数组长度 int temp = 0 ; //中间变量 for(int i = 0 ; i < size ; i++) { int k = i; //待肯定的位置 //选择出应该在第i个位置的数 for(int j = size -1 ; j > i ; j--) { if(numbers[j] < numbers[k]) { k = j; } } //交换两个数 temp = numbers[i]; numbers[i] = numbers[k]; numbers[k] = temp; } }
2. 调用API排序方法
int[] arr = {7,9,4,8,3,5}; Arrays.sort(arr);
顺序查找是在一个已知无(或有序)序队列中找出与给定关键字相同的数的具体位置。
【算法原理】
让关键字与队列中的数从最后一个开始逐个比较,直到找出与给定关键字相同的数为止。
【算法描述】
public static int ordersearch(int[] arry,int des){ int i=0; for(;i<=arry.length-1;i++){ if(des==arry[i]) return i; } return -1; }
二分查找又称折半查找,优势是比较次数少,查找速度快,平均性能好,占用系统内存较少;其缺点是要求待查表为有序表,且插入删除困难。所以,折半查找方法适用于不常常变更而查找频繁的有序列表。
【算法原理】
假设表中元素是按升序排列,将表中间位置记录的关键字与查找关键字比较,若是二者相等,则查找成功; 不然利用中间位置记录将表分红前、后两个子表,若是中间位置记录的关键字大于查找关键字,则进一步查找前一子表, 不然进一步查找后一子表。重复以上过程,直到找到知足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。
【算法要求】
1)必须采用顺序存储结构。 2)必须按关键字大小有序排列。
【算法描述】
public static int binarySearch(Integer[] srcArray, int des) { //定义初始最小、最大索引 int low = 0; int high = srcArray.length - 1; //确保不会出现重复查找,越界 while (low <= high) { //计算出中间索引值 int middle = (high + low)/2 ;//防止溢出 if (des == srcArray[middle]) { return middle; //判断下限 } else if (des < srcArray[middle]) { high = middle - 1; //判断上限 } else { low = middle + 1; } } //若没有,则返回-1 return -1; }
1. 面向过程与面向对象
面向过程就是分析出解决问题所须要的步骤,而后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就能够了;
面向对象是把构成问题事务分解成各个对象,创建对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为。
Java是面向对象的程序设计语言,类是面向对象的重要内容,咱们能够把类当成一种自定义数据类型,能够使用类来定义变量,这种类型的变量称为引用型变量。也就是说,全部类是引用数据类型。
2.1概念
面向对象的程序设计中有两个重要概念:类和对象。其中类是某一类对象的抽象。对象才是一个具体的实体。如:有一条狗叫”花花”,那么这条真实存在的狗才是对象,而”狗”是类,表明一类”花花”这样的实体。
抽象的重要性
抽象是继承和多态的基础。在抽象的过程当中,咱们得到是事物本质的东西和事物独特的东西,这样咱们很天然的认识到抽象的事物和具体的事物之间是一种继承的关系,而他们之间的不一样性能够经过多态来表现出来。
2.2定义类
2.2.1语法格式
[权限控制符] class 类名 { //零个到多个构造器 * 构造器定义 * 注意:构造器无返回值类型 [权限控制符] 类名(参数列表){}; //零个到多个属性 * 属性定义 [权限控制符] [static | final] 属性类型 属性名; //零个到多个方法 * 方法定义 [权限控制符] [abstract | final] [static] 返回值类型 方法名(参数表){}; }
提示:定义类的时候,不是必须显式写构造方法、属性、方法。
【示例】
定义一个学生类
属性:学号、姓名、年龄、班级
方法:学习、唱歌
public class Student{ public Student(){ //.... } public Student(String name,int age){ this.name = name; this.age = age; } public String name; public int age; //..... public void study(){ System.out.println(“爱学习”); } public void sing(){ //唱歌 System.out.println(“爱唱歌”); } }
2.2.2对象的建立和使用
1)对象建立语法格式
类名 对象名 = new 类名();
示例
Student s = new Student();
2)操做对象的属性和方法
【语法格式】
使用类的属性: 对象名.属性 实用类的方法: 对象名.方法名()
以上面学生类Student为例:
Student s = new Student(); s.age = 18; //为属性age赋值为18 s.sing(); //调用sing方法 Student s = new Student(“小明”,18); System.out.println(s.age);
2.3构造方法
构造方法是一种特殊的方法,它是一个与类同名且没有返回值类型的方法。对象的建立就是经过构造方法来完成,其功能主要是完成对象的初始化。当类实例化一个对象时会自动调用构造方法。构造方法和其余方法同样也能够重载。
特殊性
1)构造方法做用:构造出来一个类的实例,对构造出来的类的对象初始化。 2)构造方法的名字必须与定义他的类名彻底相同,没有返回类型,甚至连void也没有。 3)系统会默认为类定义一个无参构造方法,即默认构造方法。若显式定义了构造方法,则系统不会提供默认无参构造函数。
示例
public class Constructor_01 { int age; public static void main(String[] args) { Constructor_01 c = new Constructor_01(12); System.out.println(c.age); } //有参构造方法 public Constructor_01(int i) { age = i; } //无参构造方法 public Constructor_01() { age = 18; } }
思考
咱们能够定义两个名称同样的属性么?不能够。那么两个方法的名称同样呢?这里的两个构造方法名称相同了,可是没有报错, 为何呢?这就是方法重载。
2.4方法重载
特色
1)方法名必定要相同 2)参数列表不一样——参数类型、参数个数 3)与方法的访问控制符和返回值无关
2.5对象的引用与this
引用
Student s = new Student(“张三”);
上面的对象名s即为对象的引用,而 new Student(“张三”)才是张三对象。
this
总要有个事物来表明类的当前对象,就像C++中的this指针同样,Java中的this关键字就是表明当前对象的引用。
图例
它有三个主要的做用
1)在构造方法中调用其余构造方法
好比:有一个Student类,有三个构造函数,某一个构造函数中调用另外构造函数,就要用到this(),而不能够直接使用Student()。
2)返回当前对象的引用 3)区分红员变量名和参数名
2.6 static
static关键字的用途
被static关键字修饰的方法或者变量不须要依赖于对象来进行访问,只要类被加载了,就能够经过类名去进行访问。
static方法
static方法通常称做静态方法,因为静态方法不依赖于任何对象就能够进行访问,所以对于静态方法来讲:
1. static是没有this的,由于它不依附于任何对象,既然都没有对象,就谈不上this了。 2. 在静态方法中不能访问类的非静态成员变量和非静态成员方法,由于非静态成员方法/变量都是必须依赖具体的对象才可以被调用。 3. 虽然在静态方法中不能访问非静态成员方法和非静态成员变量,可是在非静态成员方法中是能够访问静态成员方法/变量的。
static变量
static变量也称做静态变量,静态变量和非静态变量的区别是:
1. 静态变量被全部的对象所共享,在内存中只有一个副本,它当且仅当在类初次加载时会被初始化。 2. 非静态变量是对象所拥有的,在建立对象的时候被初始化,存在多个副本,各个对象拥有的副本互不影响。
二. JVM内存分析——案例
内存分配图
JAVA的JVM的内存可分为3个区:堆(heap)、栈(stack)和方法区(method)
堆区:
1.存储的所有是对象,每一个对象都包含一个与之对应的class的信息。 2.jvm只有一个堆区(heap)被全部线程共享,堆中不存放基本类型和对象引用,只存放对象自己。 3.通常由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。
栈区:
1.每一个线程包含一个栈区,栈中只保存基础数据类型的对象和自定义对象的引用(不是对象),对象都存放在堆区中。 2.每一个栈中的数据(原始类型和对象引用)都是私有的,其余栈不能访问。 3.栈分为3个部分:基本类型变量区、执行环境上下文、操做指令区(存放操做指令)。 4.由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。
静态区/方法区:
1.方法区又叫静态区,跟堆同样,被全部的线程共享。方法区包含全部的class和static变量。 2.方法区中包含的都是在整个程序中永远惟一的元素,如class,static变量。 3.全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另外一块区域。
举例
Sample test1=new Sample(“测试1”);
1. 概念
什么是封装
封装是把对象的全部组成部分组合在一块儿,封装使用访问控制符将类的数据隐藏起来,控制用户对类的修改和访问数据的程度。
做用
适当的封装可让代码更容易理解和维护,也增强了代码的安全性。
2. 访问控制符
访问控制符用来控制父类、子类间,不一样包中的类间数据和方法的访问权限。
包括private、protected、public和默认四中类型。其访问权限以下:
访问控制符 | 同一类中 | 同一包中 | 同一子类中 | 其余 |
---|---|---|---|---|
private | 是 | 否 | 否 | 否 |
default | 是 | 是 | 否 | 否 |
protected | 是 | 是 | 是 | 否 |
public | 是 | 是 | 是 | 是 |
1. 概念
继承是从已有的类中派生出新的类,新的类能吸取已有类的属性和行为,并能扩展新的属性和行为。
1.1 Java继承特色
1) Java是单继承的,不支持多继承。这样使得Java的继承关系很简单,一个类只能有一个父类,易于管理程序。同时一个类能够实现多个接口,从而克服单继承的缺点。 2) 继承关系是传递的 3) private修饰的成员变量或方法是不能被继承的
1.2解决什么问题
提升了代码的效率,避免了代码重写。
2. 语法格式
[修饰符] class 子类 extends 父类 { //类体 }
【示例】
实现一个继承,定义学生类为父类,定义一个大学生类做为子类。
//父类 public class Student { } //子类 class BStudent extends Student{ }
3. super
this是指当前对象引用,super是指当前对象的父类对象的引用。因为继承子类能够访问父类的成员,因此this除了能够访问本身的成员还能够访问父类的成员,可是为了明确的指明访问的是父类的成员,则要用关键字super来指定。
【示例】
public class Super_01 extends A{ Super_01() { //不写,默认会有super()调用父类无参构造 super(); System.out.println("子类构造方法"); } int i = 2; public static void main(String[] args) { Super_01 s = new Super_01(); s.m1(); } public void m1(){ //子类 System.out.println(i); //父类 System.out.println(super.i); //子类 System.out.println(this.i); } } class A{ A(){ super(); System.out.println("父类构造方法"); } int i = 10; }
4. final
final表示不可改变的含义
采用final修饰的类不能被继承 采用final修饰的方法不能被重写 采用final修饰的变量不能被修改
final修饰的变量必须显式初始化 若是修饰的引用,那么这个引用只能指向一个对象,该引用不能再次赋值,但对象自己内部能够修改
构造方法不能被final修饰
5. 方法重写
在Java中,子类可继承父类中的方法,而不须要从新编写相同的方法。但有时子类并不想原封不动地继承父类的方法,而是想做必定的修改,这就须要采用方法的重写。
方法重写的特性
1)发生方法重写的两个方法返回值、方法名、参数列表必须彻底一致(子类重写父类的方法) 2)子类抛出的异常下不能超过父类相应方法抛出的异常(子类异常不能大于父类异常) 3)子类方法的访问级别不能低于父类相应方法的访问级别(子类访问级别不能低于父类访问级别)
【示例】
public class Override_01 { public static void main(String[] args) { Cat cat = new Cat(); cat.move(); System.out.println(cat.i); Animal a = new Animal(); a.move(); //多态 Animal ac = new Cat(); ac.move(); System.out.println(ac.i); } } class Animal{ int i = 10; public void move(){ System.out.println("动物在移动"); } } class Cat extends Animal{ int i = 20; @Override public void move() { // super.move(); System.out.println("猫在走猫步"); } }
6. 父子对象间转换和instanceof
父类和子类拥有公共的属性和方法,那么可否经过父类来访问子类中的继承的公共的属性和方法呢?
咱们在上面了解到,若是在子类内部确定能够,并且经过this和super关键字能够轻松的使用。 那么若是在类的外部怎么实现这个应用需求呢?Java提供了类对象间的转换来知足这个需求。 咱们回顾一下以前的基本数据类型强制转换,父类和子类之间的转换与其相似。
隐式转换:小类转大类,也叫为向上转
强制转换:大类转小类,也为向下转,须要有 “()”做为强制转换。
如:Student student = new DaXueSheng();//隐式转换 DaXueShen daXueShen= (DaXueSheng)student;//强制转换
【总结】
* 子类对象能够被视为其父类的一个对象,如一个大学生(子类)确定是一个学生(父类)。 * 父类对象不能被声明为某一个子类的对象,如一个学生不能彻底表示一个大学生。 * 父类引用能够指向子类对象,但不能访问子类对象新增的属性和方法。
instanceof运算符
Java提供了instanceof关键字,使咱们在强制转换以前,判断前一个对象是否后一个对象的实例,是否能够成功的转换,以加强代码的健壮性。
1. 概念
多态性
多态指容许不一样类的对象对同一消息作出响应。即同一消息能够根据发送对象的不一样而采用多种不一样的行为方式。(发送消息就是函数调用)
示例
public class Poly_01 { public static void main(String[] args) { Sup sup =new Sub(); sup.m1(); System.out.println(sup.i); // System.out.println(sup.a); } } //父类 class Sup{ int i = 10; public void m1(){ System.out.println("父类成员方法"); } } //子类 class Sub extends Sup{ int i = 20; int a = 1; public void m1(){ System.out.println("子类成员方法"); } }
必要条件
继承、重写、向上转型。 继承:在多态中必须存在有继承关系的子类和父类。 重写:子类对父类中某些方法进行重写,在调用这些方法时就会调用子类的方法。 向上转型:在多态中须要父类的引用指向子类的对象。
2. 体现方式
使用父类做为方法形参实现多态。 使用父类做为方法返回值实现多态 。
3. 好处
把不一样的子类对象都看成父类来看,能够屏蔽不一样子类对象之间的差别,写出通用的代码,作出通用的编程,以适应需求的不断变化。
//不使用多态,原本想拥有一条狗,后来想拥有一只猫,就须要改代码了
public class Person{ //Dog d; Cat c; //public void setAnimal(Dog d){ // this.d = d; //} public void setAnimal(Cat c){ this.c = c; } public static void main(String[] args) { Person p = new Person(); //p.setAnimal(new Dog()); p.setAnimal(new Cat()); } }
//使用多态,原本想拥有一条狗,后来想拥有一只猫,只需从新设置
public class Person{ Animal a; public void setAnimal(Animal a){ this.a = a; } public static void main(String[] args) { Person p = new Person(); //p.setAnimal(new Dog()); p.setAnimal(new Cat()); } } //动物类及其子类 class Animal{ } class Dog extends Animal{ } class Cat extends Animal{ }
1. 抽象类
1.1概念
抽象类每每用来表示设计中得出的抽象概念,是对一系列看上去不一样,可是本质上相同的具体概念的抽象。
好比:动物,它只是一个抽象的概念,并无一个 “东西”叫作 “动物”。因此,它并不能表明一个实体,这种状况下,咱们就适合把它定义成抽象类。
1.2语法格式
修饰符 abstract class 类名(){ //…… abstract 方法名(); }
abstract修饰:它修饰类就是抽象类,修饰方法就是抽象方法
含有抽象方法的类,必须是抽象类;抽象类必须被继承,抽象方法必须得重写 抽象方法只需声明,不需写具体实现 抽象类不能被实例化,即不能被new操做 abstract不能与final并列修饰同一类 abstract不能与private,static,final并列修饰同一方法 abstract方法必须位于abstract类中
【示例】
public class Abstract_01 { public static void main(String[] args) { // A a = new A(); A c= new C(); c.move(); m1(); m2(); A a = null; a.delete(); a.add(); } public static void m1() { } public static void m2() { // TODO Auto-generated method stub } } abstract class A{ public void eat(){ System.out.println("这是一个抽象类"); } //抽象方法 public abstract void move(); public abstract void add(); public abstract void load(); public abstract void delete(); A(){ System.out.println("A的构造方法"); } } abstract class B extends A{ } class C extends A{ @Override public void move() { System.out.println("着火了,快跑"); } @Override public void add() { // TODO Auto-generated method stub } @Override public void load() { // TODO Auto-generated method stub } @Override public void delete() { // TODO Auto-generated method stub } }
2.接口
2.1概念
Java接口是一些方法声明的集合,一个接口只有方法的声明没有方法的实现,所以这些方法能够在不一样的地方被不一样的类实现,而这些实现能够具备不一样的行为。
做用
1)Java是一种单继承的语言 2)实现多态
2.2语法格式
定义接口
[访问控制符] interface <接口名>{ 类型标识符final 符号常量名n = 常数; 返回值类型 方法名([参数列表]); … }
实现接口
[访问控制符] class 类名 [implements <interface>[,<interface>]*],] { //类体,必须实现接口中的方法 }
特性
咱们能够把接口看做是抽象类的一种特殊状况,在接口中只能定义抽象的方法和常量 接口不可实例化,可结合多态进行使用(接口 对象=new 对象()) 接口里的成员属性所有是以 public(公开)、static(静态)、final(最终) 修饰符修饰 接口里的成员方法所有是以 public(公开)、abstract(抽象) 修饰符修饰 接口里不能包含普通方法 子类继承接口必须实现接口里的全部成员方法,除非子类也是抽象类
【示例】
public class Interface_01 { public static void main(String[] args) { System.out.println(A.i); A.m1(); E e = new E(); e.m3(); } } interface A{ //都是静态常量 public static final String SUCCESS = "SUCCESS"; int i = 2; byte MAX_VALUE = 127; public static void m1(){ System.out.println("----"); } public default void m3(){ System.out.println("----"); } public abstract void m2(); } interface B{ void m4(); } //多继承 interface C extends A,B{ void m5(); } //抽象类实现0~N个抽象方法 abstract class D implements A,B{ } class E implements C{ @Override public void m2() { // TODO Auto-generated method stub } @Override public void m4() { // TODO Auto-generated method stub } @Override public void m5() { // TODO Auto-generated method stub } }
3.抽象类与接口的对比
普通类 抽象类 接口
表明一类实体,能够被实例化 表明一类实体,但不能被实例化 不能表明一类实体,只能表明功能或是属性
单继承 单继承 多实现
已经很具体,没有再抽象的须要 在多个普通类中有共用的方法或属性又有相同方法的不一样实现方式 单纯的规范,单纯的功能或属性须要独立体现出来
举个例子
有四个方法:吃饭,穿衣,跑步,开豪车; 吃饭,穿衣,跑步这三件事情,普通人都作获得,能够说是
“共性”的行为,只是具体行为实现不一样;开豪车不是普通人能够作到的,比较 “独特”。
吃饭,穿衣,跑步三个行为适合放在抽象类,开豪车适合放在接口。
Object类是全部Java类的祖先,每一个类都使用Object做为超类。
全部对象(包括数组)都实现这个类的方法。 在不明确给出超类的状况下,Java会自动把Object做为要定义类的超类。 能够使用类型为Object的变量指向任意类型的对象。
重点:toString()、equals()、hashCode()三个方法。
问:toString() 方法实现了什么功能? 答:toString() 方法将根据调用它的对象返回其对象的字符串形式。 问:当 toString() 方法没有被覆盖的时候,返回的字符串一般是什么样子的? 答:当 toString() 没有被覆盖的时候,返回的字符串格式是 类名@哈希值,哈希值是十六进制的。 举例说,假设有一个 Employee 类,toString() 方法返回的结果多是 Empoyee@1c7b0f4d。 问:euqals()函数是用来作什么的? 答:用来检查一个对象与调用这个equals()的对象是否相等。 问:使用Object类的equals()方法能够用来作什么比较? 答:调用它的对象和传入的对象的引用是否相等。也就是说,默认的equals()进行的是引用比较。 若是两个引用是相同的,equals()函数返回true;不然,返回false。 问:hashCode()方法是用来作什么的? 答:hashCode()方法返回给调用者此对象的哈希码(其值由一个hash函数计算得来)。 这个方法一般用在基于hash的集合类中,像HashMap,HashSet和Hashtable。 问: 在类中覆盖equals()的时候,为何要同时覆盖hashCode()? 答: 在覆盖equals()的时候同时覆盖hashCode()能够保证对象的功能兼容于hash集合。 这是一个好习惯,即便这些对象不会被存储在hash集合中。
单例模式(懒汉模式、饿汉模式)、工厂模式
懒汉模式:用到的时候再建立对象,而且只建立一次 咱们通常使用懒汉模式
[示例]
public class Singleton_01 { //1 私有化构造 private Singleton_01(){ } //保存当前对象的变量 private static Singleton_01 s = null; //用于获取对象的方法 public static Singleton_01 getInstance(){ //若是为null说明没有对象,就建立一个 //若是不能为null 说明有对象,就直接返回 if (s == null) { s = new Singleton_01(); } return s; } }
饿汉模式:类加载阶段就初始化对象
[示例]
public class Singleton_02 { //1 私有化构造 private Singleton_02(){ } //保存当前对象的变量 private static Singleton_02 s = new Singleton_02(); //用于获取对象的方法 public static Singleton_02 getInstance(){ return s; } }
异常是Java中提供的一种识别及响应错误状况的一致性机制。有效地异常处理能使程序更加健壮、易于调试。
异常发生的缘由有不少,好比:
1) 用户输入了非法数据 2) 要打开的文件不存在 3) 网络通讯时链接中断 4) JVM内存溢出 5) 这些异常有的是由于用户错误引发,有的是程序错误引发的,还有其它一些是由于物理错误引发的。
1. 概念
系统内部错误,这类错误由系统进行处理,程序自己无需捕获处理。
好比:OOM(内存溢出错误)、VirtualMachineError(虚拟机错误)、StackOverflowError(堆栈溢出错误)等,通常发生这种状况,JVM会选择终止程序。
2. 示例
//堆栈溢出错误 public class TestError { public static void recursionMethod() { recursionMethod();// 无限递归下去 } public static void main(String[] args) { recursionMethod(); } }
报错信息:
Exception in thread “main” java.lang.StackOverflowError
at com.TestError.recursionMethod(TestError.java:5)
at com.TestError.recursionMethod(TestError.java:5)
at com.TestError.recursionMethod(TestError.java:5)
at com.TestError.recursionMethod(TestError.java:5)
at com.TestError.recursionMethod(TestError.java:5)
at com.TestError.recursionMethod(TestError.java:5)
… …
1. 介绍
Exception是全部异常类的父类。分为非RuntimeException和RuntimeException 。
非RuntimeException
指程序编译时须要捕获或处理的异常,如IOException、自定义异常等。属于checked异常。
RuntimeException
指程序编译时不须要捕获或处理的异常,如:NullPointerException等。属于unchecked异常。 通常是由程序员粗心致使的。如空指针异常、数组越界、类型转换异常等。
2. 示例
//空指针异常 public class TestException { private static int[] arr; public static void main(String[] args) { for (int i = 0; i < arr.length; i++) { System.out.println(arr[i]); } } }
报错信息:
Exception in thread “main” java.lang.NullPointerException
at com.TestException.main(TestException.java:7)
3. 经常使用方法
Exception类和其余普通类同样,有本身的属性和方法,为咱们提供异常的相关信息。经常使用的方法有:
方法 | 说明 |
---|---|
public String getMessage() | 返回关于发生的异常的详细信息。这个消息在Throwable类的构造函数中初始化了。 |
public void printStackTrace() | 打印toString()结果和栈层次到System.err,即错误输出流。 |
【示例】
public class TestException { public static void main(String[] args) { Exception exp = new Exception("异常方法演示"); //打印异常信息 System.out.println("exp.getMessage()=" + exp.getMessage()); //跟踪异常栈信息 exp.printStackTrace(); } }
4. 异常捕获与处理
程序在执行时若是发生异常,会自动的生成一个异常类对象,并提交给JAVA运行环境,这个过程称为抛出异常。程序也能够自行抛出异常。
当出JAVA运行环境接收到异常对象时,会寻找能处理这个异常的代码并按程序进行相关处理,这个过程称为捕获异常。
4.1 throws
【语法格式】
修饰符 返回类型 方法名(参数列表) throws 异常类名列表
【示例】
public class TestException { public static void main(String[] args) throws FileNotFoundException{ File file = new File("our.txt"); InputStream input = new FileInputStream(file); } }
【注意】
子类继承父类,并重写父类的方法时,若方法中抛出异常,则要求:子类方法抛出异常只能是父类方法抛出的异常的同类或子类。
4.2 throw
throw的做用是抛出异常,抛出一个异常类的实例化对象。
【语法格式】
throw new XXXException();
【示例】
public class ExceptionDemo { public static void main(String[] args) throws Exception { Exception exp = new Exception("异常方法演示"); throw exp; } }
【总结】
这种抛出异常的方式通常在知足某条件时主动抛出,即知足用户定义的逻辑错误发生时执行。 含有throw语句的方法,或者调用其余类的有异常抛出的方法时,必须在定义方法时,在方法头中增长throws异常类名列表。 使用throws关键字声明的方法表示此方法不处理异常,而交给方法调用处进行处理。
4.3 try…catch
【语法格式】
try{ 有潜在异常抛出的语句组 }catch(异常类名 异常形参){ 异常处理语句组 }catch(异常类名 异常形参){ 异常处理语句组 }catch(异常类名 异常形参){ 异常处理语句组 }catch(异常类名 异常形参){ 异常处理语句组 }finally{ 语句组 }
其中:
1. try用来捕获语句组中的异常 2. catch用来处理异常能够有一个或多个,并且至少要有一个catch语句或finally语句 3. finally中的语句组不管是否有异常都会执行
经常使用捕捉异常方式
1. try…catch try…finally 2. try…catch…finally 3. try…catch1…catch2…finally(体现异常出现的大小顺序)
说明:多重catch处理异常,大异常类在后,小异常类在前。
系统定义的异常主要用来处理系统能够预见的常见运行错误,对于某个应用所特有的运行错误,须要编程人员根据特殊逻辑来建立本身的异常类。
【语法格式】
public class 自定义异常类名 extends Exception{ … }
【问】想要对基本类型数据进行更多的操做,怎么办? 【答】最方便的方式就是将其封装成对象。由于在对象描述中就能够定义更多的属性和行为对该基本数据类型进行操做。 咱们不须要本身去对基本类型进行封装,JDK已经为咱们封装好了。
【概念】
- 装箱就是自动将基本数据类型转换为包装器类型
- 拆箱就是自动将包装器类型转换为基本数据类型
基本类型 | 封装类型 |
---|---|
byte | Byte |
char | Character |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
boolean | Boolean |
以Integer为例
类目 | 表示 | 描述 |
---|---|---|
构造方法 | public Integer(int value)public Integer(String s) | |
经常使用属性 | static int MAX_VALUE static int MIN_VALUE | 返回int类型的最大值返回int类型的最小值 |
经常使用方法 | (基本类型之间转换) byte byteValue()int intValue()… … | Integer类型转byte类型Integer类型转int类型… … |
经常使用方法 | (基本类型、字符串转换) static int parseInt(String s)static Integer valueOf(String s) | 字符串类型转int类型字符串类型转Integer类型 |
【示例】
public class TestInteger { public static void main(String[] args) { // 属性值 System.out.println("Integer类型最大值:" + Integer.MAX_VALUE); System.out.println("Integer类型最小值:" + Integer.MIN_VALUE); // 构造方法 Integer int1 = new Integer(123); Integer int2 = new Integer("123"); System.out.println("构造方法传int参数:" + int1); System.out.println("构造方法传String参数:" + int2); // 类型转换 // 基本类型之间转换 System.out.println("Integer转byte类型:" + int1.byteValue()); System.out.println("Integer转int类型:" + int1.intValue()); // 基本类型与字符串之间转换 System.out.println("字符串123转成int:" + Integer.parseInt("123")); System.out.println("字符串123转成Integer:" + Integer.valueOf("123")); // System.out.println("字符串abc能够转成Integer类型吗?" + Integer.valueOf("abc")); } }
字符串类主要包括String、StringBuilder、StringBuffer。
1. String
String类是经过char数组来保存字符串的。char[]数组是final修饰的,因此String类型的变量值不可变。 String类是final类,也即意味着String类不能被继承,而且它的成员方法都默认为final方法。
类目 | 表示 | 描述 |
---|---|---|
构造方法 | public String()public String(String str) | |
经常使用方法 | equals() | 字符串相等比较,不忽略大小写 |
startsWith() | 判断字符串是否以指定的前缀开始 | |
indexOf() | 取得指定字符在字符串的位置 | |
length() | 取得字符串的长度 | |
substring() | 截取子串 |
【示例】
public static void main(String[] args) { // 不一样构造方法声明String变量 String str1 = "天亮教育"; String str2 = new String("天亮教育"); String str3 = "天亮"; // 长度:length() System.out.print(str1.length() >= str3.length() ? "str1长" : "str3长"); // 判断是否以指定字符开头 if (str1.startsWith(str3)) { // str3第一次出如今str1中的位置 int startIndex = str1.indexOf(str3); // 截取子串 String str1Sub = str1.substring(startIndex, str3.length() - 1); String str2Sub = str2.substring(startIndex, str3.length() - 1); System.out.println("两个字符串是否相等:" + str1Sub.equals(str2Sub)); } } }
2. StringBuilder
既然在Java中已经存在了String类,那为何还须要StringBuilder和StringBuffer类呢?咱们看个例子来分析一下。
public class StringDemo { public static void main(String[] args) { String str = ""; for(int i=0;i<100;i++){ str += "hello"; } } }
分析:
string += “hello”; 至关于将原有的string变量指向的对象内容取出与 “hello”作字符串相加操做 再存进另外一个新的String对象当中,再让string变量指向新生成的对象。浪费时间和空间。 StringBuilder类为可变字符串,解决String在字符变动方面的低效问题,低层依赖字符数组实现。
类目 | 表示 | 描述 |
---|---|---|
构造方法 | StringBuilder()StringBuilder(String s) | |
经常使用方法 | toString() | 返回此序列中数据的字符串表示形式 |
append() | 表示将括号里的某种数据类型的变量插入某一序列中 | |
delete() | 移除此序列的子字符串中的字符 | |
insert() | 表示将括号里的某种数据类型的变量插入某一序列中 | |
reverse() | 将此字符序列用其反转形式取代 | |
subString() | 返回一个新的 String,它包含此序列当前所包含的字符子序列 |
String和StringBuilder对比
• 都是 final 类, 都不容许被继承 • String 长度是不可变的, StringBuilder长度是可变的
3. StringBuffer
StringBuffer类的构造方法和用法与StringBuilder相同,能够认为是线程安全的StringBuilder。
StringBuilder和StringBuffer的对比
StringBuilder速度快,线程不安全的 StringBuffer线程安全的 StringBuffer、StringBuilder 长度是可变的
备注:线程安全的内容后面章节会具体讲解。
1. Math
提供科学计算和基本的数字操做方法
类目 | 表示 | 描述 |
---|---|---|
经常使用方法 | static double abs(数值型 a) | 返回指定数值的绝对值 |
static double ceil(double a) | 返回最小的(最接近负无穷大)double值,大于或等于参数,并等于一个整数 | |
static double floor(double a) | 返回最大的(最接近正无穷大)double值小于或相等于参数,并相等于一个整数 | |
static long max(数值型 a, 数值型 b) | 返回比较参数的较大的值 | |
static long min(数值型 a, 数值型 b) | 返回比较参数的较小的值 | |
static double random() | 返回一个无符号的double值,大于或等于0.0且小于1.0 | |
static double sqrt(double a) | 返回正确舍入的一个double值的正平方根 |
2. DecimalFormat
DecimalFormat类主要的做用是用来格式化数字使用,能够直接按用户指定的方式进行格式化。
类目 | 表示 | 描述 |
---|---|---|
构造方法 | public DecimalFormat() | |
public DecimalFormat(String pattern) | ||
经常使用方法 | public final String format(double number) | 按照指定格式对数值进行格式化 |
符号 | 含义 |
---|---|
0 | 阿拉伯数字 |
# | 阿拉伯数字,若是不存在则显示为空 |
3. Random
Random类专门用于生成一个伪随机数,它有两个构造器。
相对于Math的random()方法而言,Random类提供了更多方法来生成各类伪随机数,它不只能够生成浮点类型的伪随机数,也能够生成整形类型的伪随机数,还能够指数定生成随机数的范围。
Java提供了一系列用于处理日期、时间的类,包括建立日期、时间对象,获取系统当前日期、时间等操做。
1. Date类
类目 | 表示 | 描述 |
---|---|---|
构造方法 | Date() | |
Date(long date) | ||
经常使用方法 | long getTime() | 返回该时间对应的long型整数 |
int compareTo(Date anotherDate) | 比较两个日期的大小 | |
void setTime(long time) | 设置该Date对象的时间 |
2. Calendar类
Date类不方便实现国际化,已经不被推荐使用。因此,引入了Calendar类进行日期和时间处理。
【介绍】
Calendar类是抽象类,因此不能经过构造方法来建立对象。Calendar与Date都是表示日期的工具类,能够自由转换。
类目 | 表示 | 描述 |
---|---|---|
经常使用属性 | YEAR | |
MONTH | ||
WEEK_OF_YEAR | ||
WEEK_OF_MONTH | ||
DATE | ||
DATE_OF_MONTH | ||
经常使用方法 | int get(int field) | 返回指定日历字段的值 |
void set(int y,int mon,int date,int h,int min,int sec) | 设置对象的年月日时分秒 | |
void add(int field,int amount) | 为给定的日历字段添加或减去指定的时间量 |
3. SimpleDateFormat类
SimpleDateFormat是最经常使用的日期处理类,建立对象时须要传入一个日期模板字符串。
类目 | 表示 | 描述 |
---|---|---|
构造方法 | public SimpleDateFormat()public SimpleDateFormat(String pattern) | 按照日期模板格式化 |
经常使用方法 | public final String format(Date date) | 对日期格式化 |
public Date parse(String source) | 把一个字符串解析成Date对象 |
【介绍】
枚举类型是Java 5新增的特性,它是一种新的类型 枚举类型的定义中列举了该类型全部可能值 使用java.lang.Enum类型来定义枚举
【语法格式】
[修饰符] enum 类名{ ... ... }
【意义】
能够替代常量定义,自动实现类型检查,便于维护、编程,减小出错几率 。
介绍
Java集合是使程序可以存储和操纵元素不固定的一组数据。 全部Java集合类都位于java.uti包中。
数组 | 集合 |
---|---|
长度固定 | 长度不固定 |
存听任意类型 | 不能存放基本数据类型,只能存放对象的引用 |
注意:若是集合中存放基本类型,必定要将其 “装箱”成对应的”基本类型包装类”。
2. 层次结构
Java的集合类主要由两个接口派生而出:Collection和Map。Collection和Map是Java结合框架的根接口,这两个接口又包含了一些子接口或实现类。
1. Collection的继承层次结构
2. Map的继承层次结构
3. 总结
由以上两图咱们能够看出Java集合类有清晰的继承关系,有不少子接口和实现类。可是,并非全部子接口或实现类都是最经常使用的。
下面咱们列举出最经常使用的几个子接口和实现类:
Collection ——> List ——> ArrayList类 Collection ——> List ——> LinkedList类 Collection ——> Set ——> HashSet类 Collection ——> Set ——> SortedSet接口 ——> TreeSet类 Map ——> HashMap类 Map ——> SortedMap ——> TreeMap类
1. Collection介绍
Collection接口是List接口和Set接口的父接口,它定义的方法能够用于操做List集合和Set集合。
Collection接口定义的方法
方法 | 描述 |
---|---|
boolean add(Object o) | 该方法用于向集合里添加一个元素,添加成功返回true |
void clear() | 清除集合里的全部元素,将集合长度变为0 |
boolean contains(Object o) | 返回集合里是否包含指定元素 |
boolean containsAll(Collection c) | 返回集合里是否包含集合c里的全部元素 |
int hashCode() | 返回此collection的哈希码值 |
boolean isEmpty() | 返回集合是否为空,当集合长度为0时,返回true |
Iterator iterator() | 返回一个Iterator对象,用于遍历集合里的元素 |
boolean remove(Object o) | 删除集合中指定元素o,当集合中包含了一个或多个元素o时,这些元素将被删除,该方法将返回true |
boolean removeAll(Collection c) | 从集合中删除集合c里包含的全部元素,若是删除了一个或一个以上的元素,返回true |
boolean retainAll(Collection c) | 从集合中删除不在集合c里包含的元素,若是删除了一个或一个以上的元素,返回true |
int size() | 返回集合中的元素个数 |
Object[] toArray() | 该方法把集合转换成一个数组,全部集合元素变成对应的数组元素 |
【示例】
public class Collection_01 { public static void main(String[] args) { //建立集合 Collection c1 = new ArrayList(); //自动装箱为Integer类型,而后向上转型 为Object 类型,发生多态 c1.add(1); c1.add(1); c1.add(1); c1.add(1); c1.add(1.2); c1.add(true); c1.add(new Collection_01()); c1.add(new Object()); System.out.println(c1.size()); System.out.println(c1.isEmpty()); c1.remove(1); System.out.println(c1.size()); //直接遍历集合 for (Object object : c1) { System.out.println(object); } //把集合转换为Object数组,再遍历 Object[] arr = c1.toArray(); for (Object object : arr) { System.out.println(object); } //清空集合 c1.clear(); System.out.println(c1.size()); } }
2. Iterator
【介绍】
Collection接口的iterator()和toArray()方法都用于得到集合中的全部元素,前者返回一个Iterator对象,后者返回一个包含集合中全部元素的数组。
Iterator接口隐藏底层集合中的数据结构,提供遍历各类类型集合的统一接口。
【接口主要方法】
方法 | 描述 |
---|---|
boolean hasNext() | 若是被迭代的集合有下一个元素,则返回true |
Object next() | 返回集合里下一个元素 |
void remove() | 删除集合里上一次next方法返回的元素 |
【示例】
//建立迭代器 Iterator it = c.iterator(); //若是添加或删除数据以后,必定要从新生成迭代器 c.add(2); it = c.iterator(); while (it.hasNext()) { Object o = it.next(); System.out.println(o); } //1 迭代器使用完以后,不会自动复原,须要从新建立才能再次遍历 while (it.hasNext()) { Object o = it.next(); System.out.println(0); }
【for与iterator对比】
Iterator的好处在于能够使用相同方式去遍历集合中元素,而不用考虑集合类的内部实现。 使用Iterator来遍历集合中元素,若是再也不使用List转而使用Set来组织数据,则遍历元素的代码不用作任何修改 使用for来遍历,那全部遍历此集合的算法都得作相应调整,由于List有序,Set无序,结构不一样,他们的访问算法也不同 for循环须要下标
【foreach加强循环】
foreach遍历集合至关于获取迭代器,经过判断是否有下一个元素,执行操做。遍历数组至关于经典的for循环。
优势 | 缺点 |
---|---|
遍历的时候更加简洁不用关心集合下标的问题。减小了出错的几率 | 不能同时遍历多个集合在遍历的时候没法修改和删除集合数据 |
【特色】
List是一个有序集合,既存入集合的顺序和取出的顺序一致 List集合容许添加的元素重复
List不仅仅继承了Collection的方法,还增长了一些新的方法。
方法 | 描述 |
---|---|
void add(int index, Object element) | 将元素element插入到List的index处 |
boolean addAll(int index, Collection c) | 将集合c所包含的全部元素都插入在List集合的index处 |
Object get(int index) | 返回集合index处的元素 |
int indexOf(Object o) | 返回对象o在List集合中出现的位置索引 |
int lastIndexOf(Object o) | 返回对象o在List集合中最后一次出现的位置索引 |
Object remove(int index) | 删除并返回index索引处的元素 |
Object set(int index, Object element) | 将index索引处的元素替换成element对象,返回新元素 |
List subList(int fromIndex, int toIndex) | 返回从索引fromIndex(包含)到索引toIndex(不包含)处全部集合元素组成的子集合 |
【示例】
public class Collection_05_List_01 { @Override public String toString() { return "----------"; } public static void main(String[] args) { List li = new ArrayList(); li.add(1); li.add("张三"); li.add(new Collection_05_List_01()); //[1,张三,-------],由于输出一个list的时候,结构是这样的 [元素1,元素2,...] //会调用集合中每一个元素自身的toString方法 System.out.println(li); //get:获取指定索引对应的元素,等于数组[index] for (int i = 0; i < li.size(); i++) { System.out.println(li.get(i)); } //把元素插入到指定位置,原始位置数据和原位置以后的数据向后移动一位 li.add(1,"你吃了吗?"); for (Object object : li) { System.out.println(object); } //用指定的元素把指定位置上的元素替换 li.set(2, "吃了"); Iterator it = li.iterator(); while (it.hasNext()) { Object object = it.next(); System.out.println(object); } } }
3.1 ArrayList、Vector
【特色对比】
1. ArrayList和Vector都是基于数组实现的,二者用法差很少 2. ArrayList随机查询效率高,随机增删元素效率较低 3. Vector提供了一个Stack子类,模拟“栈”数据结构——”先进后出” 4. ArrayList是线程不安全的,Vector是线程安全的
3.2 LinkedList
【特色】
LinkedList是双向链表实现的 随机查询效率低,随机增删效率高
【LinkedList新增方法】
方法 | 描述 |
---|---|
void addFirst(Object e) | 将指定元素插入该集合的开头 |
void addLast(Object e) | 将指定元素插入该集合结尾 |
boolean offerFirst(Object e) | 将指定元素插入该集合的开头 |
boolean offerLast(Object e) | 将指定元素插入该集合结尾 |
boolean offer(Object e) | 将指定元素插入该集合结尾 |
Object getFirst() | 获取,但不删除集合第第一个元素 |
Object getLast() | 获取,但不删除集合最后一个元素 |
Object peekFirst() | 获取,但不删除该集合第一个元素,若是集合为空,则返回null |
Object peekLast() | 获取,但不删除该集合最后一个元素,若是集合为空,则返回null |
Object pollFirst() | 获取,并删除该集合第一个元素,若是集合为空,则返回null |
Object pollLast() | 获取,并删除该集合最后一个元素,若是集合为空,则返回null |
Object removeFirst() | 获取,并删除该集合的第一个元素 |
Object removeLast() | 获取,并删除该集合的最后一个元素 |
Object pop() | pop出该集合的第一个元素 |
void push(Object e) | 将一个元素push到集合 |
【示例】
public class Collection_07_LinkedList { public static void main(String[] args) { LinkedList li = new LinkedList(); //尾部添加 成功返回true li.add(1); //头部添加 li.push(7); //头部添加 li.addFirst(2); //尾部添加 li.addLast(3); //头部添加,成功返回true li.offerFirst(4); //尾部添加,成功返回true li.offerLast(5); //尾部添加,成功返回true li.offer(6); //上面几个方法,本质调用的就是两个方法,linkLast和linkFirst 因此没有任何区别,主要为了解决你们的命名习惯问题 System.out.println(li); System.out.println("----"); //获取指定下标对应的元素 System.out.println(li.get(2)); //获取首位元素 System.out.println(li.getFirst()); //获取最后一个元素 System.out.println(li.getLast()); //获取首位元素,并删除该元素,若是没有首位元素(就是集合中元素个数为0)返回null System.out.println(li.poll()); //获取首位元素,并删除该元素,若是没有首位元素(就是集合中元素个数为0),报错 // java.util.NoSuchElementException System.out.println(li.pop()); for (Object object : li) { System.out.println(object); } } }
【总结】
List主要有两个实现ArrayList和LinkedList,他们都是有顺序的,也就是放进去是什么顺序,取出来仍是什么顺序 ArrayList——遍历、查询数据比较快,添加和删除数据比较慢(基于可变数组) LinkedList——查询数据比较慢,添加和删除数据比较快(基于链表数据结构) Vector——Vector已经不建议使用,Vector中的方法都是同步的,效率慢,已经被ArrayList取代 Stack——继承Vector实现的栈,栈结构是先进后出,但已被LinkedList取代
【特色】
1. Set是一个无序集合,既存入集合的顺序和取出的顺序不一致 2. Set集合中元素不重复
【经常使用方法】
方法 | 描述 |
---|---|
boolean add(E e) | 若是此set中还没有包含指定元素,则添加指定元素 |
boolean isEmpty() | 若是此set不包含任何元素,则返回true |
boolean contains(Object o) | 若是此set包含指定元素,则返回 true |
boolean remove(Object o) | 若是指定元素存在于此set中,则将其移除 |
int size() | 返回此set中的元素的数量 |
void clear() | 今后set中移除全部元素 |
4.1 HashSet
HashSet是咱们学习的重点,哈希原理咱们在下面讲HashMap时,细讲。
4.2 TreeSet
TreeSet底层由TreeMap实现。可排序,默认天然升序。
【示例】
public class Collection_09_SortedSet_01 { public static void main(String[] args) throws ParseException { //TreeSet能够自动排序 SortedSet ss = new TreeSet(); ss.add(1); ss.add(22); ss.add(2); System.out.println(ss); //TreeSet也是自动排序 ss = new TreeSet(); ss.add("abc"); ss.add("abd"); ss.add("ba"); ss.add("ac"); System.out.println(ss); ss = new TreeSet(); String st1 = "2008-08-08"; String st2 = "2008-08-07"; String st3 = "2008-09-01"; String st4 = "2007-08-08"; SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); Date d1 = sdf.parse(st1); Date d2 = sdf.parse(st2); Date d3 = sdf.parse(st3); Date d4 = sdf.parse(st4); ss.add(d1); ss.add(d2); ss.add(d3); ss.add(d4); for (Object object : ss) { Date date = (Date) object; System.out.println(sdf.format(date)); } } }
【总结】
HashSet底层由HashMap实现 TreeSet底层由TreeMap实现
5.1 Collections工具类
Collections是一个包装工具类。它包含有各类有关集合操做的静态多态方法,此类不能实例化,服务于Java的Collection接口。
【经常使用方法】
sort、reverse、fill、copy、max、min、swap等
【Sort排序】
public static <T extends Comparable<? super T>> void sort(List
list)
1. 根据元素的天然顺序 对指定列表按升序进行排序。列表中的全部元素都必须实现 Comparable 接口。 2. 此外,列表中的全部元素都必须是可相互比较的(也就是说,对于列表中的任何 e1 和 e2 元素,e1.compareTo(e2) 不得抛出 ClassCastException)。
【示例】
public class Collection_11_SortedSet_03 { public static void main(String[] args) { // SortedSet products = new TreeSet(new ProductComparator()); @SuppressWarnings("unchecked") SortedSet products = new TreeSet(new Comparator() { @Override public int compare(Object o1, Object o2) { double price1 = ((Product1)o1).price; double price2 = ((Product1)o2).price; if (price1 == price2) { return 0; }else if (price1 > price2) { return 1; }else{ return -1; } } }); Product1 p1 = new Product1(1.5); Product1 p2 = new Product1(2.2); Product1 p3 = new Product1(1.5); products.add(p1); products.add(p2); products.add(p3); System.out.println(products); } } class Product1 { double price; public Product1(double price) { super(); this.price = price; } @Override public String toString() { return "Product1 [price=" + price + "]"; } }
5.2 Comparable、Comparator比较器
对象排序,就是比较大小,要实现Comparable或Comparator比较器之一,才有资格作比较排序。
【介绍】
1. Comparable:与对象紧相关的比较器,能够称“第一方比较器”。 2. Comparator:此为与具体类无关的第三方比较器。
【示例】
public class Collection_12_SortList { @SuppressWarnings("unchecked") public static void main(String[] args) { List list = new ArrayList(); list.add(new User1(18)); list.add(new User1(14)); list.add(new User1(10)); Collections.sort(list,new Comparator() { @Override public int compare(Object o1, Object o2) { return ((User1)o1).age - ((User1)o2).age ; } }); System.out.println(list); } } class User1{ int age; public User1(int age) { super(); this.age = age; } @Override public String toString() { return "User1 [age=" + age + "]"; } }
Map用于保存具备映射关系的数据,所以Map集合里保存两组值。
- 一组值用于保存key,一组值用于保存value
- key~value之间存在单向一对一关系,经过指定key能够找到惟一的value值
- key和value均可以是任何引用类型对象
- 容许存在value为null,可是只容许存在一个key为null
【经常使用方法】
方法 | 描述 |
---|---|
V put(K key, V value) | 将指定的值与此映射中的指定键关联 |
boolean containsKey(Object key) | 若是此映射包含指定键的映射关系,则返回true |
boolean containsValue(Object value) | 若是此映射将一个或多个键映射到指定值,则返回true |
boolean isEmpty() | 若是此映射未包含键-值映射关系,则返回true |
V get(Object key) | 返回指定键所映射的值,若是此映射不包含该键的映射关系,则返回null |
Set keySet() | 返回此映射中包含的键的set集合 |
Collection values() | 返回此映射中包含的值的Collection集合 |
Set<Map.Entry<K,V>> entrySet() | 返回此映射中包含的映射关系的set集合 |
boolean equals(Object o) | 返回指定的对象与此映射是否相等 |
int hashCode() | 返回此映射的哈希码值 |
V remove(Object key) | 若是存在一个键的映射关系,则将其今后映射中移除 |
void clear() | 今后映射中移除映射关系 |
int size() | 返回此映射中的键-值关系数 |
【示例】
public class Collection_14_Map_01 { public static void main(String[] args) { Map map = new HashMap(); map.put("A", "one"); map.put("B", "two"); map.put("C", "three"); map.put(1003, "rose");//Integer map.put('A', "1000"); map.put("65", "1000"); map.put("'A'", "3000"); map.put("A", "2000");//value覆盖 //能够都是null,但没什么意义 //key只能有一个为null,由于惟一,value能够有不少null map.put(null, null); //8个 System.out.println(map.size()); //false System.out.println(map.containsKey("1003")); //true System.out.println(map.containsValue("2000")); //2000 根据key获取value值 System.out.println(map.get("A")); System.out.println("--------"); //把map中的key取出来,造成set Set s = map.keySet(); for (Object object : s) { System.out.println(object + ":" + map.get(object)); } System.out.println("-----------"); //把map中的全部entry取出,造成set //而且entry覆写了toString方法,会以key=value的形式展现 Set set = map.entrySet(); for (Object object : set) { System.out.println(object); } System.out.println("--------"); System.out.println(1); System.out.println("1"); System.out.println('1'); } }
1. HashMap类
【特色】
key无序不可重复 底层是哈希表
【哈希表实现原理】
HashMap其实是一个"链表的数组"的数据结构,每一个元素存放链表头结点的数组,即数组和链表的结合体。 当咱们往HashMap中put元素的时候,先根据key的hashCode从新计算hash值,根据hash值获得这个元素在数组中的位置(即下标),若是数组该位置上已经存放有其余元素了,那么在这个位置上的元素将以链表的形式存放,新加入的放在链头,最早加入的放在链尾。若是数组该位置上没有元素,就直接将该元素放到此数组中的该位置上。 只有相同的hash值的两个值才会被放到数组中的同一个位置上造成链表。 若是这两个Entry的key经过equals比较返回true,新添加Entry的value将覆盖集合中原有Entry的value,但key不会覆盖。
【总结】
HashMap中key的hashCode值决定了<k,v>键值对组成的entry在哈希表中的存放位置。 HashMap中key经过equals()比较,肯定是覆盖key对应的value值仍是在链表中添加新的entry。 综合前两条,须要重写hashCode()和equals()方法。
【示例】
public class Practice_05 { public static void main(String[] args) { List list = new ArrayList(); Stu s1 = new Stu(1, "张三", 10, 001); Stu s2 = new Stu(1, "张三", 10, 002); Stu s3 = new Stu(2, "王五", 14, 001); Stu s4 = new Stu(3, "小李", 12, 002); Stu s5 = new Stu(5, "小马", 11, 001); list.add(s1); list.add(s2); list.add(s3); list.add(s4); list.add(s5); Set set = new HashSet(); set.add(s1); set.add(s2); set.add(s3); set.add(s4); set.add(s5); //学号重复的人有几个,就是同时学两门课的人有几个 int a = list.size() - set.size(); System.out.println(a); for (int i = 0; i < list.size(); i++) { for (int j = 0; j < list.size()-1-i; j++) { if ((Stu)list.get(i) == (Stu)list.get(j)) { String s = ((Stu)list.get(j)).name; System.out.println(s); } } } } } class Stu { int id; String name; int age; int stuId; public Stu(int id, String name, int age, int stuId) { super(); this.id = id; this.name = name; this.age = age; this.stuId = stuId; } @Override public String toString() { return "Stu [id=" + id + ", name=" + name + ", age=" + age + ", stuId=" + stuId + "]"; } @Override public boolean equals(Object obj) { if (this == obj) { return true; }else if (obj instanceof Stu) { Stu s = (Stu) obj; if (this.id == s.id) { return true; } } return false; } public int hashCode(){ return 1; } }
【HashSet】
特色
1. HashSet底层由HashMap实现 2. 无序不可重复
【示例】
public class Collection_13_Set_01 { public static void main(String[] args) { Set s = new HashSet(); s.add(1); s.add(1); s.add(2);//id = 1; System.out.println(s); HashSet hs = new HashSet(); Employee e1 = new Employee("1000", "obama"); Employee e2 = new Employee("4000", "obalv"); Employee e3 = new Employee("2000", "张三"); Employee e4 = new Employee("3000", "张三"); Employee e5 = new Employee("1000", "张三"); Employee e6 = new Employee("5000", "李四"); // System.out.println(e1.hashCode()); // System.out.println(e2.hashCode()); // System.out.println(e3.hashCode()); // System.out.println(e4.hashCode()); // System.out.println(e5.hashCode()); // System.out.println(e6.hashCode()); hs.add(e1); //若是重复就不添加 hs.add(e2); hs.add(e3); hs.add(e4); hs.add(e5); hs.add(e6); System.out.println(hs.size()); for (Object object : hs) { System.err.println(object); } } } class Employee{ String no; String name; public Employee(String no, String name) { super(); this.no = no; this.name = name; } @Override public String toString() { return "Employee [no=" + no + ", name=" + name + "]"; } @Override public boolean equals(Object obj) { System.out.println("equals 执行了"); if (this == obj) { return true; } if (obj instanceof Employee) { Employee e = (Employee) obj; if (no.equals(e.no)) { return true; } } return false; } static int i = 16; @Override public int hashCode() { System.out.println("hashCode执行了"); return no.hashCode(); } }
2. TreeMap
TreeMap是SortedMap接口的实现类,能够根据Key进行排序,HashMap没有这个功能。
【特色】
1. 底层由可排序二叉树实现 2. 不指定比较器默认按照key天然升序,指定比较器按照比较器排序
【示例】
public class Collection_15_SortedMap_01 { public static void main(String[] args) { @SuppressWarnings("unchecked") SortedMap products = new TreeMap(new Comparator() { @Override public int compare(Object o1, Object o2) { double price1 = ((Product)o1).price; double price2 = ((Product)o2).price; if (price1 == price2) { return 0; }else if (price1 < price2) { return -1; }else { return 1; } } }); Product p1 = new Product("water", 1.0); Product p2 = new Product("苹果", 3.0); Product p3 = new Product("香蕉", 2.0); Product p4 = new Product("梨", 1.5); //value 能够设置为已购买数量 products.put(p1, 4.0); products.put(p2, 2.0); products.put(p3, 1.0); products.put(p4, 4.0); //获取全部key,以Set形式返回 Set keys = products.keySet(); for (Object key : keys) { Product p = (Product) key; double value = (double)products.get(key); System.out.println(p+"------>"+value+"kg 总价="+(value*p.price)); } } } class Product{ String name; double price; public Product(String name, double price) { super(); this.name = name; this.price = price; } @Override public String toString() { return "Product [name=" + name + ", price=" + price + "]"; } }
【总结】
TreeMap须要key实现Comparable接口,排序主要看compareTo()方法。
泛型是指所操做的数据类型被指定为一个参数,在用到的时候再指定具体的类型。这种参数类型能够用在类、接口和方法的建立中,分别称为泛型类、泛型接口和泛型方法。
【示例】
class ProjectPool<T>{ private List<T> list = new ArrayList<T>(); public void add(T t){ list.add(t); } public int size(){ return list.size(); } }
List<Student> stuList = new ArrayList<Student>();
【总结】
1. 泛型能更早的发现错误,如类型转换错误 2. 使用泛型,那么在编译期将会发现不少以前要在运行期发现的问题 3. 代码量每每会少一些、运维成本减小 4. 抽象层次上更加面向对象
1. 概念
流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输特性将流抽象为各类类,方便更直观的进行数据操做。
2. 分类
按处理数据类型的不一样,分为字节流和字符流
按数据流向的不一样,分为输入流和输出流。(入和出是相对于内存来说的)
按功能不一样,分为节点流和处理流 节点流:直接操做数据源 处理流:对其余流进行处理
3. 抽象类定义
3.1 InputStream
InputStream的继承关系:蓝色为节点流,黑色为处理流(小红旗重点)
【经常使用方法】
方法 | 描述 |
---|---|
void close() | 关闭此输入流并释放与该流关联的全部系统资源 |
abstract int read() | 从输入流读取下一个数据字节 |
int read(byte[] b) | 从输入流中读取必定数量的字节并将其存储在缓冲区数组b中 |
int read(byte[] b, int off, int len) | 将输入流中最多len个数据字节读入字节数组 |
3.2 OutputStream
OutputStream的继承关系:蓝色为节点流,黑色为处理流(小红旗重点)
【经常使用方法】
方法 | 描述 |
---|---|
void close() | 关闭此输出流并释放与此流有关的全部系统资源 |
void flush() | 刷新此输出流并强制写出全部缓冲的输出字节 |
void write(byte[] b) | 将 b.length个字节从指定的字节数组写入此输出流 |
void write(byte[] b, int off, int len) | 将指定字节数组中从偏移量 off 开始的 len 个字节写入此输出流 |
abstract void write(int b) | 将指定的字节写入此输出流 |
3.3 Reader
Reader的继承关系:蓝色为节点流,黑色为处理流(小红旗重点)
【经常使用方法】
方法 | 描述 |
---|---|
abstract void close() | 关闭该流 |
int read() | 读取单个字符 |
int read(char[] cbuf) | 将字符读入数组 |
abstract int read(char[] cbuf, int off, int len) | 将字符读入数组的某一部分 |
3.4 Writer
Writer的继承关系:蓝色为节点流,黑色为处理流(小红旗重点 )
【经常使用方法】
方法 | 描述 |
---|---|
void write(int c) | 写入单个字符 |
void write(char[] cbuf) | 写入字符数组 |
abstract void write(char[] cbuf, int off, int len) | 写入字符数组的某一部分 |
void write(String str) | 写入字符串 |
void write(String str, int off, int len) | 写入字符串的某一部分 |
Writer append(char c) | 将指定字符添加到此writer |
abstract void flush() | 刷新该流的缓冲 |
abstract void close() | 关闭此流,但要先刷新它 |
1. 经常使用方法
还有一个重要方法: createNewFile() : 真正生成磁盘中的文件
2. 建立文件、删除文件
public class TestFileOperator { public static void main(String[] args) throws Exception { File txtFile = new File("auto_create.txt"); if (!txtFile.exists()) { txtFile.createNewFile(); } else { System.out.println("file existed"); System.out.println("txtFile.delete()=" + txtFile.delete()); } } }
分类 | 字节流 | 字符流 |
---|---|---|
文件输入流 | FileInputStream | FileReader |
文件输出流 | FileOutputStream | FileWriter |
分类 | 字节流 | 字符流 |
---|---|---|
文件输入流 | BufferedInputStream | BufferedReader |
文件输出流 | BufferedOutputStream | BufferedWriter |
【特色】
主要是为了提升效率而存在的,减小物理读取次数 提供readLine()、newLine()这样的便捷的方法(针对缓冲字符流) 在读取和写入时,会有缓存部分,调用flush为刷新缓存,将内存数据写入到磁盘
输入流 | 输出流 |
---|---|
InputStreamReader | OutputStreamWriter |
【特色】
转换流是指将字节流向字符流的转换,主要有InputStreamReader和OutputStreamWriter InputStreamReader主要是将字节流输入流转换成字符输入流 OutputStreamWriter主要是将字节流输出流转换成字符输出流
1. InputStreamReader
分类 | 方法 | 描述 |
---|---|---|
构造方法 | InputStreamReader(InputStream in) | 用默认字符集的该对象 |
InputStreamReader(InputStream in,Charset cs) | 建立使用给定字符集的该对象 | |
InputStreamReader(InputStream in,CharsetDecoder dec) | 建立使用给定字符集解码器的该对象 | |
InputStreamReader(InputStream in,String charsetName) | 建立使用指定字符集该对象 | |
经常使用方法 | void close() | 关闭该流并释放与之关联的全部资源 |
String getEncoding() | 返回此流使用的字符编码的名称 | |
int read() | 读取单个字符 | |
int read(char[] cbuf, int offset, int length) | 将字符读入数组中的某一部分 | |
boolean ready() | 判断此流是否已经准备好用于读取 |
2. OutputStreamWriter
参考InputStreamReader
【特色】
打印流是输出最方便的类 包含字节打印流PrintStream,字符打印流PrintWriter PrintStream是OutputStream的子类,把一个输出流的实例传递到打印流以后,能够更加方便地输出内容,至关于把输出流从新包装一下 PrintStream类的print()方法被重载不少次print(int i)、print(boolean b)、print(char c)
【标准输入/输出】
Java的标准输入/输出分别经过System.in和System.out来表明,在默认的状况下分别表明键盘和显示器,当程序经过System.in来得到输入时,其实是经过键盘得到输入。当程序经过System.out执行输出时,程序老是输出到屏幕。
在System类中提供了三个重定向标准输入/输出的方法
static void setErr(PrintStream err) 重定向“标准”错误输出流 static void setIn(InputStream in) 重定向“标准”输入流 static void setOut(PrintStream out)重定向“标准”输出流
【示例】
public class IO_19_Copy_03 { static String oldFilePath = "D:\\课件"; public static void main(String[] args) { File file = new File(oldFilePath); long startTime = System.currentTimeMillis(); checkMenu(file); long endTime = System.currentTimeMillis(); System.out.println(endTime - startTime); } public static void checkMenu(File file) { // 若是 是文件 就终止 if (file.isFile()) { // 文件全路径 // D:\\14期\\课件\\06.22_JavaSE基础之数据类型和变量/笔记.doc String filePath = file.getAbsolutePath(); // E:\\14期\\课件\\06.22_JavaSE基础之数据类型和变量/笔记.doc String newFilePath = "E" + filePath.substring(1); // E:\\14期\\课件\\06.22_JavaSE基础之数据类型和变量/笔记.doc 文件对象 File newFile = new File(newFilePath); // 输出流只能建立文件,不会建立目录,因此 须要判断目录是否存在 // getParentFile 上级文件对象 // E:\\14期\\课件\\06.22_JavaSE基础之数据类型和变量 文件对象 File paraentFile = newFile.getParentFile(); // 判断该路径是否存在,没有就建立 if (!paraentFile.exists()) { // 建立目录 paraentFile.mkdirs(); } // 到这里说明确定有目录了,就进行复制操做便可 try (FileInputStream fis = new FileInputStream(filePath); FileOutputStream fos = new FileOutputStream(newFilePath); BufferedInputStream bis = new BufferedInputStream(fis); BufferedOutputStream bos = new BufferedOutputStream(fos);) { byte[] bytes = new byte[102400]; int tmp = 0; while ((tmp = bis.read(bytes)) != -1) { bos.write(bytes, 0, tmp); } bos.flush(); } catch (Exception e) { e.printStackTrace(); } return; } // 能到这里 说明是目录 File[] files = file.listFiles(); for (File subFile : files) { checkMenu(subFile); } } }
输入流 | 输出流 |
---|---|
ObejctInputStream | ObejctOutputStream |
【概念】
1. 对象流,即为以Java对象为传输主体的IO过程。Java对象必需要被序列化后方可进行传输。 2. 所谓的对象的序列化就是将对象转换成二进制数据流的一种实现手段,经过将对象序列化,能够方便的实现对象的传输及保存。 3. 要想实现对象的序列化须要实现Serializable接口,可是Serializable接口中没有定义任何的方法,仅仅被用做一种标记, 4. 以被编译器做特殊处理。 5. 在Java中提供了ObejctInputStream 和ObjectOutputStream这两个类用于序列化对象的操做。 6. 对象的序列化的实现方便了对象间的克隆,使得复制品实体的变化不会引发原对象实体的变化。
计算机网络协议
网络协议的目的是为了在计算机物理链接以后进行交互的
目前,成熟的协议有2大类
OSI/ISO - 学术研究,教学用 - 学术上的标准 分为 : 物理层,数据链路层,网络层,传输层,会话层,表示层,应用层 TCP/IP - 实际使用 - 实际上的标准 分为 : 网络接口层,网际层,传输层,应用层 它们都是一整套协议族,并非单个或者几个协议组成的 它们之间是一个有机的总体
计算机网络
分层思想 - 分工负责,各司其职,更清晰地处理相关问题
网络协议,整个体系,就是分层思想的体现咱们使用TCP/IP协议为例进行讲解,不作深刻研究
TCP/IP协议的分层
应用层,传输层,网络层,网络接口层。
应用层。实际上本层的内容并非“应用”软件的“应用” 应用软件要想正常工做,是要基于应用层的协议的
HTTP/HTTPS(http://www.baiu.com)浏览互联网WWW服务(Web服务)
FTP(ftp://ftp.server.com)用于共享文件,如今不多使用,可能某些机构、大学内部会有这些服务器 SMTP发邮件的
传输层 传输层的做用是向应用层提供服务的 应用层那些协议要想正常工做,是要基于传输层协议的
TCP。面向链接,保证数据传输过程当中的完整,有序,丢包重传。 性能其实有些低的,但这是数据准确传输必须付出的代价
UDP。无链接,它只管闷头发数据,不保证数据的准确性(完整,有序,无重传机制) 由于不用保证数据准确传输,因此它快
QQ的有些功能就会使用UDP(固然它也使用TCP) 咱们聊天的时候,有些文字就打了个红叹号,没发送出去,这就是使用UDP的功能
Java对网络编程的支持,选择了传输层的2个协议,以TCP/UDP为基础,构建了本身的网络类继承体系。 Java的网络编程与异常、IO流、多线程部分的知识联系紧密。 网络编程的基础在于Socket编程,而Socket编程在初学阶段重点掌握TCP Socket便可。
TCP Socket编程分为服务端编程(ServerSocket类)与客户端编程(Socket类)。
咱们能够使用telnet命令链接到服务器。 如telnet 127.0.0.1 8888 也能够使用Java Socket类编程实现
ServerSocket类
实现一个简单的服务器
//建立一个工做在端口8888的服务器对象 ServerSocket ss = new ServerSocket(8888); //开启监听,调用下面的方法会使程序阻塞,一直到有客户端来链接本服务器的8888端口(能够经过telnet命令或者Socket客户端编程实现) Socket socket = ss.accept(); //一旦有客户端链接,则返回对应的客户端对象socket 而后咱们能够经过socket获取客户端的输入流与输出流,若是咱们处理的是文本数据(绝大部分状况都是处理文本数据)再使用字节字符转换流进行包装转换。注意字符集。 向客户端发送信息使用: OutputStreamWriter osw = new OutputStreamWriter(socket.getOutputStream(), "utf-8"); BufferedWriter bw = new BufferedWriter(osw);//PrintWriter与BufferedWriter二选一 PrintWriter out = new PrintWriter(osw);//PrintWriter与BufferedWriter二选一 可是PrintWriter能够解决不一样系统间换行符的兼容性问题,并且语法上更接近System.out.println(),因此建议使用这个类。 接收客户端信息使用: InputStreamReader isr = new InputStreamReader(socket.getInputStream(), "utf-8"); BufferedReader br = new BufferedReader(isr);
注意,操做完成后,必定要关闭资源(各类IO流、各类网络链接等)
Socket类
实现一个简单的客户端
//建立一个链接指定IP/域名及端口号的服务端链接对象 Socket socket = new Socket("127.0.0.1", 8888); 以后的操做可类比ServerSocket中对socket的使用。 只不过,服务端socket.getOutputStream()的内容就是客户端的socket.getInputStream(); 服务端socket.getInputStream()的内容就是客户端的socket.getOutputStream() 网络上的两个程序经过一个双向的通讯链接实现数据的交换,这个链接的一端称为一个socket,又称”套接字”。 应用程序一般经过”套接字”向网络发出请求或者应答网络请求。本质是编程接口(API),对TCP/IP的封装, TCP/IP也要提供可供程序员作网络开发所用的接口,即为Socket编程接口。
2. TCP Socket模型
TCP编程的服务器端通常步骤是:
一、建立一个socket,用函数socket(); 二、设置socket属性,用函数setsockopt(); * 可选 三、绑定IP地址、端口等信息到socket上,用函数bind(); 四、开启监听,用函数listen(); 五、接收客户端上来的链接,用函数accept(); 六、收发数据,用函数send()和recv(),或者read()和write(); 七、关闭网络链接; 八、关闭监听;
TCP编程的客户端通常步骤是:
一、建立一个socket,用函数socket(); 二、设置socket属性,用函数setsockopt();* 可选 三、绑定IP地址、端口等信息到socket上,用函数bind();* 可选 四、设置要链接的对方的IP地址和端口等属性; 五、链接服务器,用函数connect(); 六、收发数据,用函数send()和recv(),或者read()和write(); 七、关闭网络链接;
【示例】
public class TestTCPServer01 { public static void main(String[] args) throws Exception { // 一、建立一个服务器端Socket,即ServerSocket,指定绑定的端口,并监听此端口 ServerSocket ss = new ServerSocket(8888); while (true) { // 二、调用accept()方法开始监听,等待客户端的链接 Socket socket = ss.accept(); System.out.println("client" + " connect!"); // 三、获取输入流,并读取客户端信息 InputStream is = socket.getInputStream(); InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr); String info = null; while ((info = br.readLine()) != null) { System.out.println("Hello,i'm server,client say:" + info); } br.close(); } } }
public class TestTCPClient01 { public static void main(String[] args) throws Exception { // 一、建立客户端Socket,指定服务器地址和端口 Socket s = new Socket("127.0.0.1", 8888); // 二、获取输出流,向服务器端发送信息 OutputStream os = s.getOutputStream(); // 将输出流包装成打印流 PrintWriter pw = new PrintWriter(os); pw.write("hello,i'm 天亮!"); pw.flush(); pw.close(); } }
3. UDP Socket模型
UDP编程的服务器端通常步骤是:
一、建立一个socket,用函数socket(); 二、设置socket属性,用函数setsockopt();* 可选 三、绑定IP地址、端口等信息到socket上,用函数bind(); 四、循环接收数据,用函数recvfrom(); 五、关闭网络链接;
UDP编程的客户端通常步骤是:
1、建立一个socket,用函数socket(); 2、设置socket属性,用函数setsockopt();* 可选 3、绑定IP地址、端口等信息到socket上,用函数bind();* 可选 4、设置对方的IP地址和端口等属性; 5、发送数据,用函数sendto(); 6、关闭网络链接;
【示例】
public class TestUDPServer01 { public static void main(String args[]) throws Exception { //建立一个socket DatagramSocket ds = new DatagramSocket(7777); //建立一个数据包 byte buf[] = new byte[1024]; DatagramPacket dp = new DatagramPacket(buf, buf.length); //阻塞等待接收客户端发送的数据包 ds.receive(dp); //数据包中携带的数据在数据包的buf字节数组中,将其转换成字符串 String para = new String(buf, "utf-8"); //打印传递的数据 System.out.println("client print=" + para); } }
public class TestUDPClient01 { public static void main(String args[]) throws Exception { // 建立socket对象 DatagramSocket ds = new DatagramSocket(); // 建立指定端口的ip地址 InetSocketAddress inetSocketAddress = new InetSocketAddress("127.0.0.1", 7777); // 把要发送的数据转换成字节数组形式 String sendStr = "i'm 天亮 Thanks for your coming! Come on!"; byte[] buf = sendStr.getBytes("utf-8"); // 建立数据包,封装字节数组数据和目标ip地址 DatagramPacket dp = new DatagramPacket(buf, buf.length, inetSocketAddress); // 发送数据包 ds.send(dp); // 关闭socket ds.close(); System.out.println("send done!"); } }
1. 进程介绍
进程是一个具备必定独立功能的程序关于某个数据集合的一次运行活动。它是操做系统动态执行的基本单元。在操做系统中每启动一个应用程序就会启动一个进程与之相对应。不一样进程之间的内存是独立的,不共享内存。
多进程引入的优势
单个进程独占高速CPU形成CPU空闲时间太多、使用率低。引入多进程则在不一样进程之间并发共享高速CPU,使CPU空闲时间减小,提升CPU使用效率。
2. 线程介绍
线程也称轻量级进程,是程序执行的最小单元。一个进程能够启动多个线程。不一样线程堆内存和方法区内存共享,栈内存独立,一个线程一个栈。
多线程引入的优势
提升进程的执行效率
【思考】
程序中main方法结束,程序就结束了吗? 答:main方法结束程序不必定结束了。main方法结束主线程结束。有可能其余的分支线程还在运行。 分支线程和主线程没有主次高低之分,只不过度支线程是由主线程分发的。
3. 进程与线程的区别
进程有独立的代码和数据空间,进程间切换成本开销大。 同一进程的多个线程间共享进程代码和数据空间,仅保留独立的线程栈、程序计数器,切换成本小。 多进程是操做系统中可见的并行运行的多个独立任务。 多线程是同一进程内不一样的多个并行执行程序。
1. 定义
1.1定义线程有两种方式
继承Thread类 实现Runnable接口(因Java单继承,推荐使用实现接口的方式)
1.2语法格式
继承Thread类
// 线程入口方法
@Override public void run() { } }
实现Runnable接口
// 线程入口方法
@Override public void run() { } }
2. 建立和启动
线程启动是经过调用线程类的start()方法,使线程进入就绪状态。CPU时间片到来,则线程真正执行run方法。
【示例】
继承Thread类
//初始化线程对象 Thread t = new PrintThread("打印线程"); //正式启动线程 t.start();
实现Runnable接口
//初始化一个Runnable接口实现类的对象 PrintRunnable pr = new PrintRunnable(); //pt自己没有线程开启的能力,须要依附到Thread中才能开启线程 Thread pt = new Thread(pr, "打印线程"); // 开启线程执行 pt.start();
3. 生命周期
线程的生命周期存在五个状态:新建、就绪、运行、阻塞、死亡
新建:采用new语句建立完成 就绪:执行start后 运行:占用CPU时间 阻塞:执行了wait语句、执行了sleep语句和等待某个对象锁,等待输入的场合 终止:执行完run()方法
线程控制,即经过API控制线程状态之间的转换。
1. 优雅的结束
API提供了线程结束的方法:stop()方法。可是,该方法使用的过程当中常常出现问题,会形成程序关闭延迟甚至死锁。
因此想要优雅的结束,能够经过设置标志位,来控制线程是否继续运行。
所谓同步,就是在发出一个功能调用时,在没有获得结果以前,该调用就不返回,同时其它线程也不能调用这个方法。
1. 线程同步的必要性
保证多线程安全访问竞争资源。 为了防止多个线程访问一个数据对象时,对数据形成的破坏。
2. 线程同步原理
上例能够看到咱们在实现线程同步的时候,使用了synchronized关键字。该关键字修饰在方法上至关于对该方法加了锁。一个线程访问方法的时候须要先得到锁,而后才能执行该方法。此时,若是其余线程来了,发现锁已经被占用,则在方法调用处等待,直到锁被释放,再去竞争锁。得到锁,则执行该方法,不然,继续等待。
2.1线程锁
每一个Java对象都有一个内置锁,有且只有一个。 当程序执行到非静态的synchronized同步方法时,(若是锁没被其余线程占用)自动得到该方法所属对象的锁。 不仅是能够修饰在方法上同步方法,也能够对代码块加锁。 程序执行的时候,退出同步块或同步方法则释放锁。
【注意】
没必要同步类中全部的方法,根据须要进行同步。 线程sleep睡眠时,它所持的锁不会释放。 线程能够得到多个锁。 同步损害并发性,应该尽量缩小同步范围。
Lock和synchronized均是为了解决线程同步问题 ,Lock相对于synchronized的功能更多、使用更灵活、更面向对象。
【使用】
private Lock lock = new ReentrantLock(); public void take(){ lock.lock(); //同步部分 lock.unlock(); }
1.1 介绍
Lambda表达式是一种没有名字的函数,也可称为闭包,是Java 8 发布的最重要新特性。
本质上是一段匿名内部类,也能够是一段能够传递的代码。 还有叫箭头函数的…
闭包
闭包就是可以读取其余函数内部变量的函数,好比在java中,方法内部的局部变量只能在方法内部使用,因此闭包能够理解为定义在一个函数内部的函数
闭包的本质就是将函数内部和函数外部连接起来的桥梁
1.2 特色
容许把函数做为一个方法的参数(函数做为参数传递进方法中)。 使用 Lambda 表达式能够使代码变的更加简洁紧凑。
1.3 应用场景
列表迭代 Map映射 Reduce聚合 代替一个不想命名的函数或是类,该函数或类每每并不复杂。 想尽可能缩短代码量的各个场景都可以
1.4 代码实现
1.4.1 具体语法
一、(parameters) -> expression 二、(parameters) ->{ statements; }
1.4.2 语法特色
可选类型声明:不须要声明参数类型,编译器能够统一识别参数值。 可选的参数圆括号:一个参数无需定义圆括号,但多个参数须要定义圆括号。 可选的大括号:若是主体包含了一个语句,就不须要使用大括号。 可选的返回关键字:若是主体只有一个表达式返回值则编译器会自动返回值,大括号须要指定明表达式返回了一个数值 若是只有一条语句,而且是返回值语句,就能够不写return 不写 {} 若是写上{} 就必须写return 和 ; 若是有 多条语句,必须写{} return 和 ; 也必须写
案例说明-简单
// 1. 不须要参数,返回值为 5 () -> 5
// 2. 接收一个参数(数字类型),返回其2倍的值 x -> 2*x
// 3. 接受2个参数(数字),并返回他们的差值 (x, y) -> x – y
// 4. 接收2个int型整数,返回他们的和 (int x, int y) -> x + y
// 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void) (String s) ->
System.out.print(s)
1.4.3 集合遍历
public static void main(String[] args) { String[] arr = { "one", "two", "three" }; List<String> list = Arrays.asList(arr); // jdk1.7-老版写法 for (String ele : list) { System.out.println(ele); } System.out.println("---"); // jdk1.8-新版写法 list.forEach(x -> { System.out.println(x); }); // 就相似于这种写法,至关于本身建立了一个方法,而后遍历调用这个方法 // 把 集合中每一个元素做为参数传递进去,并打印参数 for (String string : list) { m1(string); } } public static void m1(String x) { System.out.println(x); }
1.4.4 集合排序
public static void main(String[] args) { Integer[] arr = { 9, 8, 10, 1, 3, 5 }; // 把数组转换为list List<Integer> list = Arrays.asList(arr); // jdk1.7-旧版写法,使用比较器进行排序 list.sort(new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return o1 - o2; } }); System.out.println(list); // jdk1.8-新版写法 // 把数组转换为list list = Arrays.asList(arr); list.sort((x, y) -> x - y); System.out.println(list); }
2.1 介绍
英文称为Functional Interface
其本质是一个有且仅有一个抽象方法,可是能够有多个非抽象方法的接口。
核心目标是为了给Lambda表达式的使用提供更好的支持,进一步达到函数式编程的目标,可经过运用函数式编程极大地提升编程效率。
其能够被隐式转换为 lambda 表达式。
2.2 特色
函数式接口是仅制定一个抽象方法的接口
能够包含一个或多个静态或默认方法
专用注解即@FunctionalInterface
检查它是不是一个函数式接口,也可不添加该注解 若是有两个或以上 抽象方法,就不能当成函数式接口去使用,也不能添加@FunctionalInterface这个注解 若是只有一个抽象方法,那么@FunctionalInterface注解 加不加 均可以当作函数式接口去使用
回调函数
简单来讲就是回调函数,方法的参数是一个方法,在这个方法中对传递的方法进行调用
2.3 应用场景
想经过函数式编程,提升编程效率的各类场景都可。
2.4 代码实现
2.4.1 无参状况
public class FunInterface_01 { // 自定义静态方法,接收接口对象 public static void call(MyFunctionInter func) { // 调用接口内的成员方法 func.printMessage(); } public static void main(String[] args) { // 第一种调用 : 直接调用自定义call方法,传入函数 FunInterface_01.call(() -> { System.out.println("HelloWorld!!!"); }); // 第二种调用 : 先建立函数对象,相似于实现接口的内部类对象 MyFunctionInter inter = () -> { System.out.println("HelloWorld2!!!!"); }; // 调用这个实现的方法 inter.printMessage(); } } // 函数式接口 @FunctionalInterface interface MyFunctionInter { void printMessage(); }
2.4.2 有参状况
public class FunInterface_02 { // 自定义静态方法,接收接口对象 public static void call(MyFunctionInter_02 func, String message) { // 调用接口内的成员方法 func.printMessage(message); } public static void main(String[] args) { // 调用须要传递的数据 String message = "有参函数式接口调用!!!"; // 第一种调用 : 直接调用自定义call方法,传入函数,并传入数据 FunInterface_02.call((str) -> { System.out.println(str); }, message); // 第二种调用 : 先建立函数对象,相似于实现接口的内部类对象 MyFunctionInter_02 inter = (str) -> { System.out.println(str); }; // 调用这个实现的方法 inter.printMessage(message); } } // 函数式接口 @FunctionalInterface interface MyFunctionInter_02 { void printMessage(String message); }
2.5 JDK自带经常使用的函数式接口
2.5.1 SUPPLIER接口
Supplier接口
表明结果供应商,因此有返回值,能够获取数据,有一个get方法,用于获取数据
public class _03_JdkOwn_01 { private static String getResult(Supplier<String> function) { return function.get(); } public static void main(String[] args) { // 1 String before = "张三"; String after = "你好"; // 把两个字符串拼接起来 System.out.println(getResult(() -> before + after)); // 2 //建立Supplier容器,声明为_03_JdkOwn类型 // 此时并不会调用对象的构造方法,即不会建立对象 Supplier<_03_JdkOwn_01> sup = _03_JdkOwn_01::new; _03_JdkOwn_01 jo1 = sup.get(); _03_JdkOwn_01 jo2 = sup.get(); } public _03_JdkOwn_01() { System.out.println("构造方法执行了"); } }
2.5.2 CONSUMER接口
Consumer接口
消费者接口因此不须要返回值有一个accept(T)方法,用于执行消费操做,能够对给定的参数T 作任意操做
public class _04_JdkOwn_02 { private static void consumeResult(Consumer<String> function, String message) { function.accept(message); } public static void main(String[] args) { // 传递的参数 String message = "消费一些内容!!!"; // 调用方法 consumeResult(result -> { System.out.println(result); }, message); } }
2.5.3 FUNCTION<T,R>接口
Function<T,R>接口
表示接收一个参数并产生结果的函数顾名思义,是函数操做的
有一个Rapply(T)方法,Function中没有具体的操做,具体的操做须要咱们去为它指定,所以apply具体返回的结果取决于传入的lambda表达式
public class _05_JdkOwn_03 { // Function<参数, 返回值> public static void convertType(Function<String, Integer> function, String str) { int num = function.apply(str); System.out.println(num); } public static void main(String[] args) { // 传递的参数 String str = "123"; // s是说明须要传递参数, 也能够写 (s) convertType(s -> { int sInt = Integer.parseInt(s); return sInt; }, str); } }
2.5.4 PREDICATE接口
Predicate接口 断言接口
就是作一些判断,返回值为boolean
有一个boolean test(T)方法,用于校验传入数据是否符合判断条件,返回boolean类型
public class _06_JdkOwn_04 { // 自定义方法,而且 Predicate 接收String字符串类型 public static void call(Predicate<String> predicate, String isOKMessage) { boolean isOK = predicate.test(isOKMessage); System.out.println("isOK吗:" + isOK); } public static void main(String[] args) { // 传入的参数 String input = "ok"; call((String message) -> { // 不区分大小写比较,是ok就返回true,不然返回false if (message.equalsIgnoreCase("ok")) { return true; } return false; }, input); } }
3.1概念说明
Lambda表达式的另一种表现形式,提升方法复用率和灵活性。
3.2 特色
更简单、代码量更少、复用性、扩展性更高。
3.3 应用场景
若Lambda 体中的功能,已经有方法提供了实现,能够使用方法引用。
不须要再复写已有API的Lambda的实现。
3.4 代码实现
3.4.1 方法引用
方法引用-3种形式
3.4.1.1 对象的引用 :: 实例方法名
public static void main(String[] args) { Integer intObj = new Integer(123456); // 常规lambda写法 Supplier<String> su = () -> intObj.toString(); System.out.println(su.get()); // 方法引用写法 Supplier<String> su1 = intObj::toString; System.out.println(su1.get()); }
3.4.1.2 类名 :: 静态方法名
public static void main(String[] args) { // 常规lambda写法 // 前两个泛型是参数类型,第三个是返回值类型 BiFunction<Integer, Integer, Integer> bi = (x, y) -> Integer.max(x, y); int apply = bi.apply(10, 11); System.out.println(apply); // 方法引用写法 BiFunction<Integer, Integer, Integer> bif = Integer::max; int apply2 = bif.apply(10, 11); System.out.println(apply2); }
3.4.1.3 类名 :: 实例方法名
public static void main(String[] args) { // 常规lambda写法 // 两个泛型都是参数类型 BiPredicate<String, String> predicate = (x, y) -> x.equals(y); System.out.println(predicate.test("a", "a")); // 方法引用写法 // 使用第一个参数调用成员方法把第二个参数传入 // ::前面的类型 要和 第一个参数的类型一致 BiPredicate<String, String> predicate2 = String::equals; System.out.println(predicate2.test("a", "b")); }
3.4.3 构造器调用
public static void main(String[] args) { // 无参构造器 // 常规lambda写法 Supplier<Object> objSup = () -> new Object(); System.out.println(objSup.get()); // 方法引用写法 Supplier<Object> s1 = Object::new; System.out.println(s1.get()); // 有参构造器 // 常规lambda写法 Function<String, Integer> func = (x) -> new Integer(x); System.out.println(func.apply("123456")); // 方法引用写法 Function<String, Integer> func2 = Integer::new; System.out.println(func2.apply("123456")); }
3.4.4 数组调用
public static void main(String[] args) { // lambda传统写法 Function<Integer, Integer[]> fun = (n) -> new Integer[n]; Integer[] intArray1 = fun.apply(5); intArray1[0] = 100; System.out.println(intArray1[0]); // 数组引用新写法 Function<Integer, Integer[]> fun1 = Integer[]::new; Integer[] intArray = fun1.apply(5); intArray[0] = 100; System.out.println(intArray[0]); }
4.1 概念说明
数据渠道、管道,用于操做数据源(集合、数组等)所生成的元素序列。
集合讲的是数据,流讲的是计算
即一组用来处理数组,集合的API。
4.2 特色
Stream 不是数据结构,没有内部存储,本身不会存储元素。 Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。 Stream 操做是延迟执行的。这意味着他们会等到须要结果的时候才执行。 不支持索引访问。 延迟计算 支持并行 很容易生成数据或集合 支持过滤,查找,转换,汇总,聚合等操做。
4.3 应用场景
流式计算处理,须要延迟计算、更方便的并行计算
更灵活、简洁的集合处理方式场景
4.4 代码实现
4.4.1 运行机制说明
Stream分为源source,中间操做,终止操做。 流的源能够是一个数组,集合,生成器方法,I/O通道等等。 一个流能够有零个或多个中间操做,每个中间操做都会返回一个新的流,供下一个操做使用,一个流只会有一个终止操做。 中间操做也称为转换算子-transformation Stream只有遇到终止操做,它的数据源会开始执行遍历操做。 终止操做也称为动做算子-action
4.4.2 代码实现
4.4.2.1 生成stream流的5种方式说明
public static void main(String[] args) { // 1 经过数组,Stream.of() String[] str = { "a", "b", "c" }; Stream<String> str1 = Stream.of(str); // System.out.println(str1); // 2 经过集合 List<String> strings = Arrays.asList("a", "b", "c"); Stream<String> stream = strings.stream(); System.out.println(stream); // 3 经过Stream.generate方法来建立 // 这是一个无限流,经过这种方法建立在操做的时候最好加上limit进行限制 Stream<Integer> generate = Stream.generate(() -> 1); generate.limit(10).forEach(x -> System.out.println(x)); // 4 经过Stream iterate Stream<Integer> iterate = Stream.iterate(1, x -> x + 2); iterate.limit(100).forEach(x -> System.out.println(x)); // 5 已有类的stream源生成API String str2 = "123456"; IntStream chars = str2.chars(); chars.forEach(x -> System.out.println(x)); }
4.4.2.2 经常使用转换算子
经常使用转换算子 filter,distinct,map,limit,skip,flatMap等
filter : 对元素进行过滤筛选,不符合的就不要了 distinct : 去掉重复的元素 skip : 跳过多少元素 limit : 取一个集合的前几条数据 map : 能够理解是在遍历集合的过程当中,对元素进行操做,好比判断集合元素是不是a 返回boolean 或者对集合元素进行更改数据,好比都加 -- flatMap : 解决一个字符串数组 返回单一的字符串使用flatMap 注意只用此算子是不会真正进行计算的,只有后边调用动做算子才会真正计算。
public static void main(String[] args) { List<String> strings = Arrays.asList("a", "b", "c", "a"); Stream<String> stream = strings.stream(); /** * 对元素进行过滤筛选,不符合的就不要了 */ // collect 把符合条件的转换为集合strings,属于动做算子,由于不用动做算子这些转换算子不会执行,因此看不到结果 // 只要 a List<String> value = stream.filter(x -> x.equals("a")).collect(Collectors.toList()); // 集合中只有 a 了 System.out.println(value); // 使用过以后,须要从新生成stream stream = strings.stream(); /** * 跳过1个元素 原来是 abca 如今就是 bca */ value = stream.skip(1).collect(Collectors.toList()); // bca System.out.println(value); /** * map : 能够理解是在遍历集合的过程当中,对元素进行操做,好比判断集合元素是不是a 返回boolean * 或者对集合元素进行更改数据,好比都加-- */ stream = strings.stream(); // 判断集合元素,这样就是booelean 是a 就是true 不然就是false List<Boolean> value1=stream.map(x -> x.equals("a")).collect(Collectors.toList()); // true,false,false,true System.out.println(value1); stream = strings.stream(); // 更改集合元素 value =stream.map(x -> x+"--").collect(Collectors.toList()); // a--, b--, c--, a-- System.out.println(value); /** * 去掉重复元素 */ stream = strings.stream(); value = stream.distinct().collect(Collectors.toList()); // 去除一个a 只有a,b,c System.out.println(value); /** * 取一个集合的前几条数据 */ stream = strings.stream(); value = stream.limit(2).collect(Collectors.toList()); // ab System.out.println(value); /** * 解决一个字符串数组 返回单一的字符串使用flatMap */ strings = Arrays.asList("1,2,3", "a,b,c"); stream = strings.stream(); // 原本集合中有两个数据 "1,2,3" 和 "a,b,c" // 会把每个元素 以 , 分割,获得字符串数组 // 而后把数组中每个元素,都单独拿出来 // 最终就会获得 1,2,3,a,b,c 6个元素 // 经过 collect 把这6个元素 放到集合中 value =stream.map(x -> x.split(",")).flatMap(arr -> Arrays.stream(arr)).collect(Collectors.toList()); // 1, 2, 3, a, b, c System.out.println(value); }
4.4.2.3 经常使用动做算子
循环 forEach 计算 min、max、count、average 匹配 anyMatch、allMatch、noneMatch、findFirst、findAny 汇聚 reduce 收集器 collect
public static void main(String[] args) { List<String> strings = Arrays.asList("a", "b", "c"); Stream<String> stream = strings.stream(); // 测试forEach stream.filter(x -> x.equals("a")).forEach(x -> System.out.println(x)); // 测试count stream = strings.stream(); long cnt = stream.count(); System.out.println(cnt); // 测试collect stream = strings.stream(); List<String> list = stream.map(x -> x + "--").collect( Collectors.toList()); System.out.println(list); }
5.1 概念说明
1.8以前接口中只能定义public static final的变量和public abstract修饰的抽象方法。
1.8及之后版本,不只兼容1.8之前的,并新增了默认方法定义和静态方法定义的功能。即default方法和static方法。 让接口更灵活、更多变,更可以适应现实开发须要。
5.2 特色
默认方法
能够被重写,也能够不重写。若是重写的话,就按实现类的方法来执行。
调用的时候必须是实例化对象调用。
静态方法
跟以前的普通类的静态方法大致相同
惟一不一样的是不能经过接口的实现类的对象来调用,必须是类.静态方法的方式。
5.3 应用场景
默认方法
是为了解决以前版本接口升级致使的大批实现类的强制重写方法升级的问题。
涉及到接口升级的场景能够多用,从而提升了程序的扩展性、可维护性。
静态方法
跟默认方法为相似,也是为了解决接口升级的问题,默认方法解决了接口方法增长后其子类没必要要所有重写的问题,静态方法解决了一次编写静态方法全部接口及其子类通用的问题,跟lambda表达式并用效果更加,进一步提升了程序扩展性和可维护性。
容许在已有的接口中添加静态方法,接口的静态方法属于接口自己,不被继承,也须要提供方法的静态实现后,子类才能够调用。
5.4 代码实现
5.4.1 默认方法
public class _01_Interface { public static void main(String[] args) { MyInter inter = new MyInterImpl(); System.out.println(inter.add(3, 4)); inter.printMessage(); } } interface MyInter { // 以前的用法 int add(int i, int j); // 新加的默认方法 default void printMessage() { System.out.println("在接口中的默认实现"); } } class MyInterImpl implements MyInter { @Override public int add(int i, int j) { return i + j; } @Override public void printMessage() { System.out.println("在接口的实现类中的默认实现"); } }
5.4.2 静态方法案例-1-通常状况
类名调用就行,各是各的,互不影响
public class _02_Interface { public static void main(String[] args) { Person.run(); Man.run(); } } interface Person { public static void run() { System.out.println("人类均可以跑!!!"); } } class Man implements Person { public static void run() { System.out.println("人类均可以跑,男人跑的更快!!!"); } }
5.4.3 静态方法案例-2-高级使用
类名调用就行,各是各的,互不影响
public class _03_Interface { public static void main(String[] args) { Person_01 m1 = PersonFactory.create(Man_01::new); m1.say(); } } interface PersonFactory { public static Person_01 create(Supplier<Person_01> supplier) { return supplier.get(); } } interface Person_01 { default void say() { System.out.println("人类会说话!!!"); } public static void run() { System.out.println("人类均可以跑!!!"); } } class Man_01 implements Person_01 { @Override public void say() { System.out.println("人类会说话,男人说话更粗糙!!!"); } public static void run() { System.out.println("人类均可以跑,男人跑的更快!!!"); } }
6.1 概念说明
新增了专用于处理时间日期API类,包括本地化、日期格式化等方面。
6.2 特色
对解决各种常见问题,更方便、更简单、更高效
6.3 应用场景
能够替换以前用Date类的各类功能操做,编程效率更高。
6.4 代码实现
6.4.1 新增核心类
均在java.time包下
LocalDate LocalTime LocalDateTime DateTimeFormatter:解析和格式化日期或时间的类 由日期时间的格式组成的 类 Instant:时间戳类 Duration:间隔计算,能够计算两个时间的间隔 Period:间隔计算,计算两个日期的间隔 ZonedDate ZonedTime ZonedDateTime:时区处理类,均带有当前系统的默认时区
6.4.2 案例演示
public static void main(String[] args) { /** * 日期相关 */ // 获取当前日期 yyyy-MM-dd LocalDate now1 = LocalDate.now(); // 2020-07-11 System.out.println(now1); // 获取年份 2020 System.out.println(now1.getYear()); // 获取月份 7 System.out.println(now1.getMonthValue()); // 获取当前是一年中的第几天 193 System.out.println(now1.getDayOfYear()); // 获取月中第几天 也就是 日期 11 System.out.println(now1.getDayOfMonth()); // 获取星期 SATURDAY (星期六) System.out.println(now1.getDayOfWeek()); /** * 时间相关 */ // 获取当前时间 HH:mm:ss.SSS LocalTime now2 = LocalTime.now(); // 18:33:38.429 System.out.println(now2); /** * 获取日期和时间 * * 默认是 yyyy-MM-ddTHH:mm:ss.SSS * * 2020-07-11T18:35:12.954 */ LocalDateTime now3 = LocalDateTime.now(); // 2020-07-11T18:35:12.954 System.out.println(now3); /** * 解析和格式化日期或时间的类 由日期时间的格式组成的 类 * * 简单来讲就是格式化日期和时间,自定义格式 */ DateTimeFormatter formater = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH点mm分ss秒SSS毫秒"); String format = now3.format(formater); // 2020年07月11日 18点36分34秒726毫秒 System.out.println(format); /** * 判断一个日期是在另外一个日期以前或以后 */ // 指定一个时间 now()是获取当前时间,of是指定时间 LocalDate of = LocalDate.of(2010, 12, 3); // 判断 now1是否在of以后 boolean after = now1.isAfter(of); // true System.out.println(after); // 判断 now1是否在of以前 boolean before = now1.isBefore(of); // false System.out.println(before); }