Java学习笔记

写在最前

本篇博客是作者的Java课期末复习笔记,复制到博客上跟大家分享。这份笔记更适合已经对各概念有过基本了解的同学作查缺补漏用,如果你不是很确定自己某块的知识是否达到了基本的“完备”的程度,可以做一下对应部分的例题(或示例)。最后感谢安莹教授,非常幸运能够遇到这样一位认真负责、非常清楚语言应该通过实践来学习的、真正面向学生教学的老师。如果你也是中南大学的学生,虽然这份笔记有些内容不在考纲内,但都是必须具备的知识,可以直接当复习提纲使用。

 

目录

第一讲 JAVA基本语法

1.1变量

1.1.1变量的命名规则

1.1.2数据类型

1.1.3基本数据类型与引用数据类型的区别

1.2数据类型转换

1.2.1自动类型转换   

1.2.2强制类型转换

1.2.3典型例题

1.3 运算符与表达式

1.3.1运算符优先级

1.3.2运算符的结合性

1.4流程控制

第二讲 重载

2.1规则

2.2对于基本数据的重载

2.2.1传入的实际参数小于重载方法声明的形式参数

2.2.2传入的实际参数大于重载方法声明的形式参数

2.3思考题

第三讲 构造函数

3.1构造函数的特点

第四讲 静态与代码块

4.1静态变量与成员变量的区别

4.2静态函数的调用

4.3静态代码块

4.3.1语法

4.3.2作用和特点

4.4其他代码块

4.4.1总览

4.4.2构造代码块

      4.4.2.1语法

      4.4.2.2构造代码块的特点

4.5练习

第五讲 封装与包

5.1访问控制修饰符

5.2包的作用

5.3包的创建

5.4包的命名规范

5.5包的使用

5.5.1通过完整的类名称

5.5.2包的导入

第六讲 类中类

6.1定义

6.2成员类中类

6.3局部类中类

6.4匿名内部类

6.5静态类中类

6.6类中类的作用

6.6.1封装性

6.6.2实现多重继承

6.6.3解决继承及实现接口出现同名方法的问题

第七讲 继承与重写

7.1继承的特点

7.2派生类的构造函数

7.3方法重写

7.3.1重写规则

7.3.2重写与重载的区别

第八讲 多态

8.1多态存在的三个必要条件

8.2多态的实现

8.3instanceof关键字

第九讲 抽象

9.1语法

9.2使用规则

第十讲 final关键字

10.1用法

第十一讲 接口

11.1语法

11.2接口的特点

11.3接口的实现

第十二讲 Object类的主要方法

12.1protected Object clone()

12.2String toString()

12.3boolean equals(Object obj)

12.3.1默认eqauls()函数

12.3.2 ==运算符

12.3.3重写equals()函数

12.3.4数组的比较

第十三讲 包装类

13.1

13.2装箱

13.3拆箱

13.4字符串转换成基本数据类型

  13.5基本数据类型转换成字符串

13.6小结

第十四讲 异常

14.1Throwable类

14.1.1Throwable类

14.1.2Error类

14.1.3Exception类

14.2就地捕获异常

14.3向前抛出异常

14.4关于异常的其它知识

第十五讲 常用API

15.1java.lang.Math类

15.1.1基本特点

15.1.2主要方法

15.2java.util.Random类

15.3java.lang.String类

15.3.1基本特点

15.3.2构造函数

15.3.3内存存储实现

15.3.4主要方法

15.3.5练习

15.4java.lang.StringBuffer类

15.4.1基本特点

15.4.2构造函数

15.4.3主要方法

15.5java.lang.System类

15.5.1基本特点

15.5.2常用方法

第十六讲 集合

16.1基本特点

16.2List集合

16.2.1特点

16.2.2ArrayList类

      16.2.2.1特点

      16.2.2.2构造函数

      16.2.2.3自动扩容

      16.2.2.4主要方法

      16.2.2.5遍历

16.3Set集合

16.3.1特点

16.3.2HashSet类

      16.3.2.1特点

      16.3.2.2构造函数

      16.3.2.3主要方法

      16.3.2.4如何实现有序

16.4Collections类

16.4.1特点

16.4.2对List集合的排序方法

16.4.3自定义排序

16.5Map集合

16.5.1特点

16.5.2HashMap类

                 16.5.2.1特点

      16.5.2.2构造函数

      16.5.2.3常用方法

第十七讲 线程

17.1进程与线程

17.2多线程实现

17.2.1继承java.lang.Thread 类

17.2.2Thread类常用方法

17.2.3实现Runnable接口

17.3线程的生命周期

17.4多线程的同步

17.4.1JAVA同步机制

17.4.2使用同步方法

17.4.3使用同步代码块

17.4.4使用Lock锁机制

17.4.5synchronized 与Lock 的对比

17.5其它

第十八讲 I/O

18.1IO流的分类

18.1.1按处理的数据单位分类

18.1.2根据流的作用分类

18.2四个基类

18.2.1InputStream

18.2.2Reader

18.2.3OutputStream

18.2.4

18.3File类

18.3.1概述

18.3.2构造函数

18.3.3路径分隔符

18.3.4创建功能

18.3.5删除功能

18.3.6其他方法

18.4节点流(文件流)

18.5缓冲流

18.6转换流

18.6.1定义

18.6.2InputStreamReader

18.6.3OutputStreamWriter

18.7标准输入输出流

18.7.1定义

18.7.2next()与 nextLine()的区别

18.8打印流

18.9数据流

18.10对象流

18.11随机存取文件流

其它


 

第一讲 JAVA基本语法

1.1变量

1.1.1变量的命名规则

 

1.1.2数据类型

 

1.1.3基本数据类型与引用数据类型的区别

(1)存储位置不同

    - 方法中定义的非全局基本数据类型变量的具体内容是存储 在内存栈(heap)中;

    - 引用数据类型变量的具体内容都是存放在内存堆(stack) 中,而栈中存放的是其具体内容所在内存的地址。

