文章目录
1. 变量、数据类型转换、运算符
1.1 变量
-
变量的数据类型:
基本数据类型:4类8种
整型:byte short int long
浮点型:float double
字符型:char
布尔型:boolean引用数据类型: 类 数组 接口 枚举 注解
-
定义:
a.数据类型 变量名 = 值;b.数据类型 变量名;
变量名 = 值;c.连续定义三个相同类型的变量
数据类型 变量名1,变量名2,变量名3;
变量名1 = 值;
变量名2 = 值;
变量名3 = 值; -
【注】
字符串不属于基本数据类型,属于引用数据类型,用String表示String是一个类,只不过字符串在定义的时候可以和基本数据类型格式一样
-
float和double的区别
a. float的小数位只有23位二进制,能表示的最大十进制为2的23次方(8388608),是7位数,所以float型代表的小数,小数位能表示7位b.double的小数位只有52位二进制,能表示的最大十进制为(4 503 599 627 370 496),是16位数,所以double型代表的小数,小数位能表示出16位
小数的默认类型为:double
-
变量使用时的注意事项
1.变量不初始化(第一次赋值)不能直接使用2.在同一个作用域(一对大括号就是一个作用域)中不能定义重名的变量
3.不同作用域中的数据尽量不要随意互相访问
在小作用域中能直接访问大作用域中的变量
在大作用域中不能直接访问小作用域中的变量
1.2 数据类型转换
a.自动类型转换
将取值范围小的数据类型赋值给取值范围大的数据类型 -> 小自动转大
取值范围小的数据类型和取值范围大的数据类型数据做运算 -> 小自动转大
b.强制类型转换
当将取值范围大的数据类型赋值给取值范围小的数据类型 -> 需要强转
1.2.1强转的注意事项
-
不要随意写成强转的格式,因为会有精度损失问题以及数据溢出现象,除非没有办法
-
byte,short定义的时候如果等号右边是整数常量,如果不超出byte和short的范围,不需要我们自己强转,jvm自动转型
byte,short如果等号右边有变量参与,byte和short自动提升为int,然后结果再次赋值给byte或者short的变量,需要我们自己手动强转
-
char类型数据如果参与运算,会自动提升为int型,如果char类型的字符提升为int型会去ASCII码表(美国标准交换代码)范围内去查询字符对应的int值,如果在ASCII码表范围内没有对应的int值,回去unicode码表(万国码)中找
1.3 进制的转换
- 十进制转成二进制
辗转相除法 -> 循环除以2,取余数
- 二进制转成十进制
8421规则
- 二进制转成八进制
将二进制数分开 (3位为一组)
- 二进制转成十六进制
将二进制数分组-> 4位为一组
1.4 位运算符
- 符号的介绍:
a. &(与) -> 有假则假
b. |(或) -> 有真则真
c. ~(非) -> 取反
d. ^(异或) -> 符号前后结果一样为false,不一样为true
true ^ true -> false
false ^ false -> false
true ^ false -> true
false ^ true -> true
1.5 运算符
- 算数运算符
【注】+
1.运算
2.字符串拼接:任何类型的数据遇到字符串都会变成字符串,此时+就不再是运算了,而是字符串拼接,将内容直接往后拼接
public class Demo02Arithmetic {
public static void main(String[] args) {
int i = 10;
int j = 3;
System.out.println(i+j+"");//13
System.out.println(i+j+""+1);//131
System.out.println(i+""+j);//103
System.out.println("i和j相加只和为:"+(i+j));
}
}
1.6 三元运算符
2. 流程控制
2.1 键盘录入_Scanner
-
概述:是java定义好的一个类
-
作用:将数据通过键盘录入的形式放到代码中参与运行
-
位置:java.util
-
使用:
a.导包:通过导包找到要使用的类 -> 导包位置:类上
import java.util.Scanner -> 导入的是哪个包下的哪个类b.创建对象
Scanner 变量名 = new Scanner(System.in);c.调用方法,实现键盘录入
变量名.nextInt() 输入整数int型的
变量名.next() 输入字符串 String型的
变量名.next():录入字符串 -> 遇到空格和回车就结束录入了
变量名.nextLine():录入字符串 -> 遇到回车就结束录入了
2.2 Random随机数
-
使用:
a.导包:import java.util.Randomb.创建对象:
Random 变量名 = new Random()c.调用方法,生成随机数:
变量名.nextInt() -> 在int的取值范围内随机一个整数
2.3 switch(选择语句)
- switch基本使用
2.4 分支语句
- if的第一种格式
- if的第二种格式
- if的第三种格式
2.5 循环语句
- for循环
- while循环
- 循环控制关键字
3. 数组
3.1 数组的定义
-
动态初始化与静态初始化的区别
a. 动态初始化:定义的时候只指定了长度,没有存具体的数据
当只知道长度,但不知道具体存啥数据时可以使用动态初始化b. 静态初始化:定义的时候就直接知道存啥了
//动态初始化 int[] arr1 = new int[3]; String[] arr2 = new String[3]; //简化静态初始化 int[] arr4 = {1,2,3,4,5};
3.2 数组操作
- 获取数组的长度
3.3 一维数组内存图
- 一个数组内存图
- 俩个数组内存图
- 两个数组指向同一片内存空间
3.4 二维数组
- 定义格式
- 动态初始化
数据类型[][] 数组名 = new 数据类型[m][n] - 简化静态初始化:
数据类型[][] 数组名 = {{元素1,元素2…},{元素1,元素2…},{元素1,元素2…}}
3.5 二维数组内存图
3.6 方法的重载
4. 类与对象
4.1 一个对象的内存图
4.2 俩个对象的内存图
4.3 两个对象指向同一片空间内存图
5. 封装
5.1 private关键字
被private修饰的成员只能在本类中使用,在别的类中使用不了
属性被私有化了,外界直接调用不了了,那么此时属性就不能直接赋值取值了,所以需要提供公共的接口
get/set方法:
- set方法:为属性赋值
- get方法:获取属性值
5.2 this关键字
5.3 static关键字
6. 继承
6.1 方法的重写
注意事项:
6.2 继承构造方法
子类对象会先执行父类中的构造方法,在执行子类中的构造方法
6.3 super关键字
6.4 this关键字
6.5 继承的特点
7. 抽象
7.1 抽象介绍
7.2 抽象的注意事项
- 抽象类不能直接new对象,只能创建非抽象子类的对象
- 抽象类中不一定非得有抽象方法,但是抽象方法所在的类一定抽象类
- 抽象类的子类,必须重写父类中的所有抽象方法,否则,编译报错,除非该子类也是抽象类
- 抽象类中可以有成员变量,构造,成员方法
- 抽象类中可以有构造方法,是供子类创建对象时,初始化父类属性使用的
8. 接口
8.1 接口的定义与使用
8.2 接口中的静态方法
接口名可以直接调用
8.3 接口中的成员变量
接口名直接调用
8.4 final关键字
final代表最终的,被它修饰的变量,不能二次赋值,可以视为常量
【注】
- 被final修饰的类不能被继承
- 被final修饰的方法,不能被重写
- 被final修饰的变量不能二次赋值,需手动赋值
- 被final修饰的对象,地址值不能改变,但是对象中的属性值可以改变
8.5 接口的特点
【注】
- 当一个类实现多个接口时,如果接口中的抽象方法有重名且参数一样的,只需要重写一次
- 当一个类实现多个接口时,如果多个接口中默认方法有重名的,且参数一样的,必须重写一次默认方法
9. 多态
9.1 多态的介绍
9.2 成员变量和成员方法的调用
- 成员变量:先调用父类中的成员变量
- 成员方法:先调用子类中重写的方法,如果子类中没有重写,则调用父类中的成员方法
9.3 多态中的转型
10.权限修饰符
在Java中提供了四种访问权限,使用不同的访问权限修饰符修饰时,被修饰的内容会有不同的访问权限
访问能力:
11. 代码块
11.1 常规格式
11.2 静态代码块
12. 内部类
内部类就是在一个类中定义一个类
12.1 静态成员内部类
12.2 匿名内部类
所谓的匿名内部类,可以理解为没有显式声明出类名的内部类
12.3 匿名内部类复杂用法_当参数传递
12.4 匿名内部类复杂用法_当返回值返回
13. 异常
13.1 异常介绍
- 概述:代码出现了不正常的现象;在java中,异常都是一个一个的类
13.2 异常出现的过程:
13.3 异常处理方式(重点)
- 异常处理方式一_throws
- 异常处理方式一_throws多个异常
- 异常处理方式二_try…catch
- 异常处理方式二_多个catch
13.4 finally关键字
13.5 抛异常时注意的事项
- 如果父类中的方法抛了异常,那么子类重写之后要不要抛?
可抛可不抛 - 如果父类中的方法没有抛异常,那么子类重写之后要不要抛?
不要抛
14. Object类
概述:所有类的根类(父类),所有的类都会直接或者间接继承Object类
14.1 Object中的toString
14.2 Object中的equals
【注】
- 创建类对象时,调用的是object类中的equals方法
- 创建字符串对象时,调用的是重写的equals方法
15. String
15.1 String介绍
15.2 String的实现原理
字符串定义完之后,数组就创建好了,被final一修饰,数组的地址值直接定死
15.3 String 面试题
public class Demo04String {
public static void main(String[] args) {
String s1 = "abc";
String s2 = "abc";
String s3 = new String("abc");
System.out.println(s1==s2);//true
System.out.println(s1==s3);//false
System.out.println(s2==s3);//false
}
}
- 问1:String s = new String(“abc”)共有几个对象? 2个
15.4 字符串常见问题
-
字符串拼接,如果等号右边是字符串字面值拼接,不会产生新对象
-
字符串拼接,如果等号右边有变量参数拼接,会产生新字符串对象
15.5 String的方法
- 判断方法
boolean equals(String s) -> 比较字符串内容
boolean equalsIgnoreCase(String s) -> 比较字符串内容,忽略大小写 - 获取功能
int length() -> 获取字符串长度
String concat(String s)-> 字符串拼接,返回新串儿
char charAt(int index) -> 根据索引获取对应的字符
int indexOf(String s) -> 获取指定字符串在大字符串中第一次出现的索引位置
String subString(int beginIndex) -> 截取字符串,从指定索引开始截取到最后,返回新串儿
String subString(int beginIndex,int endIndex) -> 截取字符串,从beginIndex开始到endIndex结束
含头不含尾,返回新串儿
public class Demo04String {
public static void main(String[] args) {
String s1 = "abcdefg";
//int length() -> 获取字符串长度
System.out.println(s1.length());
//String concat(String s)-> 字符串拼接,返回新串儿
System.out.println(s1.concat("haha"));
//char charAt(int index) -> 根据索引获取对应的字符
System.out.println(s1.charAt(0));
//int indexOf(String s) -> 获取指定字符串在大字符串中第一次出现的索引位置
System.out.println(s1.indexOf("a"));
//String subString(int beginIndex) -> 截取字符串,从指定索引开始截取到最后,返回新串儿
System.out.println(s1.substring(3));
//String subString(int beginIndex,int endIndex) -> 截取字符串,从beginIndex开始到endIndex结束
//含头不含尾,返回新串儿
System.out.println(s1.substring(1,6));
}
}
- 转换功能
1.char[] toCharArray() -> 将字符串转成char数组
2.byte[] getBytes() -> 将字符串转成byte数组
3.String replace(CharSequence c1,CharSequence c2)-> 替换字符
CharSequence->String的接口
4.byte[] getBytes(String charsetName) -> 按照指定的编码将字符串转成byte数组
public class Demo06String {
public static void main(String[] args) throws UnsupportedEncodingException {
String s = "abcdefg";
//1.char[] toCharArray() -> 将字符串转成char数组
char[] chars = s.toCharArray();
System.out.println("===============");
//2.byte[] getBytes() -> 将字符串转成byte数组
byte[] bytes = s.getBytes();
System.out.println("===============");
//3.String replace(CharSequence c1,CharSequence c2)-> 替换字符 CharSequence->String的接口
System.out.println(s.replace("a","z"));
System.out.println("===============");
}
}
- 分割功能
1.String[] split(String regex)->按照指定的规则分割字符串
注意:regex写的是正则表达式 -> . 在正则表达式中代表任意一个字符
public class Demo08String {
public static void main(String[] args) {
String s = "abc,txt";
String[] split = s.split(",");
System.out.println("===============");
String s2 = "haha.hehe";
String[] split1 = s2.split("\\.");
}
}
- 其他方法
1.boolean contains(String s) -> 判断老串儿中是否包含指定的串儿
2.boolean endsWith(String s) -> 判断老串儿是否以指定的串儿结尾
3.boolean startsWith(String s) -> 判断老串儿是否以指定的串儿开头
4.String toLowerCase()-> 将字母转成小写
5.String toUpperCase() -> 将字母转成大写
6.String trim() -> 去掉字符串两端空格
public class Demo09String {
public static void main(String[] args) {
String s = "abcdefg";
//1.boolean contains(String s) -> 判断老串儿中是否包含指定的串儿
System.out.println(s.contains("a"));
//2.boolean endsWith(String s) -> 判断老串儿是否以指定的串儿结尾
System.out.println(s.endsWith("g"));
//3.boolean startsWith(String s) -> 判断老串儿是否以指定的串儿开头
System.out.println(s.startsWith("a"));
//4.String toLowerCase()-> 将字母转成小写
System.out.println("ADbcda".toLowerCase());
//5.String toUpperCase() -> 将字母转成大写
System.out.println("dafadRWERW".toUpperCase());
//6.String trim() -> 去掉字符串两端空格
System.out.println(" hadfhad hdsfha sfhdsh ".trim());
System.out.println("==================");
// 去掉空格
System.out.println(" hadfhad hdsfha sfhdsh ".replace(" ",""));
}
}
15.6 StringBuilder类
- StringBuilder的介绍
1.概述:一个可变的字符序列,此类提供了一个与StringBuffer兼容的一套API,但是不保证同步(线程不安全,效率高)
2.作用:主要是字符串拼接
3.问题:
a.刚讲完String,String也能做字符串拼接,直接用+即可,但是为啥还要用StringBuilder去拼接呢?
b.原因:
String每拼接一次,就会产生新的字符串对象,就会在堆内存中开辟新的空间,如果拼接次数多了,会占用内存,效率比较底
StringBuilder,底层自带一个缓冲区(没有被final修饰的byte数组)拼接字符串之后都会在此缓冲区中保存,在拼接的过程中,不会随意产生新对象,节省内存
4.StringBuilder的特点:
a.底层自带缓冲区,此缓冲区是没有被final修饰的byte数组,默认长度为16
b.如果超出了数组长度,数组会自动扩容
创建一个新长度的新数组,将老数组的元素复制到新数组中,然后将新数组的地址值重新赋值给老数组
c.默认每次扩容老数组的2倍+2
如果一次性添加的数据超出了默认的扩容数组长度(2倍+2),比如存了36个字符,超出了第一次扩容的34,就按照实际数据个数为准,就是以36扩容
- StringBuilder的使用
常用方法:
StringBuilder append(任意类型数据) -> 字符串拼接,返回的是StringBuilder自己
StringBuilder reverse()-> 字符串翻转,返回的是StringBuilder自己
String toString() -> 将StringBuilder转成String-> 用StringBuilder拼接字符串是为了效率,为了不占内存,那么拼完之后我们后续可能会对拼接好的字符串进行处理,就需要调用String中的方法,所以需要将StringBuilder转成String
public class Demo02StringBuilder {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder();
StringBuilder sb1 = sb.append("张无忌");
System.out.println(sb1);
System.out.println(sb);
System.out.println(sb==sb1);
System.out.println("==============");
//链式调用
sb.append("赵敏").append("周芷若").append("小昭");
System.out.println(sb);
sb.reverse();
System.out.println(sb);
String s = sb.toString();
System.out.println(s);
}
}
16. 多线程
16.1 创建线程的方式(重点)
- 第一种方式_extends Thread
1.定义一个类,继承Thread
2.重写run方法,在run方法中设置线程任务(所谓的线程任务指的是此线程要干的具体的事儿,具体执行的代码)
3.创建自定义线程类的对象
4.调用Thread中的start方法,开启线程,jvm自动调用run方法
俩个线程交替执行:
public class Test01 {
public static void main(String[] args) {
//创建线程对象
MyThread t1 = new MyThread();
//调用start方法,开启线程,jvm自动调用run方法
t1.start();
for (int i = 0; i < 10; i++) {
System.out.println("main线程..........执行了"+i);
}
}
}
public class MyThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("MyThread...执行了"+i);
}
}
}
- 多线程在内存中的运行原理
注意:同一个线程对象不能连续调用多次start,如果想要再次调用start,那么咱们就new一个新的线程对象
- Thread类中的方法
void start() -> 开启线程,jvm自动调用run方法
void run() -> 设置线程任务,这个run方法是Thread重写的接口Runnable中的run方法
String getName() -> 获取线程名字
void setName(String name) -> 给线程设置名字
static Thread currentThread() -> 获取正在执行的线程对象(此方法在哪个线程中使用,获取的就是哪个线程对象)
static void sleep(long millis)->线程睡眠,超时后自动醒来继续执行,传递的是毫秒值
问题:为啥在重写的run方法中有异常只能try,不能throws
原因:继承的Thread中的run方法没有抛异常,所以在子类中重写完run方法之后就不能抛,只能try
- Thread中其他的方法
void setPriority(int newPriority) -> 设置线程优先级,优先级越高的线程,抢到CPU使用权的几率越大,但是不是每次都先抢到
int getPriority() -> 获取线程优先级
void setDaemon(boolean on) -> 设置为守护线程,当非守护线程执行完毕,守护线程就要结束,但是守护线程也不是立马结束,当非守护线程结束之后,系统会告诉守护线程人家结束了,你也结束吧,在告知的过程中,守护线程会执行,只不过执行到半路就结束了
static void yield() -> 礼让线程,让当前线程让出CPU使用权
void join() -> 插入线程或者叫做插队线程
-
守护线程:例子
-
礼让线程
场景说明:如果两个线程一起执行,可能会执行一会儿线程A,再执行一会线程B,或者可能线程A执行完毕了,线程B在执行那么我们能不能让两个线程尽可能的平衡一点 -> 尽量让两个线程交替执行
- 第二种方式_实现Runnable接口
1.创建类,实现Runnable接口
2.重写run方法,设置线程任务
3.利用Thread类的构造方法:Thread(Runnable target),创建Thread对象(线程对象),将自定义的类当参数传递到Thread构造中 -> 这一步是让我们自己定义的类成为一个真正的线程类对象
4.调用Thread中的start方法,开启线程,jvm自动调用run方法
public class Test01 {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
/*
Thread(Runnable target)
*/
Thread t1 = new Thread(myRunnable);
//调用Thread中的start方法,开启线程
t1.start();
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+"...执行了"+i);
}
}
}
public class MyRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+"...执行了"+i);
}
}
}
- 两种实现多线程的方式区别
1.继承Thread:继承只支持单继承,有继承的局限性
2.实现Runnable:没有继承的局限性, MyThread extends Fu implements Runnable
面试
1. 形式参数和实际参数区别
- 形式参数(形参):在定义方法的时候形式上定义的参数,此参数还没有值
- 实际参数(实参):在调用方法的时候给形参赋予的具体的值
2. 成员变量和局部变量的区别
3. 面向对象三大特征?
- 封装
- 继承
- 多态
4. 接口与抽象类的区别
5. 多态方式与原始new对象的区别
6. finally的使用场景
-
关闭资源
-
原因:对象如果没有用了,GC(垃圾回收器)回收,用来回收堆内存中的垃圾,释放内存,但是有一些对象GC回收不了,比如:连接对象(Connection),IO流对象,Socket对象,这些对象GC回收不了,就需要我们自己手动回收,手动关闭
将来不能回收的对象new完之后,后续操作不管是否操作成功,是否有异常,我们都需要手动关闭,此时我们就可以将关闭资源的代码放到finally中
7. StringBuilder和StringBuffer区别
a. 相同点:
用法一样,作用一样
b. 不同点:
StringBuilder:拼接效率比StringBuffer高,线程不安全
StringBuffer:效率比较底,线程安全
拼接效率:StringBuilder>StringBuffer>String
工具的使用
1. IDEA的创建流程
先创建project,在project下创建module,在module下创建package -> 必须记住