Java基础(一):编译和解释、数据类型、变量作用域、String常用方法、数组、面向对象、异常
Java基础(二):集合、IO流(Zip压缩输入/输出流等)、File文件类、反射、枚举
Java异常、继承结构、处理异常、自定义异常、SpringBoot中全局捕获处理异常
Java–JUC之CountDownLatch、Semaphore以及CyclicBarrier
Java多线程基本概念、线程的创建方式(有、无返回值)、常用方法、synchronized锁、线程安全问题、死锁以及如何避免
Java基础(一)
编译和解释
Java语言编写的程序既是编译型的,又是解释型的。源码编译之后成为字节码文件,JVM可以对字节码文件进行解释和运行。编译只需要执行一次,解释是在每次程序运行时都会进行。JVM虚拟机将.class(字节码文件)解释为机器码,然后在计算机上运行(CPU执行只能读懂二进制的机器码)。
版本
- Java SE:标准版,包含java基础,JDBC,IO,网络通信,多线程等,主要用于桌面应用开发
- Java EE:企业版,应用于企业级分布式的网络程序,核心是EJB(企业Java组件模型,后面使用spring的javaBean容器代替了EJB)
- Java ME:主要应用于嵌入式系统开发,掌上电脑,手机等移动通信电子设备。
数据类型
整型
整数类型为 byte,short、int、long 4种类型,有各自的取值范围,若定义时超过了各自的取值范围,那么会报错的。对于long类型,若赋的值大于 int类型的最大值或小于int类型的最小值,那么需要在后面加 L
或者l
,表示该数值为long类型。
浮点数
浮点数有单精度浮点数(float
)和双精度浮点数(double
),取值范围不相同。
牢记:默认情况下小数都是被看做是double类型的
,若要使用float型小数,那么需要在数值的后面加上 F
或者f
。也可以使用后缀D
或d
来表示是一个double类型,当然不加也可以,因为是默认的。
字符类型
-
char型,用于存储单个字符,空间占位16位(2个字节),值只能是单个字符。如
char x ='a';
其中字符a在unicode(码表)表中排位97,所以可以写成char x = 97;
。java中也可以将字符当做整数来对待,unicode码表中存储着65536个字符,可以通过字符排序位置来获取到相应的字符,如int a = 44332; // 直接获取在unicode码表中位置是44332的字符 System.out.println((char) a);
-
转义字符
转义字符是以
\
开头,后面跟一个或多个字符。如换行\n
、一个垂直制表符\t
,反斜杠字符\\
布尔类型
通过关键字boolean定义变量,只有true和false两个值,默认值是false。
常量
常量是指被final
修饰的变量,常量只能被赋值一次,且必须在声明时就赋值,否则编译不过。而且,对于基本数据类型来讲final修饰的变量,值是不能改变的,而对于引用数据类型来讲,只有引用不能变,假如要修改对象内部的属性还是可以做到的
。常量的名称尽量大写。
变量作用域(有效范围)
变量的作用域分为成员变量
和局部变量
。
成员变量
成员变量被定义在类中、方法外部,分为类变量(static修饰)和实例变量。类变量是属于整个Class类的,调用者可以通过类名.变量名
方式调用,而实例变量是属于某个实例的,也就是每个实例都会有自己的实例变量,互不干扰。
局部变量
定义在类中、方法内部,包括方法参数都是局部变量,局部变量只作用域当前方法内部,外部无法访问。且生命周期仅在方法执行期间,方法执行完毕后,这些局部变量都会被回收。
成员变量和局部变量的区别
- 定义位置不同,成员变量定义于类中方法外,局部变量定义于类中方法内
- 生命周期不同,成员变量中类变量是伴随着Class类信息被加载进JVM时就一直存在直到程序结束;实例变量是伴随着对象的产生和死亡;局部变量是随着方法的执行和执行完毕
- 初始化机制不同,成员变量可以没有初始值,那么会被赋予默认值,但是局部变量在使用前必须赋值,否则编译报错
- 作用域不同,成员变量是全局性的,局部变量是局部的(只在方法内部被访问)
逻辑运算符
- &、&&: &是逻辑与,&&是短路与,区别:&条件中的表达式都会被执行,&&条件中的表达式如果前者返回值为false,那么后面的条件表达式不再执行
- |、||: |是逻辑或,||是短路或,区别:|条件中的表达式都会被执行,||条件中的表达式如果前者返回值true,那么后面的条件表达式不再执行
- ! : 取反
String常用方法
-
length()
-
indexOf()、lastIndexOf()
-
charAt()获取指定索引位置的字符
-
subString()
-
trim()
-
replace()、replaceAll()
-
contains()是否包含字符串
-
startsWith()是否以
..
字符串开头、endsWith()是否以...
字符串结尾 -
equals()、equalsIngnoreCase()忽略大小写比较字符串
-
split()分割字符串,以
...
字符串进行分割 -
format(),格式化字符串,是一个静态方法
StringBuffer和StringBuilder
过多操作字符串时,尽量采用StringBuffer或StringBuilder类来进行操作,因为如果使用String,每次字符串拼接时使用+
可以达到目的,但是产生一个新的String的实例,会在内存中创建字符串对象。
多线程时采用StringBuffer安全性高,单线程使用StringBuilder效率高
数组
基础
数组是引用数据类型,在堆内存中开辟一块空间。定义方式有两种,一种是动态的,一种是静态的。动态是指声明完数组后,动态使用下标赋值数据,静态是声明时就将数据给定义好
// 动态写法
int[] a = new int[3];
a[0] = 1;
a[1] = 2;
a[2] = 3;
// 静态写法
int[] b = new int[]{1,2,3};
要注意:如果是基本数据类型的数组,默认值都是该基本数据类型的默认值,如果是引用数据类型的数组,那么数组中元素的默认值都是 null
。
- Arrays.fill(),填充替换数组中的元素(可指定下标范围或全部),会将数组中的值给替换掉。
- Arrays.sort(),数组排序,基本数据类型就是按照值进行排序,引用类型按照算法实现(一般就是实现了Comparable,重写compareTo方法定义排序规则)
- Arrays.copyOf(),Arrays.copyOfRange(),复制全部/下标范围的数组
- Arrays.binarySearch(),二分查询法查询元素在数组中的位置
排序:冒泡排序
public class BubbleSortTest {
public static void main(String[] args) {
int[] arr = new int[]{24, 32, 65, 2, 13};
BubbleSort.sort(arr);
}
}
class BubbleSort {
static void sort(int[] arr) {
// 控制轮数(数组数量-1次)
for (int i = 1; i < arr.length; i++) {
// 控制比较的次数,每一轮比较的次数逐渐减少的,因为最末尾的数一个个被确定好了
for (int j = 0; j < arr.length - i; j++) {
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
System.out.println(Arrays.toString(arr));
}
}
排序:直接选择排序
与冒泡排序不同,直接选择排序是从待排序的数组中直接找出最大或最小值进行排序。
public class SelectSortTest {
public static void main(String[] args) {
int[] arr = new int[]{32, 45, 13, 44, 26};
SelectSort.sort(arr);
}
}
class SelectSort {
static void sort(int[] arr) {
// 外层控制轮数(数组数量-1)
for (int i = 1; i < arr.length; i++) {
int index = 0;
// 内层控制比较次数,每次比较的次数都会递减,因为最大值已经被确认好了
for (int j = 1; j <= arr.length - i; j++) {
if (arr[j] > arr[index]) {
index = j;
}
}
// 每一轮找出最大值的 索引,然后直接替换
int temp = arr[arr.length - i];
arr[arr.length - i] = arr[index];
arr[index] = temp;
}
System.out.println(Arrays.toString(arr));
}
}
排序:反转排序
就是将数组中的所有元素反转过来。思想比较简单:思路就是把数组中最后一个元素和第一个元素位置替换,假如数组中个数是奇数,那么有一个元素就不需要进行替换.
public class ReverseTest {
public static void main(String[] args) {
int[] arr = new int[]{10, 20, 30, 40, 50};
Reverse.sort(arr);
}
}
class Reverse {
static void sort(int[] arr) {
// 替换 数组的二分之一次
for (int i = 0; i < arr.length / 2; i++) {
int temp = arr[i];
arr[i] = arr[arr.length - 1 - i];
arr[arr.length - 1 - i] = temp;
}
System.out.println(Arrays.toString(arr));
}
}
面向对象
三大特性
- 封装
- 继承
- 多态
权限修饰符
修饰符 | 本类 | 同包 | 子类 | 其他包 |
---|---|---|---|---|
public | √ | √ | √ | √ |
protected | √ | √ | √ | × |
friendly(default) | √ | √ | × | × |
private | √ | × | × | × |
对象的比较
- ==:直接比较引用地址是否相同
- equals:一般对象可重写equals方法自定义比较规则,默认是Object的equals方法,就是比较地址
对象的销毁
每个对象都有生命周期,当对象的生命周期结束时,分配给该对象的内存地址将会被回收,Java中会自动进行垃圾回收,什么样的对象会被视为垃圾呢?
- 对象引用超过其作用范围时(感觉可以理解为在方法内部定义的,并且使用完了)
- 对象的引用设置为
null
时
gc(垃圾回收)只能回收由new
创建的对象,如果某些对象不是通过new创建并在内存中获取的内存,这种对象可能无法被gc机制识别;Object类中提供了一个finalize()
方法,开发者可以重写这个方法,垃圾回收时会先调用对象的finalize()
,并且下一次垃圾回收时,真正回收对象占用的内存。
包装类
包装类是对byte、int、boolean等基本数据的包装,包装类是引用数据类型,默认值是null
。包装类提供了更多操作数据的方法
基本数据类型和包装类之间的转换被称为装拆箱
:
- 装箱:基本数据类型—>包装类
- 拆箱:包装类—>基本数据类型
常用方法:
-
xxxValue:转为指定的基本数据类型,如intValue()…
-
xxx.valueOf():将字符串转为指定的基本数据类型,如Integer.valueOf(“”);
-
String.valueOf():将指定的数据转为String类型
涉及到数学计算的尽量使用BigDecimal类,并且避免使用new BigDecimal(0.1)的方式,尽量使用BigDecimal.valueOf("0.1")
的方式。
Math数学工具类
Math工具类提供了基于数学运算的方法和一些常用的数学常量,如PI、E等。
常用方法:
- 一些三角函数的方法:sign(),cos(),tan()…
- 指数函数:exp()、log()…
- 取整函数:ceil()、floor()、round()…
- 最大、最小值、绝对值:max()、min()、abs()
- Math.random()随机数:生成0~1之间的一个double类型的数据
抽象类和接口
相同点:
- 抽象类和接口都是不能实例化
- 由子类继承/实现,重写抽象方法
不同点:
- 抽象类中可以定义普通方法,接口中只能定义抽象方法,
和一些default、static修饰的方法
- 抽象类是被单继承,接口可以被多实现
- 抽象类中可以定义普通变量,接口中定义的都是
静态常量
题:如果C类想要有A类和B类中的特性,那么需要A、B类产生父子关系,然后C类继承自即可。
final的作用
- final修饰变量,表示是常量
- final修饰方法,表示方法不能被重写
- final修饰类,表示此类是不可变类,且无法被继承。
异常
基础
首先异常类的父类Throwable
类,子类有Error
和Exception
,其中Error为系统级别的错误,为不可控的错误,无法通过调优方式缓解,多为代码问题需要优化。Exception
中的子类RuntimeException
和其他异常类,RuntimeException是指在程序运行期间出现的问题,指的是非受查异常,编译器不会进行检查这种异常,需要开发者自行检测和处理(捕获异常处理,或抛出异常交给调用者处理);其他类异常指的就是受查异常,编译器会进行检查这种异常,并且强制开发者处理或抛出此异常。
需要注意的一点:程序运行中出现了异常,但是没有进行捕获处理时,程序将会停止运行!!!
,所以一般在SpringBoot中都会有全局异常处理。
系统级别的错误:
- OOM等
受查异常:
- IOException
- SQLException
非受查异常:
- RuntimeException子类:数组越界、空指针、非法参数…
处理异常
处理异常可以使用: try-catch、try-catch-finally进行捕获异常,捕获到异常后可以选择继续抛出异常或者处理,但是千万不要把异常给偷偷吃掉
,否则后期调试就是调试地狱。
简单捕获处理。
public static void main(String[] args) {
try {
int i = 5 / 0;
System.out.println(i);
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("执行完毕了");
}
}
其中要注意finally
- 假如方法中有返回值,而在finally中写了
return
语句,不出意外的情况下一定是走的finally的return 方法中有返回值,finally中没写return,但是有修改要return的变量,如果是基本数据类型,在finally中修改要return的变量是无用的,而如果是引用数据类型,finally中修改对象的某个属性值却是完全没问题的。
什么情况下finally不会执行?
- finally语句块中出现了异常
- System.exit()手动退出程序了
- 程序所在的线程死亡
- CPU关闭了
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/48377.html