这篇是参考Java快速教程之后的一份学习笔记
基础
Hello World 到面向对象
- 类(class):上面程序定义了一个类HelloWorld,该类的名字与.java文件的名字相同。
- 方法(method):类的内部定义了该类的一个方法main。
- 语句(statement):真正的“打印”功能由一个语句实现,即: System.out.println(“Hello World!”);
- 使用
javac
编译,使用java
运行 - Java不同变量类型在程序中的内存分布
类型 | 存储大小 | 例值 | 注释 |
---|---|---|---|
byte | 1byte | 3 | 字节 |
int | 4bytes | 3 | 整数 |
short | 2bytes | 3 | 短整数 |
long | 8bytes | 3 | 长整数 |
float | 4bytes | 1.2 | 单精度浮点数 |
double | 8bytes | 1.2 | 双精度浮点数 |
char | 2bytes | ‘a’ | 字符 |
boolean | 1bit | true | 布尔值 |
- Java 数组声明和定义
- 声明:
int[] a;
- 声明的同时使用
new
来创建数组所需空间:int[] a = new int[100];
- 声明创建同时指定元素内容:
int[] a = new int[]{1,3,5,7,9};
- 声明:
- 表达式
- 数学表达式: +,-,*,/,%
- 关系表达式:>,>=,==,<=,<,!=
- 布尔表达式:&&,||,!
- 位运算:&,|,^,~,<<,>>
- 双目表达式:condition? X1:X2
- 控制结构
- 选择结构
- if else
- switch
- 循环结构:
- while
- do{} while()
- for(){}
- break
- continue
- 选择结构
方法和数据对象
- Java 使用return来返回值
- this 指代的是对象本身
- 成员方法可以添加参数列表
- 使用 this.method() 调用同一对象的其他方法
- 显式初始化:声明对象时候,对于对象进行赋值
构造器以及重载
- 构造器定义函数值: 类似于C语言中的构造函数
- 构建方法 > 显式初始值 > 默认初始值
- Java根据方法名和参数列表决定要调用的方法,叫做方法重载
封装和接口
- 三种不同的封装方法
- public
- private
- protected: 标记为protected的成员变量在该类和该类的衍生类中可见,但不能被外界访问。
- interface 接口
- interface 可以定义接口
- implements 可以实现接口
- 可以实现一个类 实现多个接口
- has-a 关系 一个对象可以拥有另一个对象 (手电筒有电池)
- package : 将Java程序代码进行打包,使用包进行访问
- JVM,实现程序的可移植性
- extends 继承
- 新类称之为衍生类
- 同名同参数方法会存在方法覆盖
- 使用super访问父层的方法
- 基类对象先被创建和进行初始化,结束之后,开始构建衍生层(衍生层对象进行创建和初始化)
类数据和类方法
- 类数据对象: 所有成员进行共享的变量 使用关键字 static
- 类方法:操作类对象的方法使用关键字static, 使用这个关键字的方法不能正常操作属于对象的数据和方法
- 对象方法可以访问类数据
- final 关键字:这个数据 / 类 / 方法不能被改变了, private 方法默认为final方法
接口继承和抽象类
- 接口的继承: 和类的继承类似, 可以添加设计更多的方法,不同点,可以实现多重继承
- 抽象类:只提供类的原型,不提供类的具体实现。
Java 对象引用
- new 在内存中为对象开辟了空间,在内存的堆上开辟了空间。
- 对象引用存储在内存的栈中
- 当我们将一个引用赋值给另一个引用的时候,我们实际上复制的是对象的地址,两个引用将操作同一个对象。当程序通过一个引用修改了对象之后,通过其他引用课也可以看到该修改。
- 垃圾回收机制:当一个对象没有引用指向的时候,这个对象就会被清空。
- Java 参数传递:Java的参数传递为值传递。当我们传递一个参数时,方法将获得该参数的一个拷贝。
- 基本对象的参数传递:传递的是值的拷贝,Java方法不会影响到值,形式变量和实际变量。
- 引用值的参数传递: 传递的是对象的地址,Java方法会直接影响到对象。
类型转换和多态
- 类型检查
- 基本类型检查: 收缩类型变换(强制类型转换),宽松变换(自动进行)
- Upcast 和多态:一个衍生类可以转换为其基类引用
- 一个衍生类对象可以当做一个基类对象使用
- 所有对象都有一个共同的继承祖先,
Object
类
进阶
String 类
创建字符串 不需要
new
关键字Java String 类别中的常用方法
方法 效果 s.length() 返回字符串s的长度 s.charAt() 返回字符串中下标为2的字符 s.substring(0,4) 返回s字符串中下标0-4的子字符串 s.indexOf(“Hello”) 返回子字符串”Hello“的下标 s.startsWith(“ “) 返回s是否以空格开始 s.endsWith(“oo”) 判断s是否以”oo”结束 s.equals(“Good World!”) 判断s是否等于”Good World!”, ==只能判断字符串是否保存在同一位置。需要使用equals()判断字符串的内容是否相同。 s.compareTo(“Hello Nerd!”) 比较s字符串与”Hello Nerd!”在词典中的顺序,返回一个整数,如果<0,说明s在”Hello Nerd!”之前;如果>0,说明s在”Hello Nerd!”之后;如果==0,说明s与”Hello Nerd!”相等。 s.trim() 去掉s前后的空格字符串,并返回新的字符串 s.toUpperCase() 将s转换为大写字母,并返回新的字符串 s.toLowerCase() 将s转换为小写字母,并返回新的字符串 s.replace(“World”, “Universe”) 将”World”替换为”Universe”,并返回新的字符串 String 类型对象是不可变对象
异常处理
try
,catch
,finally
以及其随后的代码段来组成,finally
不是必须的try
后面的程序块包含了针对该异常类型所要进行的操作。try
所监视的程序块可能抛出不止一种类型的异常,所以一个异常处理器可以有多个catch
模块。finally
后面的程序块是无论是否发生异常,都要执行的程序。- 异常都来自与
Throwable
类,一个Throwable
类对象可以抛出,异常分为unchecked
异常和checked
异常。 Error
是指Java
的内部错误或者是资源耗尽等错误,需要直接退出程序。Exception
里面一个衍生类RuntimeException
都是程序自身的问题组成的。checked
异常,是由编程与环境- 可以自己新建类,在程序中抛出异常
- 可以自定义异常,使用继承的方式,需要小心选择所继承的基类。
运行时类别识别(RTTI)
Class
类:对类的抽象和集合。当我们调用对象的getClass()
的时候,就会得到其对应Class
对象的引用Class
类方法getName()
返回类的名字getPackage()
返回类所在的包getFields()
返回所有的public数据成员getMethods()
返回所有的public方法
多线程
- 多线程是计算机实现多任务并行处理的一种方式
- 单核CPU会在不同的任务之间做切换,这是操作系统分时复用的机制
- 多个线程可以并存于同一个进程空间。在JVM的一个进程空间中,一个栈(stack)代表了方法调用的次序。对于多线程来说,进程空间中需要有多个栈,以记录不同线程的调用次序。多个栈互不影响,但所有的线程将共享堆(heap)中的对象。
Thread
基类的构造方法可以使用一个字符串作为参数,该字符串是该线程的名字,并使用getName()
返回。- 我们调用线程对象的
start()
方法启动线程 join(Thread tr)
: 等待线程tr完成setDaemon()
: 设置当前线程为后台daemon
- 我们调用线程对象的
- 另一种实现多线程的方法是实现
Runable
接口,并提供run()
方法 - Synchronized: 进程之间的同步,防止出现超票的情况
- 我们将共享的资源置于一个对象中
- 对于共享资源的操作,放在
synchronized
方法中
容器
数组
在说明类型时,在类型说明后面增加一个
[]
,来说明是一个数组。使用
new
创建容器时,需要说明数组的大小。我们可以使用 数组名[下标] 的方式来调用某个元素。我们可以逐个的初始化数组的元素,也可以在声明的同时使用
{}
初始化数组。使用
System.arraycopy()
方法来有效的复制数组1
2System.arraycopy(aFrom, 1, aTo, 0, 3);
//aFrom为想要复制出去的数组,aTo为想要复制到的数组,1为aFrom的想要复制出去的元素起始位置,0为aTo中想要存储复制来元素的起始位置,3为所要复制的元素总数。
Collection
List
表- 容器的引用为List类型, 但是容器的实施类型为
ArrayList
类型。 - 将接口和实施做分离
- 容器的引用为List类型, 但是容器的实施类型为
1
2
3
4
5
6import java.util.*;
List<String> l1 = new ArrayList<String>();
add();//方法加入新的元素
get();//方法可以获取容器中的元素,传递一个整数下标作为参数
remove();//方法可以删除容器中的元素,传递一个整数下标作为参数。(有另一个remove(),传递元素自身作为参数)
size();//方法用来返回容器中元素的总数Set
集合- 集合中不允许有等值的元素
- 集合的元素没有顺序
Map
键值对的集合Collection
主要方法:
1
2
3
4
5
6
7
8
9
10
11boolean add(Object o);//添加对象到集合
boolean addAll(Collection c);//将指定 collection 中的所有元素都添加到此 collection 中(可选操作
void clear();//删除集合中所有元素
boolean remove(Object o);//删除指定的对象
boolean removeAll(Collection c);//移除此 collection 中那些也包含在指定 collection 中的所有元素(可选操作)。
boolean retainAll(Collection c);//仅保留此 collection 中那些也包含在指定 collection 的元素(可选操作)。
int size();//返回当前集合中元素的数量
boolean contains(Object o);//查找集合中是否有指定的对象
boolean containsAll(Collection c);//查找集合中是否有集合c中的元素
boolean isEmpty();//判断集合是否为空
Iterator iterator();//返回一个迭代器
iterator
接口:不论Collection
的实际类型是什么,都支持一个iterator()
的方法,该方法返回一个迭代子,使用该迭代子可以逐一访问Collection
里面的元素。1
2
3boolean hasNext(); //如果仍有元素可以迭代,则返回True
E next(); //返回下一个迭代的元素
void next(); //将迭代器指向的集合中,移除迭代器返回的最后一个元素List
接口: 有序的Collection
,使用这个接口可以精确的控制每个元素插入的位置,用户可以使用索引(下标的方式)对于对象进行访问。LinkedList
类:允许null
元素,提供额外的get
,remove
,insert
方法,并不是线程安全的,注意它没有同步方法,需要自己新建。ArrayList
类:实现了一个大小可变的数组,允许null
元素,没有同步方法。- 快速添加删除,使用
LinkedList
,需要快速随机访问元素,使用ArrayList
类 Vector
类:类似于ArrayList
,但是存在的同步方法,是线程安全的,使用Iterator
进行遍历操作时候,不同线程对于同一个对象操作会产生异常。`Stack
类:继承自Vector
, 实现了一个后进先出的栈,提供5个额外的方法使得Vector
能够当做栈来使用,push
,pop
,peek
,empty
,search
,刚开始创建的时候是空栈。
Set
接口: 不包含重复元素的Collection
HashSet
: 方法有add()
,remove(元素)
,旗下还有实现类LinkedHashSet
TreeSet
: 是Set
的一种变体,可以实现按照树型进行插入,实现元素的排序(从小到大)
Map
接口: 没有实现Collection
类,提供从key到value的一种映射。Map
接口需要实现的方法有:put/putAll/remove/clear 增加删除
get/values 获取值
containKey/containValue 判断
entrySet/keySet 获取迭代
equals/hashcode 比较
HashMap
类: 非进程同步的HashTable
类:进程同步的TreeMap
类:Map
数据是根据key
来进行排序的
嵌套类
内部类
Java 允许我们在一个类中嵌套另一个类, 在类的内部定义一个新类,这个类称为内部类
内部类是被认为是外部对象的一个成员,在定义内部类的时候,同样有访问权限控制(public, private, protected)
内部类的默认访问权限是包访问权限,我们可以在外部测试类中访问到对象的内部类,并使用该内部类创建对象。
1
Human.Cup soloCup = me.new Cup();
在创建对象的时候,要注意必须基于一个外部类,并使用这个外部类对象来创建
Cup
对象。
闭包
- 内部类对象必须依附于某个外部类对象,与此同时,内部类对象也可以访问到它所依附的外部类对象的成员(即便是private成员)。从另一个角度来讲,内部类对象附带有创建对象时的环境信息。
嵌套static类
- 我们可以定义嵌套的static类,对象不需要依附于外部类的某个对象。相应的,这个嵌套类也无法调用外部对象的方法,也无法读取或者修改外部对象的数据。效果上看,就是扩展了类的命名空间。
GUI 图形界面以及事件响应
- Java GUI 功能主要集中在awt和swing中。awt是GUI的底层包。
- Java Layout 布局方式:Java 里面存在着不同的布局方式。Java布局方式
- 元素,事件,监听器: 通过监听器,可以将事件绑定在图形元素上面
ActionListener
,ActionEvent class
内存管理和垃圾回收
Java 是在JVM所虚拟出来的内存环境中运行的。
内存分为栈
stack
和堆heap
两个部分栈
- 记录了线程的方法调用,每个线程有一个栈
- 如果有新的方法调用,那么栈会增长
- 栈的存储单元为帧(frame)
- 栈中保存基本变量类型的变量值,以及对象的引用,引用指向堆
- 调用结束之后,栈会被释放
堆
- 堆的空间不会随着方法调用结束而清空,因此,在某个方法中创建的对象,可以在方法调用结束之后,继续存在于堆中。
垃圾回收 Garbage Collection (GC)
垃圾回收负责释放不可到达的对象(即没有引用的指向的对象)
早期垃圾回收采用引用计数机制,但是存在循环引用不可处理的问题
“mark and sweep”: 这种机制下,每个对象将有标记信息,用于表示该对象是否可到达。当垃圾回收启动时,Java程序暂停运行。JVM从根出发,找到所有的可到达对象,并标记(mark)。随后,JVM需要扫描整个堆,找到剩余的对象,并清空这些对象所占据的内存。
“copy and sweep”。这种机制下,堆被分为两个区域。对象总存活于两个区域中的一个。当垃圾回收启动时,Java程序暂停运行。JVM从根出发,找到可到达对象,将可到达对象复制到空白区域中并紧密排列,修改由于对象移动所造成的引用地址的变化。最后,直接清空对象原先存活的整个区域,使其成为新的空白区域。
这两种机制, “mark and sweep”, “copy and sweep” 都是通过分代回收来进行回收的。
每个对象会记录它的世代信息,世代就是指对该对象所经历的垃圾分类回收的次数,世代越久远的对象,在内存中存活的时间就越长。
在上图中,堆分为三代,其中永久世代不会被垃圾回收,里面存储的是Class和类相关的信息。年轻世代和成熟世代需要进行垃圾回收。年轻世代需要分为三个区域,第一个区域叫做伊甸,新生对象将存在于这个区域。from, to: 这两个区域大小相等,相当于copy and sweep中的两个区域。当新建对象无法放入eden区时,将出发minor collection。JVM采用copy and sweep的策略,将eden区与from区的可到达对象复制到to区。经过一次垃圾回收,eden区和from区清空,to区中则紧密的存放着存活对象。随后,from区成为新的to区, to区成为新的from区。如果进行minor collection的时候,发现to区放不下,则将部分对象放入成熟世代。另一方面,即使to区没有满,JVM依然会移动世代足够久远的对象到成熟世代。