编译器IDEA
1、IDEA中层级结构介绍
1.1 结构分类
-
project(项目、工程)
-
module(模块)
-
package(包)
-
class(类)
1.2 结构介绍
为了让大家更好的吸收,package这一层级,我们后面再学习,先学习最基础的project、module、class。
(1)project(项目、工程)
淘宝、京东、黑马程序员网站都属于一个个项目,IDEA中就是一个个的Project。
(2)module(模块)
在一个项目中,可以存放多个模块,不同的模块可以存放项目中不同的业务功能代码。在黑马程序员的官方网站中,至少包含了以下模块:
-
论坛模块
-
报名、咨询模块
为了更好的管理代码,我们会把代码分别放在两个模块中存放。
(3)package(包)
一个模块中又有很多的业务,以黑马程序员官方网站的论坛模块为例,至少包含了以下不同的业务。
-
发帖
-
评论
为了把这些业务区分的更加清楚,就会用包来管理这些不同的业务。
(4)class(类)
就是真正写代码的地方。
2、TODO
格式:
//TODO:内容
作用:
标记我们的代码,一般是用来表示待完成,或者待解决的部分。
举例1:
public class A {
//TODO: 缺少一个主方法需要补齐
}
举例2:
public class B {
public static void main(String[] args) {
//TODO:缺少一个打印语句需要补齐
}
}
举例3:
public class C {
// TODO:缺少一个主方法需要补齐
// TODO:缺少一个打印语句需要补齐
}
使用:
在idea主界面的左下角,会有一个TODO按钮。
点击一下TODO按钮之后,会把项目中所有标记了TODO的都展示出来。
当我们点击其中一个时,代码区域就会自动跳转。
3、快捷键
-
用循环、判断等包围:
ctrl+alt+t
; -
定义变量自动生成变量类型和变量名:`
ctrl+alt+v
;` -
写一个方法名,自动定义方法:
alt+回车+回车
; -
快速生成for循环,如用for循环遍历accounts,写作
accounts.fori
; -
快速删除某行代码:
ctrl+y
-
跳转代码后再跳回去:
ctrl+alt+方向键(左右)
JAVA基础
API文档下载:
1. 自动类型转换
类型范围小的变量,可以直接赋值给类型范围大的变量。
byte/short/char—— int——long——float——double
-
小范围的类型会自动转换成大范围的类型运算。
-
最终类型由表达式中的最高类型决定。
-
byte short char是直接转换成int类型参与运算的。
2. 强制数据类型转换
可以强行将类型范围大的变量、数据赋值给类型范围小的变量。
(直接截取后面的位)
int a = 20;
byte b = (byte)a;
注意:
-
强制类型转换可能造成数据(丢失)溢出。
-
浮点型强转成整型,直接丢掉小数部分,保留整数部分返回。
3. 运算符
3.1 基本运算符
符号 | 作用 | 说明 |
---|---|---|
+ | 加 | 参考小学一年级 |
- | 减 | 参考小学一年级 |
* | 乘 | 参考小学二年级,与“×”相同 |
/ | 除 | 与“÷”相同,注意:在Java中两个整数相除结果还是整数。 |
% | 取余 | 获取的是两个数据做除法的余数 |
“+” 做连接符:
“+”符号与字符串运算的时候是用作连接符的,其结果依然是一个字符串。
int a = 5 ;
System.out.println(“abc” + ‘a’); // abca
System.out.println("abc" + a); // abc5
System.out.println(5 + a); // 10
// 能算则算,不能算就在一起。(计算机很聪明)
3.2 关系运算符
是对数据进行条件判断的符号,最终会返回一个比较的布尔结果(false,true)。
3.3 逻辑运算符
-
可以把多个条件的布尔结果放在一起运算,最终返回一个布尔结果。
符号 | 介绍 | 说明 |
---|---|---|
& | 逻辑与 | 必须都是true,结果才是true; 只要有一个是false,结果一定是false。 |
| | 逻辑或 | 只要有一个为true、结果就是true |
! | 逻辑非 | 你真我假、你假我真。 !true=false 、 !false= true |
^ | 逻辑异或 | 如果两个条件都是false或者都是true则结果是false。两个条件不同结果是true。 |
-
短路逻辑运算符
符号 | 介绍 | 说明 |
---|---|---|
&& | 短路与 | 判断结果与“&”一样。过程是左边为 false**,右边则不执行。** |
|| | 短路或 | 判断结果与“|”一样。过程是左边为 true**, 右边则不执行。** |
注意:逻辑与 “&” 、逻辑或“|”: 无论左边是 false还是 true,右边都要执行。
3.4 运算符优先级
优先级 | 运算符 | 结合性 |
---|---|---|
1 | ()、[]、{} | 从左向右 |
2 | !、+、-、~、++、-- | 从右向左 |
3 | *、/、% | 从左向右 |
4 | +、- | 从左向右 |
5 | «、»、>>> | 从左向右 |
6 | <、<=、>、>=、instanceof | 从左向右 |
7 | ==、!= | 从左向右 |
8 | & | 从左向右 |
9 | ^ | 从左向右 |
10 | | | 从左向右 |
11 | && | 从左向右 |
12 | || | 从左向右 |
13 | ?: | 从右向左 |
14 | =、+=、-=、*=、/=、&=、|=、^=、~=、«=、»=、>>>= | 从右向左 |
4. 键盘录入
步骤:
-
导包:告诉程序去JDK的哪个包中找扫描器技术。
import java.util.Scanner;
-
写一行代码代表得到键盘扫描器对象。
Scanner sc = new Scanner(System.in);
-
等待接收用户输入数据。
int age = sc.nextInt();
String name = sc.next();
注意:
System、String在JDK中的Java.lang包下
lang包不需要我们导包,是默认的包。
5. 流程控制
5.1 分支结构
5.1.1 if分支
// 格式1:
if (条件表达式) {
语句体;
}
// 格式2:
if (条件表达式) {
语句体1;
} else {
语句体2;
}
// 格式3:
if (条件表达式1) {
语句体1;
} else if (条件表达式2) {
语句体2;
} else if (条件表达式3) {
语句体3;
}
. . .
else {
语句体n+1;
}
if 语句中,如果大括号控制的只有一行代码,则大括号可以省略不写。
5.1.2 switch分支
switch(表达式){
case 值1:
执行代码...;
break;
case 值2:
执行代码...;
break;
…
case 值n-1:
执行代码...;
break;
default:
执行代码n;
}
if适合做:区间匹配。
switch适合做:值匹配的分支选择、代码优雅。
表达式类型只能是byte、short、int、char,JDK5开始支持枚举,JDK7开始支持String,不支持double、float、long。
case给出的值不允许重复,且只能是字面量,不能是变量。
5.2 循环结构
什么时候用for循环,什么时候用while循环?
功能上是完全一样的,for能解决的while也能解决,反之亦然。
使用规范是:知道循环几次:使用for;不知道循环几次建议使用:while(更专业)。
for循环中,控制循环的变量只在循环中可以使用。While循环中,控制循环的变量在循环后还可以继续使用。
5.2.1 for循环
5.2.2 while循环
5.2.3 do-while循环
5.3 break和continue跳出外部循环
-
给外部循环起名字,如,起名OUT
OUT:
for (int i = 0; i < 4; i++) {• for (int j = 0; j < 5; j++) {
…
break OUT;
}
}
OUT:
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 5; j++) {
…
count OUT;
}
}
6. 随机数Random类
-
作用:用于在程序中获取随机数的技术。
-
使用步骤:
-
导包:告诉程序去JDK的哪个包中找随机数技术。
import java.util.Random;
-
写一行代码代表得到随机数对象。
Random r = new Random();
-
调用随机数的功能获取0-9的随机数。
int number = r.nextInt(10);
-
注:
nextInt(n) 功能只能生成: 0 至 n-1之间的随机数,不包含n。
Random生成区间随机数的技巧:减加法。
例如:Random随机数如何生成 65 – 91之间的随机数:
65 – 91 => (0 - 26)+ 65
int number = r.nextInt(27) + 65;
7. 数组
数组就是用来存储一批同种类型数据的内存区域(可以理解成容器)。
-
数组的基本原理:
注意:数组变量名中存储的是数组在内存中的地址,数组是引用类型。
数组的属性:
长度属性:length。
System.out.println(arr.length);
7.1 数组的定义与初始化
7.1.1 静态初始化数组
-
定义数组的时候直接给数组赋值。
// 完整格式
数据类型[] 数组名 = new 数据类型[]{元素1,元素2 ,元素3… };
double[] scores = new double[]{89.9, 99.5, 59.5, 88.0};
int[] ages = new int[]{12, 24, 36}
// 简化格式
数据类型[] 数组名 = { 元素1,元素2 ,元素3,… };
int[] ages = {12, 24, 36};
7.1.2 动态初始化数组
-
定义数组的时候只确定元素的类型和数组的长度,之后再存入具体数据。
// 定义数组
数据类型[] 数组名 = new 数据类型[长度];
int[] arr = new int[3];
// 后赋值
arr[0] = 10;
System.out.println(arr[0]); // 10
动态初始化数组,元素默认值规则:
数据类型 | 明细 | 默认值 |
---|---|---|
基本类型 | byte、short、char、int、long | 0 |
基本类型 | float、double | 0.0 |
基本类型 | boolean | false |
引用类型 | 类、接口、数组、String | null |
两种格式的写法是独立的,不可以混用。
错误示例:
int[] arrs = new int[3]{30,40,50};
7.2 java内存分配
数组使用常见问题:
问题1:如果访问的元素位置超过最大索引,执行时会出现ArrayIndexOutOfBoundsException(数组索引越界异常)
问题2:如果数组变量中没有存储数组的地址,而是null, 在访问数组信息时会出现NullPointerException(空指针异常)
8.方法
方法是一种语法结构,它可以把一段代码封装成一个功能,以方便重复调用。
public class Test {
// 方法
public static void main(String[] args) {
}
// 方法
public static int sum(int a, int b){
int c = a + b;
return c;
}
}
8.1 方法的定义
// 方法定义的完整形式
修饰符 返回值类型 方法名(形参列表){
方法体代码(需要执行的功能代码)
return 返回值
}
public static int add(int a, int b){
int c = a + b;
return c;
}
8.2 方法的调用
方法名(…);
int sum = add(10, 20);
注:形参列表中的参数不能给默认值
如果方法不需要返回结果,返回值类型必须申明成void(无返回值), 此时方法内部不可以使用return返回数据。
方法如果没有参数,或者返回值类型申明为void可以称为无参数、无返回值的方法,依次类推。
方法的编写顺序无所谓。
8.3 方法的调用流程 – 内存图解
方法没有被调用的时候,在方法区中的字节码文件中存放;
方法被调用的时候,需要进入到栈内存中运行;(方法的运行区域在栈内存)
8.4 方法的参数传递机制
8.4.1 基本类型的参数传递(值传递)
- 在传输实参给方法的形参的时候,并不是传输实参变量本身, 而是传输实参变量中存储的值,这就是值传递。
8.4.2 引用类型的参数传递(值传递,但传的是地址)
基本类型和引用类型的参数在传递的时候有什么不同?
都是值传递。
基本类型的参数传输存储的数据值。
引用类型的参数传输存储的地址值。
8.5 方法重载
重载方法:同一个类中,出现多个方法名称相同,但是形参列表是不同的,那么这些方法就是重载方法**。
调用方法的时候,会通过参数的不同来区分调用的是哪个方法
方法重载的作用:
可读性好,方法名称相同提示是同一类型的功能,通过形参不同实现功能差异化的选择,这是一种专业的代码设计。
方法重载的识别技巧:
只要是同一个类中,方法名称相同、形参列表不同,那么他们就是重载的方法,其他都不管!(如:修饰符,返回值类型都无所谓)
形参列表不同指的是:形参的个数、类型、顺序不同,不关心形参的名称。
8.6 小提示
-
return; 跳出并立即结束所在方法的执行。
-
break; 跳出并结束当前所在循环的执行。
-
continue; 结束当前所在循环的当次继续,进入下一次执行。
9. 面向对象
面向对象介绍:
并不是一个技术,而是一种编程指导思想。
把现实世界的具体事物全部看成一个一个的对象来解决实际问题。
面向对象编程的指导思想、优点小结:
把现实世界的具体事物全部看成一个一个的对象来解决问题。
按照面向对象编程来设计程序:程序代码符合人类思维习惯,更易理解、更简单、更易维护。
9.1 如何定义类
类名建议首字母大写。满足驼峰模式。
一个Java文件中可以定义多个类,但是只能有一个类是用public修饰的,public修饰的类名必须成为Java代码的文件名称。
按照规范:建议一个Java文件只定义一个类。
public class 类名 {
1、成员变量(代表属性)
2、成员方法(代表行为)
3、构造器 (后面学习)
4、代码块 (后面学习)
5、内部类 (后面学习)
}
public class Car {
// 属性 (成员变量)
String name;
double price;
// 行为(方法)
public void start(){
}
public void run(){
}
}
成员变量的完整定义格式是:修饰符 数据类型 变量名称 = 初始化值; 一般无需指定初始化值,存在默认值。
类名首字母建议大写,且有意义,满足“驼峰模式”。
一个Java文件中可以定义多个class类,且只能一个类是public修饰,而且public修饰的类名必须成为代码文件名。(实际开发中建议还是一个文件定义一个class类。)
9.2 如何得到类对象
类名 对象名 = new 类名();
Car c2 = new Car();
9.3 如何使用对象
-
访问属性: 对象名.成员变量
-
访问行为: 对象名.方法名(…)
(1)对象放在哪个位置?
堆内存
(2)对象变量在内存哪个位置,其中存储的是什么?
栈内存中,存储的是对象在堆内存中的地址
(3)成员变量的数据放在哪里,存在于哪个位置?
对象中,存在于堆内存中
9.4 垃圾回收
-
注意:当堆内存中的类对象或数组对象,没有被任何变量引用(指向)时,就会被判定为内存中的“垃圾”。
-
Java存在自动垃圾回收器,会定期进行清理。
9.5 构造器
构造器的作用:
用于初始化一个类的对象,并返回对象的地址。
Car c = new Car();
构造器的定义格式:
修饰符 类名(形参列表){ ... } public class Car { ... // 无参数构造器 public Car(){ ... } // 有参数构造器 public Car(String n, String b){ ... } }
初始化对象的格式:
类名 对象名称 = new 构造器;
Car c = new Car();
构造器的分类
-
无参数构造器(默认存在的):初始化的对象时,成员变量的数据均采用默认值。
-
任何类定义出来,默认就自带了无参数构造器,写不写都有。
-
-
有参数构造器:在初始化对象的时候,同时可以为对象进行赋值。
-
一旦定义了有参数构造器,无参数构造器就没有了,此时就需要自己写一个无参数构造器了。
-
9.6 this关键字
-
this关键字可以出现在成员方法、构造器中,代表当前对象的地址。
-
作用:访问当前对象的成员变量、成员方法。可以区分变量是局部的还是对象的成员变量。
public class Car {
String name;
double price;
public void goWith(String name){
System.out.println(this.name + "正在和" + name + "一起比赛!!");
}
}
9.7 封装
-
面向对象的三大特征:封装,继承,多态。
-
什么是封装? 隐藏实现细节,暴露出合适的访问方式。(合理隐藏、合理暴露)
9.7.1 封装的实现步骤
-
一般对成员变量使用private(私有)关键字修饰进行隐藏,private修饰后该成员变量就只能在当前类中访问。
-
提供public修饰的公开的getter、setter方法暴露其取值和赋值。
public class Student {
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
if (age >= 0 && age <= 200) {
this.age = age;
} else {
System.out.println("请检查年龄数值");
}
}
}
9.8 JavaBean
-
JavaBean是一种Java语言编写的可重用组件,它是一种符合特定规范的Java类。JavaBean类必须具有无参构造函数,并且可以包含一些属性和方法。JavaBean通常用于构建可重用的组件,例如用户界面控件、数据访问对象和业务逻辑组件。JavaBean的属性可以通过getter和setter方法进行访问和修改。
-
也可以理解成实体类,其对象可以用于在程序中封装数据。
标准JavaBean须满足如下要求:
成员变量使用 private 修饰。
提供每一个成员变量对应的 setXxx() / getXxx()。
必须提供一个无参构造器。
// 在这个示例中,Person类是一个JavaBean,它有两个属性:name和age。
// 这些属性可以通过getName、setName、getAge和setAge方法进行访问和修改。
// 请注意,Person类必须具有无参构造函数,以便可以通过反射创建它的实例
public class Person {
private String name;
private int age;
public Person() {}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
9.9 成员变量和局部变量的区别
区别 | 成员变量 | 局部变量 |
---|---|---|
类中位置不同 | 类中,方法外 | 常见于方法中 |
初始化值不同 | 有默认初始化值 | 没有,使用之前需要完成赋值 |
内存位置不同 | 堆内存 | 栈内存 |
生命周期不同 | 随着对象的创建而存在,随着对象的消 失而消失 | 随着方法的调用而存在,随着方法的运行结束 而消失 |
作用域 | 在所归属的大括号中 |
10. 常用API(String、ArrayList)
API (Application Programming Interface, 应用程序编程接口)
Java写好的技术(功能代码),咱们可以直接调用。
10.1 String类
String类定义的变量可以用于存储字符串,同时String类提供了很多操作字符串的功能,我们可以直接使用。
String定义变量存储字符串 | 需要知道如何创建字符串对象,并使用String定义变量指向该字符串对象。 |
---|---|
String的内存原理 | 字符串对象在内存中的原理是什么样。能够解决一些字符串的常见面试题 |
String类提供了哪些API | 能够说出并使用String类提供的操作字符串的功能:遍历、替换、截取、相等,包含 |
String解决实际案例 | 能够利用String的常用API去解决实际场景的业务需求,真正做到学以致用 |
String 概述
java.lang.String 类代表字符串,String类定义的变量可以用于指向字符串对象,然后操作该字符串。
String类特点
-
String其实常被称为不可变字符串类型,它的对象在创建后不能被更改。(String变量每次的修改其实都是产生并指向了新的字符串对象。原来的字符串对象都是没有改变的,所以称不可变字符串。)
-
字符串对象存在哪里?
-
以“ ”方式给出的字符串对象,在字符串常量池中存储,且相同内容只会在其中存储一份。
-
通过String类的构造器创建对象。通过构造器new对象,每new一次都会产生一个新对象,放在堆内存中。
构造器 | 说明 |
---|---|
public String() | 创建一个空白字符串对象,不含有任何内容 |
public String(String original) | 根据传入的字符串内容,来创建字符串对象 |
public String(char[] chs) | 根据字符数组的内容,来创建字符串对象 |
public String(byte[] chs) | 根据字节数组的内容,来创建字符串对象 |
数组的长度属性是
array.length
,不需要括号。字符串的长度方法是
string.length()
,需要括号。其他集合类一般使用
.size()
方法来获取元素的数量。
String常见面试题
注:当字符串变量通过*非字符串文字*的方式创建时,例如通过*构造函数*或*字符串连接表达式包含变量*时,它们不会指向相同的对象,而是会*创建新的字符串对象*。在这种情况下,`==` 操作符可能返回 `false`
String类常用API
-
字符串的内容比较:
推荐使用String类提供的“equals”比较:只关心内容一样即可
方法名 说明 public boolean equals (Object anObject) 将此字符串与指定对象进行比较。只关心字符内容是否一致! public boolean equalsIgnoreCase (String anotherString) 将此字符串与指定对象进行比较,忽略大小写比较字符串。只关心字符内容是否一致! -
常用API
方法名 说明 public int length() 返回此字符串的长度 public char charAt(int index) 获取某个索引位置处的字符 public char[] toCharArray(): 将当前字符串转换成字符数组返回 public String substring(int beginIndex, int endIndex) 根据开始和结束索引进行截取,得到新的字符串(包前不包后) public String substring(int beginIndex) 从传入的索引处截取,截取到末尾,得到新的字符串 public String replace(CharSequence target, CharSequence replacement) 使用新值,将字符串中的旧值替换,得到新的字符串 public String[] split(String regex) 根据传入的规则(正则表达式)切割字符串,得到字符串数组返回
10.2 ArrayList
ArrayList代表的是集合类,集合是一种容器,与数组类似,不同的是集合的大小是不固定的。
通过创建ArrayList的对象表示得到一个集合容器,同时ArrayList提供了比数组更好用,更丰富的API (功能)给程序员使用。
ArrayList集合如何创建对象 | 要知道如何利用 ArrayList创建对象代表集合容器来存放数据。 |
---|---|
ArrayList常用API | 能够说出并使用ArrayList类提供的丰富的元素操作的功能:添加、获取、删除、修改等功能 |
ArrayList存储自定义对象 | 能够使用ArrayList存储自定义的对象,并清楚ArrayList集合存储对象的底层原理 |
ArrayList解决实际问题 | 能够使用ArrayList存储对象,并完成数据搜索,删除等常见业务需求 |
集合是与数组类似,也是一种容器,用于装数据的。
数组定义完成并启动后,类型确定、长度固定。在个数不能确定,且要进行增删数据操作的时候,数组是不太合适的。
集合的大小不固定,启动后可以动态变化,类型也可以选择不固定。集合非常适合做元素个数不确定,且要进行增删操作的业务场景。集合的提供了许多丰富、好用的功能,而数组的功能很单一。
ArrayList集合
-
ArrayList是集合中的一种,它支持索引。
ArrayList集合的对象获取
构造器 | 说明 |
---|---|
public ArrayList() | 创建一个空的集合对象(ArrayList list = new ArrayList();) |
ArrayList集合添加元素的方法
方法名 | 说明 |
---|---|
public boolean add(E e) | 将指定的元素追加到此集合的末尾 |
public void add(int index, E element) | 在此集合中的指定位置插入指定的元素 |
泛型概述
ArrayLis<E>:其实就是一个泛型类,可以在编译阶段约束集合对象只能操作某种数据类型。
例:
ArrayList<String>:此集合只能操作字符串类型的元素。
ArrayList<Integer>:此集合只能操作整数类型的元素。
注意:集合中只能存储引用类型,不支持基本数据类型。
ArrayList集合常用方法
方法名称 | 说明 |
---|---|
public E get(int index) | 返回指定索引处的元素 |
public int size() | 返回集合中的元素的个数 |
public E remove(int index) | 删除指定索引处的元素,返回被删除的元素 |
public boolean remove(Object o) | 删除指定的元素,返回删除是否成功 |
public E set(int index,E element) | 修改指定索引处的元素,返回被修改的元素 |
JAVA加强
1. IDEA开发模式统一
1. 新建空工程
2. 再建模块写代码
2. 静态关键字static
2.1 static修饰成员变量
static关键字的作用
static是静态的意思,可以修饰成员变量和成员方法。
static修饰成员变量表示该成员变量只在内存中只存储一份,可以被共享访问、修改。
成员变量可以分为2类:
静态成员变量(有static修饰,属于类,内存中加载一次): 常表示如在线人数信息等需要被共享的信息,可以被共享访问。
访问方式:
类名.静态成员变量。(推荐)
对象.静态成员变量。(不推荐)
实例成员变量(无static修饰,存在于每个对象中):常表示姓名name、年龄age、等属于每个对象的信息。
2.2 static修饰成员变量的内存原理
2.3 static修饰成员方法的基本用法
成员方法的分类:
静态成员方法(有static修饰,属于类),建议用类名访问,也可以用对象访问。
实例成员方法(无static修饰,属于对象),只能用对象触发访问。
使用场景:
表示对象自己的行为的,且方法中需要访问实例成员的,则该方法必须申明成实例方法。
如果该方法是以执行一个共用功能为目的,则可以申明成静态方法。
成员方法的分类和访问分别是什么样的?
静态成员方法(有static修饰,属于类和对象共享)访问格式:
类名.静态成员方法。
对象.静态成员方法。(不推荐)
实例成员方法(无static修饰,属于对象)的访问格式:
对象.实例成员方法。
2.4 static修饰成员方法的内存原理
注:getMax方法是刚开始就有的,定义了对象之后才有study方法。
2.5 static实际应用案例:定义工具类
工具类中定义的都是一些静态方法,每个方法都是以完成一个共用的功能为目的。
工具类的好处:
一是调用方便,二是提高了代码复用(一次编写,处处可用)
为什么工具类中的方法不用实例方法做:
实例方法需要创建对象调用,此时用对象只是为了调用方法,这样只会浪费内存。
工具类的定义注意
建议将工具类的构造器进行私有,工具类无需创建对象。
里面都是静态方法,直接用类名访问即可。
2.6 static的注意事项
-
静态方法只能访问静态的成员,不可以直接访问实例成员。
-
实例方法可以访问静态的成员,也可以访问实例成员。
-
静态方法中是不可以出现this关键字的。
2.7 static应用知识:代码块
2.7.1 代码块概述
-
代码块是类的5大成分之一(成员变量、构造器,方法,代码块,内部类),定义在类中方法外。
-
在Java类下,使用 { } 括起来的代码被称为代码块 。
2.7.2 代码块分类
-
静态代码块:
-
格式:static{}
-
特点:需要通过static关键字修饰,随着类的加载而加载,并且自动触发、只执行一次
-
使用场景:在类加载的时候做一些静态数据初始化的操作,以便后续使用。
-
-
构造代码块(了解,用的少):
-
格式:{}
-
特点:每次创建对象,调用构造器执行时,都会执行该代码块中的代码,并且在构造器执行前执行
-
使用场景:初始化实例资源。
-
2.8 static应用知识:单例设计模式
什么是设计模式(Design pattern)
开发中经常遇到一些问题,一个问题通常有n种解法的,但其中肯定有一种解法是最优的,这个最优的解法被人总结出来了,称之为设计模式。
设计模式有20多种,对应20多种软件开发中会遇到的问题,学设计模式主要是学2点:
第一:这种模式用来解决什么问题。
第二:遇到这种问题了,该模式是怎么写的,他是如何解决这个问题的。
3.8.1 单例模式
-
可以保证系统中,应用该模式的这个类永远只有一个实例,即一个类永远只能创建一个对象。
-
例如任务管理器对象我们只需要一个就可以解决问题了,这样可以节省内存空间。
单例的实现方式很多
-
饿汉单例模式。
-
懒汉单例模式。
-
…
饿汉单例设计模式
在用类获取对象的时候,对象已经提前为你创建好了。
在真正需要该对象的时候,才去创建一个对象(延迟加载对象)。
设计步骤:
定义一个类,把构造器私有。
定义一个静态变量存储一个对象。
提供一个返回单例对象的方法
/** a、定义一个单例类 */ public class SingleInstance { /** c.定义一个静态变量存储一个对象即可 :属于类,与类一起加载一次 */ public static SingleInstance instance = new SingleInstance (); /** b.单例必须私有构造器*/ private SingleInstance (){ System.out.println("创建了一个对象"); } /** 必须提供一个方法返回一个单例对象 */ public static SingleInstance getInstance(){ ... return ...; } }
3. 面向对象三大特征之二:继承
什么是继承?
Java中提供一个关键字extends,用这个关键字,我们可以让一个类和另一个类建立起父子关系。
Student称为子类(派生类),People称为父类(基类 或超类)。
public class Student extends People {}
使用继承的好处:
- 当子类继承父类后,就可以直接使用父类公共的属性和方法了。因此,用好这个技术可以很好的我们提高代码的复用性,减少代码冗余,增强类的功能扩展性。
3.1 继承的设计规范、内存运行原理
继承设计规范:
子类们相同特征(共性属性,共性方法)放在父类中定义,子类独有的的属性和行为应该定义在子类自己里面。
为什么?
如果子类的独有属性、行为定义在父类中,会导致其它子类也会得到这些属性和行为,这不符合面向对象逻辑。
3.2 继承的特点
子类可以继承父类的属性和行为,但是子类不能继承父类的构造器。
Java是单继承模式:一个类只能继承一个直接父类。
Java不支持多继承、但是支持多层继承。
Java中所有的类都是Object类的子类。
1、子类是否可以继承父类的构造器?
-
不可以的,子类有自己的构造器,父类构造器用于初始化父类对象。
2、子类是否可以继承父类的私有成员?
-
可以的,只是不能直接访问。
3、子类是否可以继承父类的静态成员?
-
有争议的知识点。
-
子类可以直接使用父类的静态成员(共享)
-
但个人认为:子类不能继承父类的静态成员。(共享并非继承)
4、Java中所有类,要么直接继承了Object , 要么默认继承了Object , 要么间接继承了Object, Object是祖宗类。
3.3 继承后:成员变量、成员方法的访问特点
1、在子类方法中访问成员(成员变量、成员方法)满足:就近原则
-
先子类局部范围找
-
然后子类成员范围找
-
然后父类成员范围找,如果父类范围还没有找到则报错。
2、如果子父类中,出现了重名的成员,会优先使用子类的,此时如果一定要在子类中使用父类的怎么办?
-
可以通过super关键字,指定访问父类的成员。
3.4 继承后:方法重写
1、什么是方法重写?
-
在继承体系中,子类出现了和父类中一模一样的方法声明,我们就称子类这个方法是重写的方法。
2、方法重写的应用场景
-
当子类需要父类的功能,但父类的该功能不完全满足自己的需求时。
-
子类可以重写父类中的方法。
3、@Override重写注解
-
@Override是放在重写后的方法上,作为重写是否正确的校验注解。
-
加上该注解后如果重写错误,编译阶段会出现错误提示。
-
建议重写方法都加@Override注解,代码安全,优雅!
4、方法重写注意事项和要求
-
重写方法的名称、形参列表必须与被重写方法的名称和参数列表一致。
-
私有方法不能被重写。
-
子类重写父类方法时,访问权限必须大于或者等于父类 (暂时了解 :缺省 < protected < public)
-
子类不能重写父类的静态方法,如果重写会报错的。
3.5 继承后:子类构造器的特点
1、子类继承父类后构造器的特点:
-
子类中所有的构造器默认都会先访问父类中无参的构造器,再执行自己。
2、为什么?
-
子类在初始化的时候,有可能会使用到父类中的数据,如果父类没有完成初始化,子类将无法使用父类的数据。
-
子类初始化之前,一定要调用父类构造器先完成父类数据空间的初始化。
3、怎么调用父类构造器的?
-
子类构造器的第一行语句默认都是:super(),不写也存在。
3.6 继承后:子类构造器访问父类有参构造器
1、super调用父类有参数构造器的作用:
-
初始化继承自父类的数据。
2、如果父类中没有无参数构造器,只有有参构造器,会出现什么现象呢?
-
会报错。因为子类默认是调用父类无参构造器的。
3、如何解决?
-
子类构造器中可以通过书写 super(…),手动调用父类的有参数构造器
4、this、super使用总结
this:代表本类对象的引用;
super:代表父类存储空间的标识;
this(...)和super(…)使用注意点:
子类通过 this (...)去调用本类的其他构造器,本类其他构造器会通过 super 去手动调用父类的构造器,最终还是会调用父类构造器的。
注意:this(…) super(…) 都只能放在构造器的第一行,所以二者不能共存在同一个构造器中。
4. 面向对象进阶
4.1 包
什么是包?
包是用来分门别类的管理各种不同类的,类似于文件夹,建包利于程序的管理和维护。
建包的语法格式:package 公司域名倒写.技术名称。报名建议全部英文小写,且具备意义
建包语句必须在第一行,一般IDEA工具会帮助创建
导包
相同包下的类可以直接访问,不同包下的类必须导包,才可以使用!导包格式:import 包名.类名;
假如一个类中需要用到不同类,而这个两个类的名称是一样的,那么默认只能导入一个类,另一个类要带包名访问。
4.2 权限修饰符
什么是权限修饰符?
权限修饰符:是用来控制一个成员能够被访问的范围的。
可以修饰成员变量,方法,构造器,内部类,不同权限修饰符修饰的成员能够被访问的范围将受到限制。
权限修饰符的分类和具体作用范围:
权限修饰符:有四种作用范围由小到大(private -> 缺省 -> protected - > public )
学完权限修饰符需要具备如下能力
能够识别别人定义的成员的访问权限。
自己定义成员(方法,成员变量,构造器等)一般满足如下要求:
成员变量一般私有。
方法一般公开。
如果该成员只希望本类访问,使用private修饰。
如果该成员只希望本类,同一个包下的其他类和子类访问,使用protected修饰。
4.3 final
final的作用
final 关键字是最终的意思,可以修饰(方法,变量,类)
修饰方法:表明该方法是最终方法,不能被重写。
修饰变量:表示该变量第一次赋值后,不能再次被赋值(有且仅能被赋值一次)。
修饰类:表明该类是最终类,不能被继承。
final修饰变量的注意
final修饰的变量是基本类型:那么变量存储的数据值不能发生改变。
final修饰的变量是引用类型:那么变量存储的地址值不能发生改变,但是地址指向的对象内容是可以发生变化的。
4.4 常量
常量是使用了public static final修饰的成员变量,必须有初始化值,而且执行的过程中其值不能被改变。
常量的作用和好处:可以用于做系统的配置信息,方便程序的维护,同时也能提高可读性。
常量命名规范:英文单词全部大写,多个单词下划线连接起来。
public static final String LOGIN_NAME = “admin";
常量的执行原理:
在编译阶段会进行“宏替换”,把使用常量的地方全部替换成真实的字面量。
这样做的好处是让使用常量的程序的执行性能与直接使用字面量是一样的。
4.5 枚举
枚举是Java中的一种特殊类型
枚举的作用:"是为了做信息的标志和信息的分类"。
定义枚举类的格式:
修饰符 enum 枚举名称{ 第一行都是罗列枚举类实例的名称。 }
enum Season{ SPRING , SUMMER , AUTUMN , WINTER; }
反编译后观察枚举的特征:
Compiled from "Season.java" public final class Season extends java.lang.Enum<Season> { public static final Season SPRING = new Season(); public static final Season SUMMER = new Season(); public static final Season AUTUMN = new Season(); public static final Season WINTER = new Season(); public static Season[] values(); public static Season valueOf(java.lang.String); }
枚举的特征:
枚举类都是继承了枚举类型:java.lang.Enum
枚举都是最终类,不可以被继承。
构造器都是私有的,枚举对外不能创建对象。
枚举类的第一行默认都是罗列枚举对象的名称的。
枚举类相当于是多例模式。
5. 抽象类
在Java中abstract是抽象的意思,如果一个类中的某个方法的具体实现不能确定,就可以申明成abstract修饰的抽象方法(不能写方法体了),这个类必须用abstract修饰,被称为抽象类。
public abstract class Animal{ public abstract void run(); }
抽象的使用总结与注意事项
抽象类可以理解成类的不完整设计图,是用来被子类继承的。
一个类如果继承了抽象类,那么这个类必须重写完抽象类的全部抽象方法,否则这个类也必须定义成抽象类。
抽象类的特征、注意事项小结
有得有失: 得到了抽象方法,失去了创建对象的能力。
类有的成员(成员变量、方法、构造器)抽象类都具备
抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类
一个类继承了抽象类必须重写完抽象类的全部抽象方法,否则这个类也必须定义成抽象类。
不能用abstract修饰变量、代码块、构造器。
final和abstract是什么关系?
互斥关系
abstract定义的抽象类作为模板让子类继承,final定义的类不能被继承。
抽象方法定义通用功能让子类重写,final定义的方法子类不能重写。
什么时候使用模板方法模式?
-
当系统中出现同一个功能多处在开发,而该功能中大部分代码是一样的,只有其中部分可能不同的时候。
模板方法模式实现步骤
把功能定义成一个所谓的模板方法,放在抽象类中,模板方法中只定义通用且能确定的代码。
模板方法中不能决定的功能定义成抽象方法让具体子类去实现。
模板方法模式解决了什么问题?
-
极大的提高了代码的复用性
-
模板方法已经定义了通用结构,模 板不能确定的定义成抽象方法。
-
使用者只需要关心自己需要实现的功能即可。
6. 接口
6.1 接口的定义与特点
public interface 接口名 {
// 常量
// 抽象方法
}
-
JDK8之前接口中只能是抽象方法和常量,没有其他成分了。
-
接口不能实例化。
-
接口中的成员都是public修饰的,写不写都是,因为规范的目的是为了公开化。
6.2 接口的用法
-
接口是用来被类实现(implements)的,实现接口的类称为实现类。实现类可以理解成所谓的子类。
修饰符 class 实现类 implements 接口1, 接口2, 接口3 , ... { } 实现的关键字:implements
-
接口可以被类单实现,也可以被类多实现。
-
一个类实现接口,必须重写完全部接口的全部抽象方法,否则这个类需要定义成抽象类。
6.3 接口与接口的关系:多继承
-
类和类的关系:单继承。
-
类和接口的关系:多实现。
-
接口和接口的关系:多继承,一个接口可以同时继承多个接口。
接口多继承的作用
规范合并,整合多个接口为同一个接口,便于子类实现。
6.4 JDK8开始接口新增方法
6.4.1 第一种:默认方法
-
类似之前写的普通实例方法:必须用default修饰
-
默认会public修饰。需要用接口的实现类的对象来调用
default void run(){
System.out.println("--开始跑--");
}
6.4.2 第二种:静态方法
-
默认会public修饰,必须static修饰。
-
注意:接口的静态方法必须用本身的接口名来调用。
static void inAddr(){
System.out.println("我们都在黑马培训中心快乐的学习Java!");
}
6.4.3 第三种:私有方法
-
就是私有的实例方法:,必须使用private修饰,从JDK 1.9才开始有的。
-
只能在本类中被其他的默认方法或者私有方法访问。
private void go(){
System.out.println("--准备--");
}
注:他们都会默认被public修饰。
6.5 接口的注意事项
1、接口不能创建对象 2、一个类实现多个接口,多个接口中有同样的静态方法不冲突。 3、一个类继承了父类,同时又实现了接口,父类中和接口中有同名方法,默认用父类的。 4、一个类实现了多个接口,多个接口中存在同名的默认方法,不冲突,这个类重写该方法即可。 5、一个接口继承多个接口,是没有问题的,如果多个接口中存在规范冲突则不能多继承。
7. 面向对象三大特征之三:多态
7.1 多态概述
什么是多态?
同类型的对象,执行同一个行为,会表现出不同的行为特征。
多态的常见形式:
父类类型 对象名称 = new 子类构造器; 接口 对象名称 = new 实现类构造器;
多态中成员访问特点
方法调用:编译看左边,运行看右边。
变量调用:编译看左边,运行也看左边。(多态侧重行为多态)
多态的前提
有继承/实现关系;有父类引用指向子类对象;有方法重写。
7.2 多态的优势
-
在多态形式下,右边对象可以实现解耦合,便于扩展和维护。
-
定义方法的时候,使用父类型作为参数,该方法就可以接收这父类的一切子类对象,体现出多态的扩展性与便利。
-
多态下会产生的一个问题: 多态下不能使用子类的独有功能
7.3 多态下引用数据类型的类型转换
自动类型转换(从子到父):
子类对象赋值给父类类型的变量指向。
强制类型转换(从父到子)
此时必须进行强制类型转换:子类 对象变量 = (子类)父类类型的变量
作用:可以解决多态下的劣势,可以
实现调用子类独有的功能
。注意: 如果转型后的类型和对象真实类型不是同一种类型,那么在转换的时候就会出ClassCastException
Java建议强转转换前使用instanceof判断当前对象的真实类型,再进行强制转换
变量名 instanceof 真实类型
判断关键字左边的变量指向的对象的真实类型,是否是右边的类型或者是其子类类型,是则返回true
8. 内部类
内部类就是定义在一个类里面的类,里面的类可以理解成(寄生),外部类可以理解成(宿主)。
public class People{ // 内部类 public class Heart{ } }
内部类的使用场景、作用:
当一个事物的内部,还有一个部分需要一个完整的结构进行描述,而这个内部的完整的结构又只为外部事物提供服务,那么整个内部的完整结构可以选择使用内部类来设计。
内部类通常可以方便访问外部类的成员,包括私有的成员。
内部类提供了更好的封装性,内部类本身就可以用private protectecd等修饰,封装性可以做更多控制。
内部类的分类
-
静态内部类[了解]
-
成员内部类(非静态内部类) [了解]
-
局部内部类[了解]
-
匿名内部类(重点)
8.1 内部类之一:静态内部类
什么是静态内部类?
有static修饰,属于外部类本身。
它的特点和使用与普通类是完全一样的,类有的成分它都有,只是位置在别人里面而已。
public class Outer{
// 静态成员内部类
public static class Inner{
}
}
静态内部类创建对象的格式:
外部类名.内部类名 对象名 = new 外部类名.内部类构造器
Outer.Inner in = new Outer.Inner();
静态内部类的访问拓展:
1、静态内部类中是否可以直接访问外部类的静态成员?
-
可以,外部类的静态成员只有一份可以被共享访问。
2、静态内部类中是否可以直接访问外部类的实例成员?
-
不可以的,外部类的实例成员必须用外部类对象访问。
注意:在成员内部类中访问所在外部类对象 ,格式:外部类名.this。
8.2 内部类之二:成员内部类
什么是成员内部类?
无static修饰,属于外部类的对象。
DK16之前,成员内部类中不能定义静态成员,JDK 16开始也可以定义静态成员了。
public class Outer {
// 成员内部类
public class Inner {
}
}
成员内部类创建对象的格式:
外部类名.内部类名 对象名 = new 外部类构造器.new 内部类构造器();
Outer.Inner in = new Outer().new Inner();
成员内部类的访问拓展:
1、成员内部类中是否可以直接访问外部类的静态成员?
-
可以,外部类的静态成员只有一份可以被共享访问。
2、成员内部类的实例方法中是否可以直接访问外部类的实例成员?
-
可以的,因为必须先有外部类对象,才能有成员内部类对象,所以可以直接访问外部类对象的实例成员
8.3 内部类之三:局部内部类
局部内部类 (鸡肋语法,了解即可)
局部内部类放在方法、代码块、构造器等执行体中。
局部内部类的类文件名为: 外部类$N内部类.class。
8.4 内部类之四:匿名内部类概述
匿名内部类:
本质上是一个没有名字的局部内部类,定义在方法中、代码块中、等。
作用:方便创建子类对象,最终目的为了简化代码编写。
new 类|抽象类名|或者接口名() {
重写方法;
};
Animal a = new Animal() {
public void run() {
}
};
a. run();
特点总结:
匿名内部类是一个没有名字的内部类。
匿名内部类写出来就会产生一个匿名内部类的对象。
匿名内部类的对象类型相当于是当前new的那个的类型的子类类型。
9. 常用API
9.1 Object
Object类的作用:
Object类的方法是一切子类对象都可以直接使用的,所以我们要学习Object类的方法。
一个类要么默认继承了Object类,要么间接继承了Object类,Object类是Java中的祖宗类。
Object类的常用方法:
方法名 | 说明 |
---|---|
public String toString() | 默认是返回当前对象在堆内存中的地址信息:类的全限名@内存地址 |
public boolean equals(Object o) | 默认是比较当前对象与另一个对象的地址是否相同,相同返回true,不同返回false |
toString存在的意义
父类toString()方法存在的意义就是为了被子类重写,以便返回对象的内容信息,而不是地址信息!!
equals存在的意义
父类equals方法存在的意义就是为了被子类重写,以便子类自己来定制比较规则。
9.2 Objects
Objects是一个工具类,提供了一些方法去完成一些功能。
官方在进行字符串比较时,没有用字符串对象的的equals方法,而是选择了Objects的equals方法来比较。
@Override
public boolean equals(Object o) {
// 1、判断是否是同一个对象比较,如果是返回true。
if (this == o) return true;
// 2、如果o是null返回false 如果o不是学生类型返回false ...Student != ..Pig
if (o == null || this.getClass() != o.getClass()) return false;
// 3、说明o一定是学生类型而且不为null
Student student = (Student) o;
return sex == student.sex && age == student.age && Objects.equals(name, student.name);
}
使用Objects的equals方法在进行对象的比较会更安全。
Objects的常见方法:
方法名 | 说明 |
---|---|
public static boolean equals(Object a, Object b) | 比较两个对象的,底层会先进行非空判断,从而可以避免空指针异常。再进行equals比较 |
public static boolean isNull(Object obj) | 判断变量是否为null ,为null返回true |
9.3 StringBuilder
StringBuilder是一个可变的字符串类,我们可以把它看成是一个对象容器。
作用:提高字符串的操作效率,如拼接、修改等。
StringBuilder 构造器
名称 | 说明 |
---|---|
public StringBuilder() | 创建一个空白的可变的字符串对象,不包含任何内容 |
public StringBuilder(String str) | 创建一个指定字符串内容的可变字符串对象 |
StringBuilder常用方法
方法名称 | 说明 |
---|---|
public StringBuilder append(任意类型) | 添加数据并返回StringBuilder对象本身 |
public StringBuilder reverse() | 将对象的内容反转 |
public int length() | 返回对象内容长度 |
public String toString() | 通过toString()就可以实现把StringBuilder转换为String |
使用双引号时,字符串放在字符串常量池中。当使用加号拼接时,先创建StringBuilder对象,然后使用toString转化为String对象。
为什么拼接、反转字符串建议使用StringBuilder?
- String :内容是不可变的、拼接字符串性能差。
- StringBuilder:内容是可变的、拼接字符串性能好、代码优雅。
- 定义字符串使用String
- 拼接、修改等操作字符串使用StringBuilder
9.4 Math
Math类
包含执行基本数字运算的方法,Math类没有提供公开的构造器。
如何使用类中的成员呢?看类的成员是否都是静态的,如果是,通过类名就可以直接调用
Math 类的常用方法
方法名 | 说明 |
---|---|
public static int abs(int a) | 获取参数绝对值 |
public static double ceil(double a) | 向上取整 |
public static double floor(double a) | 向下取整 |
public static int round(float a) | 四舍五入 |
public static int max(int a,int b) | 获取两个int值中的较大值 |
public static double pow(double a,double b) | 返回a的b次幂的值 |
public static double random() | 返回值为double的随机值,范围[0.0,1.0) |
9.5 System
System也是一个工具类,代表了当前系统,提供了一些与系统相关的方法。
System 类的常用方法
方法名 | 说明 |
---|---|
public static void exit(int status) | 终止当前运行的 Java 虚拟机,非零表示异常终止 |
public static long currentTimeMillis() | 返回当前系统的时间毫秒值形式 |
public static void arraycopy(数据源数组, 起始索引, 目的地数组, 起始索引, 拷贝个数) | 数组拷贝 |
时间毫秒值
计算机认为时间是有起点的,起始时间: 1970年1月1日 00:00:00
时间毫秒值:指的是从1970年1月1日 00:00:00走到此刻的总的毫秒数,应该是很大的。 1s = 1000ms。
long time = System.currentTimeMillis(); System.out.println(time);//1575465416955
9.6 BigDecimal
BigDecimal作用
用于解决浮点型运算精度失真的问题
public static void main(String[] args) {
// 浮点型运算的时候直接+ * / 可能会出现数据失真(精度问题)。
System.out.println(0.09 + 0.01);
System.out.println(1.0 - 0.32);
System.out.println(1.015 * 100);
System.out.println(1.301 / 100);
System.out.println("-------------------------");
double c = 0.1 + 0.2;
System.out.println(c);
}
使用步骤
创建对象BigDecimal封装浮点型数据(最好的方式是调用方法)
public static BigDecimal valueOf(double val): 包装浮点数成为BigDecimal对象。
BigDecimal b1 = BigDecimal.valueOf(0.1);
BigDecima常用API
方法名 | 说明 |
---|---|
public BigDecimal add(BigDecimal b) | 加法 |
public BigDecimal subtract(BigDecimal b) | 减法 |
public BigDecimal multiply(BigDecimal b) | 乘法 |
public BigDecimal divide(BigDecimal b) | 除法 |
public BigDecimal divide (另一个BigDecimal对象,精确几位,舍入模式) | 除法 |
BigDecimal divide = bd1.divide(参与运算的对象, 小数点后精确到多少位, 舍入模式);
参数1 ,表示参与运算的BigDecimal 对象。
参数2 ,表示小数点后面精确到多少位
参数3 ,舍入模式
BigDecimal.ROUND_UP 进一法
BigDecimal.ROUND_FLOOR 去尾法
BigDecimal.ROUND_HALF_UP 四五入
9.7 日期与时间
7.9.1 Date 类
-
Date类代表当前所在系统的日期时间信息。
Date的构造器
public Date()
,创建一个Date对象,代表的是系统当前此刻日期时间。
Date的常用方法
public long getTime()
,返回从1970年1月1日 00:00:00走到此刻的总的毫秒数
时间毫秒值 -> 日期对象
public Date(long time)
,把时间毫秒值转换成Date日期对象。
public void setTime(long time)
,设置日期对象的时间为当前时间毫秒值对应的时间
7.9.2 SimpleDateFormat
时间形式一:日期类表示时间的代码:
public static void main(String[] args) { Date d = new Date(); System.out.println(d); }控制台输出:
时间形式二:时间毫秒值表示时间的代码:
public static void main(String[] args) { Date d = new Date(); long time = d.getTime(); System.out.println(time); }控制台输出:
SimpleDateFormat 类作用
-
可以去完成日期时间的格式化操作
构造器
public SimpleDateFormat(String pattern)
构造一个SimpleDateFormat,使用指定的格式
格式化方法
格式化方法 说明 public final String format(Date date) 将日期格式化成日期/时间字符串 public final String format(Object time) 将时间毫秒值式化成日期/时间字符串
格式化的时间形式的常用的模式对应关系如下
SimpleDateFormat解析字符串时间成为日期对象
案例
请计算出 2021年08月06日11点11分11秒,往后走2天14小时49分06秒后的时间是多少。
解析方法 说明 public Date parse(String source) 从给定字符串的开始解析文本以生成日期
7.9.3 Calendar
Calendar概述
Calendar代表了系统此刻日期对应的日历对象。
Calendar是一个抽象类,不能直接创建对象。
Calendar日历类创建日历对象的方法:
public static Calendar getInstance()
, 获取当前日历对象
Calendar常用方法
方法名 | 说明 |
---|---|
public int get(int field) | 取日期中的某个字段信息。 |
public void set(int field,int value) | 修改日历的某个字段信息。 |
public void add(int field,int amount) | 为某个字段增加/减少指定的值 |
public final Date getTime() | 拿到此刻日期对象。 |
public long getTimeInMillis() | 拿到此刻时间毫秒值 |
注意:calendar是可变日期对象,一旦修改后其对象本身表示的时间将产生变化。
9.8 JDK8新增日期类
从Java 8开始,java.time包提供了新的日期和时间API,主要涉及的类型有:
- 新增的API**严格区分了时刻、本地日期、本地时间**,并且,对日期和时间进行**运算更加方便**。
- 其次,新API的类型**几乎全部是不变类型**(和String的使用类似),可以放心使用**不必担心被修改**。
9.8.1 概述、LocalTime /LocalDate / LocalDateTime
LocalDate、LocalTime、LocalDateTime
他们 分别表示日期,时间,日期时间对象,他们的类的实例是不可变的对象。
他们三者构建对象和API都是通用的
构建对象的方式如下:
方法名 说明 public static Xxxx now(); 静态方法,根据当前时间创建对象 LocaDate localDate = LocalDate.now(); LocalTime llocalTime = LocalTime.now(); LocalDateTime localDateTime =LocalDateTime.now(); public static Xxxx of(…); 静态方法,指定日期/时间创建对象 LocalDate localDate1 = LocalDate.of(2099 , 11,11); LocalTime localTime1 = LocalTime.of(11, 11, 11); LocalDateTime localDateTime1 = LocalDateTime.of(2020, 10, 6, 13, 23, 43); LocalDate、LocalTime、LocalDateTime获取信息的API.
方法名 说明 public int geYear() 获取年 public int getMonthValue() 获取月份(1-12) Public int getDayOfMonth() 获取月中第几天乘法 Public int getDayOfYear() 获取年中第几天 Public DayOfWeek getDayOfWeek() 获取星期 LocalDateTime的转换API
方法名 说明 public LocalDate toLocalDate() 转换成一个LocalDate对象 public LocalTime toLocalTime() 转换成一个LocalTime对象 修改相关的API
LocalDateTime 综合了 LocalDate 和 LocalTime 里面的方法,所以下面只用 LocalDate 和 LocalTime 来举例。
这些方法返回的是一个新的实例引用,因为LocalDateTime 、LocalDate 、LocalTime 都是不可变的。
方法名 说明 plusDays, plusWeeks, plusMonths, plusYears 向当前 LocalDate 对象添加几天、 几周、几个月、几年 minusDays, minusWeeks, minusMonths, minusYears 从当前 LocalDate 对象减去几天、 几周、几个月、几年 withDayOfMonth, withDayOfYear, withMonth, withYear 将月份天数、年份天数、月份、年 份 修 改 为 指 定 的 值 并 返 回 新 的 LocalDate 对象 isBefore, isAfter 比较两个 LocalDate
9.8.2 Instant
Instant时间戳
JDK8获取时间戳特别简单,且功能更丰富。Instant类由一个静态的工厂方法now()可以返回当前时间戳。
时间戳是包含日期和时间的,与java.util.Date很类似,事实上Instant就是类似JDK8 以前的Date。
Instant和Date这两个类可以进行转换。
Instant instant = Instant.now();
System.out.println("当前时间戳是:" + instant);
Date date = Date.from(instant);
System.out.println("当前时间戳是:" + date);
instant = date.toInstant();
System.out.println(instant);
9.8.3 DateTimeFormatter
在JDK8中,引入了一个全新的日期与时间格式器DateTimeFormatter。
正反都能调用format方法。
LocalDateTime ldt = LocalDateTime.now();
System.out.println(ldt);//2021-03-01T15:09:17.444190900
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String ldtStr = ldt.format(dtf);
System.out.println(ldtStr);//2021-03-01 15:09:17
String ldtStr1 = dtf.format(ldt);
System.out.println(ldtStr1);//2021-03-01 15:09:17
9.8.4 Duration/Period
Period
在Java8中,我们可以使用以下类来计算日期间隔差异:java.time.Period
主要是 Period 类方法 getYears(),getMonths() 和 getDays() 来计算,只能精确到年月日。
用于 LocalDate 之间的比较。
LocalDate today = LocalDate.now(); System.out.println(today); // 2021-03-01 LocalDate birthDate = LocalDate.of(1995, 1, 11); System.out.println(birthDate); // 1995-01-11 Period period = Period.between(birthDate, today); System.out.printf("年龄 : %d 年 %d 月 %d 日", period.getYears(), period.getMonths(), period.getDays());
Duration
在Java8中,我们可以使用以下类来计算时间间隔差异:java.time.Duration
提供了使用基于时间的值测量时间量的方法。
用于 LocalDateTime 之间的比较。也可用于 Instant 之间的比较。
LocalDateTime today = LocalDateTime.now(); System.out.println(today); LocalDateTime birthDate = LocalDateTime.of(1990,10,1,10,50,30); System.out.println(birthDate); Duration duration = Duration.between(birthDate, today);//第二个参数减第一个参数 System.out.println(duration.toDays());//两个时间差的天数 System.out.println(duration.toHours());//两个时间差的小时数 System.out.println(duration.toMinutes());//两个时间差的分钟数 System.out.println(duration.toMillis());//两个时间差的毫秒数 System.out.println(duration.toNanos());//两个时间差的纳秒数
9.8.5 ChronoUnit
java.time.temporal.ChronoUnit
ChronoUnit类可用于在单个时间单位内测量一段时间,这个工具类是最全的了,可以用于比较所有的时间单位
LocalDateTime today = LocalDateTime.now(); System.out.println(today); LocalDateTime birthDate =LocalDateTime.of(1990,10,1,10,50,30); System.out.println(birthDate); System.out.println("相差的年数:" + ChronoUnit.YEARS.between(birthDate,today)); System.out.println("相差的月数:" + ChronoUnit.MONTHS.between(birthDate, today)); System.out.println("相差的周数:" + ChronoUnit.WEEKS.between(birthDate, today)); System.out.println("相差的天数:" + ChronoUnit.DAYS.between(birthDate, today)); System.out.println("相差的时数:" + ChronoUnit.HOURS.between(birthDate, today)); System.out.println("相差的分数:" + ChronoUnit.MINUTES.between(birthDate, today)); System.out.println("相差的秒数:" + ChronoUnit.SECONDS.between(birthDate, today)); System.out.println("相差的毫秒数:" + ChronoUnit.MILLIS.between(birthDate, today)); System.out.println("相差的微秒数:" + ChronoUnit.MICROS.between(birthDate, today)); System.out.println("相差的纳秒数:" + ChronoUnit.NANOS.between(birthDate, today)); System.out.println("相差的半天数:" + ChronoUnit.HALF_DAYS.between(birthDate, today)); System.out.println("相差的十年数:" + ChronoUnit.DECADES.between(birthDate, today)); System.out.println("相差的世纪(百年)数:" + ChronoUnit.CENTURIES.between(birthDate, today)); System.out.println("相差的千年数:" + ChronoUnit.MILLENNIA.between(birthDate, today)); System.out.println("相差的纪元数:" + ChronoUnit.ERAS.between(birthDate, today));
9.9 包装类
-
包装类其实就是8种基本数据类型对应的引用类型。
为什么提供包装类?
Java为了实现一切皆对象,为8种基本类型提供了对应的引用类型。
后面的集合和泛型其实也只能支持包装类型,不支持基本数据类型。
-
自动装箱:基本类型的数据和变量可以直接赋值给包装类型的变量。
-
自动拆箱:包装类型的变量可以直接赋值给基本数据类型的变量。
包装类的特有功能
包装类的变量的默认值可以是null,容错率更高。
可以把基本类型的数据转换成字符串类型(用处不大)
调用toString()方法得到字符串结果。
调用Integer.toString(基本类型的数据)。
可以把字符串类型的数值转换成真实的数据类型(真的很有用)
Integer.parseInt(“字符串类型的整数”)
Double.parseDouble(“字符串类型的小数”)。
9.10 正则表达式
9.10.1 正则表达式概述
正则表达式可以用一些规定的字符来制定规则,并用来校验数据格式的合法性。
9.10.2 正则表达式的使用详解
字符串对象提供了匹配正则表达式的方法
public boolean matches(String regex)
: 判断是否匹配正则表达式,匹配返回true,不匹配返回false
字符类(默认匹配一个字符)
[abc]
只能是a, b, 或c
[^abc]
除了a, b, c之外的任何字符
[a-zA-Z]
a到z A到Z,包括(范围)
[a-d[m-p]]
a到d,或m通过p:([a-dm-p]联合)
[a-z&&[def]]
d, e, 或f(交集)
[a-z&&[^bc]]
a到z,除了b和c:([ad-z]减法)
[a-z&&[^m-p]]
a到z,除了m到p:([a-lq-z]减法)
预定义的字符类(默认匹配一个字符)
.
任何字符
\d
一个数字: [0-9]
\D
非数字:[^0-9]
\ s
一个空白字符: [ \t\n\x0B\f\r]\
S
非空白字符:[^\s]
\w
[a-zA-Z_0-9] 英文、数字、下划线
\W
[^\w]
一个非单词字符
贪婪的量词(配合匹配多个字符)
X?
X , 一次或根本不
X*
X,零次或多次
X+
X , 一次或多次
X {n}
X,正好n次
X {n, }
X,至少n次
X {n,m}
X,至少n但不超过m次
System.out.println("a".matches("[abc]")); // true
System.out.println("z".matches("[abc]")); // false
System.out.println("ab".matches("[abc]")); // false
System.out.println("ab".matches("[abc]+")); //true
9.10.3 正则表达式在方法中的应用
正则表达式在字符串方法中的使用
方法名 | 说明 |
---|---|
public String replaceAll(String regex,String newStr) | 按照正则表达式匹配的内容进行替换 |
public String[] split(String regex): | 按照正则表达式匹配的内容进行分割字符串,反回一个字符串数组。 |
9.10.4 正则表达式爬取信息
String rs = "来黑马程序学习Java,电话020-43422424,或者联系邮箱" +
"itcast@itcast.cn,电话18762832633,0203232323" +
"邮箱bozai@itcast.cn,400-100-3233 ,4001003232";
// 需求:从上面的内容中爬取出 电话号码和邮箱。
// 1.定义爬取规则
String regex = "(\\w{1,}@\\w{2,10}(\\.\\w{2,10}){1,2})|" +
"(1[3-9]\\d{9})|(0\\d{2,5}-?\\d{5,15})|400-?\\d{3,8}-?\\d{3,8}";
// 2.编译正则表达式成为一个匹配规则对象
Pattern pattern = Pattern.compile(regex);
// 3.通过匹配规则对象得到一个匹配数据内容的匹配器对象
Matcher matcher = pattern.matcher(rs);
// 4.通过匹配器去内容中爬取出信息
while(matcher.find()){
System.out.println(matcher.group());
}
9.11 Arrays类
9.11.1 Arrays类概述,常用功能演示
Arrays类: 数组操作工具类,专门用于操作数组元素的。
Arrays类的常用API:
方法名 | 说明 |
---|---|
public static String toString(类型[] a) | 返回数组的内容(字符串形式) |
public static void sort(类型[] a) | 对数组进行默认升序排序 |
public static <T> void sort(类型[] a, Comparator<? super T> c) | 使用比较器对象自定义排序 |
public static int binarySearch(int[] a, int key) | 二分搜索数组中的数据,存在返回索引,不存在返回-1 |
9.11.2 Arrays类对于Comparator比较器的支持
Arrays类的排序方法
方法名 | 说明 |
---|---|
public static void sort(类型[] a) | 对数组进行默认升序排序 |
public static <T> void sort(类型[] a, Comparator<? super T> c) | 使用比较器对象自定义排序 |
自定义排序规则
-
设置Comparator接口对应的比较器对象,来定制比较规则。
-
如果认为左边数据 大于 右边数据 返回正整数
-
如果认为左边数据 小于 右边数据 返回负整数
-
如果认为左边数据 等于 右边数据 返回0
-
9.12 Lambda表达式
Lambda概述:
Lambda表达式是JDK 8开始后的一种新语法形式。
作用:简化匿名内部类的代码写法。
Lambda表达式的简化格式
(匿名内部类被重写方法的形参列表) -> {
被重写方法的方法体代码。
} 注:-> 是语法形式,无实际含义
注意:Lambda表达式只能简化函数式接口的匿名内部类的写法形式
什么是函数式接口?
首先必须是接口、其次接口中有且仅有一个抽象方法的形式
Lambda实战-简化常见函数式接口
Lambda表达式的省略规则
-
参数类型可以省略不写。
-
如果只有一个参数,参数类型可以省略,同时()也可以省略。
-
如果Lambda表达式的方法体代码只有一行代码。可以省略大括号不写,同时要省略分号!
-
如果Lambda表达式的方法体代码只有一行代码。可以省略大括号不写。此时,如果这行代码是return语句,须省略return不写,同时也必须省略";"不写
10 .集合
集合类体系结构
- Collection单列集合,每个元素(数据)只包含一个值。
- Map双列集合,每个元素包含两个值(键值对)。
10.1 Collection集合体系
Collection集合特点
List系列集合:添加的元素是有序、可重复、有索引。
ArrayList、LinekdList :有序、可重复、有索引。
Set系列集合:添加的元素是无序、不重复、无索引。
HashSet: 无序、不重复、无索引;LinkedHashSet: 有序、不重复、无索引。
TreeSet:按照大小默认升序排序、不重复、无索引。
集合对于泛型的支持
-
集合都是支持泛型的,可以在编译阶段约束集合只能操作某种数据类型
Collection<String> lists = new ArrayList<String>();
Collection<String> lists = new ArrayList<>(); // JDK 1.7开始后面的泛型类型申明可以省略不写
-
如果集合中要存储基本类型的数据怎么办?
// 存储基本类型使用包装类
Collection<Integer> lists = new ArrayList<>();
Collection<Double> lists = new ArrayList<>();
10.2 Collection集合常用API
-
Collection是单列集合的祖宗接口,它的功能是全部单列集合都可以继承使用的。
方法名称 | 说明 |
---|---|
public boolean add(E e) | 把给定的对象添加到当前集合中 |
public void clear() | 清空集合中所有的元素 |
public boolean remove(E e) | 把给定的对象在当前集合中删除 |
public boolean contains(Object obj) | 判断当前集合中是否包含给定的对象 |
public boolean isEmpty() | 判断当前集合是否为空 |
public int size() | 返回集合中元素的个数 |
public Object[] toArray() | 把集合中的元素,存储到数组中 |
10.3 Collection集合的遍历方式
10.3.1 方式一:迭代器
迭代器遍历概述
遍历就是一个一个的把容器中的元素访问一遍。
迭代器在Java中的代表是Iterator,迭代器是集合的专用遍历方式。
-
Collection集合获取迭代器
方法名称 说明 Iterator<E> iterator() 返回集合中的迭代器对象,该迭代器对象默认指向当前集合的0索引 -
Iterator中的常用方法
方法名称 说明 boolean hasNext() 询问当前位置是否有元素存在,存在返回true ,不存在返回false E next() 获取当前位置的元素,并同时将迭代器对象移向下一个位置,注意防止取出越界。