(2)传递方式不同

    - 方法中的非全局基本数据类型变量作为参数是按数值传递 的;

    - 引用数据类型变量作为参数则是按引用传递的。

1.2数据类型转换

1.2.1自动类型转换   

(1)相互转换的两种数据类型要兼容

   (2)数值类型(整型和浮点型)互相兼容

   (3)低精度的值可以直接赋给高精度变量,直接转换为高精 度

    byte < short < char < int < long < float < double    

   

(4)高精度的值不可以直接赋给低精度变量,需进行强制转 换

   (5)不同类型变量混合运算后的结果是精度最高的类型

(6)byte、short、char之间不会相互转换,三者在计算时首 先转换为int类型

1.2.2强制类型转换

语法:(类型名)表达式

1.2.3典型例题

short  s = 5;

s = s-2;

编译出错!

1.3 运算符与表达式

1.3.1运算符优先级

 

1.3.2运算符的结合性

(1)Java 语言中除了单目运算符、赋值运算符和三目运算符 是从右向左结合之外,其他运算符均是从左向右结合。

(2)当有多种运算符参与运算时,先考虑优先级,只有在优 先级相同时,再来根据结合性决定运算顺序。

1.4流程控制

常见错误:

Switch结构中如果需要每个case执行完后跳出,在每个case 后不要忘记写break。


第二讲 重载

2.1规则

  1. 除了参数类型的差异以外,参数的顺序不同也可以区分两个方法
  2. 不能根据方法的返回值来区分重载方法

2.2对于基本数据的重载

2.2.1传入的实际参数小于重载方法声明的形式参数

- 实际数据类型会被提升

- char型略有不同,如果无法找到恰好接受对应参数的方法, 就会先直接提升至int型

2.2.2传入的实际参数大于重载方法声明的形式参数

- 函数接受较小的基本类型作为参数,若传入的实际参数较 大,就得通过类型转换来执行窄化转换。否则,编译器会报错。

2.3思考题

 

 


第三讲 构造函数

3.1构造函数的特点

- 函数名与类名相同

- 不用定义返回值类型

- 不可以写return语句

- 构造函数可以有1个或多个参数也可以没有参数

- 可以对构造函数进行函数重载

- 定义类后若不声明任何构造函数,则java虚拟机会自动创建一 个空参构造函数

- 一个对象建立,构造函数只运行一次

- 只有构造函数才能调用构造函数

- 当类中显式地定义有有参构造函数,则系统不会再定义一个缺 省的无参构造函数


第四讲 静态与代码块

4.1静态变量与成员变量的区别

  1. 生命周期不同

成员变量随着对象的创建而存在,随着对象的被回收而释放;

  静态变量随着类的加载而存在,随着类的消失而消失。

(2)调用方式不同

  成员变量只能被对象调用;

  静态变量能被对象调用,还能被类名调用,推荐使用类名调用。

(3)数据存储位置不同

  成员变量数据存储在堆内存的对象中,故亦称对象的特有数 据;

  静态变量数据存储在方法区的静态区,故亦称对象的共享数 据。

4.2静态函数的调用

(1)静态函数属于类,可通过引用变量或其类名来调用(实例名 . 函数名 / 类名 . 函数名)。

(2)静态函数不能访问实例变量

(3)静态函数不能引用实例函数

(4)静态方法可以调用静态方法

4.3静态代码块

4.3.1语法

 

4.3.2作用和特点

- 只需要在项目启动时执行一次的代码,如,对所有对象的共 同信息进行一次性初始化;

- 静态代码块属于类,只需加载类就能运行;

- 静态代码块不能存在任何方法体中;

- 静态代码块不能访问普通变量;

- 只在类加载时运行一次,且优先于各种其他代码块以及构造 函数。

4.4其他代码块

4.4.1总览

 

4.4.2构造代码块

4.4.2.1语法

 

4.4.2.2构造代码块的特点

- 创建对象时被调用,每次创建时都会被调用

- 依托于类构造函数,优先于类构造函数执行

- 存在多个构造代码块,则按书写顺序依次执行

4.5练习

 

 


第五讲 封装与包

5.1访问控制修饰符

private:表示私有,只能被该类自身方法访问

public:表示公有,可被该项目的所有类访问

default:缺省修饰符,表示只能被同一个包中的类访问和引用

protected:表示受保护,可被同一包中的类以及其他包中该类的 子类访问

 

 

5.2包的作用

(1)允许类组成较小的单元(类似文件夹),易于找到和使用相 应的文件

(2)防止命名冲突

(3)更好的保护类、属性和方法

5.3包的创建

 

若有包的声明,一定要作为Java源代码的第一条语句

5.4包的命名规范

  1. 包名由小写字母组成,不能以圆点开头或结尾
  2. 包名之前最好加上唯一的前缀,通常使用组织倒置的网络域 名
  3. 包名后续部分依不同机构内部的规范不同而不同

5.5包的使用

5.5.1通过完整的类名称

包名 . 类名

5.5.2包的导入

(1)使用import关键字,在java源文件的package声明语 句之后, 所有类定义语句之前,引入要调用类的包名

(2)import PackageName.*; //导入包中的所有类
import PackageName.ClassName; //导入包中的指定类

(3)使用“*”一次只能导入一个包,而不能使用 “import.xxx.*” 导入以xxx为前缀的所有包。

(4)如果导入的类或接口是java.lang包下的,或者是当前 包下的,则可以省略此import语句


第六讲 类中类

6.1定义

将一个类定义在另一个类里面或者一个方法里面,这样的类称为类中类或内部类。按种类分为成员内部类、局部内部类、匿名内部类、静态内部类。

6.2成员类中类

(1)最普通的内部类,它的定义位于另一个类的内部。

(2)成员内部类可以无条件访问外部类的所有成员属性和成员方 法 (包括private成员和静态成员)

(3) 外部类中如果要访问成员内部类的成员,必须先创建一个 成员内部类的对象,再通过指向这个对象的引用来访问

(4)成员内部类是依附外部类而存在的,所以,如果要创建成员 内部类的对象,前提是必须存在一个外部类的对象并通过该外 部类对象来创建

