JAVA·醉翁之意不在酒
0.java
1.HelloWorld.java
1 | public class HelloWorld { //创建类 “HelloWorld”需要与文件名一致 |
使用cmd运行:(需要在该文件目录中)
1 | $ javac HelloWorld.java |
2.变量
1 | int a, b, c; // 声明三个int型整数:a、 b、c |
命名规则:
只能包含 大小写字母、数字、下划线 和 $ ,且不能由数字开头。
保留字不等于关键字,保留字中的const
,goto
都不是关键字,是java保留以供后续版本使用的
基本数据类型(八种)
整数类型
整型 | 占用字节空间大小 | 取值范围 | 默认值 |
---|---|---|---|
byte | 1字节 | $[-128 , 127]$ | 0 |
short | 2字节 | $[-32768 , 32767]$ | 0 |
int | 4字节 | $[-2^{31} , 2^{31} - 1 ] $ $\approx 2\times{10}^9$ | 0 |
long | 8字节 | $[-2^{63} , 2^{63} - 1]$ $\approx 9\times{10}^{18}$ | 0L |
浮点类型(小数)
float和double的精度是由尾数的位数来决定的。浮点数在内存中是按科学计数法来存储的,其整数部分始终是一个隐含着的“1”,由于它是不变的,故不能对精度造成影响。
浮点型 | 符号位(S) | 指数位(E) | 尾数位(M) |
---|---|---|---|
float | 1bit | 8bit | 23bit |
double | 1bit | 11bit | 52bit |
浮点型 | 占用字节空间大小 | 取值范围 | 默认值 |
---|---|---|---|
float | 4字节 | $2^{23} = 8388608$ | 0.0F |
double | 8字节 | $2^{52} = 4503599627370496$ | 0.0 |
字符类型
字符型 | 占用字节空间大小 | 取值范围 | 默认值 |
---|---|---|---|
char | 2字节 | 0 ~ 65535 | ‘\u0’ |
布尔类型
布尔型 | 占用字节空间大小 | 取值范围 | 默认值 |
---|---|---|---|
boolean | 视情况而定 | true、false | false |
数据类型转换
转化从低级到高级:byte,short,char(三者同级,不能自动转换)—> int —> long—> float —> double
低级转换高级:自动类型转换
高级转换低级:强制类型转换
1 | public class Demo { |
数据类型赋值
1 | //可以将低精度赋值给高精度 |
关于输入数字赋值的处理
当在java代码中输入一串数字时,编译器会判断一下是否在相应类型的范围内,若在,则
1 | long l = 10000000000; //整数过大 |
3.输入输出
1 | public class Main { |
next 和 nextLine 区别
next | nextLine |
---|---|
不能读入含有空格的字符串,以空格、Table、回车作为本次输入的结束符 | 可以读入空格.以回车作为结束符 |
不会读取回车作为它的值 | 会读取回车作为它的值 |
也就是说next不会消耗后面的空白符,只会跳过前面的空白符
4.循环结构
跟c++不能说是一模一样,只能说是没有区别
for
1 | for(int i = 0; i < 10; i++){ |
while
1 | int i = 0; |
do while
1 | int i = 0; |
5.分支结构
跟c++不能说是没有区别,只能说是一模一样
if
1 | public class Main { |
swich
1 | char grade = 'C'; |
输出 :
1
2 良好
你的等级是 C
假如没有break,则会输出符合条件的以下的所有case,直到出现break
1 | public class Test { |
输出:
1
2
3 1
2
default
6.数组
创建数组
数组是一种对象(但是在cpp里似乎属于变量)
以下是建议使用的方法
1 | public class TestArray { |
如果创建一个类的数组,但没有为数组中的元素赋值,那么这些元素的值将是该类的默认值。对于引用类型(如对象),默认值为null
。对于基本类型(如int
, double
等),它们的默认值是0(对于整数类型)或0.0(对于浮点类型)。
数组可以直接通过赋值创建:
1 | int[] b = {1,2,3}; |
实际上这里是编译器自己补上了缺失的内容,经过反编译后如下:
1 | int[] b = new int[]{1, 2, 3}; |
所以如果想先创建再赋值,不能缺失new
的过程
1 | int[] b ; |
二维数组的初始化
必须要设定第一个框里的值(行数)
1 | static int[][] a = new int [10][]; |
二维数组实际上只是一个包含int[]
类型的一位数组,所以说他的元素可以通过如下方式进行覆盖的,index
不需要全部一样。
1 | public static void main(String[] args) { |
遍历数组
1 | // 打印所有数组元素 |
For-Each 循环
JDK 1.5 引进了一种新的循环类型,被称为 For-Each 循环或者加强型循环,它能在不使用下标的情况下遍历数组。语法格式如下:
1 | // 打印所有数组元素 |
7.Math 类
1 | //三角函数全用弧度制 |
方法 | 含义 |
---|---|
n.???Value() |
将 Number 对象转换为xxx数据类型的值并返回**(数字间的相互转换)** |
n.compareTo(m) |
将number对象与参数比较,n>m返回1,n<m返回-1,n=m返回0 |
n.toString() |
变成字符串 |
Math.abs(n) |
绝对值 |
Math.ceil(n) |
向上取整,返回类型为double |
Math.floor(n) |
向下取整,返回类型为double |
Math.rint(n) |
四舍六入五成双 |
Math.round(n) |
四舍五入,等价于Math.floor(x+0.5) |
Math.min(n,m) Math.max(n,m) |
略 |
Math.exp(n) |
$e^n$ |
Math.log(n) |
$ln(n)$ |
Math.pow(n,m) |
$n^m$ |
Math.sqrt |
平方根 |
Math.random() |
$[0,1)$随机数 |
8.Character 类
方法 | 含义 |
---|---|
Character.isLetter(ch) |
是否是个字母(返回bool) |
Character.isDigit(ch) |
是否是个数字字符(返回bool) |
Character.toUpperCase(ch) |
转大写 |
Character.toLowerCase(ch) |
转小写 |
Character.toString(ch) |
返回字符的字符串形式,字符串的长度仅为1 |
9.BigInteger
Java中BigInteger类的使用方法详解,常用最全系列!-CSDN博客
读入方法
nextBigInteger()
:控制台读入一个BigInteger
型数据,类似于int
型的nextInt()
1 | public void test() { |
构造方法
默认为十进制,同时也支持自定义进制类型(已存在的)
1 | public void testScale() { |
基本运算
返回值为BigInteger
类型:add()
,subtract()
,multiply()
,divide()
,mod()
,remainder()
,pow()
,abs()
,negate()
1 | public void testBasic() { |
比较大小
compareTo()
返回一个int型数据:大于->1
等于->0
小于->-1
max()
,min()
:分别返回大的(小的)那个BigInteger
数据
1 | public void testCompare() { |
常量
ZERO
,ONE
,TEN
返回值为BigInteger
类型
1 | public void testFinalNum() { |
类型转换
将BigInteger
数据转换成基本数据类型,还可以转换成radix
进制的字符串形式
1 | public void testToAnother() { |
二进制运算(左移右移)
返回值为BigInteger
类型,此类方法不常用,有备无患
1 | public void testBinaryOperation() { |
权限控制
setBit()
,testBit()
:可用于菜单的权限控制,非常好用,原理如下:
1 | public void testSetAndTest() { |
构造方法没有任何返回类型,甚至没有void返回类型
10.继承(Inheritance)
可见性修饰符
public
可以在类、方法、数据源前使用public
修饰符,表示他们可以被任何其他类访问。protected
仅允许子类访问父类中的数据域或方法,同一个包中也可以访问。对于类,只能修饰内部类
默认修饰符(
default
)
默认类、方法和数据域仅可以被同一个包中的任何一个类访问。这称为包私有(package-private
)或包内访问(package-access
)。private
限定方法和数据域只能在自己的类中访问。注意修饰符private只能应用在类成员上,修饰符public可以应用在类或类成员上。在局部变量上使用public和private都会导致编译错误。对于类,只能修饰内部类
- 在大多数情况下构造方法都是公共的,但如果想防止用户创建类的实例,就使用私有构造方法,实例化时会提示构造方法不可视错误。例如Math类所有方法都是静态方法,所以为防止用户创建Math对象,其构造方法定义如下
1
2
3private Math(){
}
类中成员修饰符 | 同一类中可访问 | 同一包中可访问 | 在子类中可访问 | 在不同包中可访问 |
---|---|---|---|---|
public |
√ | √ | √ | √ |
protected |
√ | √ | √ | - |
(default ) |
√ | √ | - | - |
private |
√ | - | - | - |
- 数据、方法的访问权限 不能突破类的访问权限
- 子类可以扩大父类定义的作用范围,但是不能削弱父类的作用范围
@Override
在Java中,@Override
注解是一个元注解,它用于指示一个方法应该重写父类中的方法。使用@Override
注解可以帮助编译器检查代码的正确性,确保方法签名与父类中的方法签名匹配。
当你在子类中使用@Override
注解时,编译器会检查以下几点:
- 子类中的方法是否与父类中的方法具有相同的名称、参数列表和返回类型。
- 子类中的方法是否是父类中的方法的子类型。
- 子类中的方法是否具有与父类中要重写的方法相同(或大于)的访问级别(例如,都是public)。
如果满足上述条件,编译器将允许该方法重写父类中的方法。如果子类中的方法不满足这些条件,编译器将报错。
使用@Override
注解的好处是:
- 提高代码的可读性:通过在方法声明前添加
@Override
注解,可以清楚地表明该方法是重写父类中的方法。这有助于其他开发人员理解代码的结构和意图。 - 减少错误:编译器会检查代码的正确性,确保方法签名与父类中的方法签名匹配。这有助于避免因拼写错误或参数列表不匹配而无意间重写方法的情况。
- 增强代码的可维护性:如果父类中的方法签名发生变化,编译器将提示错误,从而及早发现并修复问题。这有助于保持代码的健壮性和可维护性。
总之,@Override
注解在Java中用于指示一个方法是重写父类中的方法,它有助于提高代码的可读性、减少错误并增强代码的可维护性。
示范代码
1 | package Book; |
1 | package Book; |
1 | package Book; |
super引用
super()
调用必须是(所有)构造函数主体中的第一条语句。- 当父类中有无参构造方法时(包括默认的),子类的构造方法可以自动调用
- 当父类不含无参构造方法时,子类必须要用
super
调用父类构造方法
- 无法使用super.super调用祖父类成员
方法重写(Overriding Methods)
子类方法访问权限不低于被覆盖的父类方法。
如果父类中的一个方法不希望被覆盖,用final修饰它:
1
public final void setPages(int numPages) {}
对象的真实类型决定方法调用的类型,子类对象调用子类版本,父类对象调用父类版本。
(调用哪一个版本,取决对象new的类型,而非对象引用类型)
且当引用类型为对象的父类时,不能调用子类中独有的方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15public static void main(String[] args) {
Dictionary dictionary = new Dictionary(1,100);
dictionary.setSuperDefinitions(101);
System.out.println(dictionary.definitions); //100
System.out.println(((Book)dictionary).definitions); //Book类中被覆盖的definitions:101
((Book)dictionary).setDefinitions(102); //这里只调用了Dictionary的setDefinitions方法
System.out.println(dictionary.definitions); //102
System.out.println(((Book)dictionary).definitions); //Book类中被覆盖的definitions:101
Book dictionary2 = new Dictionary(1,101);
dictionary2.setDefinitions(103); //这里也调用了Dictionary的setDefinitions
System.out.println(dictionary2.definitions); //Book类中被覆盖的definitions:0
System.out.println(((Dictionary)dictionary2).definitions); //Dictionary类中的definitions:103
}重写的方法要求形参相同,返回值相同或者为父类方法的返回值的子类。
(java编译器去检测时,先去看方法名是否相同,然后再去比较参数列表,如果不同就认为是重载,相同就判断是Override,随后再去判断返回值类型,不符合要求就遍历失败)
1 | //示例题目 |
- 子类无法直接访问父类的private成员,但是可以通过调用父类能访问该成员的方法来间接访问。
- 子类可以重写祖父类的方法。
- Two children of the same parent are called siblings.
标准覆盖的toString以及equals方法头
1 | class MyClass{ |
静态方法的覆盖
java静态方法不能重写,但是允许覆盖,要求是形参相同(否则也只认定为重载),返回值也必须相同或为父类返回值的子类(这就很奇怪了)
假如通过对象调用静态方法,看的是对象的引用类型而非对象new
的类型。
1 | public static void main(String[] args) { |
影子变量(Shadowing Vriables)
java中子类可以定义与父类同名的变量(虽然不提倡这么做),变量类型、是否静态、可见性修饰符毫无要求,便成为影子变量。
影子变量对于父类的变量仅仅是覆盖关系,即父类和子类中是两个不同的变量,只不过在子类中优先调用了这个影子变量,可以通过super
或者强转的方式调用。
同名变量的调用版本也取决于引用类型。
1 | public static void main(String[] args) { |
抽象类(Abstract Classes)
定义抽象方法:
1
public abstract void setDefinitions(int numDefinitions);
抽象方法需要不允许设置为
private
,尽量设置为public
或者protected
。抽象类的子类必须覆盖父类的抽象方法,否则它也将是抽象的。
抽象方法不能定义为最终方法或静态方法。
抽象类的使用是软件设计的一个重要元素,它允许我们在层次结构中建立公共元素,这些元素过于笼统,无法实例化。
抽象类不必一定包含抽象方法。
抽象类在类层次结构中充当占位符。即一个抽象类代表一个抽象体,本身并没有足够的定义使其成为可用类。(在UML类图(类层次结构)中,抽象类的类名用斜体表示)
与抽象类有关的变量,方法调用遵循正常类
1
2
3
4
5
6
7
8Media book1 = new Book(1);
book1.setDefinitions(100);
System.out.println(book1.definitions); //100
Media dictionary3 = new Dictionary(1,100);
((Book)dictionary3).setDefinitions(101);
System.out.println(((Dictionary)dictionary3).definitions); //Dictionary类中被覆盖的definitions:101
System.out.println(dictionary3.definitions); //Book类中继承Media的被覆盖的definitions:0
System.out.println(((Media)dictionary3).definitions); //Media类中被覆盖的definitions:0当抽象类中重写了一个其父类有的方法并将其抽象化时,便将其抽象化了,子类要求重写该方法。
11.接口(Interfaces)
基础操作
1 | package Test; |
1 | import Test.Doable; |
1 | package Book; |
Java接口是抽象方法和常量
final
的集合。出现非final
的变量会破坏接口的抽象性和不变性。接口中的抽象类访问权限必须是
public
,可以省略,但习惯不省略,abstract
可以被省略。接口可以继承其他接口,也只能继承接口。
1
interface I3 extends I1, I2 {}
implements
和extends
的书写顺序并没有严格的要求。但是,按照一般的编码规范,通常将implements
放在extends
之前。JDK1.8 以后,接口可以有
default
方法或static
方法(不能同时修饰),被称为默认方法和静态方法,都是**public
的可见度**,允许包含方法的实现,主要原因是为了增加代码的可读性和灵活性。通过允许接口包含实现和工具方法,我们可以将相关的行为组织在一个地方,而不是将它们分散在多个类中。- 但是
static
方法为了避免多实现带来的歧义,只能通过具体的接口名调用。在接口继承接口的情况下也无法将父接口的static
方法继承过来。
1
2
3
4
5
6
7
8public static void main(String[] args) {
CanDo dog = new CanDo();
Doable cat = new CanDo();
Doable.printTest(); //1
/*cat.printTest(); //错误:只能在包含接口类时调用static方法
dog.printTest(); //错误:只能在包含接口类时调用static方法
CanDo.printTest()*/ //错误:只能在包含接口类时调用static方法
}其中,
default
修饰的方法是可以被Override
的,并且是遵循new的类型(即对这些继承的处理等同于抽象类)。1
2
3
4
5
6
7
8
9
10
11
12
13public static void main(String[] args) {
CanDo dog = new CanDo();
Doable cat = new CanDo();
Doable.printTest(); //1
System.out.println(dog.say()); //miaomiao
System.out.println(cat.say()); //miaomiao
CanDo dogs = new VeryCanDo();
Doable dogss = new VeryCanDo();
VeryCanDo dogsss = new VeryCanDo(); //wangwang
System.out.println(dogs.say()); //wangwang
System.out.println(dogss.say()); //wangwang
System.out.println(dogsss.say()); //wangwang
}想要在其他子类调用这个
static
方法只能在父类去写一个,然后遵前文的各种规则。1
2
3
4
5
6//在CanDo中补一个这个方法
public class CanDo implements Doable {
static void printTest(){ //也就是说在父类去写一个同样的方法
System.out.println("2");
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14public static void main(String[] args) {
CanDo.printTest(); //2
VeryCanDo.printTest(); //2
CanDo dog = new CanDo();
Doable cat = new CanDo();
Doable dogs = new VeryCanDo();
CanDo dogss = new VeryCanDo();
VeryCanDo dogsss = new VeryCanDo();
/*cat.printTest(); //错误:只能在包含接口类时调用static方法*/
dog.printTest(); //2
/*dogs.printTest(); //错误:只能在包含接口类时调用static方法*/
dogss.printTest(); //2
dogsss.printTest(); //2
}- 但是
如果一个类实现了两个接口,并且这两个接口中都有同名的默认方法,那么这个类必须实现这个默认方法。
super
也可以运用于接口,形如Interface1.super.myMethod()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20interface Interface1 {
default void myMethod() {
System.out.println("Interface1's default method");
}
}
interface Interface2 {
default void myMethod() {
System.out.println("Interface2's default method");
}
}
class MyClass implements Interface1, Interface2 {
// 必须实现两个接口中的myMethod方法
public void myMethod() {
Interface1.super.myMethod(); // 调用Interface1中的myMethod
Interface2.super.myMethod(); // 调用Interface2中的myMethod
}
}
接口直接创建类
1 | interface I1{ |
1 | public static void main(String[] args) { |
在这里,直接用接口创建对象,实际上是写了一个实现了该接口的匿名类,在编译文件中可以发现多了Test$1.class
,Test$2.class
两个字节码文件
因此,虽然接口中有toString
的抽象方法,但是由于匿名类默认继承了Object
,这个抽象方法被Object
中的toString
实现了,固无需再次实现
Comparable
Comparable
位于java.lang
包中。这个接口主要用于对对象进行排序。当你希望一个类能够被排序时,通常会实现这个接口。Comparable
接口只有一个抽象方法:compareTo
,参数是一个对象,返回一个整型值。这个方法用于比较当前对象与另一个对象的大小。1
2
3public interface Comparable<T>{
int compareTo(T o); // 泛型
}为了使类能够自然排序,通常会按照某种属性或关系来定义
compareTo
方法。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15public class Person implements Comparable<Person> {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// 其他属性和方法...
public int compareTo(Person other) {
return this.age - other.age; // 比较年龄
}
}使用
Comparable
接口的好处是,你可以使用 Java 的内建排序方法(如Collections.sort()
或数组的Arrays.sort()
)来对实现这个接口的对象列表或数组进行排序,而不需要额外的比较器(Comparator)。这使得代码更加简洁和易于维护。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16import java.util.Arrays;
import java.util.List;
public class SortingExample {
public static void main(String[] args) {
Person[] persons = new Person[]{
new Person("Alice", 25),
new Person("Bob", 30),
new Person("Charlie", 20)
};
Arrays.sort(persons); // 使用默认的排序方式(按年龄升序)
for (Person person : persons) {
System.out.println(person.getName() + " " + person.getAge());
}
}
}使用
Comparator
:也可以创建一个Comparator
并传递给Arrays.sort()
方法:当
compare
方法返回负数、零或正数时,Arrays.sort()
会相应地认为第一个元素小于、等于或大于第二个元素。如果compare
方法返回正数,它意味着你告诉Arrays.sort()
方法:”第一个元素应该排在第二个元素之前”,从而导致这两个元素的位置交换。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
public class SortingExample {
public static void main(String[] args) {
Person[] persons = new Person[]{
new Person("Alice", 25),
new Person("Bob", 30),
new Person("Charlie", 20)
};
Arrays.sort(persons, new Comparator<Person>() { // 使用自定义的排序方式(按姓名升序)
public int compare(Person p1, Person p2) {
return p1.getName().compareTo(p2.getName()); // 按姓名升序排序
}
});
for (Person person : persons) {
System.out.println(person.getName() + " " + person.getAge());
}
}
}
12.多态性
- 在继承和接口两章已经讨论得差不多了,这里总结一下:
- 对于实例方法,永远调用的是对象本身的版本,而引用类型只是为了保证有这个方法。
- 当出现同名的类方法或者变量,看的都是引用类型。
- 接口里的
static
方法无法通过子类的类名来调用。
- 小讨论
- 可以这么理解:
- 当一个对象的方法发生重写时,他的父类中的方法都会链接至那个重写的方法。
- 调用一个对象的方法时还是会去看这个引用类型所对应的方法,只不过会调用到那个被重写的最新方法去罢了。
- 对于方法调用方法的情况,都是会去调用所在类中的方法,遇到重写时就会跳到最新的重写的那个类。
- 对于静态变量和变量、常量,也是遵循这个原则,调用方法所在类或者该引用类型所指类中的成员,只不过就没有跳转之类的花里胡哨了。
- 可以这么理解:
1 | package Test; |
1 | package Test2; |
1 | package Test2; |
下面给出这两个方法反编译过后的样子,便于理解:
1 | // |
1 | // |
关于继承的实验
- 这个例子里父类能调用或者重写祖父类,子类不行。
1
2
3
4
5
6
7
8
9
10
11
12package Test2;
public class B { //祖父类
public B(){
count++;
System.out.println("构造 B:" + count);
}
int h(){ //包访问权限,只有父类可见,子类不可见
System.out.println("调用了B.h()");
return 0;
}
}1
2
3
4
5
6
7
8
9
10
11
12package Test2;
public class A extends B { //父类
public A(int x){
System.out.println("构造 A: " + x);
}
public int i(){
System.out.println("调用了A.i()");
h();
return 0;
}
}1
2
3
4
5
6
7
8
9package Test;
import Test2.A;
public class C extends A{ //子类
public C(int x){
super(x);
}
}1
2
3
4
5
6
7
8
9
10public static void main(String[] args) {
C c = new C(666);
c.i();
}
\*
构造 B:1
构造 A: 666
调用了A.i()
调用了B.h()
*/
能不转就不转
对于直接使用数字,但是符合多个重载的方法的情况时,如输入g( int )
,但是同时有g( long )
,g( double )
,遵循能不自动转换就不自动转换的原则。
会优先转为int
,其次是long
,然后float
,最后考虑double
1 | package Test2; |
1 | package Test2; |
1 | public class Test { |
1 | 构造 B:1 |
13.异常
(1)try-catch-finally语句
执行顺序
在Java的try-catch语法中,如果try块中的代码抛出了异常,那么控制权将立即转移到与该异常匹配的catch块。这意味着,一旦异常被抛出,try块中剩余的代码将不会被执行。
例如:
1 | try { |
在这个例子中,10 / 0会抛出一个ArithmeticException,所以System.out.println(“Try block: Result is “ + result);这行代码将不会被执行。但是,System.out.println(“This will always be printed, regardless of whether an exception is thrown in the try block.”);这行代码会在try-catch块之后执行,无论try块中是否抛出了异常。
finally运行条件
在Java的try-catch-finally
语句中,finally
块是一个可选的部分,它总是在try
和catch
块之后执行,无论是否发生了异常。也就是说,无论try
块中的代码是否成功执行,或者是否抛出了异常,finally块中的代码都会执行。
(无论try或catch块中的代码是否返回)
1 | public void myMethod() { |
假如在finally
中也有return
,那么返回值将被覆盖。
这种设计使得finally
块非常适合执行一些清理工作,比如关闭打开的文件、释放数据库连接等。无论是否发生异常,这些清理工作都应该被执行,以确保资源的正确释放。
下面是一个简单的例子:
1 | public void myMethod() { |
(2)异常种类
1 | graph LR |
非受检异常:程序员可以直接使用throw
语句抛出异常,而不需要在方法签名中使用throws
关键字进行声明。这是因为编译器认为这些异常是可预见的,并且程序员应该负责在代码中适当地处理它们。
受检型异常:一种需要被显式处理的异常,需要在方法签名中使用throws关键字进行声明,以便告知调用者该方法可能会抛出异常,并要求调用者处理或继续抛出该异常。
IOException
IOException是Java中表示输入/输出异常的类。当进行输入/输出操作时,可能会发生各种异常,其中许多都属于IOException。以下是一些属于IOException的错误:
文件未找到异常(FileNotFoundException):当尝试打开不存在的文件时,会抛出此异常。
文件已存在异常(FileAlreadyExistsException):当尝试创建已存在的文件或目录时,会抛出此异常。
文件锁定异常(FileLockedException):当尝试对文件进行锁定操作时,如果文件已被其他进程锁定,则会抛出此异常。
非法参数异常(IllegalArgumentException):当输入参数不合法时,可能会抛出此异常。例如,当使用FileWriter构造函数时,如果传递给构造函数的字符编码无效,则会抛出此异常。
非法状态异常(IllegalStateException):当对象处于不适当的状态进行操作时,可能会抛出此异常。例如,当使用BufferedReader的readLine()方法读取已关闭的流时,会抛出此异常。
对象被破坏异常(ObjectInputValidationException):当尝试从反序列化对象时,如果输入流包含无效或损坏的对象数据,则会抛出此异常。
除了上述异常之外,IOException还包含其他与输入/输出操作相关的异常,例如读写超时、EOFException等。
(3)自定义异常
- 自定义异常作为内部类:
1 | public class MyService { |
将自定义异常作为内部类时,通常会使用public
和static
修饰符.
public
修饰符:- 确保异常类可以从外部访问:由于异常类是定义在另一个类中的,如果不使用
public
修饰符,外部类将无法直接访问它。通过将异常类声明为public
,我们确保了其他类可以访问并使用它。
- 确保异常类可以从外部访问:由于异常类是定义在另一个类中的,如果不使用
static
修饰符:- 便于引用和使用:当一个内部类被声明为
static
时,它可以作为顶层类来使用,而不需要外部类的名称。
- 便于引用和使用:当一个内部类被声明为
在其他类或包中,可以通过以下方式引用和使用这个自定义异常:
1 | import com.example.MyService.ServiceException; // 假设MyService位于com.example包中 |
- 自定义异常作为单独外部类:
1 | public class MyCustomException extends Exception { |
由于它是单独的外部类,其他类也可以直接通过MyCustomException
来引用和使用。
13.Collection
Collection Interfaces:
作集合的通用方法,包括添加、删除、遍历、查找等各个子类都需要实现
add(E e)
:将元素e添加到集合中
remove(Object o)
: 从集合中删除对象o
contains(Object o)
: 判断集合中是否包含对象o
size()
:返回集合中元素的个数
iterator()
: 返回集合中元素的迭代器
1 | graph LR |
Collections
Java集合框架提供的操作Set、List和Map等Collection的工具类
该类提供了一系列的静态方法,可以实现对集合进行排序、查找、替换、复制等操作
排序方法: sort
、reverse
、 shuffle
、swap
、rotate
查找方法: binarySearch
替换方法: replaceAll
、fill
复制方法:copy
同步方法: synchronizedCollection
、synchronizedList
、 synchronizedMap
等
不可修改方法: unmodifiableCollection
、unmodifiableList
、unmodifiableMap
等
其他方法: frequency
、maxmin
、disjoint
、frequency
、indexOfSubList
、lastlndexOfSubList
等
LinkList(链表)
总的来说,就是每一个链表的节点ListNode都是包含了data和next两个元素
其中next元素就是指向他的下个节点的位置
1 | public class ListNode<E>{ |
1 | class LinkedList<E>{ |
基本操作
1 | //=====遍历===== |
定位的基础上插入、删除
1 | //=====定位target===== |
- 本文作者: NICK
- 本文链接: https://nicccce.github.io/TechNotes/Java-Notes/
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!