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 反射

  1. Class 类:反射的核心类,可以获取类的属性,方法等信息。
  2. Field 类:Java.lang.reflec 包中的类,表示类的成员变量,可以用来获取和设置类之中的属性值。
  3. Method 类: Java.lang.reflec 包中的类,表示类的方法,它可以用来获取类中的方法信息或者执行方法。
  4. 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()

  1. 使用 Class 对象的 newInstance()方法来创建该 Class 对象对应类的实例,但是这种方法要求该 Class 对象对应的类有默认的空构造器。调用 Constructor 对象的 newInstance()
  2. 先使用 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 字节代码中是不包含泛型中的类型信息的。

表示该通配符所代表的类型是 T 类型的子类。 表示该通配符所代表的类型是 T 类型的父类。 ### JAVA 序列化(创建可复用的 Java 对象) 保存(持久化)对象及其状态到内存或者磁盘 序列化对象以字节数组保持-静态成员不保存 序列化用户远程对象传输 Serializable 实现序列化
posted @ 2021-03-20 23:06  JOKI丶  阅读(34)  评论(0)    收藏  举报