(5)当内部类和外部类拥有同名的成员变量或者方法时,会发生 隐藏现象,即默认情况下访问的是成员内部类的成员。若要访问 外部类的同名成员,需以下面形式进行访问:外部类.this.成员 变量;   外部类.this.成员方法

6.3局部类中类

  1. 定义在方法或作用域内的类,仅限方法或该作用域内访问。
  2. 局部内部类就像是方法里面的一个局部变量一样,不能被 public、protected、private以及static修饰符。

6.4匿名内部类

  1. 匿名内部类也就是没有名字的内部类。
  2. 示例

(3)匿名内部类不能定义任何静态成员、方法。

(4)匿名内部类中的方法不能是抽象的。

(5)匿名内部类必须实现接口或抽象父类的所有抽象方法。

(6)匿名内部类没有类名,因此不能定义构造器。

6.5静态类中类

  1. 由static关键字修饰的内部类
  2. 类似于静态成员变量,静态内部类不需要依赖于外部类
  3. 可定义匿名代码块、静态代码块、静态或非静态成员
  4. 不能在静态内部类中写抽象方法
  5. 外部类可通过创建静态内部类实例的方式来调用静态内部 类的非静态成员,可通过“ 外部类.内部类.成员”的方式直接调 用静态内部类中的静态成员
  6. 静态内部类可以直接调用外部类的静态成员,也可通过创建 外部类实例的方式调用外部类的非静态成员
  7. 创建方式:

非外部类中:外部类名.内部类名 name = new 外部类名.内部 类名();

外部类中:内部类名 name = new 内部类名();

6.6类中类的作用

6.6.1封装性

例:

仅能知道OuterClass的getInner()能返回一个 InnerInterface 接口实例却无从知晓其实现方式;同时由于 InnerClass是私有 的,因此,连其具体类名都隐藏了起来。

6.6.2实现多重继承

6.6.3解决继承及实现接口出现同名方法的问题


第七讲 继承与重写

7.1继承的特点

(1)Java中的类只支持单继承,而多继承的功能是通过接口 (interface)来间接实现的。

(2)子类可获取父类的属性和方法,但子类不能直接访问父 类中私有的(private)的成员变量和方法。

(3)Java类的继承结构为树状结构(即层次结构),Java系 统类库中的java.lang.Object类为整个树状结构类图的、最 顶层的树根节点。若定义的是不包含有继承子句的一般类,则 隐含着继承系统提供的java.lang包中的Object类。

(4)有些父类成员不能继承

  - private成员

  - 子类与父类不在同包,使用默认访问权限的成员

  - 构造函数(只可调用,不能继承)

(5)在Java类中使用super关键字来调用父类中的指定操作。

(6)super可用于在子类构造函数中调用父类的构造函数

7.2派生类的构造函数

- 在派生类的构造函数包括无参构造函数和带参构造函数。   

- 在有参构造函数中首行必须用super(参数)语句,实现对基类 数据成员初始化的任务。

- 在无参构造函数中可以省略super()语句,因为系统会隐含调 用基类的无参构造函数,自动实现对基类成员的初始化。

- 若子类没有定义构造函数,则会自动调用(运行)父类的无 参数构造函数作为自己的构造函数

- 若子类自己定义了构造函数,则在创建新对象时,它将先执行 继承自父类的无参数构造函数,然后再执行自己的构造函数

- 例题

7.3方法重写

7.3.1重写规则

(1)如果一个方法不能被继承,则它也不能被重写

(2)子类重写的方法必须和父类被重写的方法具有相同的 方法名称、参数列表

(3)子类重写的方法使用的访问权限不能小于父类被重写 的方法的访问权限(例如:若父类的一个方法被声明为 public,那么在子类中重写该方法就不能声明为 protected。)

(4)返回类型与被重写方法的返回类型可以不相同,但是 必须是父类返回值的派生类。若父类返回值类型是基本数 据类型,则子类返回值类型是相同的基本数据类型

(5)声明为private和final的方法不能被重写

(6)声明为 static 的方法不能被重写,但可被再次声明

(7)构造方法不能被重写

7.3.2重写与重载的区别


第八讲 多态

8.1多态存在的三个必要条件

(1)继承

(2)重写

(3)父类引用指向子类对象

     当使用多态方式调用方法时,首先检查父类中是否有该方 法,若无,则编译错误;若有,则调用父类同名同参数的方法, 但实际执行的是子类重写父类方法,称为虚拟方法调用

8.2多态的实现

  1. 子类对象向上转型为父类对象,使得该对象可访问子类从父 类继承或重写的方法。
  2. 成员变量不具备多态性,只看引用变量所声明的类。
  3. 示例

(4)父类引用指向子类对象时,只会调用父类的静态方法。 所 以,静态方法并不具有多态性。

(5)向上转型后,父类对象失去了调用子类特有方法的权力。

(6)正确的向下转型:Father A=new Child(); Child B=(Child)A;

不安全的向下转型:Father A=new Father(); Child B=(Child)A;

编译无错但运行时会出错

8.3instanceof关键字

作用:判断某个对象是否属于某种数据类型,返回值为boolean 型。


第九讲 抽象

9.1语法

9.2使用规则

- 若一个方法被声明为抽象的,那么这个类也必须声明为抽象的;

- 一个抽象类中可有任意个抽象方法,以及任意个具体方法;

- 抽象类不能实例化,抽象类是用来被继承的;

- 抽象类的子类必须重写父类的抽象方法,并提供方法体。若没 有重写全部的抽象方法,则仍为抽象类;

- Abstract不能修饰变量、代码块、构造函数;

- Abstract不能修饰私有方法、静态方法、final方法、final 类;

- 抽象类可以有构造函数,但构造函数不可用abstract修饰


第十讲 final关键字

10.1用法

(1)final标记的类不能被继承

    如 String类、System类、StringBuffer类

(2)final标记的方法不能被子类重写

    如Object类中的getClass()

