1 Java基础教程
1.1 流、文件、IO
输入流用于从源读取数据,输出流用于向目标谢写数据
(1) 控制台输入:System.in
① 为了获得一个绑定到控制台到字符流,把System.in包装在BufferReader对象中:BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
② BufferReader对象创建后,使用read()方法从控制台读取一个字符,或者用readLine()方法读取一个字符串
③ read()方法从输入流中读取一个字符串并把该字符串作为整数值返回。流程结束的时候返回-1
(2) 控制台输出:
① 控制台到输出:print()、printIn()
② write():将低八位字节写入流中(不常用)
(3) 读写文件:
1) 读文件
FileInputStream类:该流用于从文件读取数据,它的对象为InputStream(例如:InputStream f = new FileInputStream("C:/java/hello");)
ByteArrayInputStream类:字节数据输入流在内存中创建一个字节数组缓冲区,从输入流读取的数据保存在该字节数组缓冲区中
DataInputStram类:数据输入流允许应用程序以与机器无关方式从底层输入流中读取基本Java数据类型
FileReader类:按字符读取流中的数据
2) 写文件
FileOutputStream类:该类用来创建一个文件并向文件中写数据(如果在打开文件进行输出前发现目前文件不存在,那么会创建该文件),其对象为:OutputStream
ByteArrayOutputStream
DataOutputStream
FileWriter:按字符向流中写入数据
3) File类
File类主要用于文件和目录的创建、文件的查找和文件的删除
File对象代表磁盘中实际存在的文件和目录
创建目录:
a. mkdir():创建一个文件夹,成功返回true,失败返回false(失败则表明File对象指定的路径已经存在,或者由于整个路径还不存在所以该文件夹不能被创建)
b. mkdirs():创建一个文件夹和它所有的父文件夹
读取目录:
a. 一个目录其实就是一个File对象,如果创建一个File对象并且它是一个目录,那么调用isDirectory()返回true
b. list():提取目录包含的文件和文件夹的目录(文件夹中包含的内容)
1.2 Scanner类
使用Scanner类来获取用户的输入:next()和nextLine()方法获取输入的字符串,在读取前一般需要使用hasNext()和hasNextLine()来判断是否还有输入的数据
(1) next()
① 一定要读取到有效字符之后才能结束输入(?),只有输入有效字符后才能将其后面输入的空白作为分隔符或者结束符
② next()不能得到带有空格的字符串
(2) nextLine()
以Enter为结束符,返回的是输入回车之前的所有字符(包括空字符)
1.3 异常处理
(1) 异常分类:
用户输入非法数据
要打开的文件不存在
网络通信时连接中断,或JVM内存溢出
(2) 需要掌握的异常:
检查性异常:程序员无法预见的,例如用户错误、打开一个不存在的文件
运行时异常:
错误:不是异常,而是脱离程序员控制的问题,例如栈溢出
(3) Throwable的两个子类
Error(用来指示运行时环境发生的错误)、Exception(异常类)
1) 捕获异常:try catch
2) 多重捕获异常:
一个try代码块后面跟随多个catch代码块
try{
// 程序代码
}catch(异常类型1 异常的变量名1){
// 程序代码
}catch(异常类型2 异常的变量名2){
// 程序代码
}catch(异常类型2 异常的变量名2){
// 程序代码
}
如果抛出异常的数据类型与第一个catch块匹配,则在第一个catch块捕获,如果不匹配,会被传递给第二个...(类似switch case)
(3) thows/thorw关键字
(4) finally关键字
创建在try代码块后面执行的代码,无论是否发生异常,finally代码块中的代码都会被执行
注意:try、catch、finally块之间不能添加任何代码
(5) 声明自定义异常
所有异常必须是Thowable的子类,如果希望编写一个检查性异常类,则继承Exception类,如果希望编写一个运行时异常类,则继承RuntimeException类
2 Java面向对象
2.1 继承
(1) 一些概念:
① 类的继承是单一继承,一个子类只能有一个父类
② 继承最常用的关键字:extends、implements
这两个关键字的使用决定了一个对象和另一个对象是否是IS-A(是一个)关系
③ 所有Java类都是由java.lang.Object类继承而来,所以Object是所有类的祖先类。除了Object外,所有类必须有一个父类
(2) IS-A关系
一个对象是另一个对象的一个分类
可以通过使用instanceof操作符确定是否有关系
(3) HAS-A关系
代表类和它的成员之间的从属关系
一般继承基本类和抽象类使用extends关键字,实现接口类的继承用implements关键字
2.2 重写和重载
(1) 重写
① 重写的规则:
1) 参数列表、返回类型必须和被重写的方法一致(即外壳不变,核心重写)
2) 访问权限不能比被重写方法的访问权限高
3) 声明为final、static的方法不能被重写,但声明为static的方法能够被再次声明
4) 如果子类和父类在同一个包中,那么子类可以重写父类中所有方法,声明为private和final的方法除外
5) 如果之类和父类不在同一个包中,那么子类只能重写父类中声明为public和protected的非final的方法
6) 只有被继承的方法能被重写,如果一个方法没有被继承,那么该方法不能被重写,构造方法不能被重写
② super关键字
当需要在子类中调用父类中被重写的方法时,要用到super关键字
(2) 重载
重载是在一个类里面,方法名字相同,而参数不同,返回类型可以相同有可以不同
① 重载的规则
1) 重载的方法其参数列表必须改变,即参数类型或参数个数不能与被重载函数相同(调用重载函数时是依据参数列表来决定调用哪个重载函数,所以参数列表必须不同)
2) 返回类型和修饰符可以相同也可以不同,不做要求
(3) 重写和重载的区别
①参数列表、返回类型上:重写不能修改被重写方法的参数列表和返回值类型,重载必须改变被重载函数的参数列表,返回值类型不做要求,可改可不改
②访问权限上:重写不能对访问权限不能高于被重写方法,重载不做要求
2.3 多态
2.4 抽象类
抽象类除了不能实例化对象,其他都和普通类相同。因为抽象类不能实例化对象,所以抽象类必须被继承才能使用
(1) 抽象类的声明
使用 abstract class 来定义抽象类
(2) 抽象方法
① 声明:abstract关键字,方法名后直接跟一个分号,而不是花括号
② 概念:抽象方法只包含一个方法名,而没有方法体,抽象方法的具体实现由它的子类确定
③ 继承抽象方法的子类必须重写该方法,否则该子类也要声明为抽象类。最终,必须有子类重写抽象方法,否则从最初父类继承的抽象方法都不能用来实例化对象
2.5 封装
封装可以认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问。
例如,成员变量的访问和修改都要通过类方法getter和setter
2.6 接口Interface
接口是一个抽象类型,是抽象方法的集合,通常以interface声明
接口不是类,类描述对象的属性和方法,接口则包含类要实现的抽象方法
接口无法被实例化,但可以被实现。实现接口的类必须实现接口内所描述的所有方法,否则就必须声明为抽象类
接口类型可以用来声明一个变量
接口不能包含成员变量,除了static和final变量
(1) 声明:interface关键字用来声明一个接口
① 接口是隐式抽象的,当声明一个接口时,不必使用abstract关键字
② 接口中的方法也是隐式抽象的,声明时同样不需要abstract关键字
③ 接口中的方法都是公有的
(2) 实现:类使用implements关键字实现接口
① 当类实现接口时,要实现接口中所有的方法,除非该类声明为抽象类
② implements关键字放在class声明后面
③ 一个类只能继承一个类,但可以实现多个接口
(3) 继承:extends关键字
(4) 多重继承
在接口的多重继承中,extends关键字只需要使用一次,继承的接口以逗号隔开
(5) 标记接口
最常用的继承接口是没有包含任何方法的接口。
① 定义:指没有任何方法和属性的接口,它仅仅表明实现它的类属于一个特定的类型,供其他代码来测试
② 作用:简单来说,就是给某个对象打个标记,使对象拥有某个/些权限
③ 常用于以下目的:
1) 建立一个公共的父接口:
例如:当一个接口继承了EventListener接口,Java虚拟机(JVM)就知道该接口将要被用于一个事件的代理方案。
2) 向一个类添加数据类型
2.7 包
(1) 包的作用
①方便类的查找和使用。将功能相似或相关的类或接口组织在同一个包中
②避免命名冲突。包如同文件夹一样采用了树形目录的存储方式,当同时调用不同包中相同类名的类时,可以加上包名加以区别
③访问控制。只有拥有包访问权限的类才能访问包中的类
(2) 语法格式
package pkg1[. pkg2[. pkg3...]];
(3) 一些java包
java.lang(打包基础的类)、java.io(包含输入输出功能的函数)
(4) 创建、声明包
① 创建一个package,并取一个合适的名字
② 包声明在源文件的第一行,每个源文件只能有一个包声明(?)
③ 如果一个源文件中没有使用包声明,那么其中的类、函数、枚举、注释等将被放在一个无名包(unnamed package)中
(5) import关键字
① 作用:用于在使用某个包的成员前倒导入该包
② 语法格式(导入语法):import package1[ .package2...].(classname|*);(*为通配符)
③ 导入规则:类文件可以包含任意数量的import声明,import声明必须在包声明之后,类声明之前
④使用规则:
1)如果两个类在同一个包中,一个类想要使用另一个类,那么包名可以省略
2)如果两个类不在同一个包,一个类使用另外一个类,要使用类全名描述,如package.classname
(6)目录结构
(看不懂在说啥TT)
3 Java高级应用
3.1 数据结构
(1) 数据结构分类
枚举(Enumeration)
位集合(Bitset)
向量(Vector)
栈(Stack)
字典(Dictionary)
哈希表(Hashtable)
属性(Properties)
(2) Enumeration接口
接口定义了一些方法,通过这些方法可以枚举(一次获得一个)对象集合中的元素
这种传统接口已经被迭代器取代,已经很少用
(3) BitSet(在java2中被完全重新设计)
位集合类实现了一组可以单独设置和清清除的位或标志
常用于处理一组布尔值
(4) Vector
Vector类与传统数组相似,也能通过索引访问对象中的元素,其大小还能动态地变化
好处:在创建对象时不必给定对象的大小,其大小会根据需要动态变化
(5) Stack
栈是Vector的一个子类
先进后出
(6) Dictionary
字典类是一个抽象类,用来存储 键/值 对,作用和map类似
在实际开发中,字典已经过时啦,可以使用map
(7) Map
key/value 一一映射,通过key来获取value
(8) Hashtable
Hashtable类提供了一种在用户定义键结构的基础上组织数据的手段
Hashtable是原始java.util的一部分,是字典的一个具体实现
然而java2重构的Hashtable实现了Map接口,因此Hashtable集成到集合框架中
(9) Properties
Properties继承自Hashtable.Properties类,表示一个持久的属性集
属性列表中的每个键及其对应值都是一个字符串
3.2 集合框架
集合框架是一个用来代表和操作集合的统一框架,所有的集合框架都包含:
接口:集合的抽象数据类型
实现(类):集合接口的具体实现,即可重复使用的数据结构
算法
除了集合,该框架也定义了几个Map接口和类。
(1) 集合接口:
Collection接口:对象组,位于集合层次结构的顶部
List接口(扩展Collection):存储了有序的元素集合
Set接口(扩展Collection):必须包含唯一元素
SortSet:扩展了Set来处理有序集
Map接口:将唯一键映射到值
Map.Entry:描述了地图中的元素(key/value对),是Map的内部类
SortMap(扩展Map):按升序维护密钥
枚举:遗留接口,已被Iterator取代
(2) 集合类
标准集合类完整实现了Collection接口,其他抽象类供了用作创建具体集合的起点的骨架实现:
AbstractCollection:实现了大部分Collection接口
AbstractList:扩展AbstractCollection,并实现大部分List接口
AbstractSequentiaList:扩展AbstractList,以供使用其元素的顺序访问而不是随机访问集合
LinkedList:扩展AbstractSequentiaList,实现链接列表
ArrayList:扩展AbstractList,实现动态数组
AbstractSet:扩展AbstractCollection,实现大部分Set接口
HashSet:扩展AbstractSet,以与哈希表一起使用
LinkedHashSet:扩展HashSet,以允许插入顺序迭代
TreeSet:扩展AbstractSet,实现存储在树中的集合
AbstractMap:实现大部分Map接口
HashMap:扩展AbstractMap,以使用哈希表
TreeMap:扩展AbstractMap,以使用树
WeakHashMap:扩展AbstractMap,以使用具有弱键的哈希表(弱键?)
LinkedHashMap:扩展HashMap,以允许插入顺序迭代
IdentityHashMap:扩展AbstractMap,在比较文档时使用引用相等
(3) 集合算法
集合框架定义了几种算法,用于集合和映射,这些算法被称为集合类的静态方法。
集合定义的三个静态变量:EMPTY_SET、EMPTY_LIST、EMPTY_MAP
(4) 迭代器的使用
迭代器是一个对象,能够通过循环来得到、删除集合中的元素,实现了Iterator接口和ListIterator接口。
ListIterato继承Iterator,以允许双向遍历列表。
(5) 比较器的使用
3.3 泛型
泛型方法和泛型类允许开发人员使用一个方法指定一组相关方法,或者使用一个类指定一组相关的类型
(1) 泛型方法
① 定义:泛型方法在调用时可以接收不同类型的参数,编译器根据传递泛型方法的参数类型适当地处理每一个方法的调用
② 定义:例如,public static < E > void printArray( E[] inputArray )
③ 有界的类型参数
1) 作用:限制传递到泛型方法中的参数的类型范围
2) 声明:先列出参数类型的名称,后跟extends关键字,最后紧跟参数的上界
3) 例子:T extends Comparable<T>
(2)泛型类
3.4 序列化
(1)概念
① 序列化机制:一个对象可以被表示为一个字节系列
② 将对象写入文件后,可以从文件中读取出来,并且对它进行反序列化,也就是说可以根据对象中的数据等在内存中新建对象
③ ObjectInputStream和ObjectOutputStream是最高层次的数据流,包含了序列化和反序裂化对象的方法
(2)序列化对象
① 使用ObjectInputStream类来序列化一个对象
② 当序列化一个对象到文件时,按照java的标准约定是给文件一个.ser扩展名
(3)反序列化对象
3.5 网络编程
网络编程是指编写运行在多个、通过网络连接起来的设备(计算机)的程序
(1)Socket编程
套接字使用TCP提供两台计算机之前的通信,步骤:客户端程序创建一个套接字,并尝试连接服务器的套接字。连接建立时,服务器会创建一个Socket对象。此时,客户端和服务器可以通过对Socket对象的读、写进行通信。
ava.net.Socket类:代表一个套接字
java.net.SeverSocket类为服务器程序提供一种用来监听客户端,并与客户端建立连接的机制
步骤:
服务器实例化一个ServerSocket对象,表示通过服务器上的端口通信
服务器调用ServerSocket类的accept()方法,该方法将一直等待,直到客户端连接到服务器上给定的端口
服务器正在等待时,客户端实例化一个Socket对象,指定服务器名称和端口号来请求连接
Socket类的构造函数试图将客户端连接到指定的服务器和端口号。如果通信被建立,则在客户端创建一个能够与服务器进行通信的Socket对象
在服务器端,accept()方法返回服务器上一个新的socket引用,该socket连接到客户端的socket
连接建立后,通过对I/O流进行通信。每一个socket都有一个输出流和一个输入流,客户端的输出流连接到服务器端的输入流,而客户端的输入流连接到服务器端的输出流
(2)URL处理
① URL类方法
在java.net包中定义了URL类(java.net.URL)用来处理有关URL的内容
② URLConnection类方法
openConnection()返回一个java.net.URLConnection,例如:
如果你连接HTTP协议的URL, openConnection() 方法返回 HttpURLConnection 对象
如果你连接的URL为一个 JAR 文件, openConnection() 方法将返回JarURLConnection 对象
...
③
3.6 发送电子邮件
(1) 步骤
① 在机器上安装JavaMailAPI和JavaActivationFramework(JAF)
将mail.jar和activation.jar 添加到你的CLASSPATH中
②...(看实例)
(2) 用户认证部分
如果使用的是第三方邮件服务器,如QQ的SMTP服务器,需要提供用户名和密码给e-mail服务器来认证用户
设置:
props.put("mail.smtp.auth", "true");
props.setProperty("mail.user", "myuser");
props.setProperty("mail.password", "mypwd");
3.7 多线程编程
Java给多线程编程提供了内置支持,一个多线程程序包含两个或多个能并发运行的部分,程序的每一部分都称作一个线程,每个线程有一个独立的执行路径
(1)线程的优先级
Java优先级在MIN_PRIORITY(1)和MAX_PRIORITY(10)之间
默认情况下,每个线程都会分配一个NORM_PRIORITY(5)的优先级
(2)创建一个线程
Java提供了两种创建线程的方法:
实通过实现Runnable接口
通过继承Thread类本身
1) 通过实现Runnable接口
创建一个线程最简单的方法是:创建一个类实现Runnable接口,该类只需执行一个方法调用run()就可以了
2) 通过继承Thread类本身
继承类必须重写run()方法,因为该方法是新线程的入口点,也必须调用start()方法才能执行