java总结
1.面向对象课程总结
1.1 变量的命名
必须以字母,下划线或$字符开头,不能以数字开头
英文字母大小写敏感,长度不限
不能含有java的关键字
不能含有空格
类名字母第一个大写
用做变量的标识符第二个单词的首个字母大写
常量的标识符全大写
1.2 面向对象
面向对象是一种符合人类思维习惯的编程思想。现实生活中存在各种形态不同的事物,这些事物之间存在着各种各样的联系。
在程序中使用对象来映射现实中的事物,使用对象的关系来描述事物之间的联系,这种思想就是面向对象。
面向过程就是分析解决问题所需要的步骤,面向对象则是把解决的问题按照一定规则划分为多个独立的对象,然后通过调用对象的方法来解决问题。
面向对象的特点主要可以概括为封装性、继承性和多态性。
1.3 类的定义
类是对某一类事物的抽象描述,而对象用于表示现实中该类事物的个体
1.4 类与对象的关系
类是对象的类型,对象是类的事例
1.5 封装
所谓类的封装是指在定义一个类时,将类中的属性私有化,即使用private关键字来修饰,私有属性只能在它所在类中被访问,为了能让外界访问私有属性,需要提供一些使用public修饰的公有方法,其中包括用于获取属性值的getXxx方法和设置属性值的setXxx方法
1 | |
1.6 一般方法
一般方法是用于执行各种任务的普通方法
1.7 构造方法
在Java中,构造方法是一种特殊类型的方法,它用作进行对象实例化,一般用于给成员变量赋初值
在一个类中定义的方法如果同时满足以下三个条件,该方法称为构造方法,具体如下:
方法名和类名相同
方法名的前面没有返回值类型的声明
方法中不能使用return语句返回一个值
与普通方法一样,构造方法也可以重载,在一个类中可以定义多个构造方法,只要每个构造方法的参数类型或参数个数不同即可
在Java中的每个类都至少有一个构造方法,如果在一个类中没有定义构造方法,系统会自动为这个类创建一个默认的构造方法,这个默认的构造方法没有参数,在其方法体中没有任何代码,即什么也不做。如果为该类定义了构造方法,系统就不再提供默认的构造方法了
通过this关键字可以明确地去访问一个类的成员变量,解决与局部变量名称冲突问题
构造方法是在实例化对象时被Java虚拟机自动调用的,在程序中不能像调用其它方法一样去调用构造方法,但可以在一个构造方法中使用“this([参数1,参数2…])”的形式来调用其它的构造方法通过this关键字调用成员方法
1、只能在构造方法中使用this调用其它的构造方法
2、在构造方法中,使用this调用构造方法的语句必须位于第一行,且只能出现一次,下面的写法是非法的。
3、不能在一个类的两个构造方法中使用this互相调用
类的构造方法使用private修饰,声明为私有,这样就不能在类的外部使用new关键字来创建实例对象了。
在类的内部创建一个该类的实例对象,并使用静态变量INSTANCE引用该对象,由于变量应该禁止外界直接访问,因此使用private修饰,声明为私有成员
为了让类的外部能够获得类的实例对象,需要定义一个静态方法getInstance(),用于返回该类实例INSTANCE。由于方法是静态的,外界可以通过“类名.方法名”的方式来访问
1.8 重载与重写(覆盖)
重载是方法名完全一样,采用不同的形参个数,或者不同的形参类型实现同一个方法具备不同的功能
重写是子类对父类的允许访问的方法的实现过程进行重新编写, 返回值和形参都不能改变
重载规则:
被重载的方法必须改变参数列表(参数个数或类型不一样);
被重载的方法可以改变返回类型;
被重载的方法可以改变访问修饰符;
被重载的方法可以声明新的或更广的检查异常;
方法能够在同一个类中或者在一个子类中被重载。
无法以返回值类型作为重载函数的区分标准。
方法的重写规则:
参数列表与被重写方法的参数列表必须完全相同。
返回类型与被重写方法的返回类型可以不相同,但是必须是父类返回值的派生类(java5 及更早版本返回类型要一样,java7 及更高版本可以不同)。
访问权限不能比父类中被重写的方法的访问权限更低。例如:如果父类的一个方法被声明为 public,那么在子类中重写该方法就不能声明为 protected。
父类的成员方法只能被它的子类重写。
声明为 final 的方法不能被重写。
声明为 static 的方法不能被重写,但是能够被再次声明。
子类和父类在同一个包中,那么子类可以重写父类所有方法,除了声明为 private 和 final 的方法。
子类和父类不在同一个包中,那么子类只能够重写父类的声明为 public 和 protected 的非 final 方法。
重写的方法能够抛出任何非强制异常,无论被重写的方法是否抛出异常。但是,重写的方法不能抛出新的强制性异常,或者比被重写方法声明的更广泛的强制性异常,反之则可以。
构造方法不能被重写。
如果不能继承一个类,则不能重写该类的方法。
1.9 垃圾回收
java的垃圾回收机制是一种自动管理内存的机制,它可以自动检测和回收不再使用的对象,以释放内存空间
1.10 静态变量
在一个Java类中,可以使用static关键字来修饰成员变量,该变量被称作静态变量
静态变量被所有实例共享,可以使用“类名.变量名”的形式来访问
static关键字只能用于修饰成员变量,不能用于修饰局部变量,否则编译会报错,下面的代码是非法的。
1.11静态代码块
在Java类中,使用一对大括号包围起来的若干行代码被称为一个代码块,用static关键字修饰的代码块称为静态代码块
当类被加载时,静态代码块会执行,由于类只加载一次,因此静态代码块只执行一次
在程序中,通常使用静态代码块来对类的成员变量进行初始化
1.12 设计模式
设计模式就是针对这些问题和需求,在大量的实践中总结和理论化之后优选的代码结构、编程风格、以及解决问题的思考方式
单例模式是Java中的一种设计模式,它是指在设计一个类时,需要保证在整个程序运行期间针对该类只存在一个实例对象
看一个实现了单例模式的类
内部类
内部类(包括成员内部类、局部内部类和匿名内部类)具有对外部类实例的隐式引用,因此可以访问外部类的成员,就好像这些成员是内部类自己的成员一样。
1.13 成员内部类
在一个类中除了可以定义成员变量、成员方法,还可以定义类,这样的类被称作成员内部类。
内部类可以在外部类中被使用,并能访问外部类的成员
如果想通过外部类去访问内部类,则需要通过外部类对象去创建内部类对象,创建内部类对象的具体语法格式如下:
外部类名.内部类名 变量名 =new 外部类名().new 内部类名();
1.14 静态内部类
可以使用static关键字来修饰一个成员内部类,该内部类被称作静态内部类,它可以在不创建外部类对象的情况下被实例化。创建静态内部类对象的具体语法格式如下:
外部类名.内部类名 变量名 = new 外部类名.内部类名();
1.15 方法内部类
方法内部类是指在成员方法中定义的类,它只能在当前方法中被使用。方法内部类,因此程序只能在方法中创建该类的实例对象并调用show()方法,方法内部类也可以访问外部类的成员变量
1.16 匿名内部类
匿名内部类是存在于某个类中且没有名称的类,可以匿名内部类于接口(或者抽象类)配合使用,在实例化时,直接采用匿名内部类
1.17 继承
程序中,继承描述的是事物之间的所属关系,通过继承可以使多种事物之间形成一种关系体系。
在Java中,类的继承是指在一个现有类的基础上去构建一个新的类,构建出来的新类被称作子类,现有类被称作父类,子类会自动拥有父类所有可继承的属性和方法。在程序中,如果想声明一个类继承另一个类,需要使用extends关键字,接下来通过一个案例来学习子类是如何继承父类的。
在类的继承中,需要注意一些问题,具体如下:
1、在Java中,类只支持单继承,不允许多重继承,也就是说一个类只能有一个直接父类,例如下面这种情况是不合法的。
2、多个类可以继承一个父类,例如下面这种情况是允许的。
3、在Java中,多层继承是可以的,即一个类的父类可以再去继承另外的父类,例如C类继承自B类,而B类又可以去继承A类,这时,C类也可称作A类的子类。下面这种情况是允许的。
4、继承后的方法其访问权限范围不能缩小(可以扩大或者保持)
在继承关系中,子类会自动继承父类中定义的方法,但有时在子类中需要对继承的方法进行一些修改,即对父类的方法进行重写。需要注意的是,在子类中重写的方法需要和父类被重写的方法具有相同的方法名、参数列表以及返回值类型。
1.17.1 super关键字
当子类重写父类的方法后,子类对象将无法访问父类被重写的方法,为了解决这个问题,在Java中专门提供了一个super关键字用于访问父类的成员。例如访问父类的成员变量、成员方法和构造方法。接下来分两种情况来学习一下super关键字的具体用法。
1、使用super关键字调用父类的成员变量和成员方法。
2、使用super关键字调用父类的构造方法
1 | |
1.18 final关键字
final关键字可用于修饰类、变量和方法,它有“这是无法改变的”或者“最终”的含义,因此被final修饰的类、变量和方法将具有以下特性:
1、final修饰的类不能被继承。
2、final修饰的方法不能被子类重写。
3、final修饰的变量(成员变量和局部变量)是常量,只能赋值一次。
Java中的类被final关键字修饰后,该类将不可以被继承,也就是不能够派生子类,当一个类的方法被final关键字修饰后,这个类的子类将不能重写该方法
1.19 抽象方法
Java允许在定义方法时不写方法体,不包含方法体的方法为抽象方法,抽象方法必须使用abstract关键字来修饰
1.20 抽象类
含有抽象方法的类,叫做抽象类,该类必须使用abstract关键字来修饰,在定义抽象类时需要注意,包含抽象方法的类必须声明为抽象类,但抽象类可以不包含任何抽象方法,只需使用abstract关键字来修饰即可。另外,抽象类是不可以被实例化的,因为抽象类中有可能包含抽象方法,抽象方法是没有方法体的,不可以被调用。如果想调用抽象类中定义的方法,则需要创建一个子类,在子类中将抽象类中的抽象方法进行实现。
抽象类不能直接实例化对象,一般有子类实现父类中的所有抽象方法,然后才能实例化对象
抽象类的子类如果没有完全实现抽象父类的所有抽象方法,则也要声明为abstract也不能实例化对象
抽象类的非抽象子类必须重写父类中的abstract方法
1.21 包装类
包装类(Packaging class):Java语言是一个面向对象的语言,但是Java中的基本数据类型却是不面向对象的。基本型的数据不具备”对象”的特性(没有成员变量和成员方法可以调用),因此,java为每种数据类型分别设计了对应的类,即包装类。
1.22 接口
如果一个抽象类中的所有方法都是抽象的,则可以将这个类用另外一种方式来定义,即接口。在定义接口时,需要使用interface关键字来声明,接口中定义的方法和变量都包含一些默认修饰符。接口中定义的方法默认使用“public abstract”来修饰,即抽象方法。接口中的变量默认使用“public static final”来修饰,即全局常量。
由于接口中的方法都是抽象方法,因此不能通过实例化对象的方式来调用接口中的方法。此时需要定义一个类,并使用implements关键字实现接口中所有的方法。在程序中,还可以定义一个接口使用extends关键字去继承另一个接口
为了加深初学者对接口的认识,接下来对接口的特点进行归纳,具体如下:
1、接口中的方法都是抽象的,不能实例化对象。
2、当一个类实现接口时,如果这个类是抽象类,则实现接口中的部分方法即可,否则需要实现接口中的所有方法。
3、一个类通过implements关键字实现接口时,可以实现多个接口,被实现的多个接口之间要用逗号隔开。
4、一个接口可以通过extends关键字继承多个接口,接口之间用逗号隔开。
5、一个类在继承另一个类的同时还可以实现接口,此时,extends关键字必须位于implements关键字前
1.23 一般类,抽象类,接口区别
java中有三种不同类型的类:一般类、抽象类和接口。它们之间有以下区别:
- 一般类是普通的类,它们可以有字段、方法和构造函数等。一般类的实例可以直接创建,并且可以被其他类继承。
- 抽象类是不能被实例化的类,它们只能被继承。抽象类可以有字段、方法和构造函数等,但方法可以是抽象的,这意味着它们没有实现,需要由子类实现。抽象类通常用于作为其他类的基类,它们定义了一些通用的属性和方法,并强制要求子类实现它们。
- 接口是一种特殊的抽象类,它们没有字段,并且所有的方法都是抽象的。接口只定义了方法的名称、返回类型和参数,而没有提供实现。接口通常用于定义类之间的协议,它们强制要求实现它们的类提供指定的方法。
1.24 多态
在设计一个方法时,通常希望该方法具备一定的通用性。多态性是指调用同一方法实现不同的行为特征的技术
在Java中为了实现多态,允许使用一个父类类型的变量来引用一个子类类型的对象,根据被引用子类对象特征的不同,得到不同的运行结果,将子类对象当做父类使用时不需要任何显式地声明,需要注意的是,此时不能通过父类变量去调用子类中某些方法,需要类型转换,需要注意的是,在进行类型转换时也可能出现错误。
1.24.1 instanceof
针对这种情况,Java提供了一个关键字instanceof,它可以判断一个对象是否为某个类(或接口)的实例或者子类实例,具体代码如下:
对象(或者对象引用变量) instanceof 类(或接口)
在java中多态性可以通过方法的重载和重写来实现 ,代码如下:
1 | |
1.25 object类
在JDK中提供了一个Object类,它是所有类的父类,即每个类都直接或间接继承自该类,Animal默认继承自Object类,在Object类中定义了toString()方法
1.26 匿名内部类
前面多态的讲解中,如果方法的参数被定义为一个接口类型,那么就需要定义一个类来实现接口,并根据该类进行对象实例化。除此之外,还可以使用匿名内部类来实现接口。
匿名内部类格式:
new 父类(参数列表) 或父接口(){
//匿名内部类实现部分
}
调用者和被调用者必须共同遵守某一限定,调用者按照这个限定进行方法调用,被调用者按照这个限定进行方法实现”的应用情况,在面向对象的编程语言中,这种限定就是通过接口类来表示的
在写匿名内部类的大括号后,一定要跟着一个语句;
1.27 异常
简要讲一下如何理解Java中的异常处理机制
在Java中,异常处理机制是一种处理程序运行时出现异常情况的机制。当程序执行过程中发生异常时,异常处理机制可以捕捉和处理异常,以避免程序崩溃或出现未预期的结果
在程序运行的过程中,也会发生这种非正常状况,比如程序运行时磁盘空间不足,网络连接中断,被装载的类不存在。针对这种情况,在Java语言中,引入了异常,以异常类的形式对这些非正常情况进行封装,通过异常处理机制对程序运行时发生的各种问题进行处理。
Throwable有两个直接子类Error和Exception,其中Error代表程序中产生的错误,Exception代表程序中产生的异常。接下来就对这两个直接子类进行详细讲解。
Error类称为错误类,它表示Java运行时产生的系统内部错误或资源耗尽的错误,是比较严重的,仅靠修改程序本身是不能恢复执行的。举一个生活中的例子,在盖楼的过程中因偷工减料,导致大楼坍塌,这就相当于一个Error。使用java命令去运行一个不存在的类就会出现Error错误
Exception类称为异常类,它表示程序本身可以处理的错误,在开发Java程序中进行的异常处理,都是针对Excption类及其子类。在Exception类的众多子类中有一个特殊的RuntimeException类,该类及其子类用于表示运行时异常,除了此类,Exception类下所有其它的子类都用于表示编译时异常
由于发生了异常,程序立即终止,无法继续向下执行。为了解决这样的问题,Java中提供了一种对异常进行处理的方式——异常捕获 try …catch finally
在程序中,有时候我们希望有些语句无论程序是否发生异常都要执行,这时就可以在try…catch语句后,加一个finally代码块。需要注意的是,finally中的代码块有一种情况下是不会执行的,那就是在try…catch中执行了System.exit(0)语句。System.exit(0)表示退出当前的Java虚拟机,Java虚拟机停止了,任何代码都不能再执行了。
1.28 throws关键字
在前面学习的例程4-23中,由于调用的是自己写的divide()方法,因此很清楚该方法可能会发生异常。试想一下,如果去调用一个别人写的方法时,是否能知道别人写的方法是否会有异常呢?这是很难做出判断的。针对这种情况,Java中允许在方法的后面使用throws关键字对外声明该方法有可能发生的异常,这样调用者在调用方法时,就明确地知道该方法有异常,并且必须在程序中对异常进行处理,否则编译无法通过。
throws关键字声明抛出异常的语法格式如下:
修饰符 返回值类型 方法名 [参数1,参数2….]throws ExceptionType1[,ExceptionType2….]{
1.29 运行时异常与编译时异常
在实际开发中,经常会在程序编译时期产生一些异常,而这些异常必须要进行处理,这种异常被称为编译时期异常,也称为checked异常。另外还有一种异常是在程序运行时期产生的,这种异常即使不编写异常处理代码,依然可以通过编译,因此我们称之为运行时异常,也称为unchecked异常。
运行时异常与编译时异常
1、编译时异常
在Java中,Exception类中除了RuntimeException类及其的子类都是编译时异常。编译时异常的特点是Java编译器会对其进行检查,如果出现异常就必须对异常进行处理,否则程序无法通过编译。
处理编译时期的异常有两种方式,具体如下:
使用try…catch语句对异常进行捕获
使用throws关键字声明抛出异常,调用者对其处理。
2、运行时异常
RuntimeException类及其子类都是运行时异常。运行时异常的特点是Java编译器不会对其进行检查,也就是说,当程序中出现这类异常时,即使没有使用try..catch语句捕获或使用throws关键字声明抛出,程序也能编译通过。运行时异常一般是由于程序中的逻辑错误引起的,在程序运行时无法恢复。比如通过数组的角标访问数组的元素时,如果超过了数组的最大角标,就会发生运行时异常,
1.30 自定义异常
JDK中定义了大量的异常类,虽然这些异常类可以描述编程时出现的大部分异常情况,但是在程序开发中有时可能需要描述程序中特有的异常情况,例如在设计divide()方法时不允许被除数为负数。为了解决这个问题,在Java中允许用户自定义异常,但自定义的异常类必须继承自Exception或其子类
在实际开发中,如果没有特殊的要求,自定义的异常类只需继承Exception类,在构造方法中使用super()语句调用Exception的构造方法即可。
既然自定义了异常,那么该如何使用呢?这时就需要用到throw关键字,throw关键字用于在方法中声明抛出异常的实例对象,其语法格式如下:
throw Exception 异常对象
在一个方法内使用throw关键字抛出异常对象时,需要使用try…catch语句对抛出的异常进行处理,或者在divide()方法上使用throws关键字声明抛出异常,由该方法的调用者负责处理。
1.31 包
为了便于对硬盘上的文件进行管理,通常都会将文件分目录进行存放。同理,在程序开发中,也需要将编写的类分目录存放便于管理,为此,Java引入了包(package)机制,程序可以通过声明包的方式对Java类定义目录。Java中的包是专门用来存放类的,通常功能相同的类存放在相同的包中。在声明包时,使用package语句,需要注意的是,包的声明只能位于Java源文件的第一行。
1.32 断言
断言语句主要用于程序调试阶段,通过设置断言语句,我们可以快速找到错误的语句,语句块,或者错误的方法体,在 Java 中,断言使用 assert 关键字来定义,其语法格式如下:assert expression1;assert expression2 : expression3;其中,expression1 是一个布尔表达式,如果它为 true,则程序继续执行;如果为 false,则程序抛出 AssertionError 异常。expression2 是一个布尔表达式,如果它为 false,则抛出 AssertionError 异常,并将 expression3 的值作为异常信息输出。
1.33 import语句
在程序开发中,位于不同包中的类经常需要互相调用,Java中提供了import关键字,使用import可以在程序中一次导入某个指定包下的类
import语句
在JDK中,不同功能的类都放在不同的包中,其中Java的核心类主要放在java这个包以及其子包下,Java扩展的大部分类都放在javax包以及其子包下。为了便于后面的学习,接下来简单介绍Java语言中的常用包。
java.lang:包含Java语言的核心类,如String、Math、System和Thread类等,使用这个包中的类无须使用import语句导入,系统会自动导入这个包下的所有类。
java.util:包含Java中大量工具类、集合类等,例如Arrays、List、Set等。
java.net:包含Java网络编程相关的类和接口。
java.io:包含了Java输入、输出有关的类和接口。
java.awt:包含用于构建图形界面(GUI)的相关类和接口。
给Java应用打包
给Java应用打包有很多好处,接下来简单介绍一下打包jar文件的好处,如下所示:
安全:可以对jar文件进行数字签名,让能够识别数字签名的用户使用。
节省空间:当把.class文件打成jar压缩文件,会节省空间,如果将jar文件在网络上传输,也会加快传输速率。
可移植性:只要有Java虚拟机,jar包就可以在任何平台上运行。
1.34 访问权限符
private(类访问级别) :如果类的成员被private访问控制符来修饰,则这个成员只能被该类的其它成员访问,其它类无法直接访问。实现类的良好封装。
default(包访问级别) :如果一个类或者类的成员不使用任何访问控制符修饰,则称它为默认访问控制级别,这个类或者类的成员只能被本包中的其它类访问。
protected(子类访问级别) :如果一个类的成员被protected访问控制符修饰,那么这个成员既能被同一包下的其它类访问,也能被不同包下该类的子类访问。
public(公共访问级别) :这是一个最宽松的访问控制级别,如果一个类或者类的成员被public访问控制符修饰,那么这个类或者类的成员能被所有的类访问,不管访问类与被访问类是否在同一个包中。
1.35 进程与线程
•进程
1 | |
•线程
1 | |
1.36 如何实现多线程
继承Thread类创建多线程
1 | |

通过继承Thread类实现了多线程,但是这种方式有一定的局限性。因为Java中只支持单继承,一个类一旦继承了某个父类就无法再继承Thread类
实现Runnable接口创建多线程
1 | |

实现Runnable接口相对于继承Thread类来说,有如下显著好处:
1、适合多个相同程序代码的线程去处理同一个资源的情况,把线程同程序代码、数据有效的分离,很好的体现了面向对象的设计思想。
2、可以避免由于Java的单继承带来的局限性。在开发中经常碰到这样一种情况,就是使用一个已经继承了某一个类的子类创建线程,由于一个类不能同时有两个父类,所以不能用继承Thread类的方式,那么就只能采用实现Runnable接口的方式。
后台线程
对Java程序来说,只要还有一个前台线程在运行,这个进程就不会结束,如果一个进程中只有后台线程运行,这个进程就会结束。这里提到的前台线程和后台线程是一种相对的概念,新创建的线程默认都是前台线程,如果某个线程对象在启动之前调用了setDaemon(true)语句,这个线程就变成一个后台线程。
1.37 线程生命周期
线程整个生命周期可以分为五个阶段,分别是新建状态(New)、就绪状态(Runnable)、运行状态(Running)、阻塞状态(Blocked)和死亡状态(Terminated),线程的不同状态表明了线程当前正在进行的活动。
1、新建状态(New) 创建一个线程对象后,该线程对象就处于新建状态,此时它不能运行,和其它Java对象一样,仅仅由Java虚拟机为其分配了内存,没有表现出任何线程的动态特征。
2、就绪状态(Runnable) 当线程对象调用了start()方法后,该线程就进入就绪状态(也称可运行状态)。处于就绪状态的线程位于可运行池中,此时它只是具备了运行的条件,能否获得CPU的使用权开始运行,还需要等待系统的调度。
3、运行状态(Running) 如果处于就绪状态的线程获得了CPU的使用权,开始执行run()方法中的线程执行体,则该线程处于运行状态。当一个线程启动后,它不可能一直处于运行状态(除非它的线程执行体足够短,瞬间就结束了),当使用完系统分配的时间后,系统就会剥夺该线程占用的CPU资源,让其它线程获得执行的机会。需要注意的是,只有处于就绪状态的线程才可能转换到运行状态。
4、阻塞状态(Blocked) 一个正在执行的线程在某些特殊情况下,如执行耗时的输入/输出操作时,会放弃CPU的使用权,进入阻塞状态。线程进入阻塞状态后,就不能进入排队队列。只有当引起阻塞的原因被消除后,线程才可以转入就绪状态。
当线程试图获取某个对象的同步锁时,如果该锁被其它线程所持有,则当前线程会进入阻塞状态,如果想从阻塞状态进入就绪状态必须得获取到其它线程所持有的锁。
当线程调用了一个阻塞式的IO方法时,该线程就会进入阻塞状态,如果想进入就绪状态就必须要等到这个阻塞的IO方法返回。
当线程调用了某个对象的wait()方法时,也会使线程进入阻塞状态,如果想进入就绪状态就需要使用notify()方法唤醒该线程。
当线程调用了Thread的sleep(long millis)方法时,也会使线程进入阻塞状态,在这种情况下,只需等到线程睡眠的时间到了以后,线程就会自动进入就绪状态。
当在一个线程中调用了另一个线程的join()方法时,会使当前线程进入阻塞状态,在这种情况下,需要等到新加入的线程运行结束后才会结束阻塞状态,进入就绪状态。
5、死亡状态(Terminated) 线程的run()方法正常执行完毕或者线程抛出一个未捕获的异常(Exception)、错误(Error),线程就进入死亡状态。一旦进入死亡状态,线程将不再拥有运行的资格,也不能再转换到其它状态。
1.38 线程的优先级
优先级越高的线程获得CPU执行的机会越大,而优先级越低的线程获得CPU执行的机会越小。
线程的优先级用110之间的整数来表示,数字越大优先级越高。
除了可以直接使用数字表示线程的优先级,还可以使用Thread类中提供的三个静态常量表示线程的优先级
程序在运行期间,处于就绪状态的每个线程都有自己的优先级,例如main线程具有普通优先级。然而线程优先级不是固定不变的,可以通过Thread类的setPriority(int newPriority)方法对其进行设置,该方法中的参数newPriority接收的是110之间的整数或者Thread类的三个静态常量。
1.39 线程休眠
如果希望人为地控制线程,使正在执行的线程暂停,将CPU让给别的线程,这时可以使用静态方法sleep(long millis),该方法可以让当前正在执行的线程暂停一段时间,进入休眠等待状态。
当前线程调用sleep(long millis)方法后,在指定时间(参数millis)内该线程是不会执行的,这样其它的线程就可以得到执行的机会。
1.40 线程让步
在校园中,我们经常会看到同学互相抢篮球,当某个同学抢到篮球后就可以拍一会,之后他会把篮球让出来,大家重新开始抢篮球,这个过程就相当于Java程序中的线程让步。
线程让步可以通过yield()方法来实现,该方法和sleep()方法有点相似,都可以让当前正在运行的线程暂停,区别在于yield()方法不会阻塞该线程,它只是将线程转换成就绪状态,让系统的调度器重新调度一次。当某个线程调用yield()方法之后,只有与当前线程优先级相同或者更高的线程才能获得执行的机会。
1.41 线程插队
现实生活中经常能碰到“插队”的情况,同样,在Thread类中也提供了一个join()方法来实现这个“功能”。
当在某个线程中调用其它线程的join()方法时,调用的线程将被阻塞,直到被join()方法加入的线程执行完成后它才会继续运行。
1.42 同步代码块
要解决线程安全问题,必须得保证下面用于处理共享资源的代码在任何时刻只能有一个线程访问。
为了实现这种限制,Java中提供了同步机制。当多个线程使用同一个共享资源时,可以将处理共享资源的代码放置在一个代码块中,使用synchronized关键字来修饰,被称作同步代码块,其语法格式如下
synchronized(lock){
操作共享资源代码快
}
lock是一个锁对象,它是同步代码块的关键。当线程执行同步代码块时,首先会检查锁对象的标志位,默认情况下标志位为1,此时线程会执行同步代码块,同时将锁对象的标志位置为0。当一个新的线程执行到这段同步代码块时,由于锁对象的标志位为0,新线程会发生阻塞,等待当前线程执行完同步代码块后,锁对象的标志位被置为1,新线程才能进入同步代码块执行其中的代码。循环往复,直到共享资源被处理完为止。
1.43 同步方法
同步代码块可以有效解决线程的安全问题,当把共享资源的操作放在synchronized定义的区域内时,便为这些操作加了同步锁。
在方法前面同样可以使用synchronized关键字来修饰,被修饰的方法为同步方法,它能实现和同步代码块同样的功能,具体语法格式如下:
synchronized 返回值类型 方法名[参数1,….]{}
被synchronized修饰的方法在某一时刻只允许一个线程访问,访问该方法的其它线程都会发生阻塞,直到当前线程访问完毕后,其它线程才有机会执行方法。
1.44 死锁
两个线程在运行时都在等待对方的锁,这样便造成了程序的停滞,这种现象称为死锁
问题引出
假设有两个线程同时去操作同一个存储空间,其中一个线程负责向存储空间中存入数据,另一个线程负责则取出数据。
问题如何解决
如果想解决上述问题,需要控制多个线程按照一定的顺序轮流执行,此时需要让线程间进行通信。在Object类中提供了wait()、notify()、notifyAll()方法用于解决线程间的通信问题,由于Java中所有类都是Object类的子类或间接子类,因此任何类的实例对象都可以直接使用这些方法。
1.45 设计模式
设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计
经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。
总体来说设计模式分为三大类:
创建型模式 共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
结构型模式 共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式 共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
1.46 设计模式需要遵循的原则
1.开闭原则 说对扩展开放,对修改关闭。在程序需要拓展时,不能去修改原有的代码,实现热插拔的效果
2.里式替换原则 任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石
3.依赖倒转原则 真对接口编程,依赖于抽象而不依赖于具体
4.接口隔离原则 使用多个隔离的接口,比使用单个接口要好。还是一个降低类之间的耦合度的意思
5.迪米特法则 一个实体应尽量少的与其他实体发生相互作用,使系统功能相对独立
6.合成复用原则 尽量使用合成/聚合的方式,而不是使用继承
1.47 几种典型设计模式
单例模式:单例对象能保证在一个JVM中,该对象只有一个实例存在。
饿汉式:类加载该实例就被创建
懒汉式:对象在使用时实例才被创建
双检锁式: 多线程监督
策略模式:策略模式定义了一系列算法,并将每个算法封装起来,使他们可以相互替换,且算法的变化不会影响到使用算法的客户。
策略模式可以选择不同的策略进行业务处理 ,抽象策略类通常有接口或者抽象类定义方法,具体策略类则对方法进行实现。
工厂模式:建立一个工厂类,对实现了同一接口的一些类进行实例的创建。
简单工厂 静态工厂 抽象工厂
适配器模式:适配器模式将某个类的接口转换成客户端期望的另一个接口表示,目的是消除由于接口不匹配所造成的类的兼容性问题
适配器模式是转换不同业务类型的通用“插口”,可以将一个或多个类的接口转换为标准接口,使得原本不兼容的接口可以同时使用。
设计模式于人于系统都是多赢的,它使代码编写工程化,是软件工程的基石。项目中合理的运用设计模式可以完美的解决很多问题,每种模式在现实中都有相应的原理来与之对应,每种模式描述了一个在我们周围不断重复发生的问题并能够解决,这是它被广泛应用的原因
1.48 集合
集合是指具有某种特定性质的具体的或抽象的对象汇总而成的集体,有时集合也称之为容器
程序中可以通过数组来保存多个对象,但在某些情况下无法确定到底需要保存多少个对象,此时数组将不再适用,因为数组的长度不可变。
JDK中提供了一系列特殊的类,这些类可以存储任意类型的对象,并且长度可变,统称为集合。
集合按照其存储结构可以分为两大类,即单列集合Collection和双列集合Map
Collection:单列集合类的根接口,存储一系列符合某种规则的元素,它有两个重要的子接口,分别是List和Set。其中,List的特点是元素有序、元素可重复。Set的特点是元素无序并且不可重复。List接口的主要实现类有ArrayList和LinkedList,Set接口的主要实现类有HashSet和TreeSet。
Map:双列集合类的根接口,用于存储具有键(Key)、值(Value)映射关系的元素,每个元素都包含一对键值,在使用Map集合时可以通过指定的Key找到对应的Value,例如根据一个学生的学号就可以找到对应的学生。Map接口的主要实现类有HashMap和TreeMap。
Collection是所有单列集合的父接口,因此在Collection中定义了单列集合(List和Set)通用的一些方法,这些方法可用于操作所有的单列集合。

1.49 List接口简介
List接口继承自Collection接口,是单列集合的一个重要分支,习惯性地会将实现了List接口的对象称为List集合。
在List集合中允许出现重复的元素,所有的元素是以一种线性方式进行存储的,在程序中可以通过索引来访问集合中的指定元素。
另外,List集合还有一个特点就是元素有序,即元素的存入顺序和取出顺序一致。
List不但继承了Collection接口中的全部方法,而且还增加了一些根据元素索引来操作集合的特有方法。
1.50 ArrayList集合
ArrayList (Java SE 11 & JDK 11 ) (runoob.com)
void |
add(int index, E element) |
将指定元素插入此列表中的指定位置。 |
|---|---|---|
boolean |
contains(Object o) |
如果此列表包含指定的元素,则返回 true 。 |
E |
get(int index) |
返回此列表中指定位置的元素。 |
int |
indexOf(Object o) |
返回此列表中第一次出现的指定元素的索引,如果此列表不包含该元素,则返回-1。 |
E |
remove(int index) |
删除此列表中指定位置的元素。 |
E |
set(int index, E element) |
用指定的元素替换此列表中指定位置的元素。 |
int |
size() |
返回此列表中的元素数。 |
Object[] |
toArray() |
以适当的顺序(从第一个元素到最后一个元素)返回包含此列表中所有元素的数组。 |
ArrayList是List接口的一个实现类,它是程序中最常见的一种集合
在ArrayList内部封装了一个长度可变的数组对象,当存入的元素超过数组长度时,ArrayList会在内存中分配一个更大的数组来存储这些元素,因此可以将ArrayList集合看作一个长度可变的数组
ArrayList集合中大部分方法都是从父类Collection和List继承过来的,其中add()方法和get()方法用于实现元素的存取。
1.51 LinkedList集合
LinkedList (Java SE 11 & JDK 11 ) (runoob.com)
| 变量和类型 | 方法 | 描述 |
|---|---|---|
void |
add(int index, E element) |
将指定元素插入此列表中的指定位置。 |
boolean |
add(E e) |
将指定的元素追加到此列表的末尾。 |
boolean |
addAll(int index, Collection<? extends E> c) |
从指定位置开始,将指定集合中的所有元素插入此列表。 |
boolean |
addAll(Collection<? extends E> c) |
将指定集合中的所有元素按指定集合的迭代器返回的顺序附加到此列表的末尾。 |
void |
addFirst(E e) |
在此列表的开头插入指定的元素。 |
void |
addLast(E e) |
将指定的元素追加到此列表的末尾。 |
void |
clear() |
从此列表中删除所有元素。 |
Object |
clone() |
返回此 LinkedList的浅表副本。 |
boolean |
contains(Object o) |
如果此列表包含指定的元素,则返回 true 。 |
Iterator<E> |
descendingIterator() |
以相反的顺序返回此双端队列中元素的迭代器。 |
E |
element() |
检索但不删除此列表的头部(第一个元素)。 |
E |
get(int index) |
返回此列表中指定位置的元素。 |
E |
getFirst() |
返回此列表中的第一个元素。 |
E |
getLast() |
返回此列表中的最后一个元素。 |
int |
indexOf(Object o) |
返回此列表中第一次出现的指定元素的索引,如果此列表不包含该元素,则返回-1。 |
int |
lastIndexOf(Object o) |
返回此列表中指定元素最后一次出现的索引,如果此列表不包含该元素,则返回-1。 |
ListIterator<E> |
listIterator(int index) |
从列表中的指定位置开始,返回此列表中元素的列表迭代器(按正确顺序)。 |
boolean |
offer(E e) |
将指定的元素添加为此列表的尾部(最后一个元素)。 |
boolean |
offerFirst(E e) |
在此列表的前面插入指定的元素。 |
boolean |
offerLast(E e) |
在此列表的末尾插入指定的元素。 |
E |
peek() |
检索但不删除此列表的头部(第一个元素)。 |
E |
peekFirst() |
检索但不删除此列表的第一个元素,如果此列表为空,则返回 null 。 |
E |
peekLast() |
检索但不删除此列表的最后一个元素,如果此列表为空,则返回 null 。 |
E |
poll() |
检索并删除此列表的头部(第一个元素)。 |
E |
pollFirst() |
检索并删除此列表的第一个元素,如果此列表为空,则返回 null 。 |
E |
pollLast() |
检索并删除此列表的最后一个元素,如果此列表为空,则返回 null 。 |
E |
pop() |
弹出此列表所代表的堆栈中的元素。 |
void |
push(E e) |
将元素推送到此列表所表示的堆栈上。 |
E |
remove() |
检索并删除此列表的头部(第一个元素)。 |
E |
remove(int index) |
删除此列表中指定位置的元素。 |
boolean |
remove(Object o) |
从该列表中删除指定元素的第一个匹配项(如果存在)。 |
E |
removeFirst() |
从此列表中删除并返回第一个元素。 |
boolean |
removeFirstOccurrence(Object o) |
删除此列表中第一次出现的指定元素(从头到尾遍历列表时)。 |
E |
removeLast() |
从此列表中删除并返回最后一个元素。 |
boolean |
removeLastOccurrence(Object o) |
删除此列表中最后一次出现的指定元素(从头到尾遍历列表时)。 |
E |
set(int index, E element) |
用指定的元素替换此列表中指定位置的元素。 |
int |
size() |
返回此列表中的元素数。 |
Spliterator<E> |
spliterator() |
在此列表中的元素上创建*late-binding和故障快速* Spliterator 。 |
Object[] |
toArray() |
以适当的顺序(从第一个元素到最后一个元素)返回包含此列表中所有元素的数组。 |
<T> T[] |
toArray(T[] a) |
以适当的顺序返回包含此列表中所有元素的数组(从第一个元素到最后一个元素); 返回数组的运行时类型是指定数组的运行时类型。 |
List接口的另一个实现类LinkedList,克服了ArrayList集合在查询元素时速度很快,但在增删元素时效率较低的局限性。
该集合内部维护了一个双向循环链表,链表中的每一个元素都使用引用的方式来记住它的前一个元素和后一个元素,从而可以将所有的元素彼此连接起来。
当插入一个新元素时,只需要修改元素之间的这种引用关系即可,删除一个节点也是如此。
LinkedList集合除了具备增删元素效率高的特点,还专门针对元素的增删操作定义了一些特有的方法。

1.52 Iterator集合
Iterator接口也是Java集合框架中的一员,但它与Collection、Map接口有所不同,Collection接口与Map接口主要用于存储元素,而Iterator主要用于迭代访问(即遍历)Collection中的元素,因此Iterator对象也被称为迭代器。Iterator迭代器对象在遍历集合时,内部采用指针的方式来跟踪集合中的元素
在使用Iterator迭代器对集合中的元素进行迭代时,如果调用了集合对象的remove()方法去删除元素,会出现异常。
这个异常是迭代器对象抛出的,出现异常的原因是集合中删除了元素会导致迭代器预期的迭代次数发生改变,导致迭代器的结果不准确
为了解决上述问题,可以采用两种方式:
1.在使用break语句跳出循环以后,由于没有继续使用迭代器对集合中的元素进行迭代,因此,集合中删除元素对程序没有任何影响,不会出现异常
2.如果需要在集合的迭代期间对集合中的元素进行删除,可以使用迭代器本身的删除方法
1.52.1 Java Iterator(迭代器)
Java迭代器(Iterator)是 Java 集合框架中的一种机制,是一种用于遍历集合(如列表、集合和映射等)的接口。
它提供了一种统一的方式来访问集合中的元素,而不需要了解底层集合的具体实现细节。
Java Iterator(迭代器)不是一个集合,它是一种用于访问集合的方法,可用于迭代 ArrayList 和 HashSet 等集合。
Iterator 是 Java 迭代器最简单的实现,ListIterator 是 Collection API 中的接口, 它扩展了 Iterator 接口。

迭代器接口定义了几个方法,最常用的是以下三个:
- next() - 返回迭代器的下一个元素,并将迭代器的指针移到下一个位置。
- hasNext() - 用于判断集合中是否还有下一个元素可以访问。
- remove() - 从集合中删除迭代器最后访问的元素(可选操作)。
Iterator 类位于 java.util 包中,使用前需要引入它,语法格式如下:
1 | |
通过使用迭代器,我们可以逐个访问集合中的元素,而不需要使用传统的 for 循环或索引。这种方式更加简洁和灵活,并且适用于各种类型的集合。
获取一个迭代器
集合想获取一个迭代器可以使用 iterator() 方法:
实例
// 引入 ArrayList 和 Iterator 类
import java.util.ArrayList;
import java.util.Iterator;
public class RunoobTest {
public static void main(String[] args) {
1 | |
// 创建集合
ArrayList
sites.add(“Google”);
sites.add(“Runoob”);
sites.add(“Taobao”);
sites.add(“Zhihu”);
1 | |
// 获取迭代器
Iterator
1 | |
// 输出集合中的第一个元素
System.out.println(it.next());
}
}
执行以上代码,输出结果如下:
1 | |
使用迭代器遍历集合时,如果在遍历过程中对集合进行了修改(例如添加或删除元素),可能会导致 ConcurrentModificationException 异常,为了避免这个问题,可以使用迭代器自身的 remove() 方法进行删除操作。
循环集合元素
让迭代器 it 逐个返回集合中所有元素最简单的方法是使用 while 循环:
1 | |
以下输出集合 sites 中的所有元素:
实例
// 引入 ArrayList 和 Iterator 类
import java.util.ArrayList;
import java.util.Iterator;
public class RunoobTest {
public static void main(String[] args) {
1 | |
// 创建集合
ArrayList
sites.add(“Google”);
sites.add(“Runoob”);
sites.add(“Taobao”);
sites.add(“Zhihu”);
1 | |
// 获取迭代器
Iterator
1 | |
// 输出集合中的所有元素
while(it.hasNext()) {
System.out.println(it.next());
}
}
}
执行以上代码,输出结果如下:
1 | |
删除元素
要删除集合中的元素可以使用 remove() 方法。
以下实例我们删除集合中小于 10 的元素:
实例
// 引入 ArrayList 和 Iterator 类
import java.util.ArrayList;
import java.util.Iterator;
public class RunoobTest {
public static void main(String[] args) {
ArrayList
numbers.add(12);
numbers.add(8);
numbers.add(2);
numbers.add(23);
Iterator
while(it.hasNext()) {
Integer i = it.next();
if(i < 10) {
it.remove(); // 删除小于 10 的元素
}
}
System.out.println(numbers);
}
}
执行以上代码,输出结果如下:
1 | |
**注意:**Java 迭代器是一种单向遍历机制,即只能从前往后遍历集合中的元素,不能往回遍历。同时,在使用迭代器遍历集合时,不能直接修改集合中的元素,而是需要使用迭代器的 remove() 方法来删除当前元素。
1.53 foreach循环
虽然Iterator可以用来遍历集合中的元素,但写法上比较繁琐,为了简化书写,从JDK5.0开始,提供了foreach循环。foreach循环是一种更加简洁的for循环,也称增强for循环。foreach循环用于遍历数组或集合中的元素,其具体语法格式如下:
for(容器中元素类型 临时变量 : 容器变量){
1 | |
}
与for循环相比,foreach循环不需要获得容器的长度,也不需要根据索引访问容器中的元素,但它会自动遍历容器中的每个元素
foreach循环虽然书写起来很简洁,但在使用时也存在一定的局限性。当使用foreach循环遍历集合和数组时,只能访问集合中的元素,不能对其中的元素进行修改
1.54 ListIterator接口
Iterator迭代器提供了hasNext()方法和next()方法,通过这两个方法可以实现集合中元素的迭代,迭代的方向是从集合中的第一个元素向最后一个元素迭代,也就是所谓的正向迭代。
为了使迭代方式更加多元化,JDK中还定义了一个ListIterator迭代器,它是Iterator的子类,该类在父类的基础上增加了一些特有方法。

1.55 Enumeration接口
在JDK1.2以前还没有Iterator接口的时候,遍历集合需要使用Enumeration接口,它的用法和Iterator类似。
JDK中提供了一个Vevtor集合,该集合是List接口的一个实现类,用法与ArrayList完全相同,区别在于Vector集合是线程安全的,而ArrayList集合是线程不安全的。在Vector类中提供了一个elements()方法用于返回Enumeration对象,通过Enumeration对象就可以遍历该集合中的元素。
1.56 Set接口简介
Set接口和List接口一样,同样继承自Collection接口,它与Collection接口中的方法基本一致,并没有对Collection接口进行功能上的扩充,只是比Collection接口更加严格了。与List接口不同的是,Set接口中元素无序,并且都会以某种规则保证存入的元素不出现重复。
Set接口主要有两个实现类,分别是HashSet和TreeSet。其中,HashSet是根据对象的哈希值来确定元素在集合中的存储的位置,因此具有良好的存取和查找性能。TreeSet则是以二叉树的方式来存储元素,它可以实现对集合中的元素进行排序。
1.57 HashSet集合
HashSet是Set接口的一个实现类,它所存储的元素是不可重复的,并且元素都是无序的。当向HashSet集合中添加一个对象时,首先会调用该对象的hashCode()方法来确定元素的存储位置,然后再调用对象的equals()方法来确保该位置没有重复元素。
1.58 TreeSet集合
TreeSet是Set接口的另一个实现类,它内部采用平衡二叉树来存储元素,这样的结构可以保证TreeSet集合中没有重复的元素,并且可以对元素进行排序。
所谓二叉树就是说每个节点最多有两个子节点的有序树,每个节点及其子节点组成的树称为子树,通常左侧的子节点称为“左子树”,右侧的节点称为“右子树”,其中左子树上的元素应小于它的根结点,而右子树上的元素应大于它的根结点。
二叉树中元素的存储过程:
当二叉树中存入新元素时,新元素首先会与第1个元素(最顶层元素)进行比较,如果小于第1个元素就执行左边的分支,继续和该分支的子元素进行比较。如果大于第1个元素就执行右边的分支,继续和该分支的子元素进行比较。如此往复,直到与最后一个元素进行比较时,如果新元素小于最后一个元素就将其放在最后一个元素的左子树上,如果大于最后一个元素就将其放在最后一个元素的右子树上。
在TreeSet集合中存放Student类型对象时,如果Student类没有实现Comparable接口,则Student类型的对象将不能进行比较,这时,TreeSet集合就不知道按照什么排序规则对Student对象进行排序,最终导致程序报错。因此,为了在TreeSet集合中存放Student对象,必须使Student类实现Comparable接口。
定义的类没有实现Comparable接口或者对于实现了Comparable接口的类而不想按照定义的compareTo()方法进行排序,,例如,希望字符串可以按照长度来进行排序,这时,可以通过自定义比较器的方式对TreeSet集合中的元素排序,即实现Comparator接口,在创建TreeSet集合时指定比较器。
1.59 Map接口简介
在现实生活中,每个人都有唯一的身份证号,通过身份证号可以查询到这个人的信息,这两者是一对一的关系。
在应用程序中,如果想存储这种具有对应关系的数据,则需要使用JDK中提供的Map接口。
Map接口是一种双列集合,它的每个元素都包含一个键对象Key和值对象Value,键和值对象之间存在一种对应关系,称为映射。
从Map集合中访问元素时,只要指定了Key,就能找到对应的Value。

1.60 HashMap集合
HashMap集合是Map接口的一个实现类,它用于存储键值映射关系,但必须保证不出现重复的键。
在程序开发中,经常需要取出Map中所有的键和值,那么如何遍历Map中所有的键值对呢?
有两种方式可以实现,第一种方式就是先遍历Map集合中所有的键,再根据键获取相应的值。
另外一种遍历方式是先获取集合中的所有的映射关系,然后从映射关系中取出键和值
在Map中,还提供了一个values()方法,通过这个方法可以直接获取Map中存储所有值的Collection集合。
HashMap集合迭代出来元素的顺序和存入的顺序是不一致的。
如果想让这两个顺序一致,可以使用Java中提供的LinkedHashMap类,它是HashMap的子类,和LinkedList一样也使用双向链表来维护内部元素的关系,使Map元素迭代的顺序与存入的顺序一致。
1.61 TreeMap集合
TreeMap集合是用来存储键值映射关系的,其中不允许出现重复的键。在TreeMap中是通过二叉树的原理来保证键的唯一性,这个TreeSet集合存储的原理一样,因此TreeMap中所有的键是按照某种顺序排列的。
在使用TreeMap集合时,也可以通过自定义比较器的方式对所有的键进行排序。
1.62 Properties集合
Map接口中还有一个实现类Hashtable,它在存取元素时速度很慢,目前基本上被HashMap类所取代。
但Hashtable类有一个子类Properties在实际应用中非常重要,Properties主要用来存储字符串类型的键和值,在实际开发中,经常使用Properties集合来存取应用的配置项。
假设有一个文本编辑工具,要求默认背景色是红色,字体大小为14px,语言为中文,其配置项应该是下面的样子:
Backgroup-color=red
Font-size=14px
language=chinese
1.63 泛型
为什么使用泛型
当把一个对象存入集合后,集合会“忘记”这个对象的类型,将该对象从集合中取出时,这个对象的编译类型就变成了Object类型。
换句话说,我们在程序中无法确定一个集合中的元素到底是什么类型的。那么在取出元素时,如果进行强制类型转换就很容易出错。
为了解决这个问题,在Java中引入了“参数化类型(parameterized type)”这个概念,即泛型。
它可以限定方法操作的数据类型,在定义集合类时,可以使用“<参数化类型>”的方式指定该类中方法操作的数据类型。
限定了ArrayList集合只能存储String类型元素,将改写后的程序再次编译,程序在编译时期就会出现错误提示

程序编译报错的原因是修改后的代码限定了集合元素的数据类型,ArrayList
1.64 自定义泛型
那么泛型的作用是什么,在程序中是否能自定义泛型呢
从运行结果可以看出,程序在编译时期就报错,这是因为在代码第13行处存入了一个Integer类型的数据,在代码第14行处取出这个数据时,将该数据转换成了String类型,出现了类型不匹配的错误。
为了避免这个问题,就可以使用泛型,如果在定义一个类CachePool时使用
1.65 collections
•JDK提供了一个工具类专门用来操作集合,这个类就是Collections,它位于java.util包中。Collections类中提供了大量的方法用于对集合中元素进行排序、查找和修改等操作,接下来对这些常用的方法进行介绍。
1 排序操作

2、查找、替换操作

1.66 Arrays
java.util包中还提供了一个专门用于操作数组的工具类——Arrays。Arrays工具类提供了大量的静态方法
使用Arrays的sort()方法排序
使用Arrays的binarySearch(Object[] a, Object key)方法查找元素
使用Arrays的copyOfRange(int[] original, int from, int to)方法拷贝元素
在程序开发中,经常需要在不破坏原数组的情况下使用数组中的部分元素,这时可以使用Arrays工具类的copyOfRange(int[] original,int from,int to)方法将数组中指定范围的元素复制到一个新的数组中,该方法中参数original表示被复制的数组,from表示被复制元素的初始索引(包括),to表示被复制元素的最后索引(不包括)
使用Arrays的fill(Object[] a, Object val)方法填充元素
程序开发中,经常需要用一个值替换数组中的所有元素,这时可以使用Array的fill(Object[] a, Object val)方法,该方法可以将指定的值赋给数组中的每一个元素
使用Arrays的toString(int[] arr)方法把数组转换为字符串
在程序开发中,经常需要把数组以字符串的形式输出,这时就可以使用Arrays工具类的另一个方法toString(int[] arr)。需要注意的是,该方法并不是对Object类toString()方法的重写,只是用于返回指定数组的字符串形式
1.67处理模型
Java中常用的处理模型有两种:Servlet和JSP。
Servlet是一种Java类,它可以接收来自客户端的HTTP请求,并生成HTTP响应。它们通常用于处理Web应用程序的后端逻辑。Servlet可以通过扩展 javax.servlet.http.HttpServlet类来创建,并实现 doGet()、doPost()等方法来处理请求。Servlet通常用于处理业务逻辑、数据存储和数据处理等任务。
JSP(JavaServer Pages)是一种动态网页技术,它使用Java代码和HTML标记创建动态网页。JSP文件通常包含HTML标记和Java代码块,可以通过JSP引擎来动态生成HTML页面。JSP通常用于呈现页面内容和与客户端进行交互。
这两个类型在Java Web开发中都扮演着重要的角色。Servlet提供了一种处理请求的方式,而JSP提供了一种动态生成HTML页面的方式。通常情况下,在Web应用程序中,Servlet和JSP是相互配合使用的,Servlet负责业务逻辑和数据处理,而JSP负责呈现页面内容。
1.68 JDBC
JDBC(Java Database Connectivity)是一种用于与关系型数据库进行交互的Java API。要连接到数据库并执行SQL语句,需要执行以下基本连接语法和步骤:
1.加载数据库驱动程序:在连接到数据库之前,需要加载数据库驱动程序。可以使用Class.forName()方法动态加载驱动程序,也可以使用Java 6及以上版本的自动驱动程序加载功能。
1 | |
2.创建数据库连接:要连接到数据库,需要指定数据库的URL、用户名和密码。可以使用DriverManager.getConnection()方法创建数据库连接。
1 | |
3.创建Statement对象:要执行SQL语句,需要创建一个Statement对象。可以使用Connection.createStatement()方法创建Statement对象。
1 | |
4.执行SQL语句:可以使用Statement对象的execute()、executeUpdate()或executeQuery()方法执行SQL语句。
1 | |
5.处理结果集:如果SQL语句返回结果集,可以使用ResultSet对象处理结果集。
1 | |
6.关闭资源:在使用完数据库连接、Statement对象和ResultSet对象后,需要及时关闭它们以释放资源。
1 | |
关于 JDBC, 哪一项叙述是不正确的(D)。
A.JDBC 屏蔽了底层数据库系统的差异性, 为程序员访问不同数据库提供统一的
面向对象的编程接口。
B.JDBC 编程接口 中的很多方法声明可能抛出 SQLException 异常, 必须用
try-catch 进行捕捉处理或继续声明抛出。
C.Connection 类型的实例代表具体的数据库连接, 为向目 标数据库发送和执行
SQL 语句提供支持。
D.Statement 类型的实例用于执行不带参数的 SQL 语句, PreparedStatement 可用
于执行带参数的 SQL 语句, 相比之下, Statement 的执行效率较高。
个人解析: PreparedStatement 有预编译机制, 与 Statement 相比较, 执行效率较
高。
1.69 java API
StringBuffer
为了便于对字符串的修改,在JDK中提供了一个StringBuffer类(也称字符串缓冲区)。StringBuffer类和String类最大的区别在于它的内容和长度都是可以改变的。StringBuffer类似一个字符容器,当在其中添加或删除字符时,并不会产生新的StringBuffer对象。
StringBuffer类和String类有很多相似之处,初学者使用时容易混淆。
•1、String类表示的字符串是常量,一旦创建后,内容和长度都是无法改变的。StringBuffer表示字符容器,其内容和长度都可以随时修改。在操作字符串时,如果该字符串仅用于表示数据类型,则使用String类即可,但是如果需要对字符串中的字符进行增删操作,则使用StringBuffer类。
•2、String类覆盖了Object类的equals()方法,而StringBuffer类没有覆盖Object类的equals()方法
•3、String类对象可以用操作符“+”进行连接,而StringBuffer类对象之间不能
1.70 按值传递与按引用传递
按值传递是指在函数调用时,将参数的值复制一份,传递给函数内部使用。函数内部对该参数的任何修改都不会影响原始参数的值。
按引用传递是指在函数调用时,将参数的地址传递给函数。这意味着,在函数内部对参数进行的任何修改都将影响原始参数的值
2.知识点总结
2.1 关系
实现关系是实现类和接口之间的关系; 泛化关系是类(或接口) 和子
类(或子接口) 之间的关系, 因此 A 和 B 很容易被排除掉; 类和该类数据成员
类之间的关系是组合关系的一种形式; 类与该类方法成员的形参类所对应的关系
就是依赖关系的一种形式。
2.2 equals == compareTo区别
主要考查 equals、 ==和 compareTo 知识点。 equals 比较两个字符串对
象的值是否相同, ==比较两个字符串对象的地址是否相同, compareTo 按照字典
顺序比较两个字符串的值是否相等(如果参数字符串等于此字符串, 则返回值 0,
否则返回值就是两个字符串首次出现不同字符的 ASCII 的差值, 为正数或者负
数)。
2.3 java关键字
48个关键字:abstract、assert、boolean、break、byte、case、catch、char、class、continue、default、do、double、else、enum、extends、final、finally、float、for、if、implements、import、int、interface、instanceof、long、native、new、package、private、protected、public、return、short、static、strictfp、super、switch、synchronized、this、throw、throws、transient、try、void、volatile、while。
2个保留字(现在没用以后可能用到作为关键字):goto、const。
3个特殊直接量:true、false、null。
2.4 计算数组的最值
Arrays.steam(arr).max().getAsInt();
Arrays.steam(arr).min().getAsInt();
2.5 Java Arrays方法
https://www.runoob.com/manual/jdk11api/java.base/java/util/Arrays.html#toString(boolean
static <T> List<T> |
asList(T... a) |
返回由指定数组支持的固定大小的列表。 |
|---|
1 | |
static int |
compare(int[] a, int[] b) |
int字典顺序比较两个 int阵列。 |
|---|
1 | |
static int[] |
copyOf(int[] original, int newLength) |
使用零复制指定的数组,截断或填充(如有必要),以使副本具有指定的长度。 |
|---|
1 | |
static int[] |
copyOfRange(int[] original, int from, int to) |
将指定数组的指定范围复制到新数组中。 |
|---|
1 | |
static String |
deepToString(Object[] a) |
返回指定数组的“深层内容”的字符串表示形式。 |
|---|
1 | |
static boolean |
equals(int[] a, int aFromIndex, int aToIndex, int[] b, int bFromIndex, int bToIndex) |
如果指定范围内的两个指定的int数组彼此相等 ,则返回true。 |
|---|
1 | |
static void |
fill(int[] a, int fromIndex, int toIndex, int val) |
将指定的int值分配给指定的int数组的指定范围的每个元素。 |
|---|
1 | |
static int |
hashCode(int[] a) |
根据指定数组的内容返回哈希码。 |
|---|
1 | |
static int |
mismatch(int[] a, int aFromIndex, int aToIndex, int[] b, int bFromIndex, int bToIndex) |
查找并返回指定范围内两个 int数组之间第一个不匹配的相对索引,否则如果未找到不匹配则返回-1。 |
|---|
1 | |
static void |
parallelSort(int[] a, int fromIndex, int toIndex) |
将指定的数组范围按数字升序排序。 |
|---|
1 | |
static void |
sort(int[] a, int fromIndex, int toIndex) |
按升序对数组的指定范围进行排序。 |
|---|
1 | |
static <T> void |
sort(T[] a, int fromIndex, int toIndex, Comparator<? super T> c) |
根据指定比较器引发的顺序对指定对象数组的指定范围进行排序。 |
|---|
1 | |
static IntStream |
stream(int[] array, int startInclusive, int endExclusive) |
返回指定数组的指定范围作为其源的顺序IntStream 。 |
|---|
1 | |
static String |
toString(int[] a) |
返回指定数组内容的字符串表示形式。 |
|---|
1 | |
2.6 字符串长度与数组长度
字符串 :length()
数组:length
2.7 字符串方法
https://www.runoob.com/manual/jdk11api/java.base/java/lang/String.html
char |
charAt(int index) |
返回指定索引处的 char值。 |
|---|
1 | |
int |
codePointAt(int index) |
返回指定索引处的字符(Unicode代码点)。 |
|---|
1 | |
int |
compareTo(String anotherString) |
按字典顺序比较两个字符串。 |
|---|
1 | |
int |
compareToIgnoreCase(String str) |
按字典顺序比较两个字符串,忽略大小写差异。 |
|---|
1 | |
String |
concat(String str) |
将指定的字符串连接到此字符串的末尾。 |
|---|
1 | |
boolean |
contains(CharSequence s) |
当且仅当此字符串包含指定的char值序列时,才返回true。 |
|---|
1 | |
static String |
copyValueOf(char[] data, int offset, int count) |
相当于valueOf(char[], int, int) 。 |
|---|
1 | |
boolean |
endsWith(String suffix) |
测试此字符串是否以指定的后缀结尾。 |
|---|
1 | |
boolean |
equals(Object anObject) |
将此字符串与指定的对象进行比较。 |
|---|
1 | |
boolean |
equalsIgnoreCase(String anotherString) |
将此 String与另一个 String比较,忽略了大小写。 |
|---|
static String |
format(String format, Object... args) |
使用指定的格式字符串和参数返回格式化字符串。 |
|---|
1 | |
byte[] |
getBytes() |
使用平台的默认字符集将此 String编码为字节序列,将结果存储到新的字节数组中。 |
|---|
int |
hashCode() |
返回此字符串的哈希码。 |
|---|
int |
indexOf(int ch) |
返回指定字符第一次出现的字符串中的索引。 |
|---|---|---|
int |
indexOf(int ch, int fromIndex) |
返回指定字符第一次出现的此字符串中的索引,从指定索引处开始搜索。 |
int |
indexOf(String str) |
返回指定子字符串第一次出现的字符串中的索引。 |
int |
indexOf(String str, int fromIndex) |
从指定的索引处开始,返回指定子字符串第一次出现的字符串中的索引。 |
int |
lastIndexOf(int ch) |
返回指定字符最后一次出现的字符串中的索引。 |
|---|---|---|
int |
lastIndexOf(int ch, int fromIndex) |
返回指定字符最后一次出现的字符串中的索引,从指定的索引开始向后搜索。 |
int |
lastIndexOf(String str) |
返回指定子字符串最后一次出现的字符串中的索引。 |
int |
lastIndexOf(String str, int fromIndex) |
返回指定子字符串最后一次出现的字符串中的索引,从指定索引开始向后搜索。 |
static String |
join(CharSequence delimiter, CharSequence... elements) |
返回由 CharSequence elements的副本组成的新String,该副本与指定的 delimiter的副本连接在一起。 |
|---|---|---|
static String |
join(CharSequence delimiter, Iterable<? extends CharSequence> elements) |
返回由 String的副本组成的新 String ,其中 CharSequence elements指定的 delimiter的副本。 |
1 | |
boolean |
matches(String regex) |
判断此字符串是否与给定的regular expression匹配。 |
|---|
String |
replace(char oldChar, char newChar) |
返回从替换所有出现的导致一个字符串 oldChar在此字符串 newChar |
|---|
1 | |
String |
replace(CharSequence target, CharSequence replacement) |
将此字符串中与文字目标序列匹配的每个子字符串替换为指定的文字替换序列。 |
|---|---|---|
String |
replaceAll(String regex, String replacement) |
将给定替换的给定regular expression匹配的此字符串的每个子字符串替换。 |
String |
replaceFirst(String regex, String replacement) |
将给定替换的给定regular expression匹配的此字符串的第一个子字符串替换。 |
String[] |
split(String regex, int limit) |
|---|
1 | |
boolean |
startsWith(String prefix, int toffset) |
测试从指定索引开始的此字符串的子字符串是否以指定的前缀开头。 |
|---|
1 | |
CharSequence |
subSequence(int beginIndex, int endIndex) |
返回作为此序列的子序列的字符序列。 |
|---|
String |
substring(int beginIndex, int endIndex) |
返回一个字符串,该字符串是此字符串的子字符串。 |
|---|
1 | |
char[] |
toCharArray() |
将此字符串转换为新的字符数组。 |
|---|---|---|
String |
toLowerCase() |
使用默认语言环境的规则将此 String所有字符转换为小写。 |
String |
toLowerCase(Locale locale) |
使用给定 Locale的规则将此 String所有字符转换为 Locale 。 |
String |
toString() |
这个对象(已经是一个字符串!) |
String |
toUpperCase() |
使用默认语言环境的规则将此 String所有字符转换为大写。 |
String |
toUpperCase(Locale locale) |
使用给定 Locale的规则将此 String所有字符转换为大写。 |
static String |
valueOf(int i) |
返回 int参数的字符串表示形式。 |
|---|
字符串与其他数据类型的转换
| 数据类型 | 字符串转换为其他数据类型的方法 | 其它数据类型转换为字符串的方法1 | 其他数据类型转换为字符串的方法2 |
|---|---|---|---|
| boolean | Boolean.getBoolean(str) | String.valueOf([boolean] b) | Boolean.toString([boolean] b) |
| int | Integer.parseInt(str) | String.valueOf([int] i) | Int.toString([int] i) |
| long | Long.parseLong(str) | String.valueOf([long] l) | Long.toString([long] l) |
| float | Float.parseFloat(str) | String.valueOf([float] f) | Float.toString([float] f) |
| double | double.parseFloat(str) | String.valueOf([double] d) | Double.toString([double] d) |
| byte | Byte.parseByte(str) | String.valueOf([byte] bt) | Byte.toString([byte] bt) |
| char | str.charAt(i) | String.valueOf([char] c) | Character.toString([char] c) |
2.8 Integer方法
static int |
compare(int x, int y) |
以数字方式比较两个 int值。 |
|---|
1 | |
int |
compareTo(Integer anotherInteger) |
以数字方式比较两个 Integer对象。 |
|---|---|---|
static int |
compareUnsigned(int x, int y) |
比较两个 int值,将数值视为无符号。 |
int |
intValue() |
返回此值 Integer为 int 。 |
|---|
static int |
max(int a, int b) |
返回两个 int值中较大的一个, int调用 Math.max一样 。 |
|---|---|---|
static int |
min(int a, int b) |
返回两个 int值中较小的一个, int调用 Math.min一样 。 |
static int |
parseInt(CharSequence s, int beginIndex, int endIndex, int radix) |
解析CharSequence参数作为有符号 int指定 radix ,在指定的开始 beginIndex并延伸到 endIndex - 1 。 |
|---|---|---|
static int |
parseInt(String s) |
将字符串参数解析为带符号的十进制整数。 |
static int |
parseInt(String s, int radix) |
将字符串参数解析为第二个参数指定的基数中的有符号整数。 |
1 | |
static int |
sum(int a, int b) |
根据+运算符将两个整数相加。 |
|---|
static String |
toBinaryString(int i) |
返回整数参数的字符串表示形式,作为base 2中的无符号整数。 |
|---|---|---|
static String |
toHexString(int i) |
返回整数参数的字符串表示形式,作为基数为16的无符号整数。 |
static String |
toOctalString(int i) |
返回整数参数的字符串表示形式,作为基数为8的无符号整数。 |
static String |
toString(int i, int radix) |
返回第二个参数指定的基数中第一个参数的字符串表示形式。 |
|---|
static Integer |
valueOf(int i) |
返回表示指定的 int值的 Integer实例。 |
|---|---|---|
static Integer |
valueOf(String s) |
返回一个 Integer物体保持在指定的值 String 。 |
static Integer |
valueOf(String s, int radix) |
返回 Integer对象,当使用第二个参数给出的基数进行解析时,该对象保存从指定的 String提取的值。 |
1 | |
2.9 Math方法
https://www.runoob.com/manual/jdk11api/java.base/java/lang/Math.html
2.10 for与while循环
1 | |
2.11判断是否为整数
1 | |
2.12因子,因数(约数),素数(质数),合数,自然数的概念
因子就是可以整除这个数的数,不不包括这个数本身
因数(约数)包括这个数本身
完数是指此数的因子之和等于此数
素数(质数)是在大与1的自然数中,除1和它本身外,不能被其他自然数整除(除0以外)的数称之素数
合数是比1大但不是素数的数
自然数是0,1,2,3,4….
2.13 初始化最小值与最大值
1 | |
初始化,确保任何出现的次数都会比这些初始化值更大或更小,这样就可以找到最大和最小值,而不会受到初始化值干扰
2.14 处理换行符
经过从网上查询资料,了解到Scanner是一个扫描器,它扫描数据都是去内存中一块缓冲区中进行扫描并读入数据的,而我们在控制台中输入的数据也都是被先存入缓冲区中等待扫描器的扫描读取。这个扫描器在扫描过程中判断停止的依据就是“空白符”,空格、回车等都算作是空白符。
next()与nextLine()的区别
next()方法在读取内容时,会过滤掉有效字符前面的无效字符,对输入有效字符之前遇到的空格键、Tab键或Enter键等结束符,next()方法会自动将其过滤掉;只有在读取到有效字符之后,next()方法才将其后的空格键、Tab键或Enter键等视为结束符;所以next()方法不能得到带空格的字符串。
nextLine()方法字面上有扫描一整行的意思,它的结束符只能是Enter键,即nextLine()方法返回的是Enter键之前没有被读取的所有字符,它是可以得到带空格的字符串的。
next()方法在扫描到空白符的时候会将前面的数据读取走,但会丢下空白符“\r”在缓冲区中
nextLine()方法在扫描的时候会将扫描到的空白符一同清理掉
问题解决
1.可以在后面加一个 nextLine();专门读取无效字符
2.或者就别用nextLine()输入, 直接用next();
例如
1 | |
1 | |
[java] next()和nextLine()的区别和使用,干活满满哦_next和nextline-CSDN博客
2.15 除法问题
不可以两个 int变量直接做除法,会丢失精度。
推荐:将其中一个 int变量强制转换类型为小数即可。
两个 int 变量的除法运算 结果的精度问题
代码如下:
1 | |
两个 int类型加减、乘法都没有问题。但是除法:
两个 int进行除法运算,结果依旧是 int类型。
所以像 5 / 2这样,结果明明为 2.5,但是小数部分会直接省略(int只用于存整数,没有存储浮点数的机制)。
2.16 正则表达式
https://www.runoob.com/java/java-regular-expressions.html
1 | |
2.17 BigDecimal
https://www.runoob.com/manual/jdk11api/java.base/java/math/BigDecimal.html
1 | |
常用构造方法

常用方法

BigDecimal |
abs() |
返回 BigDecimal其值是此的绝对值 BigDecimal ,其标为 this.scale() 。 |
|---|---|---|
BigDecimal |
abs(MathContext mc) |
返回 BigDecimal其值为此 BigDecimal的绝对值,并根据上下文设置进行舍入。 |
BigDecimal |
add(BigDecimal augend) |
返回 BigDecimal其值为 (this + augend) ,其比例为 max(this.scale(), augend.scale()) 。 |
BigDecimal |
add(BigDecimal augend, MathContext mc) |
返回 BigDecimal其值为 (this + augend) ,根据上下文设置进行舍入。 |
byte |
byteValueExact() |
将 BigDecimal转换为 byte ,检查是否丢失了信息。 |
int |
compareTo(BigDecimal val) |
将此 BigDecimal与指定的 BigDecimal 。 |
BigDecimal |
divide(BigDecimal divisor) |
返回 BigDecimal其值为 (this / divisor) ,其首选比例为 (this.scale() - divisor.scale()) ; 如果无法表示准确的商(因为它具有非终止的十进制扩展),则抛出 ArithmeticException 。 |
BigDecimal |
divide(BigDecimal divisor, int roundingMode) |
**已过时。**应该优先使用方法divide(BigDecimal, RoundingMode) ,而不是这种传统方法。 |
BigDecimal |
divide(BigDecimal divisor, int scale, int roundingMode) |
**已过时。**应该优先使用方法divide(BigDecimal, int, RoundingMode)来使用该传统方法。 |
BigDecimal |
divide(BigDecimal divisor, int scale, RoundingMode roundingMode) |
返回 BigDecimal其值为 (this / divisor) ,其比例为指定的比例。 |
BigDecimal |
divide(BigDecimal divisor, MathContext mc) |
返回 BigDecimal其值为 (this / divisor) ,根据上下文设置进行舍入。 |
BigDecimal |
divide(BigDecimal divisor, RoundingMode roundingMode) |
返回 BigDecimal其值为 (this / divisor) ,其比例为 this.scale() 。 |
BigDecimal[] |
divideAndRemainder(BigDecimal divisor) |
返回一个两元件 BigDecimal阵列含有的结果 divideToIntegralValue ,随后的结果 remainder上的两个操作数。 |
BigDecimal[] |
divideAndRemainder(BigDecimal divisor, MathContext mc) |
返回一个两元件 BigDecimal阵列含有的结果 divideToIntegralValue ,随后的结果 remainder上与根据上下文设置进行舍入计算出的两个操作数。 |
BigDecimal |
divideToIntegralValue(BigDecimal divisor) |
返回 BigDecimal其值是 (this / divisor)舍入的商 (this / divisor)的整数部分。 |
BigDecimal |
divideToIntegralValue(BigDecimal divisor, MathContext mc) |
返回 BigDecimal ,其值是整数部分 (this / divisor) 。 |
double |
doubleValue() |
将 BigDecimal转换为 double 。 |
boolean |
equals(Object x) |
将此 BigDecimal与指定的 Object进行相等性比较。 |
float |
floatValue() |
将 BigDecimal转换为 float 。 |
int |
hashCode() |
返回此 BigDecimal的哈希码。 |
int |
intValue() |
将 BigDecimal成 int 。 |
int |
intValueExact() |
将 BigDecimal转换为 int ,检查是否丢失了信息。 |
long |
longValue() |
将 BigDecimal转换为 long 。 |
long |
longValueExact() |
将此 BigDecimal转换为 long ,检查是否丢失了信息。 |
BigDecimal |
max(BigDecimal val) |
返回 BigDecimal和 val 。 |
BigDecimal |
min(BigDecimal val) |
返回 BigDecimal和 val 。 |
BigDecimal |
movePointLeft(int n) |
返回一个 BigDecimal ,相当于这个小数点向左移动 n位置。 |
BigDecimal |
movePointRight(int n) |
返回一个 BigDecimal ,相当于这个小数点向右移动 n位置。 |
BigDecimal |
multiply(BigDecimal multiplicand) |
返回 BigDecimal其值为 (this × multiplicand) ,其比例为 (this.scale() + multiplicand.scale()) 。 |
BigDecimal |
multiply(BigDecimal multiplicand, MathContext mc) |
返回 BigDecimal其值为 (this × multiplicand) ,根据上下文设置进行舍入。 |
BigDecimal |
negate() |
返回 BigDecimal其值为 (-this) ,其比例为 this.scale() 。 |
BigDecimal |
negate(MathContext mc) |
返回 BigDecimal其值为 (-this) ,根据上下文设置进行舍入。 |
BigDecimal |
plus() |
返回 BigDecimal其值为 (+this) ,其比例为 this.scale() 。 |
BigDecimal |
plus(MathContext mc) |
返回 BigDecimal其值为 (+this) ,根据上下文设置进行舍入。 |
BigDecimal |
pow(int n) |
返回 BigDecimal其值为 (thisn) ,精确计算功率,精度无限制。 |
BigDecimal |
pow(int n, MathContext mc) |
返回 BigDecimal其值为 (thisn) 。 |
int |
precision() |
返回此 BigDecimal的 精度 。 |
BigDecimal |
remainder(BigDecimal divisor) |
返回 BigDecimal其值为 (this % divisor) 。 |
BigDecimal |
remainder(BigDecimal divisor, MathContext mc) |
返回 BigDecimal其值为 (this % divisor) ,根据上下文设置进行舍入。 |
BigDecimal |
round(MathContext mc) |
返回 BigDecimal根据四舍五入 MathContext设置。 |
int |
scale() |
返回 BigDecimal的 比例 。 |
BigDecimal |
scaleByPowerOfTen(int n) |
返回其数值等于(this * 10 n )的BigDecimal。 |
BigDecimal |
setScale(int newScale) |
返回 BigDecimal其标度为指定值,其值在数值上等于此 BigDecimal 。 |
BigDecimal |
setScale(int newScale, int roundingMode) |
**已过时。**应该优先使用方法setScale(int, RoundingMode)来使用该传统方法。 |
BigDecimal |
setScale(int newScale, RoundingMode roundingMode) |
返回 BigDecimal其比例为指定值,其未缩放值通过将此 BigDecimal值乘以或除以适当的10的幂来确定,以保持其总值。 |
short |
shortValueExact() |
将此 BigDecimal转换为 short ,检查是否丢失了信息。 |
int |
signum() |
返回此 BigDecimal的signum函数。 |
BigDecimal |
sqrt(MathContext mc) |
返回 this平方根的 this并根据上下文设置进行舍入。 |
BigDecimal |
stripTrailingZeros() |
返回 BigDecimal ,它在数值上等于此值,但从表示中删除了任何尾随零。 |
BigDecimal |
subtract(BigDecimal subtrahend) |
返回 BigDecimal其值为 (this - subtrahend) ,其比例为 max(this.scale(), subtrahend.scale()) 。 |
BigDecimal |
subtract(BigDecimal subtrahend, MathContext mc) |
返回 BigDecimal其值为 (this - subtrahend) ,根据上下文设置进行舍入。 |
BigInteger |
toBigInteger() |
将 BigDecimal转换为 BigInteger 。 |
BigInteger |
toBigIntegerExact() |
将 BigDecimal转换为 BigInteger ,检查是否丢失了信息。 |
String |
toEngineeringString() |
如果需要指数,则使用工程符号返回此 BigDecimal的字符串表示形式。 |
String |
toPlainString() |
返回此 BigDecimal的字符串表示形式,不带指数字段。 |
String |
toString() |
如果需要指数,则使用科学计数法返回此 BigDecimal的字符串表示形式。 |
BigDecimal |
ulp() |
返回此 BigDecimal的ulp(最后一个单位)的 BigDecimal 。 |
BigInteger |
unscaledValue() |
返回 BigInteger其值是此的 非标度值 BigDecimal 。 |
static BigDecimal |
valueOf(double val) |
转换一个 double成 BigDecimal ,使用 double通过所提供的规范的字符串表示 Double.toString(double)方法。 |
static BigDecimal |
valueOf(long val) |
将 long值转换为 BigDecimal ,其标度为零。 |
static BigDecimal |
valueOf(long unscaledVal, int scale) |
将 long值和 int比例转换为 BigDecimal 。 |
divide()方法的多种模式


2.18 BigInteger
https://www.runoob.com/manual/jdk1.6/java.base/java/math/BigInteger.html
https://blog.csdn.net/weixin_44259720/article/details/87002816
1 | |
1 | |

2.19 String数组的初始化
1 | |
1 | |
2.20 toCharArray() 方法
public char[] toCharArray()
toCharArray() 方法将字符串转换为字符数组。
1 | |
2.21 将数字转为字符串
1 | |
2.22 集合的扩容机制
1 | |
2.23 Collections方法
https://www.runoob.com/manual/jdk11api/java.base/java/util/Collections.html#reverseOrder()
Java Collections reverseOrder()用法及代码示例
2.24
2.25 Java printf 用法
https://www.runoob.com/w3cnote/java-printf-formate-demo.html
2.26 java四舍五入
1 | |
1 | |
1 | |
2.27 Java Comparator
Java Comparator使用指南 —- 看这一篇就够了_comparator接口-CSDN博客
【Java 8 新特性】Java Comparator | 比较器-CSDN博客
java8-Lambda中比较器Comparator的使用 - 知乎 (zhihu.com)
1 | |
1 | |
2.28 hasNext、hasNextLine、next、nextLine保姆级详解
https://blog.csdn.net/m0_56079407/article/details/120576881
2.29IntelliJ IDEA快捷键大全 + 动图演示
https://zhuanlan.zhihu.com/p/615560482
2.30 Eclipse 快捷键
https://zhuanlan.zhihu.com/p/117582747
2.31 List 与 new ArrayList<>() 与 List<List<String
我们为什么经常使用List list = new ArrayList<>() 而不是ArrayListlist = new ArrayList<>()-CSDN博客
List<List
1 | |
2.32 Deque deque = new LinkedList<>();
1 | |
deque: [Apple, Banana, Orange]
1 | |
2.33 Java8 Stream API 之 IntStream 用法全解
https://blog.csdn.net/qq_31865983/article/details/106443244
https://www.jianshu.com/p/461429a5edc9
https://www.runoob.com/manual/jdk11api/java.base/java/util/stream/IntStream.html
2.34 Java 8 Stream
Java 8 Stream | 菜鸟教程 (runoob.com)
Java8 Stream 用法大全 - 掘金 (juejin.cn)
2.35 LinkedList转换为数组,数组转换为LinkedList
Java程序将LinkedList转换为数组,数组转换为LinkedList - Java教程 - 鸟哥教程 (niaoge.com)
1 | |
1 | |
2.36 java的lambda表达式
Java Lambda 表达式 | 菜鸟教程 (runoob.com)
java8中的lambda表达式,看这篇就够了_java8 lambda-CSDN博客
2.37 哪些接口和类有contains方法
在Java的集合框架中,以下接口和类具有contains方法:
List接口:List接口的实现类(如ArrayList、LinkedList等)都具有contains(Object obj)方法,用于判断列表中是否包含指定的元素。
Set接口:Set接口的实现类(如HashSet、TreeSet等)也具有contains(Object obj)方法,用于判断集合中是否包含指定的元素。
Map接口:Map接口的实现类(如HashMap、TreeMap等)具有containsKey(Object key)和containsValue(Object value)方法,用于判断映射中是否包含指定的键或值。
String类:字符串类(java.lang.String)具有contains(CharSequence sequence)方法,用于判断字符串中是否包含指定的字符序列。
这些方法提供了便捷的方式来判断集合中是否包含某个元素或映射中是否包含某个键或值。请注意,不同的接口和类可能有不同的contains方法,参数的类型和功能可能会有所不同。因此,在使用contains方法时,请根据具体的集合类型选择正确的方法。
2.38 char[]数组转成String
我们可以使用 String 类的 String.valueOf(char) 方法和 Character 类的 Character.toString(char) 方法在 java 中将 char 转换为 String。
String.valueOf(char) 方法和 Character 类的 Character.toString(char)方法的区别:
1.String.valueOf(char) 方法可以将char[] 和char 变量转成String类型
2.Character.toString(char)方法只能将char 变量转成String类型
1 | |
还可以用String str = new String(charArray)
1 | |
2.39 Java Integer[]和int[]互相转换
Integer[]和int[]互转
JDK8之前
可以使用Apache Commons Lang3包中的工具类进行转换
1 | |
同理,其它基本类型的数组也可以使用这个方法转换成对应的对象数组.
该方法的底层是使用循环将基本类型数组中的元素给复制到一个新的对象数组中
JDK8
可以使用Stream流来实现互相转化
1 | |
2.40 Java Integer[]和int[]互相转换
1 | |
3.选择题
3.1 命名
1 | |
3.2 线程
1 | |
3.3 classpath
1 | |
3.4 扩容
1 | |
3.5 变量与对象
1 | |
3.6 异常
1 | |
3.7 覆盖(重写)和重载
1 | |
Java 集合框架