(3)final标记的变量(成员变量或局部变量)即称为常量。名称 大写,且只能被赋值一次。

  1. final修饰方法的形式参数 ,则该形参数在方法中不能修 改,是常量
  2.  final修饰的成员变量必须在定义时或者构造器中进行初 始化赋值
  3. 示例1

final修饰的变量被当成编译器常量直接替换成对应的值

示例2

只有在编译期间能确切知道final变量值的情况下,才会进行 常量替换。

(7)被final修饰的引用变量一旦初始化赋值之后就不能再指向 其他的对象,但是它指向的对象的内容是可变的。


第十一讲 接口

11.1语法

11.2接口的特点

- 所有成员变量都默认是public static final修饰,必须在定义 时进行初始化

- 所有抽象方法都默认是由public abstract修饰

- 没有构造函数

- 支持多继承机制

11.3接口的实现

- 除非实现接口的类是抽象类,否则该类要定义接口中的所有方 法

- 一个类可以实现多个接口,接口也可以继承其它接口

- 无论何时实现一个由接口定义的方法,它都必须实现为 public, 因为接口中的所有成员都显式声明为 public


第十二讲 Object类的主要方法

12.1protected Object clone()

- 用于复制一个对象,所谓的复制对象,首先要分配一个和 源对象同样大小的空间,在这个空间中创建一个新的对象。

- 被克隆的对象需要实现Cloneable接口,否则会抛出 CloneNotSupportedException异常。

- 示例:

创建了一个新的对象,二者具有不同的地址

12.2String toString()

- Object 类的 toString 方法返回一个字符串,该字符串由类 名(对象是该类的一个实例)、标记符“@”和此对象哈希码的无 符号十六进制表示组成。

- Object中默认的toString方法

- 在进行String与其它类型数据的连接操作时,会自动调用 toString()方法,如使用print方法时

- 可以根据需要在用户自定义类型中重写toString()方法。 String类重写了toString()方法,返回字符串的值。基本类型 数据转换为String类型时会调用对应包装类的toString()方法

- 可以使用print直接打印字符数组

- System.out.println(Arrays.toString(sArr));输出数组的 元素值。Arrays是类java.util.Arrays

12.3boolean equals(Object obj)

12.3.1默认eqauls()函数

Object类默认的eqauls()函数进行比较的依据是:调用方 法的对象和传入的对象的引用是否相等。即用来判断两个 对象引用的是否是同一对象。

12.3.2 ==运算符

- 对于基本类型执行值的比较。即,只要两个变量的值相 等,则为true,类型可以不同。

- 对于引用类型执行引用比较(是否指向同一个对象)。即, 只有指向同一个对象时,==才返回true。

   - 用“==”进行比较时,符号两边的数据类型必须兼容(可 自动转换的基本数据类型除外),否则编译出错。

12.3.3重写equals()函数

- 类File、String、Date及包装类等的equals()方法都 被重写过,是比较类型及内容而不考虑引用的是否是同一 个对象

- 重写equals()函数时需要遵守的规则:自反性、对称 性、传递性、一致性

12.3.4数组的比较

- 使用java.util.Arrays 类中声明的 static boolean deepEquals(Object[] a1, Object[] a2) 方法来实现

- deepEquals()方法要求传入的数组元素必须是对象


第十三讲 包装类

13.1

13.2装箱

(1)通过包装类的构造器实现:

  int i= 500;   Integer t = new Integer(i);

(2)还可以通过字符串参数构造包装类对象:

  Float f = new Float(“4.56”);

13.3拆箱

调用包装类的.xxxValue()方法:

boolean b = bobj.booleanValue();

13.4字符串转换成基本数据类型

(1)通过包装类的构造器实现:

  int i= new Integer(“12”);

(2)通过包装类的parseXxx(String s)静态方法:

  Float f = Float.parseFloat(“12.1”);

13.5基本数据类型转换成字符串

(1)调用字符串重载的valueOf()方法:

  String fstr= String.valueOf(2.34f);

(2)String intStr= 5 + “”

13.6小结

练习1

练习2


第十四讲 异常

14.1Throwable类

14.1.1Throwable类

- Java通过API中Throwable类的众多子类描述各种不同的 异常。Java语言中定义了很多异常类,每个异常类都代表了 一种运行错误,类中包含了该运行错误的信息。

- Java异常都是对象,是Throwable子类的实例,描述了出 现在一段编码中的错误条件。当条件生成时,错误将引发异常。

- Throwable类是类库java.lang包中的一个类,该类不能直 接使用。它派生了两个子类:Exception和Error。

14.1.2Error类

- 表示程序无法处理的错误,是运行应用程序中较严重问 题。

- 大多数Error与代码编写者执行的操作无关,而表示代码运 行时JVM出现的问题。 如,Java虚拟机运行错误(Virtual MachineError),JVM内存资源不足(OutOfMemoryError), 类定义错误(NoClassDefFoundError)等。

14.1.3Exception类

- Exception指程序员可以用针对性代码处理的不正常。(编 译异常、运行时异常)

- Exception类有若干子类,每个子类代表了一种特定的错误。

- 最重要的子类RuntimeException,表示“JVM 常用操作” 引发的错误。

14.2就地捕获异常

Java的异常处理是通过5个关键字来实现的:try、catch、 finally、throw、throws

语法:

小结:

- try后不能既无catch也无finally,catch不能独立于try 存在;

- try里面不宜放置过多的内容,catch里面不能没有内容;

- 在 try/catch 后面添加 finally 块并非强制性要求,但并 不意味着finally可有可无;

- finally里面的代码最终一定会执行(除了JVM退出);

- try, catch, finally 块之间不能添加任何代码;

14.3向前抛出异常

  1. 通过throws声明某个方法可能抛出的各种异常。可以同时 声明多个异常,之间由逗号隔开。语法如下:

  1. 如果想要抛出所有类型的异常,则直接通过throws Exception来实现。
  2. 对于抛出的异常,调用者可以就地处理,也可以再通过thows 继续抛出。
  3. 除了系统自动生成异常对象,还可以手动生成异常对象,并 用throw语句抛出异常。
  4. 除了系统定义好的异常,用户还可以自己定义异常类型。定 义方法如下:1、自定义异常类,继承RuntimeException或 Exception 2、定义重载构造函数,其中构造函数初始化异常信息

