JavaSE
2023-02-20 11:28:06 2 举报
AI智能生成
Java基础知识
作者其他创作
大纲/内容
Java历史
由sun公司于1995年推出的,Java之父是詹姆斯.高斯林。2009年被Oracle收购。
Java介绍
Java是一种强类型的编程语言,Java是一种静态类型的语言,变量类型一旦被定义就不能改变
特点
面向对象
跨平台
编译与解释并存
安全稳定
社区丰富
Java源程序执行过程
java源代码经过编译器编译生成.class的字节码文件,再经过java虚拟机变成计算机可识别的机器代码
LTS(Long Time Support):长期支持版
jdk 8.0 LTS
jdk 11.0 LTS
jdk 17.0 LTS
jdk 11.0 LTS
jdk 17.0 LTS
环境配置
Windows环境下配置java环境
JAVA_HOME:JDK安装位置;
PATH:%JAVA_HOME%/bin;%JAVA_HOME%/jre/bin;
PATH:%JAVA_HOME%/bin;%JAVA_HOME%/jre/bin;
CLASSPATH:.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar;
注意:jdk1.5以上的版本,不用设置CLASSPATH环境变量,也可以正常编译和运行Java程序
Linux环境下配置java环境
1.解压jdk包
2.在/etc/profile文件的最后面加上
JAVA_HOME=/opt/jdk/jdk1.8.0_181
PATH=$JAVA_HOME/bin:$PATH
export PATH JAVA_HOME
保存退出
3.用source /etc/profile命令使环境生效
4.用java -version查看java版本
2.在/etc/profile文件的最后面加上
JAVA_HOME=/opt/jdk/jdk1.8.0_181
PATH=$JAVA_HOME/bin:$PATH
export PATH JAVA_HOME
保存退出
3.用source /etc/profile命令使环境生效
4.用java -version查看java版本
验证java安装版本号命令
java -vesion
javac -version
javac -version
第一个java程序
public class Hello{
public static void main(String[] args){
System.out.println("Hello World!");
}
}
public static void main(String[] args){
System.out.println("Hello World!");
}
}
注意:类名和文件名一致
cmd命令行执行Java程序过程
编译命令:javac Hello.java
执行命令:java Hello
其它命令
生成java文档:javadoc *.java
注释
单行注释(//)
快捷键(Ctrl+/)
多行注释(/* */)
快捷键(Ctrl+Shift+/)
文档注释(/** */)
转义字符
\n 换行
\r 回车
\t 制表符
\\ \(斜杠)
\' '(单引号)
\" "(双引号)
\r 回车
\t 制表符
\\ \(斜杠)
\' '(单引号)
\" "(双引号)
关键字
定义:赋予特殊意义的标识符,单词全部是小写
保留关键字:goto,const
标识符
含义:标识某个实体的符号
规则:使用数字,字母,下划线(_),美元符号($),不能以数字开头,不能包含空格,不能是java中的关键字,区别大小写
包名:要求全部小写,一般是公司的域名倒着写
类名:要求首字母大写,多个单词相连时,每个单词的首字母都要大写
方法和变量:一个单词时,首字母小写;多个单词时,从第二个单词开始,首字母要大写
常量:所有字母大写,多个单词相连时,使用下划线连接
变量
作用:存储一个数据的容器,可以改变里面存储的数据
声明格式:数据类型 变量名
int a;
赋值格式:变量名 = 变量值
a = 100;
声明赋值(初始化)格式:数据类型 变量名 = 变量值
int a = 100;
使用变量格式:System.out.println(a);
命名规则:
1.如果只有一个单词,可以小写
2.如果有多个单词,第一个单词小写,后面的单词都大写,也就是驼峰命名法
成员变量:
定义:在建一个类时,变量定义在类的内部,方法的外部,这样的变量称为成员变量
作用域:在整个类中
初始值:成员变量默认有初始值,可以不显示赋值就可以使用
访问修饰符:成员变量有访问修饰符和static
生存时间 :成员变量是对象的一部分,它随着对象的创建而创建,随着对象的销毁而销毁
存储位置 :如果成员变量是使用 static 修饰的,那么这个成员变量是属于类的,如果没有使用 static 修饰,这个成员变量是属于实例的。而对象存在于堆内存
局部变量:
定义:定义在类的方法的内部的变量,称为局部变量
作用域:在方法内部
初始值:局部变量没有默认初始值,必须显式的赋值,才能使用
访问修饰符:局部变量无法使用访问修饰符和static,它的访问权限跟其所在方法的权限相同
生存时间:局部变量随着方法的调用而创建,随着方法的结束而销毁
存储位置:局部变量则存在于栈内存
注意
1.变量要先声明再使用
2.是什么类型就存储什么类型数据
3.变量存在访问范围,同一范围变量名不能重复,声明只能一次,赋值可以多次
4.变量定义时可以没有初始值,但是使用时必须有初始值
5.成员变量作用在整个类中,整个类中和类的方法内部都可以使用成员变量;局部变量作用在方法内部,只能在方法内部使用
常量
格式:public final int ONE_YEAR_DAYS = 1000;
单位
比特(bit位):数据运算的最小存储单位
字节(byte):数据的最小存储单位
数据大小的单位换算
比特 bit
字节 Byte 1Byte=8bit
千字节 KB 1KB=1024B
兆字节 MB 1MB=1024KB
吉字节 GB 1GB=1024MB
太字节 TB 1TB=1024GB
字节 Byte 1Byte=8bit
千字节 KB 1KB=1024B
兆字节 MB 1MB=1024KB
吉字节 GB 1GB=1024MB
太字节 TB 1TB=1024GB
ASCII
A-Z(65-90)
a-z(97-122)
数字(48-57)
进制转换
二进制:由0,1组成,以0b开头,逢二进一
八进制:由0-7组成,以0开头
十进制:由0-9组成(常用进制)
十六进制:由0-9,A-F(10-15)组成,以0x开头,逢十六进一
八进制:由0-7组成,以0开头
十进制:由0-9组成(常用进制)
十六进制:由0-9,A-F(10-15)组成,以0x开头,逢十六进一
二进制转十进制,从右往左,每一位乘以2的次方(次方从零开始),然后相加
八进制转十进制,从右往左,每一位乘以8的次方(次方从零开始),然后相加
十六进制转十进制,从右往左,每一位乘以16的次方(次方从零开始),然后相加
八进制转十进制,从右往左,每一位乘以8的次方(次方从零开始),然后相加
十六进制转十进制,从右往左,每一位乘以16的次方(次方从零开始),然后相加
十进制转二进制,除以2,取余,从下到上
十进制转八进制,除以8,取余,从下到上
十进制转十六进制,除以16,取余,从下到上
十进制转八进制,除以8,取余,从下到上
十进制转十六进制,除以16,取余,从下到上
二进制转八进制,从右到左,以三个为一组,从右到左,每组的每一位乘以2的次方(次方从零开始),然后相加得到每组的和,总数为每组的和所组成的数(不相加)
二进制转十六进制,从右到左,以四个为一组,从右到左,每组的每一位乘以2的次方(次方从零开始),然后相加得到每组的和,总数为每组的和所组成的数(不相加)
二进制转十六进制,从右到左,以四个为一组,从右到左,每组的每一位乘以2的次方(次方从零开始),然后相加得到每组的和,总数为每组的和所组成的数(不相加)
二进制:Binary
八进制:Octal
十进制:Decimal
十六进制:Hexadecimal
八进制:Octal
十进制:Decimal
十六进制:Hexadecimal
二进制的原码、反码、补码
原码
最高位的0、1表示符号位,0表示正数,1表示负数;其余7位表示数值
反码
正数的反码等于原码
负数的反码等于它的原码的符号位不变,其余位取反
补码
正数的补码等于原码
负数的补码等于反码+1
知道一个正数,求正数数的二进制
通过十进制转二进制公式得到二进制数
知道一个正数的二进制,求十进制数
通过二进制转十进制公式得到十进制数
知道一个负数,求负数的二进制
将对应的正数的二进制位的最高位变成1得到原码,通过原码求得反码,通过反码求得补码,补码就是结果
知道一个负数的二进制(就是补码),求十进制数
知道补码,反码等于补码-1,然后取反,得到对应的二进制正数,通过二进制转十进制的公式得到十进制数,然后添负号
位运算
按位与&,都为1才为1,否则为0
按位或|,都为0才为0,否则为1
按位取反~,1就取0,0就取1
按位异或^,一样为0,不一样为1
按位或|,都为0才为0,否则为1
按位取反~,1就取0,0就取1
按位异或^,一样为0,不一样为1
<< : 左移运算符,向左移若干位,高位丢弃,低位补零
左移算法:操作数乘以2的位移次幂
例子:8 << 1,相当于 8 乘以 2的1次幂
>> : 带符号右移,向右移若干位,高位补符号位,低位丢弃。正数高位补 0,负数高位补 1
右移算法:操作数除以2的位移次幂
例子:8 >> 1,相当于 8 除以 2的1次幂。
>>> : 无符号右移,忽略符号位,高位都以 0 补齐
面试
1.求8*2的最快方式是?
使用位移:*表示乘法,所以要用左移运算符<<;2的位移次幂等于2,得位移数为1
写成:8 << 1
2.交换a,b值的最快方法?
使用三次异或
写成:a = 1;
b = 2;
a = a ^ b;
b = a ^ b;
a = a ^ b;
结果:a = 2;
b = 1;
b = 2;
a = a ^ b;
b = a ^ b;
a = a ^ b;
结果:a = 2;
b = 1;
基本数据类型和字符串之间的转换
基本数据类型转换成为字符串,3种方式
int a = 1;
double b = 1;
boolean c = true;
char d = 'e';
//第一种
String s1 = a + "";
String s2 = b + "";
String s3 = c + "";
String s4 = d + "";
double b = 1;
boolean c = true;
char d = 'e';
//第一种
String s1 = a + "";
String s2 = b + "";
String s3 = c + "";
String s4 = d + "";
//第二种
String s1 = Integer.toString(a);
String s2 = Double.toString(b);
String s3 = Boolean.toString(c);
String s4 = Character.toString(d);
String s1 = Integer.toString(a);
String s2 = Double.toString(b);
String s3 = Boolean.toString(c);
String s4 = Character.toString(d);
//第三种
String s1 = String.valueOf(a);
String s2 = String.valueOf(b);
String s3 = String.valueOf(c);
String s4 = String.valueOf(d);
String s1 = String.valueOf(a);
String s2 = String.valueOf(b);
String s3 = String.valueOf(c);
String s4 = String.valueOf(d);
字符串转换成为基本数据类型,有2种方式
String s1 = "123";
String s2 = "123.0";
String s3 = "true";
String s4 = "china"; //长度不为1的字符串
//第一种
int num1 = Integer.parseInt(s1);
double num2 = Double.parseDouble(s2);
boolean num3 = Boolean.parseBoolean(s3);
char num4 = s4.charAt(0);
String s2 = "123.0";
String s3 = "true";
String s4 = "china"; //长度不为1的字符串
//第一种
int num1 = Integer.parseInt(s1);
double num2 = Double.parseDouble(s2);
boolean num3 = Boolean.parseBoolean(s3);
char num4 = s4.charAt(0);
//第二种
int num1 = Integer.valueOf(s1);
double num2 = Double.valueOf(s2);
boolean num3 = Boolean.valueOf(s3);
char num4 = s4.charAt(0);
int num1 = Integer.valueOf(s1);
double num2 = Double.valueOf(s2);
boolean num3 = Boolean.valueOf(s3);
char num4 = s4.charAt(0);
数据类型
基本数据类型
整型(默认值为0)
类型 内存占用(字节数)
byte 1
short 2
int 4
long 8
byte 1
short 2
int 4
long 8
布尔型(默认值为false)
boolean 1
值:true、false
字符型(默认值是空格)
char 2
浮点型(默认值为0.0)
float 4
double 8
double 8
引用数据类型(默认值为null)
String
基本数据类型的包装类
类
接口
数组
枚举
特殊类型值:null
自动类型转换
类型范围小的变量,可以直接赋值给类型范围大的变量
转换等级(由小到大)
byte-short,char-int-long-float-double
强制类型转换
格式:低类型 变量名 = (低类型) 高类型的数据
double b = 100;
int a = (int)b + 0.3;
int a = (int)b + 0.3;
例子:int i = (int)100.5;
注意:类型范围大的变量转换为类型范围小的变量可能会造成精度损失,不管低类型是否全部装的下,都必须要显式的加低类型
运算符
算术运算符
二元运算符(同类型的两个元素参与运算)
+ 加
- 减
* 乘
/ 除
% 取模
- 减
* 乘
/ 除
% 取模
注意:两个元素参与运算得到的结果,结果类型是两个元素类型中最大的那一种,最小使用的类型为int类型
一元运算符(一个元素参与运算)
++ 自增
-- 自减
关系运算符
==
!=
>=
<=
>
<
!=
>=
<=
>
<
逻辑运算符
&& 短路与
|| 短路或
! 逻辑非
^ 逻辑异或
|| 短路或
! 逻辑非
^ 逻辑异或
赋值运算符
=
+=
-=
*=
/=
%=
+=
-=
*=
/=
%=
注意:如果使用了复合赋值运算符,那么数据的类型不会发生变化。
三元运算符
格式: 条件表达式 ? 值1 : 值2;
运算优先级
单目>算术运算符>关系运算符>逻辑运算符>赋值运算符
接收用户输入
格式:Scanner input = new Scanner(System.in);
int a = input.nextInt();
int a = input.nextInt();
注意:Scanner对象只需要创建一次就可以
常用API
next()方法返回的是String类型
nextInt()方法返回的是int类型
nextDouble()方法返回的是double类型
流程控制语句
顺序结构(程序默认流程)
从上到下执行
分支结构
if语句
单分支:
if(条件表达式){
语句体;
}
语句体;
}
双分支:
if(条件表达式){
语句体1;
} else {
语句体2;
}
语句体1;
} else {
语句体2;
}
多分支:
if(条件表达式1){
语句体1;
} else if(条件表达式2){
语句体2;
} else {
语句体n;
}
语句体1;
} else if(条件表达式2){
语句体2;
} else {
语句体n;
}
嵌套分支:(嵌套层次不能过多,建议不超过3层)
if(条件表达式1){
if(条件表达式3){
语句体3;
} else {
语句体4;
} else {
语句体2;
}
if(条件表达式3){
语句体3;
} else {
语句体4;
} else {
语句体2;
}
switch语句
switch(条件表达式){
case 值1:
语句体1;
break;
case 值2:
语句体2;
break;
......
case 值n:
语句体n;
break;
default:
语句体n+1;
}
case 值1:
语句体1;
break;
case 值2:
语句体2;
break;
......
case 值n:
语句体n;
break;
default:
语句体n+1;
}
注意:default下的break可以省略
注意:1.遇到判断值匹配的时候选择使用switch分支结构实现
2.遇到判断区间范围的时候选择使用if分支结构实现
2.遇到判断区间范围的时候选择使用if分支结构实现
循环结构
for循环
for (初始化语句; 循环条件; 迭代语句) {
循环体语句(重复执行的代码);
}
循环体语句(重复执行的代码);
}
while循环
初始化语句;
while(循环条件){
循环体语句(被重复执行的代码);
迭代语句;
}
while(循环条件){
循环体语句(被重复执行的代码);
迭代语句;
}
do-while循环
初始化语句;
do {
循环体语句;
迭代语句;
} while (循环条件);
do {
循环体语句;
迭代语句;
} while (循环条件);
嵌套循环
for (初始化语句; 循环条件; 迭代语句) {
for (初始化语句; 循环条件; 迭代语句) {
循环体语句(重复执行的代码);
}
}
for (初始化语句; 循环条件; 迭代语句) {
循环体语句(重复执行的代码);
}
}
无限循环
while(true){
循环语句;
}
循环语句;
}
for(int i = 1; ; i++){
循环语句;
}
循环语句;
}
for-each循环
注意:
break:中断距离最近的循环语句
contuiue:跳过最近的一个循环,继续下一个循环
方法
定义:用来对具有特定功能的一段代码进行封装,使得这种功能可以被复用
格式:
修饰符 [静态/非静态] 返回值类型 方法名(参数1,参数n,...){
方法体;
}
方法体;
}
调用:方法名();
方法的运行区域在哪里?
栈内存
main方法(程序的入口)
public static void main(String[] args){
}
}
构造方法
作用:完成对象属性的初始化
无参
public 类名(){
}
}
有参
public 类名(参数列表){
}
}
普通方法
格式
修饰符 返回值类型 方法名(形参列表){
方法体代码(需要执行的功能代码);
return 返回值;
}
方法体代码(需要执行的功能代码);
return 返回值;
}
public void 方法名(){
方法体;
}
方法体;
}
有哪些类型?
无参,无返回值
无参,有返回值,需要使用return
有参,无返回值
有参,有返回值,需要使用return
方法重载
发生在同一个类中
同一个类中的多个方法的名称要一致,形参列表(个数,顺序,类型)不一致
方法重写
当子类继承父类时,父类的方法对子类不适用,于是子类可以重写父类的方法
发生在子类和父类中
子类重写父类的方法时,方法的名称、形参列表必须与被重写方法的名称和参数列表一致;方法的返回值类型、异常必须要小于或等于被重写方法的返回值类型、异常;方法的访问修饰符必须要大于或等于被重写方法的访问修饰符;(两同两小一大)
时间复杂度顺序
O(1) < O(logn) < O(n) < O(nlogn) < O(n^2) < O(n^3) < O(2^n)
代码块
普通代码块(局部代码块):定义在方法内部
构造代码块:跟创建对象相关的代码块,与构造器相同,也起到初始化对象的作用,构造代码块先于构造器执行
{
构造代码块;
}
构造代码块;
}
静态代码块
用于对一个类中的类变量进行初始化
static {
静态代码块中的代码;
}
静态代码块中的代码;
}
当类加载的时候,静态代码块要被执行
静态代码块中不能出现实例成员变量
同步代码块
数组
定义:数组是一块连续的内存空间,用来存储一批同种类型的数据
创建:两种方式
静态初始化:int[] arr = {1, 2, 3};
动态初始化:int[] arr = new int[10];
数组的索引是从0开始的
数组的长度是用length属性
arr.length
可变参数
定义:
可变参数类型的本质就是一个数组,相比于数组来说可变参数的优势是:方便方法的调用者,无需对传入的数值进行数组的封装,只需要以逗号间隔的方式直接传递
格式:
int... a
double... b
String... s
...
递归调用
定义:自己调用自己
注意:一定要有一个出口
集合
怎么去统一ArrayList集合存储数据的类型?
- 使用泛型:<数据类型>
- 规定这个集合类型只能存储字符串数据
集合是java中存储对象数据的一种容器
特点:
- 集合的大小不固定,启动后可以动态变化,类型也可以选择不固定。集合更像气球。
- 集合非常适合做元素的增删操作。
- 集合中只能存储引用类型数据,如果要存储基本类型数据可以选用包装类
集合适合做数据个数不确定,且要做增删元素的场景
Collection的常用API
- add() 将元素插入到指定位置的 arraylist 中
- public E get(int index) 通过索引值获取 arraylist 中的元素
- public E remove(int index) 删除指定索引处的元素,返回被删除的元素
- public boolean remove(Object o) 删除指定的元素,返回是否删除成功
- public int size() 返回 arraylist 里元素数量
- public E set(int index,E element) 修改指定索引处的元素,返回被修改的元素
从集合中遍历元素,并筛选出元素删除它,应该怎么解决?
从集合后面遍历然后删除,可以避免漏掉元素
集合体系
Collection(单列集合)
单列集合,直接存储对象的引用
Collection(接口)
List(接口)
ArrayList(实现类)
LinkedList(实现类)
Vector(实现类)
Set(接口)
HashSet(实现类)
LinkedHashSet(实现类)
TreeSet(实现类)
经典代码:
List<String> list = new ArrayList<>();
Collection集合特点
List系列集合:添加的元素是有序、可重复、有索引。
ArrayList
底层使用的是数组,查询性能更好, 线程不安全,特定场景下增删性能较差
常用API
boolean add(E element) 在集合末尾添加元素
void add(int index,E element) 在指定索引位置插入元素
E get(int index) 通过索引值获取元素
int indexOf(Object o) 返回集合中指定元素第一次出现的索引,没有则返回-1
E remove(int index) 删除指定索引处的元素,返回被删除的元素
boolean remove(Object obj) 删除指定元素,返回是否成功
E set(int index,E element) 修改指定索引处的元素,返回被修改的元素
void add(int index,E element) 在指定索引位置插入元素
E get(int index) 通过索引值获取元素
int indexOf(Object o) 返回集合中指定元素第一次出现的索引,没有则返回-1
E remove(int index) 删除指定索引处的元素,返回被删除的元素
boolean remove(Object obj) 删除指定元素,返回是否成功
E set(int index,E element) 修改指定索引处的元素,返回被修改的元素
boolean addAll(Collection c) 在集合末尾添加另外一个集合的所有元素
boolean addAll(int index,Collection c) 在指定索引位置插入另外一个集合的所有元素
void clear() 删除集合中所有的元素
boolean removeAll(Collection c) 删除指定集合中的所有元素,返回是否成功
boolean addAll(int index,Collection c) 在指定索引位置插入另外一个集合的所有元素
void clear() 删除集合中所有的元素
boolean removeAll(Collection c) 删除指定集合中的所有元素,返回是否成功
LinkedList
底层使用双向链表,增删新能较好,查询性能不好
Vector
底层使用数组(线程安全的,不推荐使用)
List特有的遍历方式
for循环(因为List集合存在索引)
Set系列集合:添加的元素是无序、不重复、无索引。
HashSet:无序、不重复、无索引。
LinkedHashSet:有序、不重复、无索引。
TreeSet:按照大小默认升序排序、不重复、无索引。
Collection集合使用场景
1.如果希望元素可以重复,又有索引,索引查询要快?
- 用ArrayList集合,基于数组的。(用的最多)
2.如果希望元素可以重复,又有索引,增删首位操作快?
- 用LinkedList集合,基于链表的。
3.如果希望增删改查都快,但是元素不重复,无序,无索引?
- 用HashSet集合,基于哈希表的。
4.如果希望增删改查都快,但是元素不重复,有序,无索引?
- 用LinkHashSet集合,基于哈希表和双链表的。
5.如果要对对象进行排序?
- 用TreeSet集合,基于红黑树的。后续也可以用List集合实现排序。
Collection集合遍历的方式
迭代器
增强for循环(forEach)
Lambda表达式
三种迭代方式的删除
普通for循环,可以删除,但是需要索引
迭代器,可以删除,但是必须使用迭代器自身的remove方法,否则会出现并发修改异常
增强for循环不能删除
Map(双列集合)
Map集合是什么?使用的场景是什么样的?
- Map集合是键值对集合
- Map集合非常适合做类购物车这样的业务场景
Map集合体系
Map(接口)
HashMap(实现类)
LinkedHashMap(实现类)
HashTable(实现类)
Properties(实现类)
...(接口)
TreeMap(实现类)
经典代码
Map<String,Integer> maps = new HashMap<>();
Map集合体系特点
- Map集合的特点都是由键决定的
- Map集合的键是无序的,不重复的,无索引的,值不做要求(可以重复)
- Map集合后面重复的键对应的值会覆盖前面重复键的值
- Map集合的键值对都可以为null
Map集合常用Api
- isEmpty() 判断集合是否为空,为空返回true,反之
- get(key) 根据键获取对应值
- remove(key) 根据键删除整个元素
- containsKey(key) 判断是否包含某个键,包含返回true,反之
- containsValue(value) 判断是否包含某个值
- keySet() 获取全部键的集合,返回的是Set集合
- values() 获取全部值的集合,返回的是Collection集合
- size() 集合的大小
Map集合的遍历方式
1.使用entrySet()来遍历(很重要)
- 先把Map集合转换成Set集合,Set集合中每个元素都是键值对实体类型
- 遍历Set集合,然后提取键以及提取值
2.使用keySet()来遍历
- 先获取Map集合的全部键的Set集合
- 遍历键的Set集合,然后通过键提取对应值
3.使用values()来获取Map中的所有value
Lambda
Map集合实现类特点
HashMap:元素按照键是无序,不重复,无索引,值不做要求。(与Map体系一致)
LinkedHashMap:元素按照键是有序,不重复,无索引,值不做要求。
TreeMap:元素按照键是排序,不重复,无索引,值不做要求。
数组和集合的区别
数组和集合的元素存储的个数问题?
- 数组定义后类型确定,长度固定
集合类型可以不固定,大小是可变的
数组和集合存储元素的类型问题?
- 数组可以存储基本类型和引用类型的数据
集合只能存储引用数据类型的数据
数组和集合适合的场景?
数组适合做数据个数和类型确定的场景
- 集合适合做数据个数不确定,且要做增删元素的场景
面向对象
类和对象是什么?
类:类是一个模板,描述一类对象的行为和状态
对象:对象是类的一个实例,有状态和行为,是真实存在的具体实例,简称类的实例化;
对象:对象是类的一个实例,有状态和行为,是真实存在的具体实例,简称类的实例化;
类的语法
public class 类名 {
// 属性(0个或多个)
权限修饰符 类型 名称 = 值
// 方法(0个或多个)
权限修饰符 返回值 方法名 (){
逻辑代码
}
}
// 属性(0个或多个)
权限修饰符 类型 名称 = 值
// 方法(0个或多个)
权限修饰符 返回值 方法名 (){
逻辑代码
}
}
注意:类名的首字母大写
创建对象的语法
类名 对象名 = new 类名();
拿到对象后能做到什么?
对象.属性
对象.方法()
对象.方法()
栈中存储方法、变量;堆中存储对象;元空间存储类信息;
方法
方法中的参数传递
基本类型的参数传输存储的数据值
引用类型的参数传输存储的地址值
引用类型的参数传输存储的地址值
先有类,后有对象;有对象就一定有类,有类不一定有对象;所以成员方法可以访问静态方法和静态变量,但是静态方法不能访问成员方法和成员变量
面向对象三大特征
封装
关键字:private
概念:将对象的属性和方法封装在一起,隐藏内部细节,但提供一些对外访问的方法
继承(单继承)
关键字:extends
概念
子类继承父类的属性和方法,父类的私有属性和方法,子类只是拥有,无法直接访问
子类无法继承父类的构造方法
优点:提高代码的复用性和维护性
多态
多态的概述、形式
什么是多态?
同类型的对象,执行同一个行为,会表现出不同的行为特征。
多态的常见类型
- 父类类型 对象名 = new 子类构造器();
- 子类类型 对象名 = new 子类构造器();
- 接口 对象名 = new 实现类构造器();
- 实现类类型 对象名 = new 实现类构造器();
多态中成员访问特点
- 方法调用:编译看左边,运行看右边;
- 变量调用:编译看左边,运行也看左边;
多态的前提
有继承/实现关系;有父类引用指向子类对象;有方法重写。
多态的优势
- 在多态形势下,右边对象可以实现解耦,便于扩展和维护。
- 定义方法的时候,使用父类型作为参数,该方法就可以接收这父类的一切子类对象,体现出多态的扩展性与便利。
多态下会产生的一个问题:
多态下不能使用子类的独有功能
类型转换
自动类型转化(从子到父)(向上转型):
子类对象指向父类引用:父类类型 对象名称 = new 子类对象();
Person person = new Man();
或者
Person person = new Woman();
或者
Person person = new Woman();
强制类型转换(从父到子)(向下转型):
- 此时必须进行强制类型转换:子类类型 对象名称 = (子类类型)父类类型的变量
- 作用:可以解决多态下的劣势,可以实现调用子类独有的功能。
- 注意:如果转型后的类型和对象真实类型不是同一种类型,那么在转换的时候就会出现ClassCastException
Man man = (Man)person;
注意:向下转型的前提是必须是有一个已经向上转型的子类对象,才能将父类引用转为子类引用,可以使用强制类型转换的格式,便是向下转型
Java建议强制转换前使用instanceof判断当前对象的真实类型,再进行强制转换。
if (person instanceof Man){
Man man = (Man)person;
}
if (person instanceof Woman){
Woman woman = (Woman)person;
}
Man man = (Man)person;
}
if (person instanceof Woman){
Woman woman = (Woman)person;
}
内部类
成员内部类
普通的成员内部类
定义:内部类直接定义在类的内部,方法的外部
创建内部类的对象:外部类.内部类 对象名 = 外部类的对象.new 内部类的构造器;
静态的成员内部类
定义:静态内部类直接定义在类的内部,方法的外部,加一个static关键字
创建静态的内部类的对象:外部类.内部类 对象名 = new 外部类.内部类的构造器;
局部内部类
普通的局部内部类
定义:内部类直接定义在类中方法的内部
匿名局部内部类(匿名内部类)
定义:
匿名内部类就是内部类的简写形式,相当于是一个没有名字的子类
匿名内部类用于定义接口或者类的子类
使用:
前提是必须存在一个类,或者接口
这里的类可以是具体的类也可以是抽象类
相当于是有一个没有名字的子类继承或者实现一个类或接口,然后重写里面的方法,本质是一个继承了该类或者实现了该接口的子类匿名对象
多用于规则简单,子类使用很少的接口应用中
注意:内部类就当成外部类的属性使用即可
因为内部类可以看作外部类的属性,所以需要构建外部类对象才可以使用
例子:
访问权限修饰符
1.private 私有的,只能在同类中访问
2.default 默认权限,只能在同类,同包中访问
3.protected 受保护的,只能在同类,同包,其他包中的子类访问
4.public 公共的,任何地方都可以访问
2.default 默认权限,只能在同类,同包中访问
3.protected 受保护的,只能在同类,同包,其他包中的子类访问
4.public 公共的,任何地方都可以访问
return关键字
return:跳出并立即结束所在方法的执行
return 值:将方法的返回值返回给调用者使用
final关键字
修饰变量:表示该变量第一次赋值后,不能再次被赋值(常量必须赋初始化值有且仅能被赋值一次)
public final int NUM = 100;
静态常量:表示类的常量
public static final int NUM = 100;
- 修饰方法:表明该方法是最终方法,不能被重写,final用在返回值前面
public final void eat(){};
修饰类:表明该类是最终类,不能被继承,final用在class关键字前面
public final class A{};
final修饰成员变量
如果final修饰的是类变量,声明该类变量时就需要赋值,或者在静态初始化块中赋值
如果final修饰的是成员变量,声明该变量时就需要赋值或者可以在非静态初始化块中赋值或者构造器中赋值
final修饰局部变量
final可以修饰形参
局部变量只声明没有初始值,不会报错,与final无关,在使用前一定要赋值,但是不允许第二次赋值
final修饰基本数据类型和引用数据类型
基本数据类型,是值不能被改变
引用数据类型,是地址值不能被改变,对象中的属性可以改变
static关键字
static是静态的意思,可以修饰成员变量,表示该成员变量只在内存中只存储一次,可以被共享访问、修改
成员变量可以分为2类
静态成员变量(有static修饰,属于类,内存中加载一次):常表示如在线人数信息、等需要被共享的信息,可以被共享访问
访问方式:类名.静态成员变量
实例成员变量(无static修饰,存在于每个对象中):常表示姓名name、年龄age、等属于每个对象的信息
访问方式:对象.实例成员变量
成员方法可以分为2类
静态成员方法(有static修饰,属于类):建议用类名访问,也可以用对象访问
使用场景:如果该方法是以执行一个通用功能为目的,或者需要方便访问,则可以申明成静态方法
实例成员方法(无static修饰,属于对象):只能用对象触发访问
使用场景:表示对象自己的行为的,且方法中需要访问实例成员的,则该方法必须申明成实例方法
static访问注意实现
静态方法只能访问静态成员变量,只能访问静态方法
实例方法可以访问实例成员变量和实例方法,也可以访问静态成员变量和静态方法
静态方法中是不可以出现this关键字的,this表示的是当前对象,静态方法的加载是早于对象的创建
this关键字
定义:
表示的是当前对象,常在当前类中使用
使用:
" this.属性"表示当前属性
" this.方法(参数列表)"表示当前方法
" this()"表示调用当前类的无参构造
" this(参数列表)"表示调用当前类的带参构造
如果要在一个类中的构造方法中调用其他构造方法。如:
1.在一个类的无参构造方法中调用该类的带参构造方法,就需要在无参构造方法中写" this(带参构造的参数列表);"语句,我们可以通过不同的参数列表调用不同带参构造方法。
2.在一个类的带参构造方法中调用该类的无参构造方法,就需要在带参构造方法中写" this( ); "语句。
注意:在构造方法中使用this关键字调用其他构造方法时,this语句必须出现在构造器的首行
super关键字
定义:描述的是父类,常在子类中使用
使用:
调用父类属性
格式:super.属性
如果子类和父类中有相同的属性,需要调用父类的属性时,需要显式的用super.属性。
调用父类方法
格式:super.方法
如果子类和父类中有相同的方法,需要调用父类的方法时,需要显式的用super.方法。
调用父类构造方法
格式:
"super()"表示调用父类的无参构造方法,当创建子类对象的时候,默认会调用父类的无参构造方法
"super(参数列表)"表示调用父类的带参构造方法
注意:
1.只能在子类的构造器中使用super调用父类的构造器
2.在子类的构造过程中不管是无参构造还是带参构造,都默认会调用父类的无参构造方法,如果父类没有构造方法,可以使用super([参数列表])引入;如果也不使用super引入,则系统就会报错。
3.如果构造子类的无参构造,就使用" super( )语句"调用父类的无参构造方法;如果构造子类的带参构造,就使用" super(参数列表)"语句调用父类的带参构造参构造方法;
4.在子类的构造方法中使用super关键字调用父类构造方法时,super()必须出现在构造器的首行。因此,在一个构造器中,不能同时出现this(),super()
final和abstract是什么关系?
- 互斥关系
- abstract定义的抽象类作为模板让子类继承,final定义的类不能被继承
- 抽象方法定义通用功能让子类重写,final定义的方法子类不能重写
抽象类
标识关键字:抽象类要用abstract关键字标识
public abstract class Person{};
成员变量:可以是各种类型;
构造器:可以有0个或多个构造方法
方法:抽象类可以有0个或多个抽象方法,也可以有普通方法;抽象方法没有方法体,普通方法有方法体;若一个类中有抽象方法,此类必须标识为抽象类;
public abstract void eat();
子类继承抽象类:单继承,使用extends关键字;如果子类想要实例化就需要重写抽象类中所有的抽象方法
public class B extends A {};
抽象类不能被实例化,不能创建对象
抽象类的子类要么是抽象类,要么是实现了所有抽象方法的子类
接口
概念:接口是一个极端的抽象类,只有抽象方法和静态常量;是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为(功能)。
标识关键字:接口要用interface关键字标识;
public interface A {};
成员变量:默认是用public static final修饰的静态常量,并且必须赋值。
public static final int NUM = 100; 等价于 int NUM = 100;
构造器:没有构造器
方法:接口中的方法只能是抽象方法,默认是用public abstract修饰,没有方法体;
public abstract String eat(); 等价于 String eat();
实现类实现接口:多实现,使用implements关键字;并且需要重写接口中所有的抽象方法
pulic class B implements A {};
接口和接口之间是多继承
Object类
常用方法
hashCode()
获取该对象的哈希码,实际上就是返回一个int整数。哈希码的作用是确定该对象在哈希表中的索引位置。
不同对象的hashCode()一般来说不会相同。但是,同一个对象的hashCode()值肯定相同
toString()
返回该对象的字符串表示
默认方法返回的数据一般对我们没有意义,建议重写
JavaBean中一定要去重写,别的类中重写的概率很低
equal()
本质使用的是==
==对于基本数据类型来说,比较的是值
==对于引用数据类型来说,比较的是地址值
equals()相等两个对象 hashCode()一定相同, equals不等的两个对象, hashCode()也有可能相同
建立在equals和hashCode同步重写的情况下
Objects
对象进行内容比较的时候建议使用什么?为什么?
- 建议使用Objects提供的equals()方法
- 比较的结果是一样的,但是更安全
单例模式
懒汉单例
在真正需要该对象的时候,才去创建一个对象(延迟加载对象)
设计步骤
1.定义一个类,把构造器私有
2.定义一个静态变量存储一个对象
3.提供一个返回单例对象的方法
2.定义一个静态变量存储一个对象
3.提供一个返回单例对象的方法
public class SingleInstance {
2.private static SingleInstance instance = null;
1.private SingleInstance() {}
3.public static SingleInstance getInstance(){
if (instance == null) {
instance = new SingleInstance();
}
return instance;
}
}
2.private static SingleInstance instance = null;
1.private SingleInstance() {}
3.public static SingleInstance getInstance(){
if (instance == null) {
instance = new SingleInstance();
}
return instance;
}
}
饿汉单例
在用类获取对象的时候,对象已经提前为你创建好了
实现步骤
1.定义一个类,把构造器私有
2.定义一个静态变量存储一个对象
2.定义一个静态变量存储一个对象
public class SingleInstance {
2.public static SingleInstance instance = new SingleInstance();
1.private SingleInstance() {}
}
2.public static SingleInstance instance = new SingleInstance();
1.private SingleInstance() {}
}
枚举
枚举是一个特殊的类,其中包含了一组特定的对象,这些对象不会发生改变,一般都使用大写的标识符
枚举使用enum关键字
枚举类会将对象放置在最前面,那么和后面的语法需要使用分号隔开
枚举类不能创建对象,它的对象是在内部自行创建
enum City {
BEIJING("北京",1001),SHANGHAI("上海",1002);
City ( String name, int code ) {
this.code = code;
this.name = name;
}
public String name;
public int code;
}
BEIJING("北京",1001),SHANGHAI("上海",1002);
City ( String name, int code ) {
this.code = code;
this.name = name;
}
public String name;
public int code;
}
String(不可变)
String底层实际上是一个字符数组
String是什么?可以做什么?
字符串类型,可以定义字符串变量指向字符串对象
String是不可变字符串的原因?
Sring变量每次修改其实都是产生并指向新的的字符串对象
原来的字符串对象都是没有改变的,所以称不可变字符串
原来的字符串对象都是没有改变的,所以称不可变字符串
字符串的内容比较不适合用“==”比较,要用equal()方法
常用构造器
public String():空构造
public String(byte[] bytes):把字节数组转成字符串
public String(byte[] bytes,int index,int length):把字节数组的一部分转成字符串
public String(char[] value):把字符数组转成字符串
public String(char[] value,int index,int count):把字符数组的一部分转成字符串
public String(String original):把字符串常量值转成字符串
常用API
判断方法
public boolean equals(Object anObject); 比较此字符串与指定的对象的内容是否相同,区分大小写
public boolean equalsIgnore(String str); 比较此字符串与指定的字符串的内容是否相同,忽略大小写
public boolean contains(String str); 判断此字符串与是否包含其他字符串
public boolean startsWith(String prifix); 判断此字符串是否以指定的字符串前缀结尾
public boolean endsWith(String suffix); 判断此字符串是否以指定的字符串后缀结尾
public boolean isEmpty(); 判断此字符串是否为空
获取方法
public int length(); 获取此字符串的长度
public char charAt(int index); 获取指定索引处的字符
public int indexOf(String str/int ch); 返回指定字符串或指定字符在此字符串中第一次出现处的索引
public int indexOf(String str/int ch,int index); 返回指定字符串或指定字符在此字符串中第一次出现处的索引,从指定索引开始搜索
public int lastIndexOf(String str/int ch); 返回指定字符串或指定字符在此字符串中最后一次出现处的索引
public int lastIndexOf(String str/int ch,int index); 返回指定字符串或指定字符在此字符串中最后一次出现处的索引,从指定索引开始反向搜索
public String substring(int beginIndex); 返回一个新的字符串,它是此字符串的一个子字符串,从指定位置开始到末尾结束
public String substring(int beginIndex,int endIndex); 返回一个新的字符串,它是此字符串的一个子字符串,从指定位置开始到指定位置结束(包前不包后)
转换方法
public byte[] getBytes(); 将此字符串转换为一个新的字节数组
public char[] toCharArray(); 将此字符串转换为一个新的字符数组
public static String valueOf(char[] chs); 把字符数组转成字符串
public static String valueOf(int i); 把int类型的数据转成字符串
注意:String类的valueOf方法可以把任意类型的数据转成字符串
public String toLowerCase(); 把字符串转成小写
public String toUpperCase(); 把字符串转成大写
public String concat(String str); 把两个字符串拼接,产生一个新的字符串
替换方法
public String replace(char oldChar, char newChar);将字符串中的一部分字符用新的字符代替,产生一个新的字符串,它是通过用 newChar 替换此字符串中出现的所有 oldChar 得到的
public String replace(String oldStr, String newStr);将字符串中的一部分字符串用新的代替,产生一个新的字符串,它是通过用 newStr 替换此字符串中出现的所有 oldStr 得到的
切割方法
public String[] split(String regex); 根据给定正则表达式的匹配拆分此字符串
public String[] split(String regex, int limit); 根据给定正则表达式的匹配拆分此字符串,limit表示总共切成几段
其他方法
public String trim(); 去除字符串前后的空格
public int compareTo(String anotherString); 按字典顺序比较两个字符串的差值(不忽略大小写),结果有三种
如果是正数:说明前一个比后一个大
如果是0:说明前一个等于后一个
如果是负数:说明前一个比后一个小
public int compareToIgonreCase(String str); 按字典顺序比较两个字符串的差值(忽略大小写)
StringBuilder(可变)
为什么拼接、反转字符串建议使用StringBuilder?
- String:内容是不可变的、拼接字符串性能差。
- StringBulider:内容是可变的、拼接字符串性能好、代码优雅
- 定义字符串使用String
- 拼接、修改等操作字符串使用StringBuilder
适合在单线程的环境下使用
速度快,是线程不安全的
StringBuffer(可变)
适合在多线程的环境下使用
速度慢,是线程安全的
StringBuilder和StringBuffer共同的常用API
append(); 追加
insert(); 插入
delete(); 删除
reverse(); 反转
工具类
工具类是什么,有什么好处?
- 内部都是一些静态方法,每个方法完成一个功能
- 一次编写,处处可用,提高代码的重用性
Arrays(数组工具类)
- Arrays.toString(数组),返回字符长类型的数组内容
- Arrays.sort(数组),排序(默认对数组元素进行升序排序)
- Arrays.binarySearch(数组,要查找的元素),返回要查找的元素索引,二分搜索技术(前提数组必须排序好)
Collections(集合工具类)
sort(List<T> list)根据元素的自然顺序排序
swap(List<T> list , int i , int j)交换集合中两个角标位上的值o reverse(List<?> list )反转集合中的元素的顺序
replaceAll(List<T> list, T oldVal,T newVal)替换
Math
public static int-abs(int a):返回一个数的绝对值
public static double ceil(double a):返回大于参数的最小整数
public static double floor(double a):返回小于参数的最大整数
public static int max(int a,int b):获取最大值
public static double pow(double a,double b):计算某个数的几次幂
public static double random():获取一个大于等于0且小于1的随机数
public static int round(float a):对象小数四舍五入
public static double sqrt(double a):计算平方根
Random
public int nextInt()
public int nextInt(int n)(重点掌握):产生一个0到参数(不包括)之内的随机整数
System
public static void gc():暗示垃圾回收器运行
public static void exit(int status):虚拟机退出
public static long currentTimeMillis():获取当前时间的毫秒值
pubic static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length):复制数组
Date
public long getTime()
public void setTime(long time)
yyyy-MM-dd HH-mm-ss EEE a
年 月 日 时 分 秒 星期 上午/下午
年 月 日 时 分 秒 星期 上午/下午
Calendar
Calendar日期类是一个抽象类,不能直接实例化
public static Calendar getInstance()获取万年历对象
public int get(int field)获取时间的某个值
public void add(int field,int amount)在当前时间的基础上加上一段时间
public final void set(int year,int month,int date)设置时间点
包装类
定义:基本数据类型自身没有方法,这样就限制了我们的使用,将基本数据类型封装成对象的好处在于可以在对象中定义更多的功能方法操作该数据
对应关系
将基本数据类型转成对应的引用数据类型叫装箱
将引用数据类型转成对应的基本数据类型叫拆箱
将引用数据类型转成对应的基本数据类型叫拆箱
包装类是什么,目的是什么?
- 基本数据类型对应的引用类型
- 实现了一切皆对象
- 后期集合和泛型不支持基本类型,只能使用包装类
包装类有哪些特殊功能?
- 可以把基本类型的数据转换成字符串类型(用处不大)
- 可以把字符串类型的数值转换成真实的数据类型(真的很有用)
正则表达式
字符类(默认匹配一个字符)
- [abc] 只能是a或b或c中的一个
- [^abc] 除了a,b,c之外的任何一个字符
- [a-zA-Z] a到z A到Z
- [a-d[m-p]] a到d或m到p(表示或)
- [a-z&&[def]] a到z并且有d或e或f中的一个(表示与)
- [a-z&&[^bc]] a到z,除了b和c
- [a-z&&[^m-p]] a到z,除了m到p
预定义的字符类(默认匹配一个字符)
- . 任何一个字符
- \d 一个数字:[0-9]
- \D 非数字:[^0-9]
- \s 一个空白字符:[\t\n\xOB\f\r]
- \S 非空白字符:[^\s]
- \w 英文、数字、下划线:[a-zA-Z_0-9]
- \W 一个非单词字符[^\w]
- ^ 匹配行首
- $ 匹配行尾
- a 表示的就是a
贪婪的量词(配合匹配多个字符)
- ? 前一个字符的0次或1次
- * 前一个字符的0次或无限次
- + 前一个字符的1次或无限次
- | 左右表达式任意一个
- {m} 前一个字符的m次
- {m,} 前一个字符的至少m次
- {m,n} 前一个字符的m到n次
0 条评论
下一页