因为每次要复习Java基础的时候,找起来总是复杂了些,就想着在博客中进行一个网站总结,之后还会不断更新。本博客的学习笔记是主要对于第一个网址的资料学习。
Java基础资料
C语言中文网(很全):Java学习教程,Java基础教程(从入门到精通)
菜鸟教程:Java 简介 | 菜鸟教程
Java笔试题
1. 简书:Java笔试题(单选题) - 简书
Java在线编译工具
Java入门基础
主要了解一些Java基础概念。
Java跨平台特性
java的跨平台,是指java在运行时是凌驾于os之上,是在jvm中运行的,跟os没有直接联系。
参考网址:java的跨平台特性是指_如何理解JAVA的跨平台特性_继续者张付的博客-CSDN博客
一、常量
常量值又称为字面常量,它是通过数据直接表示的,分为整型、实型、布尔值、字符型和字符串型、转义字符。
整型常量
整型占32位
- 十进制:54
- 八进制:0开头,如0125表示125
- 十六进制:0x或0X开头,如0x100表示十进制的256
特别注意:
1. 定义Java常量使用final
2. 定义Java常量时必须进行初始化
3. 常量不允许被修改,强行修改会报错
实型常量
分为float和double类型
特别注意:
1. 一定要有小数点
2. 科学记数法:1.75e5
3. float占32位,double占64位,实型默认为double类型
布尔型常量
......
字符型和字符串型
......
转义字符
......
二、数组
定义一维数组
type[] arrayName; // 数据类型[] 数组名;
或者
type arrayName[]; // 数据类型 数组名[];
分配空间
arrayName = new type[size]; // 数组名 = new 数据类型[数组长度];
初始化二位数组
type[][] arrayName = new type[][]{值 1,值 2,值 3,…,值 n}; // 在定义时初始化
type[][] arrayName = new typ,e[size1][size2]; // 给定空间,再赋值
type[][] arrayName = new type[size][]; // 数组第二维长度为空,可变化
三、封装、继承与多态(三大特征)
封装
封装将类的某些信息隐藏在类内部,不允许外部程序直接访问,只能通过该类提供的方法来实现对隐藏信息的操作和访问。
封装的特点:
* 只能通过规定的方法访问数据。
* 隐藏类的实例细节,方便修改和实现。
继承
继承就是在已经存在类的基础上进行扩展,从而产生新的类。已经存在的类称为父类、基类或超类,而新产生的类称为子类或派生类。在子类中,不仅包含父类的属性和方法,还可以增加新的属性和方法。
继承通过extends实现(接口继承接口时)。
类实现接口通过implements实现。
多态
多态是指在父类中定义的属性和方法被子类继承之后,可以具有不同的数据类型或表现出不同的行为,这使得同一个属性或方法在父类及其各个子类中具有不同的含义。
四、重载与重写
重载
如果同一个类中包含了两个或两个以上方法名相同的方法,但形参列表不同,这种情况被称为方法重载(overload)。
重写
在子类中如果创建了一个与父类中相同名称、相同返回值类型、相同参数列表的方法,只是方法体中的实现不同,以实现不同于父类的功能,这种方式被称为方法重写(override),又称为方法覆盖
五、抽象类
在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,那么这样的类称为抽象类。(定义有待修改)
抽象类的定义和使用规则如下:
- 抽象类和抽象方法都要使用 abstract 关键字声明。
- 如果一个方法被声明为抽象的,那么这个类也必须声明为抽象的。而一个抽象类中,可以有 0~n 个抽象方法,以及 0~n 个具体方法。
- 抽象类不能实例化,也就是不能使用 new 关键字创建对象。
六、接口
特别注意
1. 接口定义使用关键字interface;
2. 当没有public修饰时,接口的访问权限局限于所属的包;
3. 使用extends实现接口的继承(接口继承接口时);
4. 一个接口可以有多个直接父接口,但接口只能继承接口,不能继承类;
5. 方法的声明不需要其他修饰符,在接口中声明的方法,将隐式地声明为公有的 (public)和抽象的(abstract);
6. 在 Java 接口中声明的变量其实都是常量,接口中的变量声明,将隐式地声明为 public、static 和 final,即常量,所以接口中定义的变量必须初始化;
7. 接口没有构造方法,不能被实例化。
实现接口
接口的主要用途就是被实现类实现,一个类可以实现一个或多个接口,继承使用 extends 关键字。
七、抽象类和接口的区别
(1)接口是公开的,里面不能有私有的方法或变量,是用于让别人使用的,而抽象类是可以有私有方法或私有变量的。
(2)abstract class 在 Java 语言中表示的是一种继承关系,一个类只能使用一次继承关系。但是,一个类却可以实现多个interface,实现多重继承。接口还有标识(里面没有任何方法,如Remote接口)和数据共享(里面的变量全是常量)的作用。
(3)在abstract class 中可以有自己的数据成员,也可以有非abstarct的成员方法,而在interface中,只能够有静态的不能被修改的数据成员(也就是必须是 static final的,不过在 interface中一般不定义数据成员),所有的成员方法默认都是 public abstract 类型的。
(4)abstract class和interface所反映出的设计理念不同。其实abstract class表示的是"is-a"关系,interface表示的是"has-a"关系。
(5)实现接口的一定要实现接口里定义的所有方法,而实现抽象类可以有选择地重写需要用到的方法,一般的应用里,最顶级的是接口,然后是抽象类实现接口,最后才到具体类实现。抽象类中可以有非抽象方法。接口中则不能有实现方法。
(6)接口中定义的变量默认是public static final 型,且必须给其初值,所以实现类中不能重新定义,也不能改变其值。抽象类中的变量默认是 friendly 型,其值可以在子类中重新定义,也可以在子类中重新赋值。
八、内部类
在类内部可定义成员变量和方法,且在类内部也可以定义另一个类。如果在类 Outer 的内部再定义一个类 Inner,此时类 Inner 就称为内部类(或称为嵌套类)。
一般的非内部类是不允许有 private 与 protected 权限的,但内部类可以。内部类拥有外部类的所有元素的访问权限。
内部类可以分为:实例内部类、静态内部类和成员内部类。
类 A 中有内部类 B,而类 B 中还有内部类 C,那么通常将最外层的类称为顶层类(或者顶级类)。
内部类的特点如下:
1. 内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.class
文件,但是前面冠以外部类的类名和$
符号。
2. 内部类不能用普通的方式访问。内部类是外部类的一个成员,因此内部类可以自由地访问外部类的成员变量,无论是否为 private 的。
3. 内部类声明成静态的,就不能随便访问外部类的成员变量,仍然是只能访问外部类的静态成员变量。
注意:内部类与外部类不能重名。
实例内部类
定义:实例内部类是指没有用 static 修饰的内部类,有的地方也称为非静态内部类。
(实例内部类的举例说明见C语言中文网的参考教程)
1. 在实例内部类中,可以访问外部类的所有成员。
2. 在实例内部类中不能定义 static 成员,除非同时使用 final 和 static 修饰。
静态内部类
定义:静态内部类是指使用 static 修饰的内部类。
(静态内部类的举例说明见C语言中文网的参考教程)
1. 在创建静态内部类的实例时,不需要创建外部类的实例。
2. 静态内部类中可以定义静态成员和实例成员。外部类以外的其他类需要通过完整的类名访问静态内部类中的静态成员,如果要访问静态内部类中的实例成员,则需要通过静态内部类的实例。
3. 静态内部类可以直接访问外部类的静态成员,如果要访问外部类的实例成员,则需要通过外部类的实例去访问。
局部内部类
定义:局部内部类是指在一个方法中定义的内部类
(局部内部类的举例说明见C语言中文网的参考教程)
1. 局部内部类与局部变量一样,不能使用访问控制修饰符(public、private 和 protected)和 static 修饰符修饰。
2. 局部内部类只在当前方法中有效。
3. 局部内部类中不能定义 static 成员。
4. 局部内部类中还可以包含内部类,但是这些内部类也不能使用访问控制修饰符(public、private 和 protected)和 static 修饰符修饰。
5. 在局部内部类中可以访问外部类的所有成员。
6. 在局部内部类中只可以访问当前方法中 final 类型的参数与变量。如果方法中的成员与外部类中的成员同名,则可以使用 <OuterClassName>.this.<MemberName> 的形式访问外部类中的成员。
匿名类、匿名内部类
定义:匿名类是指没有类名的内部类,必须在创建时使用 new 语句来声明类。
(匿名内部类的举例说明见C语言中文网的参考教程)
其语法形式如下:
new <类或接口>() {
// 类的主体
};
匿名类有两种实现方式:
1. 继承一个类,重写其方法。
2. 实现一个接口(可以是多个),实现其方法。
匿名类的特点:
1. 匿名类和局部内部类一样,可以访问外部类的所有成员。如果匿名类位于一个方法中,则匿名类只能访问方法中 final 类型的局部变量和参数。
2. 匿名类中允许使用非静态代码块进行成员初始化操作。
Out anonyInter = new Out() {
int i; { // 非静态代码块
i = 10; //成员初始化
}
public void show() {
System.out.println("调用了匿名类的 show() 方法"+i);
}
};
3 .匿名类的非静态代码块会在父类的构造方法之后被执行。
lambda表达式
重点:9.23 lambda表达式的使用
九、Java集合
Java集合有Collection集合、List集合、Set集合、Map集合
特别注意
1. Collection 接口是 List、Set 和 Queue 接口的父接口,通常情况下不被直接使用;
2. List集合主要学习ArrayList和LinkedList这两个实现类的相关方法;
3. List集合允许有相同的元素,而Set集合不允许有相同的元素;
list.add(int index, E element)在指定位置插入元素,后面的元素都往后移一个元素;
list.add(E element)在表尾添加元素;
4. Set集合最多只允许包含一个 null 元素;
5. Set集合主要学习HashSet类和TreeSet类;
6. HashSet 不是同步的,如果多个线程同时访问或修改一个 HashSet,则必须通过代码来保证其同步。
7. HashSet:如果有两个元素通过 equals() 方法比较返回的结果为 true,但它们的 hashCode不相等,HashSet 将会把它们存储在不同的位置,依然可以添加成功。但是,如果向 Set 集合中添加两个相同的元素,则后添加的会覆盖前面添加的元素,即在 Set 集合中不会出现相同的元素。
8. TreeSet 类同时实现了 Set 接口和 SortedSet 接口。SortedSet 接口是 Set 接口的子接口,可以实现对集合进行自然排序;
9. TreeSet 只能对实现了 Comparable 接口的类对象进行排序;
10. Map 是一种键-值对(key-value)集合,Map 集合中的每一个元素都包含一个键(key)对象和一个值(value)对象。用于保存具有映射关系的数据;
11. Map:key 和 value 都可以是任何引用类型的数据;
12. Map 的 key 不允许重复,value 可以重复;
13. Map 中的 key 和 value 之间存在单向一对一关系,即通过指定的 key,总能找到唯一的、确定的 value;
Java中遍历Map集合的四种方式:章节11.6
for循环、for-each循环、迭代器Iterator、通过键找值
十、泛型
主要讲解:泛型集合、泛型类、泛型方法、泛型的高级用法
作用
泛型可以在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,提高了代码的重用率。
泛型集合
List<Book> bookList = new ArrayList<Book>(); // 定义泛型的 List 集合
泛型类
泛型类一般用于类中的属性类型不确定的情况下。在声明属性时,使用下面的语句:
private data_type1 property_name1;
public class Stu<N, A, S> {
private N name; // 姓名
private A age; // 年龄
private S sex; // 性别
...
}
泛型方法
注意
是否拥有泛型方法,与其所在的类是不是泛型没有关系。
如果 static 方法需要使用泛型能力,就必须使其成为泛型方法。
定义泛型方法的语法格式如下:
public static <T> List find(Class<T> cs,int userId){}
一般来说编写 Java 泛型方法,其返回值类型和至少一个参数类型应该是泛型,而且类型应该是一致的,如果只有返回值类型或参数类型之一使用了泛型,那么这个泛型方法的使用就被限制了。
泛型的高级用法
具体内容见:“Java基础资料->C语言中文网->11.17节”
11.18节图书信息查询,可以帮助理解“集合”与“泛型”。
十一、类与对象
面向对象的三个核心特性
1. 可重用性(代码重用,继承、封装、多态都是围绕这个特性);
2. 可扩展性:新的功能很容易加到系统中;
3. 可管理性:将功能和数据结合,方便管理;
认识类和对象
类是描述了一组有相同特性(属性)和相同行为(方法)的一组对象的集合;
类是实体对象的概念模型,因此通常是笼统的、不具体的;
类是构造面向对象程序的基本单位;
类的定义
定义类时,abstract和final不能同时出现;
abstract
:如果类被 abstract 修饰,则该类为抽象类,抽象类不能被实例化
但抽象类中可以有抽象方法(使用 abstract 修饰的方法)和具体方法(没有使用 abstract 修饰的方法)。继承该抽象类的所有子类都必须实现该抽象类中的所有抽象方法(除非子类也是抽象类)。
如果类被 final 修饰,则不允许被继承。
类的属性
final:表示将该成员变量声明为常量,其值无法更改。
初始化默认值:
- 整数型(byte、short、int 和 long)的基本类型变量的默认值为 0。
- 单精度浮点型(float)的基本类型变量的默认值为 0.0f。
- 双精度浮点型(double)的基本类型变量的默认值为 0.0d。
- 字符型(char)的基本类型变量的默认值为 “\u0000”。
- 布尔型的基本类型变量的默认值为 false。
- 数组引用类型的变量的默认值为 null。如果创建了数组变量的实例,但没有显式地为每个元素赋值,则数组中的元素初始化值采用数组数据类型对应的默认值。
成员方法的声明和调用
1. 一个完整的方法通常包括方法名称、方法主体、方法参数和方法返回值类型。
2. 方法的名称第一个单词的第一个字母是小写,第二单词的第一个字母是大写。
3. 形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。
4. 实参可以是常量、变量、表达式、方法等,无论实参是何种类型的量,在进行方法调用时,它们都必须具有确定的值
5. 方法调用中发生的数据传送是单向的,即只能把实参的值传送绐形参,而不能把形参的值反向地传送给实参。因此在方法调用过程中,形参的值发生改变,而实参中的值不会变化。
6. 对无参成员方法来说,是没有实际参数列表的(即没有 paramList),但方法名后的括号不能省略。
7. 程序中执行到调用成员方法时,Java 把实参值复制到一个临时的存储区(栈)中,形参的任何修改都在栈中进行,当退出该成员方法时,Java 自动清除栈中的内容。
8. 方法体中的局部变量的生存期与作用域是在本方法内。
9. 局部变量在使用前必须明确赋值,否则编译时会出错。
this关键字
1. 对于 static 修饰的方法而言,可以使用类来直接调用该方法,static 修饰的方法中不能使用 this 引用。
2. this( )访问构造方法:
public Student() {
this("张三");
}
3. this( ) 不能在普通方法中使用,只能写在构造方法中,并且在构造方法中使用时,必须是第一条语句。
创建对象
显式创建对象
1. 使用new关键字创建对象( 类名 对象名 = new 类名(); )
2. 调用 java.lang.Class 或者 java.lang.reflect.Constuctor 类的 newlnstance() 实例方法;
java.lang.Class Class 类对象名称 = java.lang.Class.forName(要实例化的类全称);
类名 对象名 = (类名)Class类对象名称.newInstance();
3. 调用对象的 clone() 方法(要实例化的类必须继承 java.lang.Cloneable 接口):
类名对象名 = (类名)已创建好的类对象名.clone();
特别注意
1. 使用 new 关键字或 Class 对象的 newInstance() 方法创建对象时,都会调用类的构造方法。
2. 使用 Class 类的 newInstance() 方法创建对象时,会调用类的默认构造方法,即无参构造方法。
3. 使用 Object 类的 clone() 方法创建对象时,不会调用类的构造方法,它会创建一个复制的对象,这个对象和原来的对象具有不同的内存地址,但它们的属性值相同。
匿名对象
特别注意
1. 匿名对象就是没有明确的给出名字的对象;
2. 而且匿名对象只在堆内存中开辟空间,而不存在栈内存的引用;
3. 匿名对象在实际开发中基本都是作为其他类实例化对象的参数传递的;、
访问对象的属性和行为
如果一个对象要被使用,则对象必须被实例化,如果一个对象没有被实例化而直接调用了对象中的属性或方法,则程序运行时会出现以下异常:
Exception in thread "main" java.lang.NullPointerException
对象的销毁
在清除对象时,由系统自动进行内存回收。
Java 语言的内存自动回收称为垃圾回收(Garbage Collection)机制,简称 GC。垃圾回收机制是指 JVM 用于释放那些不再使用的对象所占用的内存。
一个对象被当作垃圾回收的情况主要如下两种。
1)对象的引用超过其作用范围。
{
Object o = new Object(); // 对象o的作用范围,超过这个范围对象将被视为垃圾
}
2)对象被赋值为 null。
{
Object o = new Object();
o = null; // 对象被赋值为null将被视为垃圾
}
在 Java 的 Object 类中还提供了一个 protected 类型的 finalize() 方法,因此任何 Java 类都可以覆盖这个方法,在这个方法中进行释放对象所占有的相关资源的操作。
类注释
文档注释,可以生成开发者文档
类注释
/**
*@author: user
**/
方法注释
/**
* @param num1: 参数1
**/
字段注释
/**
* 字段含义
**/
访问控制符
通过使用访问控制修饰符来限制对对象私有属性的访问,可以获得 3 个重要的好处。
1. 防止对封装数据的未授权访问。
2. 有助于保证数据完整性。
3. 当类的私有实现细节必须改变时,可以限制发生在整个应用程序中的“连锁反应”。
类的访问控制符只能是空或者 public,方法和属性的访问控制符有 4 个,分别是 public、 private、protected 和 friendly,其中 friendly 是一种没有定义专门的访问控制符的默认情况。
访问范围 | private | friendly(默认) | protected | public |
---|---|---|---|---|
同一个类 | 可访问 | 可访问 | 可访问 | 可访问 |
同一包中的其他类 | 不可访问 | 可访问 | 可访问 | 可访问 |
不同包中的子类 | 不可访问 | 不可访问 | 可访问 | 可访问 |
不同包中的非子类 | 不可访问 | 不可访问 | 不可访问 | 可访问 |
static关键字
特别注意:
静态方法不能调用非静态成员,编译会报错。
静态变量与实例变量的区别如下:
1)静态变量
- 运行时,Java 虚拟机只为静态变量分配一次内存,在加载类的过程中完成静态变量的内存分配。
- 在类的内部,可以在任何方法内直接访问静态变量。
- 在其他类中,可以通过类名访问该类中的静态变量。
2)实例变量
- 每创建一个实例,Java 虚拟机就会为实例变量分配一次内存。
- 在类的内部,可以在非静态方法中直接访问实例变量。
- 在本类的静态方法或其他类中则需要通过类的实例对象进行访问。
静态变量在类中的作用如下:
1. 静态变量可以作为实例之间的共享数据,增加实例之间的交互性。
2. 如果类的所有实例都包含一个相同的常量属性,则可以把这个属性定义为静态常量类型,从而节省内存空间。例如,在类中定义一个静态常量 PI。
注意:在类中定义静态的属性(成员变量),在 main() 方法中可以直接访问,也可以通过类名访问,还可以通过类的实例对象来访问。
注意:在静态方法中不能使用 this 关键字,也不能使用 super 关键字。
静态代码块
静态代码块指 Java 类中的 static{ } 代码块,主要用于初始化类,为类的静态变量赋初始值,提升程序性能。
静态代码块的特点
1. 静态代码块类似于一个方法,但它不可以存在于任何方法体中。
2. 静态代码块可以置于类中的任何地方,类中可以有多个静态初始化块。
3. Java 虚拟机在加载类时执行静态代码块,所以很多时候会将一些只需要进行一次的初始化操作都放在 static 代码块中进行。
4. 如果类中包含多个静态代码块,则 Java 虚拟机将按它们在类中出现的顺序依次执行它们,每个静态代码块只会被执行一次。
5. 静态代码块与静态方法一样,不能直接访问类的实例变量和实例方法,而需要通过类的实例对象来访问。
静态导入
使用import static语句,用于导入指定类的单个静态成员变量、方法和全部静态成员变量、方法。
特别注意:
1. import static 语句也放在Java源文件的 package 语句(如果有的话)之后、类定义之前;
2. import 语句和 import static 语句之间没有任何顺序要求;
3. 使用 import 可以省略写包名,而使用 import static 可以省略类名;
final修饰符
final修饰变量:
2. final 用在变量的前面表示变量的值不可以改变,此时该变量可以被称为常量;
3. final修饰的变量即成为常量,只能赋值一次,但是 final 所修饰局部变量和成员变量有所不同:1) final 修饰的局部变量必须使用之前被赋值一次才能使用。2) final 修饰的成员变量在声明时没有赋值的叫“空白 final 变量”。空白 final 变量必须在构造方法或静态代码块中初始化;
4. 在使用 final 声明变量时,要求全部的字母大写;
final修饰方法
1. final 修饰的方法仅仅是不能被重写,并不是不能被重载;
final修饰类
1. final 用在类的前面表示该类不能有子类,即该类不可以被继承;
构造函数
特别注意:
1. 构造函数可以省略不写,但构造函数方法名必须与类同名且不能有返回值 (void也不行);普通方法也可以和类名相同;但是要有返回值或void,
2. 构造函数可以重载。
3. 构造方法不能被 static、final、synchronized、abstract 和 native(类似于 abstract)修饰。(构造方法用于初始化一个新对象,所以用 static 修饰没有意义;构造方法不能被子类继承,所以用 final 和 abstract 修饰没有意义;多个线程不会同时创建内存地址相同的同一个对象,所以用 synchronized 修饰没有必要。)
4. 只能与 new 运算符结合使用
5. 自行编写无参数、没有内容的构造函数,不能称为默认构造函数
析构函数
特别注意:
1. 当对象脱离其作用域时(例如对象所在的方法已调用完毕),系统自动执行析构方法;
2. 在Java的 Object 类中还提供了一个 protected 类型的 finalize() 方法,因此任何 Java 类都可以覆盖这个方法,在这个方法中进行释放对象所占有的相关资源的操作
对象的 finalize() 方法具有如下特点:
- 垃圾回收器是否会执行该方法以及何时执行该方法,都是不确定的;
- finalize() 方法有可能使用对象复活,使对象恢复到可触及状态;
- 垃圾回收器在执行 finalize() 方法时,如果出现异常,垃圾回收器不会报告异常,程序继续正常运行。
Java包
包的 3 个作用如下:
1. 区分相同名称的类。
2. 能够较好地管理大量的类。
3. 控制访问范围。
包定义
1. package 语句应该放在源文件的第一行,在每个源文件中只能有一个包定义语句;
Java 包的命名规则如下:
1. 包名全部由小写字母(多个单词也全部小写);
2. 如果包名包含多个层次,每个层次用“.”分割;
import example.*;
3. 上面 import 语句中的星号(*)只能代表类,不能代表包,表明导入 example 包下的所有类;
4. 使用星号(*)只可能会增加编译时间,不会增加运行时间的类的大小;
5. Java 默认为所有源文件导入 java.lang 包下的所有类;
十二、Java异常处理
异常原因
在 Java 中一个异常的产生,主要有如下三种原因:
1. Java 内部错误发生异常,Java 虚拟机产生的异常。
2. 编写的程序代码中的错误所产生的异常,例如空指针异常、数组越界异常等。
3. 通过 throw 语句手动生成的异常,一般用来告知该方法的调用者一些必要信息。
异常类型
在 Java 中所有异常类型都是内置类 java.lang.Throwable 类的子类,即 Throwable 位于异常类层次结构的顶层。Throwable 类下有两个异常分支 Exception 和 Error
Exception 又分为运行时异常和非运行时异常,这两种异常有很大的区别,也称为不检查异常(Unchecked Exception)和检查异常(Checked Exception)。
Error 错误是任何处理技术都无法恢复的情况,肯定会导致程序非正常终止。
- Exception 类用于用户程序可能出现的异常情况,它也是用来创建自定义异常类型类的类。
- Error 定义了在通常环境下不希望被程序捕获的异常。一般指的是 JVM 错误,如堆栈溢出。
异常处理机制
关键字:try、catch、throw、throws 和 finally
try catch 语句用于捕获并处理异常,finally 语句用于在任何情况下(除特殊情况外)都必须执行的代码,throw 语句用于拋出异常,throws 语句用于声明可能会出现的异常。
输出异常信息:
1. printStackTrace() 方法:指出异常的类型、性质、栈层次及出现在程序中的位置
2. getMessage() 方法:输出错误的性质。
3. toString() 方法:给出异常的类型与性质。
特别注意:
1. catch 语句可以有多个,用来匹配多个异常;
2. 对于处理不了的异常或者要转型的异常,在方法的声明处通过 throws 语句拋出异常,即由上层的调用方法来处理;
3. try 后面的花括号{ }
不可以省略,即使 try 块里只有一行代码,也不可省略这个花括号,catch后面的花括号也不可以省略;
4. try 块里声明的变量只是代码块内的局部变量,它只在 try 块内有效,其它地方不能访问该变量;
5. 异常处理语法结构中只有 try 块是必需的,其他如catch和finally等都可以不要(但catch 块和 finally 块至少出现其中之一,也可以同时出现);
6. 多个 catch 块必须位于 try 块之后,finally 块必须位于所有的 catch 块之后。
7. 在多个 catch 代码块的情况下,当一个 catch 代码块捕获到一个异常时,其它的 catch 代码块就不再进行匹配。
8. 当捕获的多个异常类之间存在父子关系时,捕获异常时一般先捕获子类,再捕获父类。所以子类异常必须在父类异常的前面,否则子类捕获不到。
9. 通常情况下不在 finally 代码块中使用 return 或 throw 等导致方法终止的语句,否则将会导致 try 和 catch 代码块中的 return 和 throw 语句失效;
throw和throws
1. 注意区分throws和throw:throws用于声明异常,throw用于抛出异常,所以使用throw才会引起程序异常,而throws不一定引起异常,如下:
//throws主要使用场景
public class Test04 {
public void readFile() throws IOException {
// 定义方法时声明异常
FileInputStream file = new FileInputStream("read.txt"); // 创建 FileInputStream 实例对象
}
//throw主要使用场景
throw new IllegalArgumentException("用户名只能由字母和数字组成!");
2. throws 用来声明一个方法可能抛出的所有异常信息,表示出现异常的一种可能性,但并不一定会发生这些异常;throw 则是指拋出的一个具体的异常类型,执行 throw 则一定抛出了某种异常对象。
3 .throws 通常不用显示地捕获异常,可由系统自动将所有捕获的异常信息抛给上级方法; throw 则需要用户自己捕获相关的异常,而后再对其进行相关包装,最后将包装后的异常信息抛出。
多异常捕获
多 catch 代码块虽然客观上提高了程序的健壮性,但是也导致了程序代码量大大增加。如果有些异常种类不同,但捕获之后的处理是相同的。如2个不同类型的异常,要求捕获之后的处理都是调用 methodA 方法。为了解决这种问题,Java7 推出了多异常捕获技术,可以把这些异常合并处理。
try{
// 可能会发生异常的语句
} catch (IOException | ParseException e) {
// 调用方法methodA处理
}
使用一个 catch 块捕获多种类型的异常时需要注意如下两个地方。
- 捕获多种类型的异常时,多种异常类型之间用竖线
|
隔开。 - 捕获多种类型的异常时,异常变量有隐式的 final 修饰,因此程序不能对异常变量重新赋值。
十三、IO
数据流分类
1. 按照流的方向主要分为输入流和输出流两大类。
2. 数据流按照数据单位的不同分为字节流和字符流。
3. 按照功能可以划分为节点流和处理流。
InputStream抽象类:字节输入流
Reader抽象类:字符输入流
OutputStream:字节输出流
Writer抽象类:字符输出流
系统流
1. System.in:标准输入流,默认设备是键盘。
2. System.out:标准输出流,默认设备是控制台。
3. System.err:标准错误流,默认设备是控制台。
在程序的任何部分都不需引用 System 对象就可以使用它们;
System.in 是 InputStream 类的一个对象;
System.out 和 System.error 是 PrintStream 类的对象;
尽管它们通常用于对控制台进行读取和写入字符,但是这些都是字节流;
File类
1. File 类不能访问文件内容本身,如果需要访问文件内容本身,则需要使用输入/输出流;
2. Windows 的路径分隔符使用反斜线“\”,而 Java 程序中的反斜线表示转义字符,所以如果需要在 Windows 的路径下包括反斜线,则应该使用两条反斜线或直接使用斜线“/”也可以;
3. Windows 中使用反斜杠\
表示目录的分隔符,Linux 中使用正斜杠/
表示目录的分隔符;
4. 在操作文件时一定要使用 File.separator 表示分隔符,这样就可以适用于不同操作系统;
字节流
1. 需要实际使用一遍InputStream抽象类、OutputStream抽象类、字节数组输入流ByteArrayInputStream、字节数组输出流ByteArrayOutputStream、文件输入流FileInputStream;
字符流
1. 需要实际使用一遍字符输入流Reader类、字符输出流Writer类、字符文件输入流FileReader类、字符文件输出流FileWriter类、字符缓冲区输入流BufferedReader类、字符缓冲区输出流BufferedWriter类;
转换流
转换流包括InputStreamReader、OutputStreamWriter;
InputStreamReader 用于将字节输入流转换为字符输入流,OutputStreamWriter 用于将字节输出流转换为字符输出流
作用与优点:使用转换流可以在一定程度上避免乱码,还可以指定输入输出所使用的字符集。
特别注意:
1. 输入就是将数据从各种输入设备(包括文件、键盘等)中读取到内存中,输出则正好相反。
2. 文件既可以作为输入设备,又可以作为输出设备;
3. 数据流的处理只能按照数据序列的顺序来进行,即前一个数据处理完之后才能处理后一个数据;
4. InputStream 类中所有方法遇到错误时都会引发 IOException 异常;
5. InputStream/OutputStream 类是所有字节输入/输出流的超类,用于以二进制的形式将数据写入目标设备,该类是抽象类,不能被实例化;
十四、设计模式
参考网址:菜鸟教程:工厂模式 | 菜鸟教程
工厂模式
属于创建型模式
在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
单例模式
属于创建型模式
主要解决:一个全局使用的类频繁地创建与销毁;
如何使用:判断系统是否已经有这个单例,如果有则返回,如果没有则创建。
在内存里只有一个实例,减少了内存的开销;
特别注意
1. 单例类只能有一个实例。
2. 单例类必须自己创建自己的唯一实例。
3. 单例类必须给所有其他对象提供这一实例。
4. 没有接口,不能继承
懒汉式实现单例模式
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
饿汉式实现单例模式(最常见,一般使用这种)
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton (){}
public static Singleton getInstance() {
return instance;
}
}
观察者模式
属于行为型模式;
当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知依赖它的对象。
十五、多线程
详见本文菜鸟教程Java多线程
十六、Java.util.logging记录日志
该内容见“Java基础资料-->C语言中文网-->10.16节”
修改日志管理器配置
该内容可用于修改默认的日志记录级别。
特别注意
Logger 的默认级别是 INFO,比 INFO 级别低的日志将不显示。Logger 的默认级别定义在 jre 安装目录的 lib 下面。
对于所有的级别有下面几种记录方法:
logger.log(Level.FINE, message);
logger.fine(message);
十七、数据结构
参考网址:菜鸟教程Java数据结构
排序
冒泡排序(基于交换的排序)
void BubbleSort(int A[], int n) {
for(int i=0; i<n-1; i++) {
bool flag = false; //表示本趟冒泡是否发生交换的标志
for(int j=n-1; j>i; j--) {
if(A[j] < A[j-1]) {//交换
int temp = i;
i = j;
j = temp;
flag = true;
}
if(flag == false)
return;
}
}
归并排序(分治思想)
见自己的百度网盘-第八章-排序9
*******Java实现归并排序******
public class MergeSort {
public static void MergeSort(int[] arr, int left, int right) {
if(left < right){
int mid = (left+right)/2;
merSort(arr, left, mid); //左边归并排序,使得左子序列有序
merSort(arr, mid+1, right); //右边归并排序,使得右子序列有序
merge(arr, left, mid, right); //合并两个子序列
}
}
private static void merge(int[] arr, int left, int mid, int right) {
int[] temp = new int[right-left+1];//申请一个与原数组大小相同的数组
int i = left;
int j = mid +1;
int k = 0;
while(i<=mid&&j<=right) {
if(arr[i] < arr[j]) {
temp[k++] = arr[i++];
}else {
temp[k++] = arr[j++];
}
}
while(i<=mid){//将左边剩余元素填充进temp中
temp[k++] = arr[i++];
}
while(j<=right){//将右序列剩余元素填充进temp中
temp[k++] = arr[j++];
}
//将temp中的元素全部拷贝到原数组中
for (int k2 = 0; k2 < temp.length; k2++) {
arr[k2 + left] = temp[k2];
}
}
剩余需要学习的内容
接口、接口回调、内部类、Collection集合、List集合、Set集合、Map集合、泛型
参考网址中的Java IO流整章内容
实战演练:Java程序利用FileInputStream、FileOutputStream完成下面要求:
1)用FileOutStream在当前目录创建一个文件"test.txt",并向文件输出"Hello World",如果文件已存在,则在原有文件内容后面追加。
2)用FileInput读入test.txt文件,并在控制台上打印出test.txt中的内容。
3)要求try-catch-finally处理异常,并且关闭流应放在finally块中。
异常处理、自定义异常
多线程实现方法、应用场景、原理、线程池等
单例模式、工厂模式 、代理模式的实现方法
堆、栈、队列、树、哈希、排序算法等
学习笔记
对于笔试题1中的题目,笔记如下:
24题. 考查静态语句块、构造语句块(就是只有大括号的那块)以及构造函数的执行顺序:
(1)类加载之后,按从上到下(从父类到子类)执行被static修饰的语句;
(2)对象被创建之后,按从上到下(从父类到子类)执行构造函数;
26题.
抽象类遵循的原则:
(1)abstract关键字只能修饰类和方法,不能修饰字段。
(2)抽象类不能被实例化(无法使用new关键字创建对象实例),只能被继承。
(3)抽象类可以包含属性,方法,构造方法,初始化块,内部类,枚举类,和普通类一样,普通方法一定要实现,变量可以初始化或不初始化但不能初始化后在抽象类中重新赋值或操作该变量(只能在子类中改变该变量)。
(4)抽象类中的抽象方法(加了abstract关键字的方法)不能实现。
(5)含有抽象方法的类必须定义成抽象类。