14.4关于异常的其它知识

- 调用异常对象的方法void printStackTrace()输出异常的堆栈 信息

- out是标准输出流,err是标准错误输出流;

- out输出流可能会被缓存,而err输出流不做缓存;

- out能重定向到其他输出流,此时屏幕将无输出;

- err只能在屏幕上实时打印输出;


第十五讲 常用API

15.1java.lang.Math类

15.1.1基本特点

- 包含了用于执行基本数学运算的一系列属性和方法;

- java.lang.Math类用final修饰,所以不能有子类;

- private构造方法,不能通过new的方法在其它类中构造 Math对象;

- 所有方法均为static,可供直接调用。

15.1.2主要方法

15.2java.util.Random类

  1. 相关方法

public boolean nextBoolean()//生成一个随机的boolean值

   public double nextDouble()//生成一个[0, 1.0)间的随机 double值

   public int nextInt()//生成一个随机的int值

   public int nextInt(int n)//生成一个[0, n)之间的随机int 值

(2)有参构造函数public Random(long seed)

- 该构造函数可以通过指定一个种子数来创建对象。

- 种子数只是随机算法的起始数字,和生成的随机数字的区间 无关;

- 相同种子数的Random对象,相同次数生成的随机数字是完 全相同的。

(3)无参构造函数是以当前系统时间作为种子数的,因此,每次 创建对象时的种子数都不相同。

15.3java.lang.String类

15.3.1基本特点

- 字符串变量属于对象;

- java.lang.String是一个final类,也不能有子类;

- 字符串存储在一个final的char类型字符数组中;

- 属于常量,用””引起来表示。创建后其值不能更改;

- 具有丰富的public构造方法,用于创建String对象;

- 提供了多种支持字符串操作的方法。

- Java 程序中的所有字符串字面值(如“abc”)都作为此 类的实例实现。

15.3.2构造函数

15.3.3内存存储实现

  1. 字符串常量存储在字符串常量池,旨在共享,存储相同 内容的字符串。
  2. 注意,String是不可变的序列。字符串重新赋值时,是 重新在新内存区赋值,而不是对原有存储区的value数组 赋值。
  3. 当对现有字符串进行连接操作时,也是重新指定新内存 区赋值。注意:常量与常量的拼接结果在常量池。且常量 池中不会存在相同内容的常量。只要其中有一个是变量, 结果就在堆中。如果拼接的结果调用intern()方法,返回 值就在常量池中。

补充:调用intern()方法后,JVM 会在当前类的常量池中查找是否存在与str等值的String,若存在则直接返回常量池中相应String的引用;若不存在,则会在常量池中创建一个等值的String,然后返回这个String在常量池中的引用。

  1. 当调用replace方法修改字符串时,也是重新指定新内 存区赋值。
  2. 字符串非常量对象存储在堆中。

15.3.4主要方法

15.3.5练习

练习1

  

练习2

 

引用数据类型传地址,实参的值会改变,但String是不可 变的。

15.4java.lang.StringBuffer类

15.4.1基本特点

- StringBuffer又称可变字符序列,是一个类似于 String 的 字符串缓冲区;

- 提供了String不支持的添加、插入、修改和删除之类的操 作。

- char[] value没有final声明,可以不断扩容

15.4.2构造函数

序列内容发生变化时,若内容长度小于16则默认容器的大小 为16。若大于16则会调用expandCapacity 函数将capcity 扩展为:旧容量*2+2,以此类推。

15.4.3主要方法

15.5java.lang.System类

15.5.1基本特点

- 该类的构造器是private的,故无法创建该类的对象;

- 其内部成员变量和方法都是static的,可直接调用;

- System类内部包含in、out和err三个成员变量,分别代 表标准输入流(键盘输入),标准输出流(显示器)和标准错误输 出流(显示器)。

15.5.2常用方法

(1)native long currentTimeMillis():

该方法用于返回当前计算机时间,时间格式为当前计算机 时间和GMT时间(格林威治时间)1970年1月1号0时0分 0秒所差的毫秒数。

(2)void exit(int status)

该方法的作用是退出程序。其中status的值为0代表正常 退出。

(3)void gc()

该方法的作用是请求系统进行垃圾回收。至于系统是否立 刻回收,则取决于系统中垃圾回收算法的实现以及系统执 行时的情况;

(4)String getProperty(String key)

该方法的作用是获得系统中属性名为key的属性对应的 值。


第十六讲 集合

16.1基本特点

  1. 集合可以存放不同类型、可变数量的数据。
  2. Java集合类是Java数据结构的实现,存放在java.util包 中,是一个用来存放对象的容器;

(3)允许以各种方式将元素分组,并定义了各种使这些元素更容 易操作的方法。

(4)与数组不同,集合只能存放对象;

(5)集合存放的都是对象的引用,而非对象本身;

(6)集合主要包括Collection和Map两个接口。

Collection是一维集合的顶层接口,分别被List、Set和Queue 继承。Collection是一个高度封装的集合接口,它提供了所有集合要实现的默认方法接口。

List被AbstractList实现,然后分为ArrayList、LinkedList和Vector 3个子类;

  Set被AbstractSet实现,又分为HashSet和TreeSet 2 个子类。

Map是二维集合的顶层接口,被AbstractMap实现,又分为HashMap和TreeMap 2个子类。

  Hashtable也实现了Map接口,但现在已基本为HashMap 取代。

16.2List集合

16.2.1特点

- 实现了java.util.List接口;

- 集合中的元素是有序的;

- 允许重复元素;

- 每个元素可以通过下标访问,下标从0开始;

- 最主要的三个实现类:ArrayList、LinkedList和Vector。

16.2.2ArrayList类

