Java 学习笔录
Java 理解
java 是面向对象编程语言。面向对象的特点:封装、继承、多态
封装:是面向对象的核心思想,将对象的属性和行为封装起来,不需要让外界知道具体实现细节,这就是封装思想。
继承:继承性主要描述的是类与类之间的关系,通过继承,可以在无须重新编写原有类的情况下,对原有类的功能进行扩展。
多态:多态性指的是在程序中允许出现重名现象,它指在一个类中定义的属性和方法被其他类继承后,它们可以具有不同的数据类型或表现出不同的行为,这使得同一个属性和方法在不同的类中具有不同的语义。
JVM
JVM:是可以运行Java代码的虚拟机。分为:Java代码执行、内存管理、线程资源同步和交互机制。
Hotspot JVM 后台运行的系统线程主要有下面几个:
虚拟机线程(VM thread):这个线程等待 JVM 到达安全点操作出现。这些操作必须要在独立的线程里执行,因为当堆修改无法进行时,线程都需要 JVM 位于安全点。这些操作的类型有:stop-theworld 垃圾回收、线程栈 dump、线程暂停、线程偏向锁(biased locking)解除。
周期性任务线程:这线程负责定时器事件(也就是中断),用来调度周期性操作的执行。
GC 线程:这些线程支持 JVM 中不同的垃圾回收活动。
编译器线程:这些线程在运行时将字节码动态编译成本地平台相关的机器码。
信号分发线程:这个线程接收发送到 JVM 的信号并调用适当的 JVM 方法处理。
Java代码执行:
① Java 源文件—->编译器—->字节码文件
② 字节码文件—->JVM—->机器码
Java 内存区域:线程私有区域【程序计数器、虚拟机栈、本地方法区】、线程共享区域【JAVA 堆、方法区(永久代)】、直接内存。
Java 8 移除永久代,元空间取代。元空间和永久代类似,区别是元空间不在Java虚拟机中,而是在内存中
垃圾回收:引用计数法
JVM 类加载机制分为五个部分:加载,验证,准备,解析,初始化
加载:这个阶段会在内存中生成一个代表这个类的 java.lang.Class 对 象,作为方法区这个类的各种数据的入口
验证:确保 Class 文件的字节流中包含的信息是否符合当前虚拟机的要求
准备:在方法区中分配这些变量所使用的内存空间
解析:虚拟机将常量池中的符号引用替换为直接引用的过程
初始化:开始真正执行类中定义的 Java 程序代码
Java四种引用类型
强引用:在 Java 中最常见的就是强引用,把一个对象赋给一个引用变量,这个引用变量就是一个强引用。当一个对象被强引用变量引用时,它处于可达状态,它是不可能被垃圾回收机制回收的,即使该对象以后永远都不会被用到 JVM 也不会回收。因此强引用是造成 Java 内存泄漏的主要原因之一
软引用:软引用需要用 SoftReference 类来实现,对于只有软引用的对象来说,当系统内存足够时它不会被回收,当系统内存空间不足时它会被回收。软引用通常用在对内存敏感的程序中。
弱引用:弱引用需要用 WeakReference 类来实现,它比软引用的生存期更短,对于只有弱引用的对象来说,只要垃圾回收机制一运行,不管 JVM 的内存空间是否足够,总会回收该对象占用的内存。
虚引用:虚引用需要 PhantomReference 类来实现,它不能单独使用,必须和引用队列联合使用。虚引用的主要作用是跟踪对象被垃圾回收的状态。
JAVA IO/NIO
阻塞 IO 模型
非阻塞 IO 模型
多路复用 IO 模型
JAVA IO包
字节流:InputStream、OutputStream
字符流:Reader、Writer
NIO 主要有三大核心部分:Channel(通道),Buffer(缓冲区), Selector。
NIO 和传统 IO 之间第一个最大的区别是,IO 是面向流的,NIO 是面向缓冲区的。
JAVA 集合
集合类存放于 Java.util 包中,主要有 3 种:set(集)、list(列表包含 Queue)和 map(映射)。
Collection:Collection 是集合 List、Set、Queue 的最基本的接口。
Iterator:迭代器,可以通过迭代器遍历集合中的数据
Map:是映射表的基础接口
List
ArrayList、Vector 、LinkedList
ArrayList(数组):有序可重复,底层使用数组,线程不安全,查询快增删慢,容量不够自增 1.5 + 1
Vector(数组):有序可重复,底层使用数组,线程安全,查询快增删慢,容量不够自增 1
LinkedList(链表):有序可重复,底层使用双向链表数据结构,查询慢增删快,线程不安全
Set
HashSet(Hash 表):无序不重复,读取速度快,线程不安全
TreeSet(二叉树):无序不重复,线程不安全
LinkHashSet(HashSet+LinkedHashMap):线程不安全
Map
HashMap(数组+链表+红黑树):键不可重复值可重复,线程不安全,允许key为null,value也可以为null
Hashtable:键不可重复值可重复,线程安全,允许key、value都不能为null
TreeMap:键不可重复值可重复,底层二叉树
JAVA 线程
继承 Thread 类、实现 Runnable 接口
有返回值的任务必须实现 Callable 接口,类似的,无返回值的任务必须 Runnable 接口
//创建一个线程池
ExecutorService pool = Executors.newFixedThreadPool(taskSize);
// 创建多个有返回值的任务
List<Future> list = new ArrayList<Future>();
for (int i = 0; i < taskSize; i++) {
Callable c = new MyCallable(i + " ");
// 执行任务并获取 Future 对象
Future f = pool.submit(c);
list.add(f);
}
// 关闭线程池
pool.shutdown();
// 获取所有并发任务的运行结果
for (Future f : list) {
// 从 Future 对象上获取任务的返回值,并输出到控制台
System.out.println("res:" + f.get().toString());
}
4种线程池
Java 里面线程池的顶级接口是 Executor,但是严格意义上讲 Executor 并不是一个线程池,而只是一个执行线程的工具。真正的线程池接口是 ExecutorService。
newCachedThreadPool:创建一个可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们。对于执行很多短期异步任务的程序而言,这些线程池通常可提高程序性能
newFixedThreadPool:创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程。
newScheduledThreadPool:创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行。
newSingleThreadExecutor:xecutors.newSingleThreadExecutor()返回一个线程池(这个线程池只有一个线程),这个线程池可以在线程死后(或发生异常时)重新启动一个线程来替代原来的线程继续执行下去
线程生命周期(状态)
新建状态(NEW):当程序使用 new 关键字创建了一个线程之后,该线程就处于新建状态,此时仅由 JVM 为其分配内存,并初始化其成员变量的值
就绪状态(RUNNABLE):当线程对象调用了 start()方法之后,该线程处于就绪状态。Java 虚拟机会为其创建方法调用栈和程序计数器,等待调度运行。
运行状态(RUNNING):如果处于就绪状态的线程获得了 CPU,开始执行 run()方法的线程执行体,则该线程处于运行状态。
阻塞状态(BLOCKED):阻塞状态是指线程因为某种原因放弃了 cpu 使用权,也即让出了 cpu timeslice,暂时停止运行。直到线程进入可运行(runnable)状态,才有机会再次获得 cpu timeslice 转到运行(running)状态。
阻塞的情况分三种:
等待阻塞(o.wait->等待对列):运行(running)的线程执行 o.wait()方法,JVM 会把该线程放入等待队列(waitting queue)中。
同步阻塞(lock->锁池):运行(running)的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则 JVM 会把该线程放入锁池(lock pool)中
其他阻塞(sleep/join):运行(running)的线程执行 Thread.sleep(long ms)或 t.join()方法,或者发出了 I/O 请求时,JVM 会把该线程置为阻塞状态。当 sleep()状态超时、join()等待线程终止或者超时、或者 I/O处理完毕时,线程重新转入可运行(runnable)状态。
线程死亡(DEAD):线程会以下面三种方式结束,结束后就是死亡状态。
正常结束 1. run()或 call()方法执行完成,线程正常结束。
异常结束 2. 线程抛出一个未捕获的 Exception 或 Error。
调用 stop 3. 直接调用该线程的 stop()方法来结束该线程—该方法通常容易导致死锁,不推荐使用。
终止线程 4 种方式
1.正常运行结束
2.使用退出标志退出线程
3.Interrupt 方法结束线程
4.stop 方法终止线程(线程不安全)
JAVA 反射
- Class 类:反射的核心类,可以获取类的属性,方法等信息。
- Field 类:Java.lang.reflec 包中的类,表示类的成员变量,可以用来获取和设置类之中的属性值。
- Method 类: Java.lang.reflec 包中的类,表示类的方法,它可以用来获取类中的方法信息或者执行方法。
- Constructor 类: Java.lang.reflec 包中的类,表示类的构造方法。
获取 Class 对象
Class clazz=Class.forName("类的全路径"); (最常用)
//获取 Person 类的 Class 对象
Class clazz=Class.forName("reflection.Person");
//获取 Person 类的所有方法信息
Method[] method=clazz.getDeclaredMethods();
for(Method m:method){
System.out.println(m.toString());
}
//获取 Person 类的所有成员属性信息
Field[] field=clazz.getDeclaredFields();
for(Field f:field){
System.out.println(f.toString());
}
//获取 Person 类的所有构造方法信息
Constructor[] constructor=clazz.getDeclaredConstructors();
for(Constructor c:constructor){
System.out.println(c.toString());
}
创建对象
Class 对象的 newInstance()
- 使用 Class 对象的 newInstance()方法来创建该 Class 对象对应类的实例,但是这种方法要求该 Class 对象对应的类有默认的空构造器。调用 Constructor 对象的 newInstance()
- 先使用 Class 对象获取指定的 Constructor 对象,再调用 Constructor 对象的 newInstance()方法来创建 Class 对象对应类的实例,通过这种方法可以选定构造方法创建实例
//获取 Person 类的 Class 对象
Class clazz=Class.forName("reflection.Person");
//使用.newInstane 方法创建对象
Person p=(Person) clazz.newInstance();
//获取构造方法并创建对象
Constructor c=clazz.getDeclaredConstructor(String.class,String.class,int.class);
//创建对象并设置属性
Person p1=(Person) c.newInstance("李四","男",20);
JAVA 注解
Annatation(注解)是一个接口
@Target说明了Annotation所修饰的对象范围: Annotation可被用于 packages、types(类、接口、枚举、Annotation 类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch 参数)。
@Retention定义了该 Annotation 被保留的时间长短:表示需要在什么级别保存注解信息,用于描述注解的生命周期(即:被描述的注解在什么范围内有效),取值(RetentionPoicy)由:
- SOURCE:在源文件中有效(即源文件保留)
- CLASS:在 class 文件中有效(即 class 保留)
- RUNTIME:在运行时有效(即运行时保留)
@ Documented 用于描述其它类型的 annotation 应该被作为被标注的程序成员的公共 API,因此可以被例如 javadoc 此类的工具文档化。
@Inherited 元注解是一个标记注解,@Inherited 阐述了某个被标注的类型是被继承的。
JAVA 内部类
内部类分为:静态内部类,成员内部类,局部内部类,匿名内部类四种
- 静态内部类
public class Out {
private static int a;
private int b;
public static class Inner {
public void print() {
System.out.println(a);
}
} }
- 成员内部类
public class Out {
private static int a;
private int b;
public class Inner {
public void print() {
System.out.println(a);
System.out.println(b);
}
} }
- 局部内部类
public class Out {
private static int a;
private int b;
public void test(final int c) {
final int d = 1;
class Inner {
public void print() {
System.out.println(c);
}
}
} }
- 匿名内部类
public abstract class Bird {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public abstract int fly();
}
public class Test {
public void test(Bird bird){
System.out.println(bird.getName() + "能够飞 " + bird.fly() + "米");
}
public static void main(String[] args) {
Test test = new Test();
test.test(new Bird() {
public int fly() {
return 10000;
}
public String getName() {
return "大雁";
}
});
}
}
JAVA 泛型
泛型方法(
泛型类
类型通配符<?>
类型擦除:Java 中的泛型基本上都是在编译器这个层次来实现的。在生成的 Java 字节代码中是不包含泛型中的类型信息的。

浙公网安备 33010602011771号