对象基本要素
状态
数据成员
行为
- 方法成员
- 访问控制(封装):public,private,protected
类型
- 对象是某个类(型)的
- 通过之前的类型定义新的类型
组合 : has-a
继承 : is - 不同类型间的关系
- 基本类型之间的转换关系
- Autoboxing, unboxing
- Upcasting, downcasting
Java类型
基本类型
int double ...
数组
- 静态初始化
int []a = {1,2};
直接赋值 - 动态初始化
int []a = new int[5];
元素初始化为0 - 不规则数组
int [][]a = {{1,2},{3,4,5},{7,8,9,10}};
——>a.lenth
为3,且a[0][2]
为空(未被初始化 - 未知错误
int [] a = new int[3]{1,2,3};
- 使用
输出数组时,int []a = {1,2};
System.out.println(a);
出现乱码
System.out.println(a[0]);
输出1
引用
- 同一对象不同名字。不管使用哪个名字对 对象 进行修改,其他名字访问到的对象都是修改后的那个
- 引用首先要初始化
new
- 类class中的数据成员的引用:默认初始化为
null
不可变类型
- 一旦创建不能改变
- 不可变类型 String,Integer,Float等
对比:可变类型:MyType,数组
final 关键字
不可变对象
final 数据
- 编译时为常数;一旦被赋值就不能被修改
static final
仅有一个不可变的存储空间- final 成员在定义时可以不给初值
必须在构造函数中初始化
final 参数
函数不能修改参数的引用
final method
不能被重写
final class
不能被继承
Java控制结构
Java操作符
移位
- 带符号
>>
- 不带符号
>>>
等于
“==” 与 equals()
字符串连接操作 +=
Java控制语句
循环 for each
int []a = {1, 2, 3, 4, 5};
for (int i : a)
System.out.println(i);
类
静态成员
静态方法
即static method() {}
- 不用创建对象就可以调用
- 不能使用需要 实例化 后才分配空间的变量/函数
- 比如:main函数
class hi {
double d;
static void display() {
System.out.println(d);
}
public static void main(String []args) {
display();
hi.display();
hi s = new hi();
s.display();
}
}
静态数据
所有对象共享数据
static int i = 1;
可以对i重新赋值,函数中使用到i的地方i值会全部改变,但是i
的引用a
,(如int a = i;
) 值不变(为原来的i)static int i;
初始化为0,可以重新赋值,等同于int i;
- 不管何时引用,在什么对象后
.引用
,都获得不变的值
类的数据成员
this
关键字
- 含义:在类的非静态方法中 , 返回调用该方法的对象的引用
- 作用:
区分参数名称与数据成员名称
返回当前对象return this;
作为其他方法的参数return OneClass.OneMethod(this)
- 在构造函数中调用构造函数
形式:this(...)
出现在构造函数第一行
只能调用一个构造函数 - 静态方法无法使用
this
解决办法:传入this
类型的参数
public static void set(MyType t, double x) { t.d = x; }
//对比
void set(double x) { this.d = x; }
super
关键字
- 每个子类对象都包含一个隐藏的父类对象
- 在子类中 , super 用来指代父类对象的引用
数据成员的初始化
- 初始化的值
- 初始化的顺序
- 静态成员 / 非静态成员
- 子类成员 / 父类成员
- 构造函数
- 所有数据成员初始化在构造函数调用前完成
- 按照成员定义的顺序初始化
类的方法
构造函数
- 名称与类名称相同
- 无返回值
- 为类的静态方法
- 在子类构造函数调用前 , 首先调用父类构造函数
- 带参数的构造函数,调用前依然先调用父类构造函数
- 构造函数中不能重写
public class MySubType extends MyType {
public MySubType () {
super(1.0);//注意
System.out.println("In sub class");
}
public static void main(String [ ]args) {
MySubType ms = new MySubType();
}
}
重载 (overload)
- 方法名相同 , 参数类型 / 数量不同
- 区分:函数名 + 参数列表
- 函数重载与基本类型的转换
当转换不损失精度 (up-casting)
调用参数类型 '' 最近 '' 的函数
例如 :char
→int
,byte
→short
,short
→int
,int
→long
,long
→
float
,float
→double
- 当转换损失精度 (down-casting)
需要强制转换 - 函数重载与 autoboxing/unboxing
int and Integer 装箱/拆箱
重写 (override)
子类重新实现父类的方法 ( 同一个函数 )
相同函数名 , 不同参数列表
类的销毁
- 对象占有的资源
- 系统自动分配:
new
操作时系统分配的内存 - 程序显式分配:
如r.open();
- 销毁对象占有的资源
- 系统自动回收 ( 垃圾回收 ):
new
操作时系统分配的内存
- 系统自动回收 ( 垃圾回收 ):
- 程序显式回收
如r.colse();
- 垃圾回收
System.gc()
通知JVM可以进行回收
Java包
- 创建包
package mypackage;
在.java 文件首行javac mypackage/MyType.java
java mypackage.MyType
- 使用包
import mypackage.MyType;
- 包内 名字空间 共享
- jar包
- 打包 包(packed package)
- 将包 ( 目录 ) 变成文件
c: create
f: output to file
(如:jar cf restaurant.jar restaurant
)
访问控制
package access
- 同一个包中的类可以访问
其他包中的类不能访问 - 如果没有 package 语句 , java 默认当前目录中的
java 文件属于同一个包
public
- 每个 .java 文件包含一个 public class, 且该 class 的名字等于 .java 文件名
- 每个 .java 文件中除去 public class 外 , 其他的 class
为 package access
private
- private 构造函数 : 统计该类有多少对象
private MyType(int i1, double d1, char c1) {
i = i1; d = d1; c = c1;
}
public static int count= 0;
public static MyType makeMyType(int i1, double d1, char c1) {
count++;
return new MyType(i1, d1, c1);
}
- private 构造函数 : 该类只有一个对象
private static MyType mytype = new MyType(1, 1.0, 'a');
public static MyType access() { return mytype; }
protected
- 可以被子类 / 同一包中的类访问 , 不能被其他类访问
- 弱化的 private
- 同时赋予 package access
protected void set(double x) { d = x;}
封装
- 将易变的与稳定的部分区分开
- 在满足需求的情况下 , 接口尽量简单
类的复用
组合 has-a
将已有类作为新类的数据成员
class Person {
Name name;
Age age;
...
}
class Name{...}
class Age{...}
继承 is-a
新类 包含已有类 的所有数据与方法 , 并能增添修改(重写)
extends
关键字
- 子类可以使用父类所有方法和数据成员
- 子类可以定义新的方法和数据
- 子类可以重写父类的方法
class A {//父类 基类
...
}
public class B extends A {//子类
...
}
protected关键字
super关键字
Object class
所有类都是它的子类
Upcasting和多态
Upcasting
- 类型转换 : 父类的引用可以指向子类对象
- 同一基类的不同子类可以被视为同一类型 ( 基类 )
class A{ …}
class B extends A{ …}
A a = new A();
B b = new B();
A a = new B(); // upcasting
//对比
class A{ …}
class B{ …}
A a = new A();
B b = new B();
// A a = new B();compile error
class Instrument {
public void play() {}
static void tune(Instrument i) {
i.play();
}
}
public class Wind extends Instrument {
public static void main(String[] args) {
Wind flute = new Wind();
Instrument.tune(flute);
}
}
多态
- 参数可以代表不同的子类 , 并能
正确调用它们的方法 ( 即 , 有多种表现形态 ) - 子类重写了父类方法f()
- 当使用父类引用访问子类对象时 , 调用 f() 将绑定到子类的方法
动态绑定
- 函数的调用在运行时才能确定
- Java 中的所有方法都采用动态绑定 , 除了
final
static
- 数据成员不动态绑定
接口与抽象类
抽象
抽象方法
- 仅提供方法的名称 , 参数和返回值
- 没有具体实现
- 需要子类重写后才有意义
- 使用
abstract
关键字
abstract class Instrument {
public abstract void play(int note) ;
}
public class Wind extends Instrument {
public void play (int note) {
System.out.println ("Wind.play()"+ n);
}
}
public class Stringed extends Instrument {
public void play(int note) {
System.out.println("Stringed.play()"+ n);
}
}
抽象类
- 包含抽象方法的类
- 不能创建对象(实例化),必须被继承
- 是不完整的类
接口
相当于一个功能列表
特点
- 所有方法都是抽象方法,且默认为
public
(没有方法的实现) - 所有数据默认为
final static
- 没有代码重用 , 仅仅保留 upcasting 和多态
- 所有实现该接口的类都具有接口提供的方法
- 任何使用该接口类型的方法 , 都可以使用他的任何一种实现
- 某种协议 (protocol)
实现
关键字interface
和 implements
interface Instrument {
void play(int note) ;
String what();
}
class Stringed implements Instrument {
public void play(int note) {
System.out.println("Stringed.play()"+ n);
}
public String what() {return "Stringed";}
}
一个类实现多个接口
class Seaplane implements Plane, Boat {...}
对比
error:class C extends A, B {...} //继承: 只能有一个父类
扩展接口
interface A {…}
interface B extends A{…}
interface D {…}
interface D extends A,C{…}
接口适配器
没有深入接触
内部类
普通内部类
关系
- 定义在一个类的内部
- 返回内部类的引用
OutClassName.InnerClassName
- 在内部类中访问外部类对象的引用
OuterClassName.this
public class Outer{
void f() { System.out.println(“Outer.f()”);}
class Inner{
public Outer g() {return Ourter.this;}
}
public Inner inner() { return new Inner(); }
public static void main(String []args){
Outer o = new Outer();
Outer.Inner i = o.inner();
i.g().f();
}
}
创建内部类的对象
- 在外部类的方法中 : 直接创建
- 其他地方 :
OuterClassObject.new
- 内部类的对象隐含了一个引用 , 指向包含它的外部类对象
- 创建内部类对象前 , 需要有包含它的外部类对象
- 内部类对象能够访问该外部对象的所有成员 / 方法
public class Outer{
class Inner{}
public static void main(String []args){
Outer o = new Outer();
Outer.Inner i = o.new Inner();
}
}
匿名内部类
- 没有名字
- 没有构造函数
- 同时定义和创建
- 必须继承另一个类或者实现一个接口(不出现implements等关键词)
- return new oneClassName() {...}(在
{}
中定义)
public class Parcel{
public Contents contents(){
return new Contents() {
private int i = 11;
public int value() {return i;}
};//注意分号
}
}
interface Contents{
int value();
}
- 使用外部变量对匿名类数据成员初始化
外部变量需要final
public class Parcel{
public Contents contents(final int v){
return new Contents() {
private int i = v;
public int value() {return i;}
}
}
}
嵌套类(不考)
- 静态的内部类(无法访问外部类的非静态成员)
- 不需要外部的对象就可创建(不包含指向外部类对象的引用)
- 可以放入接口中
内部类的作用
- 多继承
父类只能是一个普通类 / 抽象类
但可以通过多个内部类继承多个类 / 抽象类 / 接口 - 闭包 (closure)
带有自由变量的函数 + 被绑定的自由变量 - 回调函数 (callbacks)
函数指针
容器
- 动态添加/删除
import java.util.*;
类型安全的
- 泛型 (generic)
- 定义容器为只能存放某种类型的对象,编译时才确定类型
- 容器可以存放的类型为
Object
,这样任何类型的对象都能放入容器 - 在确定了容器类型后 , Upcasting适用
- 不能指定基本类型
- 使用基本类型的wrapper(包装)
- Autoboxing and unboxing
compile error: ArrayList<int> a = new ArrayList<int>();
ArrayList<Integer> a = new ArrayList<Integer>();
输出容器
容器重写了 toString()
方法 , 可以帮助可视化容器的内容
Collection
Collection is an interface
用于存放一组对象
List
- List is an interface
- 按照插入顺序排列(数组、链表)
ArrayList
- 可扩展数组
- 适用于随机访问,插入删除较慢,浪费空间
- 每次扩张或缩减数组长度时 , 保证新的数组有一半的可用空间
- 构造函数
ArrayList<E>();
ArrayList<E>(int initialCapacity);
ArrayList<E>(Collection<E> c);
LinkedList
- 双向链表
- 适用于顺序访问,插入删除较快,无空间浪费
- 实现
List
接口 - 实现
Queue
接口 add()
,remove()
,element()
offer()
,poll()
,peek()
- 构造函数
LinkedList<E>();
LinkedList<E>(Collection<E> c);
- 方法
- 返回链表首元素,若链表为空则抛出异常
a.getFirst();
a.element();
- 返回链表首元素,若链表为空则返回 null
a.peek();
- 删除并返回链表首元素,若链表为空则抛出异常
String s = a.remove();
String s = a.removeFirst();
- 删除并返回链表首元素,若链表为空则返回 null
String s = a.poll();
- 在链表头添加对象
a.addFirst(“tiger”);
- 在链表尾添加对象
a.add(“cow”);
a.addLast(“cow”);
a.offer("cow")
- 应用:
Stack
- 后进先出 (Last In First Out, LIFO)
- push: 将一个对象入栈
- pop: 从栈中取出一个元素
接口
add()
添加元素remove()
删除元素get()
返回第 i 个位置的元素size()
返回元素数量contains()
查询indexOf()
序号subList()
子表isEmpty()
是否为空iterator()
返回迭代器listIterator()
返回List迭代器toArray()
转为数组
迭代器
Iterable 接口
- 提供
iterator()
返回迭代器 - Collection 扩展了 Iterable 接口
- foreach 语句
- 对所有实现
Iterable
接口的类 - 数组
ListIterator
- List 接口提供
- 扩展了 Iterator
- 双向遍历
hasNext()
,hasPrevious()
next()
,previous()
Set
- 集合(没有重复元素)
- 没有对Collection接口扩展
- 方法
put()
add(Object o)
,addAll(Collection<E> c)
remove(Object o)
,removeAll(Collection<E> c)
contains(Object o)
iterator()
size()
toArray()
HashSet
实现为 hash 表,查询较快(无序)
TreeSet
实现为查询树,较慢,按顺序排列(自动字典排序)
LinkedHashSet
速度快,按照插入顺序排列
Queue
- 队列->先进先出
- enqueue进队 ,dequeue出队
- 应用:任务调度
LinkedList
PriorityQueue
- 优先级队列
- 每次出队时 , 选择优先级最高的对象
- 队列中的对象可以比较优先级
- 普通队列也可看成优先级队列 : 优先级为加入队列的时间
- 自定义优先级
- 构造函数
PriorityQueue<E>(int initialCapacity, Comparator<E> comparator)
Comparator
接口——定义两个元素的优先级关系
包含方法compare(E e1,E e2)
返回负数: 当 e1 优先级低于 e2
返回正数: 当 e1 优先级高于 e2
返回 0: 当 e1 优先级等于 e2- 方法
offer(Object o)
,add(Object o)
将对象加入队列尾部poll()
,remove()
弹出位于队首的对象peek()
,element()
返回位于队首的对象 , 并不删除
Map
dictionary, associative array
HashMap a = new HashMap<T,T>();
- Key-value对应
- Key不重复,value可以重复
- Map is an interface
- 方法
- 存入键值对
put(K key, V value)
- 返回键对应的值
get(K key)
- 是否包含键key
containsKey(Object key)
- 是否包含值 value
containsValue(Object value)
- 返回键组成的 Set
keySet()
- 返回值组成的 Collection
values()
- 应用:单词出现次数
HashMap
实现为 hash 表 , 查询较块
TreeMap
实现为查询树 , 按顺序排列
LinkedHashMap
按照插入顺序排列
异常处理
错误处理场景
- 某方法中发现错误
- 中断当前执行路径
- 创建 / 捕捉
Exception
类对象 - 跳转到相应的异常处理代码段
- 在代码段中处理该异常
语法
抛出异常 : throw
If (t == null) throw new NullPointerException();
- 检查错误条件
- 含义
- 发生了一个异常 , 请找到合适的异常处理模块处理
- 该异常的具体信息存储在一个
Exception
对象中 .
处理异常 : try, catch
try{ // 可能会抛出异常的代码 } catch(Type1Exception e){ // 处理类型为 "Type1Exception" 的异常 } catch(Type2Exception e){ // 处理类型为 "Type2Exception" 的异常 }
- 处理对应异常
- 一旦发生异常立即跳转 , 不是
等到所有的异常都发生 - On error goto
异常对象 : Exception 类的子类
- 方法:
toString()
printStackTrace()
- 直接写
catch(Exception e)
简单 - 可以只抛出异常(只有
throw
),将异常交给该方法调用者(可能是另一个方法)处理
类方法的异常说明
throws
关键字
bar() throws Type1Exception, Type2Exception{
…
throw (Type1Exceptione);
…
throw (Type2Exceptione);
}
- 标识该方法可能会抛出何种类型的异常
- compile error if no throws
- 包含
throws
关键字 , 但函数本身并不抛出相应
异常 - 用于
interface
,abstract method
- 保证重写的方法必须考虑所列出的异常
- 不包含
throws
关键字,默认会抛出RuntimeException
类型的异常 - 重新抛出异常
调用函数可以将 catch 到的异常重新抛出,交给调用者的调用者来处理(可以一直抛到嵌套函数最外层) - 举例(现成异常)
- 当数组越界时 , 自动抛出
ArrayOutOfBoundsException
- 当数组越界时 , 自动抛出
- 当访问 null 的成员时 , 自动抛出
NullPointerException
- 当除以 0 时 , 自动抛出
ArithmaticException
finally
关键字
- 无论try 语句中是否有异常抛出 , 都会执行
- 作用:帮助保证一致性,简化代码
return;
->统一执行finally
继承 , 接口与异常
- 父类 / 接口的方法有异常说明 (
throws
关键字 ) - 子类 / 实现重写该方法时,应满足
- 有同样的异常说明
- 有 " 更少 " 的异常说明
- 抛出(相对于父类异常的)子类异常
- 原因
upcasting
I/O
介绍
- I/O流
- 字节 (01 串 ):
ByteArrayStream
- 文件 :
FileStream
- 字符串 :
StringStream
- 对象 :
ObjectStream
- 最重要的操作
- InputStream:
read()
- OutputStream:
write()
close()
- 便利操作
- 从文件读取一行 :
readLine()
- 读取一个基本类型 :
readInt()
,readDouble()
- 读取对象
Path接口
- java.nio.file
- 提供对文件路径字符串的操作
- 创建 Path 类型的对象
Path p1 = Paths.get("C:/Document/tmp/Hello.java");
Path p2 = FileSystems.getDefault().getPath("C:/Document/tmp/Hello.java");
System.out.format("toString: %s%n", path.toString()); // C:homejoefoo
System.out.format("getFileName: %s%n", path.getFileName()); // foo
System.out.format("getName(0): %s%n", path.getName(0)); // home
System.out.format("getNameCount: %d%n", path.getNameCount()); // 3
System.out.format("subpath(0,2): %s%n", path.subpath(0,2)); // homejoe
System.out.format("getParent: %s%n", path.getParent());
// homejoe
System.out.format("getRoot: %s%n", path.getRoot()); // C:
Files类
包含文件操作的静态方法
Path p;
- 判断文件是否存在
Files.exists(p)
- 判断文件是否可读 / 可写 / 可执行
Files.isReadable(p));
Files.isWritable(p);
Files.isExecutable(p);
- 删除文件
try {
Files.delete(path);
} catch (NoSuchFileException x) {
System.out.format("%s: no such" + " file or directory%n", path);
} catch (DirectoryNotEmptyException x) {
System.out.format("%s not empty%n", path);
} catch (IOException x) {
// File permission problems are caught here.
System.out.println(x);
}
获得文件相关的信息
size(Path)
isDirectory(Path, LinkOption)
isRegularFile(Path, LinkOption...)
isSymbolicLink(Path)
getLastModifiedTime(Path, LinkOption...)
setLastModifiedTime(Path, FileTime)
getOwner(Path, LinkOption...)
setOwner(Path, UserPrincipal)
流Stream
每次读入/写出一个字节
InputStream类
read()
,close()
- 不同源头对应不同子类
ByteArrayInputStream
,StringBufferInputStream
,FileInputStream
装饰器FilterInputStream
- 为
InputStream
的子类 - 具有
InputStream
所有的类的子类接口
BufferedInputStream
缓冲 装饰器
DataInputStream
读取基本类型 装饰器
readInt()
, readDouble()
OutputStream类
write()
,close()
- 不同目的地对应不同子类(改为“Output”即可
String objects
没有对应的StringBufferOutputStream
装饰器FilterOutputStream
- 为 OutputStream 的子类
- 具有 OutputStream 所有的类的子类接口
BufferedOutputStream
缓冲 装饰器
DataOutputStream
读取基本类型 装饰器
readInt()
, readDouble()
PrintStream
格式化输出(到文件中) 装饰器
println()
, print()
实现带缓冲的输入/输出流
read()
方法增加参数
read(byte[ ], int off, int len)
- 缺点
buffer长度需要用户指定
用户需要知道更多实现细节
继承
BufferedByteArrayInputStream
,BufferedByteArrayOutputStream
BufferedStringBufferInputStream
,BufferedStringBufferOutputStream
BufferedFileInputStream
,BufferedFileOutputStream
- 缺点
类过多
无法动态加载
组合
- 定义
BufferedInputStream
类 - 包含一个
InputStream
对象作为成员 - 调用该
InputStream
对象的read(byte[], int off, int len)
实
现缓冲 - 该调用在不同系统上有不同的优化 , 并且被封装
Reader/Writer
每次读入/写出一个字符
- Utf-16
每次读入 / 写出 16bit, 或者 32bit
读写字节 | 读写字符 |
---|---|
InputStream | Reader |
OutputStream | Writer |
FileInputStream | FileReader |
FileOutputStream | FileWriter |
StringBufferInputStream | StringReader |
(no corresponding class) | StringWriter |
ByteArrayInputStream | CharArrayReader |
ByteArrayOutputStream | CharArrayWriter |
FilterInputStream | FilterReader |
FilterOutputStream | FilterWriter |
BufferedInputStream | BufferedReader |
BufferedOutputStream | BufferedWriter |
**DataInputStream ** | DataInputStream |
DataOutputStream | DataOutputStream |
PrintStream | PrintWriter |
PrintWriter 可以用 OutputStream |
|
作为参数 |
Standard I/O
System.out
PrintStream
System.err
PrintStream
System.in
需要一些预处理
public class Echo {
public static void main(String[] args) throws IOException {
BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
String s;
while((s = stdin.readLine()) != null && s.length()!= 0)
System.out.println(s);
}
}
RTTI
运行时类型信息(RunTime Type Information)
Class类
每一个类都包含一个 Class 类的对象
该对象包含该类的信息
获得对象
- 类的静态成员
此时所有对象共享一个 Class 对象 - 每个对象调用
getClass()
获得 Class 类的对象
String s = “hello”; Class c = s.getClass();
- 每个类通过
.class
获得 Class 类的对象
Class c = String.class;
拥有方法
getName()
getInterfaces()
getSuperclass()
newInstance()
RTTI 的用途
给定 Object 引用 , 判断它的类型
String s = new String(“hello”);
Object o = s;
Class c = o.getClass().getName();
String t = (String)s;
泛型
- 参数化类型
在定义类的成员和方法时 , 类型为可变参数
泛型类
public class TwoTuple<A, B>{ //... }
泛型接口
带有类型参数的接口
public interface Generator<T>{ T next(); }
泛型方法
- 带有类型参数的方法的参数以及返回值
- 语法
public <T> void f(T x) { //…}
说明该方法带有类型参数T
,且<T>
需要放在返回值说明之前
类型擦除 (Type Erasure)
T
仅作为占位符 , 不包含任何具体类型的信息- 所有
T
类型的对象引用最终实现为Object
对象引用 - 类型变量仅仅对编译器的静态检查有用
- 当通过静态检查 , 所有类型参数被擦除
被限定的类型参数
限定类型参数的范围
- 语法:
class A <T extends B> { //…}
表示类型参数 T 只能是 B 类型或者 B 的子类型 - 作用 : 静态检查时 , 可以合法引用 T 的方法 ( 但最终仍然是
Object
) - 多个限定类型
class A <T extends B & C> { //…}
如果有类和接口 , 类应该出现在第一个位置
通配符*(不考)
<? extends B>
类型参数为某个 B 的子类型
- 具体是哪一个无法确定
List<? extends Apple>
- 无法
add
任何对象 - 可以
get
对象
<? super B>
类型参数为某个 B 的父类型
- 具体是哪一个无法确定
List<? super Apple>
- 无法
get
任何对象 - 无法确定是哪个父类
- 可以
add
B的子类对象