16.2.2.1特点

  - Java集合框架中使用最多的一个类;

  - 是一个数组队列,线程不安全集合;

  - ArrayList实现List,得到了List集合框架基础功能;

  - ArrayList实现RandomAccess,获得了快速随机访问元 素的功能;

- ArrayList实现Cloneable,得到了clone()方法,可实 现克隆功能;

  - ArrayList实现Serializable,可以被序列化。

16.2.2.2构造函数

16.2.2.3自动扩容

ArrayList会自动扩容,扩容规则是:

capacity=0  ->  capacity=10

capacity>10  ->  capacity=1.5capacity

16.2.2.4主要方法

- boolean add(Element e) 增加指定元素到链表尾部。

- void add(int index, Element e)增加指定元素到链表 指定位置。

- void clear() 从链表中删除所有元素。

- E remove(int index) 删除链表中指定位置的元素。

- protected void removeRange(int start, int end)删 除链表中从某一个位置开始到某一个位置结束的元素。

- E get(int index) 获取链表中指定位置处的元素.

- Object[] toArray() 获取一个数组,数组中所有元素是 链表中的元素.(即将链表转换为一个数组)。

- boolean contains(Object o) 如果链表包含指定元素, 返回true。

- int indexOf(Object o) 返回元素在链表中第一次出现 的位置,若无则返回-1。

- int lastIndexOf(Object o) 返回元素在链表中最后一 次出现的位置,若无则返回-1。

- E set(int index, E element) 将链表中指定位置上的 元素替换成新元素。

- boolean isEmpty() 返回true表示链表中没有任何元 素。

16.2.2.5遍历

16.3Set集合

16.3.1特点

- 实现了java.util.Set接口;

- 默认情况下,集合中元素没有顺序;

- 不允许重复元素,若重复元素被添加,则覆盖原来的元 素;

- 元素不可以通过下标访问;

- 最主要的两个实现类:HashSet和TreeSet。

16.3.2HashSet类

16.3.2.1特点

- 继承AbstractSet类,实现了Set、Cloneable和 Serializable接口;

- 底层由HashMap来实现,为哈希表结构,新增元素相 当于HashMap的key,value默认为一个固定的Object;

- 不允许存在重复元素;

- 允许插入Null值;

- 元素无序(添加顺序和遍历顺序不一致);

- 线程不安全

16.3.2.2构造函数

16.3.2.3主要方法

16.3.2.4如何实现有序

使用HashSet的子类java.util.LinkedHashSet。

其底层使用hash算法计算存储位置并保证元素的唯一 性;同时使用链表来维护顺序,顺序与添加顺序一致。

16.4Collections类

16.4.1特点

- Collections是一个出现于JDK1.2时期,专门用于操作 集合的工具类;

- 该类的构造方法是私有的,不可实例化;

  - 提供对List、Map、Set等集合元素的排序、查询和修改 等操作方法;

  - 所有方法均为static,可直接通过类名调用。

16.4.2对List集合的排序方法

16.4.3自定义排序

(1)使用sort(List list, Comparator c),并重写比 较器compare()方法。例:

(2)重写Comparable接口中的compareTo()方法。例:

16.5Map集合

16.5.1特点

- Map是用于保存具有Key到 Value映射关系数据的集 合。

- Map中Key和Value可为任意类型的数据,是一一对应 关系;

- Map的Key具有唯一性,构成一个Set集合;

- Map的Value允许重复,构成一个Collection集合;

- HashMap是Map最常用的实现类。

16.5.2HashMap类

16.5.2.1特点

- HashMap底层是数组和链表的结合体;

- 底层是一个线性数组结构Entry[],数组中的每一项 都是key-value键值对,并持有一个指向下一元素的 next引用,即构成一个单向链表;

- HashMap底层数组长度是2n,默认值16,负载因子 为0.75。这意味着,当数组实际长度超过16*0.75=12 时,便开始扩容;

- 允许使用null值和null键,线程不同步。

16.5.2.2构造函数

16.5.2.3常用方法


第十七讲 线程

17.1进程与线程

(1)进程:指程序的一次执行活动,是一个动态的过程。它是资 源申请、调度和独立运行的单位,使用系统中的运行资源,具有 生命周期;

(2)线程:进程内部的一个独立执行单元(路径),一个进程 可以同时并发运行多个线程。

(3)进程与线程的区别

- 一个进程至少包含一个线程,同一个进程中的多个线程 之间可以并发执行;

- 进程是操作系统资源分配的基本单位,而线程是任务调 度和执行的基本单位;

- 系统在运行的时候会为每个进程分配独立的内存空间, 线程自己基本上不拥有系统资源 (除了程序计数器、寄存 器和栈),但可共享所属同一进程的所有资源。

17.2多线程实现

17.2.1继承java.lang.Thread 类

实现步骤:

(1)定义一个线程类 A 继承于 java.lang.Thread 类

(2)在 A 类中重写 Thread 类的 run() 方法。在 run() 方法中编写需要执行的操作

(3)在 main 方法(线程)中,创建线程对象,并启动线 程。创建线程类:A类 a = new A()类;

   调用 start() 方法启动线程:a.start();

17.2.2Thread类常用方法

void start()

启动线程,并执行对象的run()方法。

void run()

线程在被调度时执行的操作。

static Thread currentThread()

返回当前线程。在Thread子类中就是this,通常用于主 线程和Runnable实现类。

String getName()

返回线程的名称。

void setName(String name)

设置该线程名称。

static  void  yield()

暂停当前的执行线程,把执行机会让给优先级相同或更高 的线程。

final void join()

当线程A中调用线程B的join() 方法时,线程A将被阻 塞,直到线程B执行完为止,线程A才结束阻塞。

static void sleep(long millitime)

让当前线程“睡眠”指定的时长。在该时间内线程处于阻 塞状态。

final void setPriority(int priority))

设置当前线程的优先级。

final int getPriority()    

获取当前线程的优先级。

final boolean isAlive()

判断当前线程是否存活。

17.2.3实现Runnable接口

实现步骤:

(1)定义类 A (非线程类)实现 java.lang.Runnable 接 口   

   (2)在 A 类中重写 Runnable接口的 run() 方法。在 run() 方法中编写需要执行的操作

(3)在 main 方法(线程)中,创建线程对象,并启动线 程。创建线程类:Thread t = new Thread(new A类);

   调用 start() 方法启动线程:t.start();

17.3线程的生命周期

1、新建状态(New)

即创建了一个线程对象后,还没有在其上调用start()方法。

就绪状态(Runnable)

   使用start()方法启动一个线程后,系统分配了资源,但调度 程序还没有把它选定为运行线程时线程所处的状态。此外,线程 从阻塞、等待或睡眠状态回来后,也会返回到可运行状态。

2、运行状态(Running)

线程调度程序从可运行池中选择一个线程作为当前线程时线程所处的状态,这也是线程进入运行状态的唯一方式。

3、阻塞状态(Blocked)

线程因某种原因放弃CPU使用权,暂停运行。可分3种情况:

  (1)等待阻塞:运行的线程执行wait()方法,该线程放入等 待池中。

  (2)同步阻塞:运行的线程在获取对象的同步锁时,若该同 步锁被别的线程占用,该线程放入锁池中。

  (3)其他阻塞:运行线程执行sleep()或join()方法,该线程 置为阻塞状态。

4、死亡状态(Dead)

线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

  注意:

    (1)死亡状态的线程对象有可能仍然存在,只是不再是一 个单独执行的线程了;

     (2)线程一旦死亡,就不能再通过start()方法复生。

17.4多线程的同步

17.4.1JAVA同步机制

- Java中每个对象都有一个内置锁,当程序运行到非静态的synchronized同步方法上时,自动获得与正在执行代码类的当前实例有关的锁(该过程又称获取锁、锁定对象、在对象上锁定或在对象上同步)。

  - 每个对象只有一个锁。当一个线程获得该锁,任何其他 线程就不能再进入该对象上的synchronized方法或代码块, 直到该锁被释放。

17.4.2使用同步方法

实现方式:在要标志为同步的方法前加上synchronized关键 字。

17.4.3使用同步代码块

实现方式:用synchronized来指定某个对象,此对象的锁被 用来对花括号内的代码进行同步控制。

17.4.4使用Lock锁机制

  从JDK5.0开始,Java提供了更强大的线程同步机制—— 通过显式定义同步锁对象来实现,同步锁使用Lock对象充当。

java.util.concurrent.locks.Lock接口是控制多个线程 对共享资源进行访问的工具。锁提供了对共享资源的独占访 问,每次只能有一个线程对Lock对象锁,线程开始访问共享 资源之前应先获得Lock对象。

ReentrantLock类是Lock接口最常用的实现类,拥有与 synchronized 相同的并发性和内存语义。

实现方式:创建ReentrantLock对象,在同步方法中,调用 lock() 方法后,将同步代码块置于try中,然后在finally中调用 unlock()以防死锁。

 

17.4.5synchronized 与Lock 的对比

 - Lock是显式锁(需手动开启和关闭锁);

   synchronized是隐式锁,出了作用域自动释放;

 - Lock只有代码块锁,synchronized有代码块锁和方法锁;

 - 使用Lock锁,JVM将花费较少的时间来调度线程,性能更 好且具有更好的扩展性(提供更多的子类);

 - 优先使用顺序:

  Lock > 同步代码块(已经进入了方法体,分配了相应资源)

   > 同步方法(在方法体之外)

17.5其它

  1. 输出线程对象将产生一个数组输出,其格式为: [线程名称, 优先级别,线程组名]。
  2. 一个线程对象只能调用一次start()方法启动,否则会抛出 “IllegalThreadStateException”异常。

第十八讲 I/O

18.1IO流的分类

18.1.1按处理的数据单位分类

(1)字节流

    操作的数据单元是8位的字节。以InputStream、 OutputStream作为抽象基类;

(2)字符流

    操作的数据单元是16位的字符。以Writer、Reader作为 抽象基类。

(3)字节流可以处理所有数据文件。但是,若处理的是纯文 本数据,建议使用字符流。

(4)Java的IO流共涉及40多个类,实际上,都是从4个抽 象基类派生的。由这四个类派生出来的子类名称都是以其父类 名作为子类名后缀。

18.1.2根据流的作用分类

(1)节点流

程序直接与数据源连接,和实际的输入/输出节点连接;

(2)处理流

  对节点流进行包装,扩展原来的功能,由处理流执行IO 操作。

(3)处理流可以隐藏底层设备上节点流的差异,无需关心数 据源的来源,程序只需要通过处理流执行IO操作。实际应 用中,一般推荐使用处理流来完成IO操作。

18.2四个基类

18.2.1InputStream

18.2.2Reader

18.2.3OutputStream

18.2.4

18.3File类

18.3.1概述

(1)java.io.File类:文件和文件目录路径的抽象表示形式, 与平台无关。

(2)File 能新建、删除、重命名文件和目录,但File 不能 访问文件内容本身。如果需要访问文件内容本身,则需要使用 输入/输出流。

(3)想要在Java程序中表示一个真实存在的文件或目录,那 么必须有一个File对象,但是Java程序中的一个File对象, 可能没有一个真实存在的文件或目录。

(4)File对象可以作为参数传递给流的构造函数。

18.3.2构造函数

18.3.3路径分隔符

- 路径中的每级目录之间用一个路径分隔符隔开。

- windows和DOS系统默认使用“\”来表示

- UNIX和URL使用“/”来表示

- File类提供了一个常量:public  static final String separator。根据操作系统,动态的提供分隔符。

18.3.4创建功能

18.3.5删除功能

18.3.6其他方法

18.4节点流(文件流)

使用节点流的注意事项:

(1)在写入一个文件时,如果使用构造器 FileOutputStream(file),则目录下有同名文件将被覆盖。

(2)如果使用构造器FileOutputStream(file, true),则目 录下的同名文件不会被覆盖,在文件内容末尾追加内容。

(3)在读取文件时,必须保证该文件已存在,否则报异常。

(4)字节流操作字节,比如:.mp3,.avi,.rmvb, mp4,.jpg,

.doc,.ppt

(5)字符流操作字符,只能操作普通文本文件。最常见的文 本文件:.txt,.java,.c,.cpp 等语言的源代码。尤其 注意 .doc, .excel, .ppt这些不是文本文件。

18.5缓冲流

  1. 缓冲流是处理流的一种, 它依赖于原始的输入输出流, 它会创建一个内部缓冲区数组,缺省使用8192个字节(8Kb) 的缓冲区, 显著减少与外部设备的IO次数, 而且提供一些额 外的方法。
  2. 缓冲流要“套接”在相应的节点流之上,根据数据操作 单位可以把缓冲流分为:BufferedInputStream, BufferedOutputStream,BufferedReader和BufferedWriter
  3. 当使用BufferedInputStream读取字节文件时, BufferedInputStream会一次性从文件中读取8192个字节 (8Kb),存在缓冲区中,直到缓冲区内数据处理完了,才重新 从文件中读取下一个8192个字节数组。
  4. 向流中写入字节时,不会直接写到文件,先写到缓冲区 中直到缓冲区写满,BufferedOutputStream才会把缓冲区中 的数据一次性写到文件里。
  5. 使用方法flush()可强制将缓冲区的内容全部写入输出 流。
  6. 关闭流的顺序和打开流的顺序相反。只要关闭最外层流 即可,关闭最外层流也会相应关闭内层节点流。
  7. 如果是带缓冲区的流对象的close()方法,不但会关闭 流,还会在关闭流之前刷新缓冲区。

18.6转换流

18.6.1定义

- 转换流提供了在字节流和字符流之间的转换。

- InputStreamReader:将InputStream转换为Reader

- OutputStreamWriter:将Writer转换为OutputStream

- 字节流中的数据都是字符时,转成字符流操作更高效。

- 很多时候我们使用转换流来处理文件乱码问题,实现编码和 解码的功能。解码:字节->字符。编码:字符->字节。

18.6.2InputStreamReader

- 实现将字节的输入流按指定字符集转换为字符的输入流。

- 需要和InputStream“套接”。

- 构造函数:

public InputStreamReader(InputStream in)

public InputSreamReader(InputStream in, String charsetName)

18.6.3OutputStreamWriter

- 实现将字符的输出流按指定字符集转换为字节的输出流。

- 需要和OutputStream“套接”。

- 构造函数:

public OutputStreamWriter(OutputStream out)

public OutputSreamWriter(OutputStream out, String charsetName)

18.7标准输入输出流

18.7.1定义

- System.in和System.out分别代表了系统标准的输入和输 出设备。

- 默认输入设备是:键盘

- 默认输出设备是:显示器

- System.in的类型是InputStream

- System.out的类型是PrintStream,其是OutputStream的 子类

18.7.2next()与 nextLine()的区别

next()

  - 一定要读取到有效字符后才可以结束输入

  - 对输入有效字符之前遇到的空白,next() 方法会自动将 其去掉

  - 只有输入有效字符后才将其后输入的空白作为分隔符或 者结束符

- next() 不能得到带有空格的字符串

nextLine()

  - 以Enter为结束符,也就是说nextLine()方法返回的是 输入回车之前的所有字符

  - 可以获得带空白的字符串

18.8打印流

- 打印输出指定内容,实现将基本数据类型的数据格式转化为字 符串输出,根据构造参数中的节点流来决定输出到何处。

- PrintStream :打印输出字节数据。

- PrintWriter : 打印输出文本数据。

- 提供了一系列重载的print()和println()方法,用于多种数据 类型的输出。

- System.out返回的是PrintStream的实例。

18.9数据流

- 为了方便地操作Java语言的基本数据类型和String的数据, 可以使用数据流。

- 数据流有两个类: DataInputStream和DataOutputStream,分 别用于读取和写出基本数据类型、String类的数据

- DataInputStream和DataOutputStream分别“套接”在 InputStream和OutputStream子类的流上

- DataInputStream中的方法

18.10对象流

1、用于存储和读取基本数据类型数据或对象的处理流。

2、它的强大之处就是可以把Java中的对象写入到数据源中,也能把对象从数据源中还原回来。

3、序列化:用ObjectOutputStream类保存基本类型数据或对象的机制

4、反序列化:用ObjectInputStream类读取基本类型数据或对象的机制

5、注意:

只有字节流没有字符流

类必须实现Serializable接口

给类加个序列化编号,给类定义一个标记,新修改后的类还可以操作曾经序列化的对象

静态是不能被序列化的,序列化只能对堆中的成员进行序列化 ,不能对“方法区”中的进行序列化

不需要序列化的字段前加 transient

18.11随机存取文件流

1、RandomAccessFile 声明在java.io包下,但直接继承于java.lang.Object类。它实现了DataInput、DataOutput这两个接口,也就意味着这个类既可以读也可以写。

2、RandomAccessFile 类支持“随机访问” 的方式,程序可以直接跳到文件的任意地方来读、写文件。

3、RandomAccessFile 对象包含一个记录指针,用以标示当前读写处的位置。

4、RandomAccessFile类对象可以自由移动记录指针:

  long getFilePointer():获取文件记录指针的当前位置

  void seek(long pos):将文件记录指针定位到pos位置

5、构造函数:

  public RandomAccessFile(File file, String mode)

public RandomAccessFile(String name, String mode)

        注:mode 参数指定RandomAccessFile的访问模式:

r: 以只读方式打开

  rw:打开以便读取和写入


其它

  1. 定义方法参数时使用(Object... args),表示可传入任意个数的指定类型参数。取值时根据顺序取,从0开始,第一个是args[0],依此类推。
  2. final变量必须初始化
  3. 泛型(Generic type)是对 Java 语言的类型系统的一种扩展,以支持创建可以按类型进行参数化的类,从而避免遍历或使用对象时的强制转换。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值