JavaSE 知识点梳理学习笔记【精华版】

文章目录

  • DOS 窗口常用命令
    • 路径跳转
    • 列出当前目录下所有文件/子目录
    • 退出当前DOS命令窗口
    • 清屏
    • 内容复制
    • 编译 .Java 文件
    • 运行 .class 文件
  • JDK 环境变量配置
  • Java 基础
    • Java 三大模块
    • Java 术语
    • Java 注释写法
    • Java 标识符规则与规范
    • Java 编码方式
    • Java 变量的分类
    • Java 变量类型转换
    • Java 进制
    • Java 运算符注意点
  • Java 中级
    • JVM 内存划分三块主要区域
      • 方法区内存
        • 基础知识
        • 存储内容
      • 堆内存
        • 基础知识
        • 存储内容
      • 栈内存 (stack)
        • 基础知识
        • 存储内容
    • 面向对象的三大特征
      • 类、对象、引用
      • 封装
      • 继承
      • 多态
        • 上转型 / 下转型
    • Java 数组相关知识
      • Array 的内存分配
      • Array 优缺点
      • Array 的方法与属性
      • Array 扩容
      • main 主方法 String[] args 作用
      • 引用数组上/下转型
    • Java 方法相关知识
      • Java 方法的内存分配
      • Java 构造方法
      • Java 方法的重载(overload)
      • Java 方法的重写 / 覆盖(override)
      • Java 方法的递归
      • Java 静态方法(静态代码块)
      • Java 方法代码块
        • 静态代码块
        • 实例代码块
    • Java 修饰符相关知识
      • public static final 常量
      • final 修饰符
      • 访问控制修饰符
    • Java 抽象类与接口
      • Java 抽象类
      • Java 接口
      • Java 抽象类与接口
    • Java 内部类
      • 静态、实例、局部、匿名内部类
    • Java 枚举类型
      • 使用方法
  • Java 高级
    • 类加载器
    • 可变长度参数
    • 异常
      • 异常分类
      • 异常处理方式
      • 获取异常信息两个方法
      • finally
      • 自定义异常
      • 面试题
    • 集合
      • 概念
      • 集合的两大类
        • 单个方式存储元素
        • 键值对方式存储元素
      • 泛型
        • 概念与构造方法
        • 自动类型推断机制
        • 自定义泛型
      • 增强 for 的使用
        • 基本语法
        • 集合使用
      • Collection(接口)
        • 常用方法
        • Iterator(迭代器)
          • 构造方法
          • 迭代 / 遍历元素
          • 删除元素(迭代器)
      • List(接口)
        • 常用方法
      • ArrayList
        • 构造方法
      • LinkedList
      • Vector
      • Map(接口)
        • 常用方法
      • HashMap
        • 哈希表 / 散列表
        • 源代码
        • map.put 实现原理
        • map.get 实现原理
        • JDK8改进
      • Hashtable
      • Properties
        • 常用方法
      • TreeSet
        • 构造方法
        • 自定义类排序
      • Collections(集合工具类)
        • 常用方法
    • IO流
      • 分类
      • 16个掌握的流
      • java.io.FileInputStream
      • java.io.FileOutputStream
      • 文件拷贝(所有)
      • java.io.FileReader
      • java.io.FileWriter
      • 文本拷贝(文本)
      • java.io.BufferedReader / InputStreamReader
      • java.io.BufferedWriter / OutputStreamWriter
      • java.io.DataOutputStream
      • java.io.DataInputStream
      • java.io.printStream
      • 日志文件
      • ObjectOutputStream
      • ObjectInputStream
      • IO 流 + Properties
    • 多线程
      • 进程与线程的区别
      • 线程两大分类
      • 线程调度模型
      • 多线程并发安全问题
      • 实现多线程的方法
      • 线程的生命周期
      • 获取 / 修改线程名字
      • 获取当前线程对象
      • sleep(睡眠)
      • interrupt(唤醒)
      • stop(强行终止)
      • 合理终止方式
      • 常用方法
      • 定时器
      • wait / notify(生产消费者模型)
    • 反射机制
      • 概念
      • 获取类的三种方法
      • 实例化对象
      • 获取绝对路径读配置
      • 资源绑定器(IO+Properties)
      • Field 属性
      • Method 方法
      • Constructor 构造方法
      • 父类与接口
    • 注解
      • 概念
      • 语法格式
      • JDK自带注解
      • 反编译注解
  • Java 常用类库
    • Object 类库
      • clone
      • hasCode
      • equals (重写)
      • toString(重写)
      • finalize(重写)
    • Arrays 类库
      • binarySearch(二分法查找)
      • sort
    • String 类包
      • 构造方法
      • charAt(返回索引char值)
      • compareTo(比较字典序)
      • contains(包含)
      • endWith / startWith
      • equalsIgnoreCase(忽略大小写判断相等)
      • getBytes(转为byte数组)
      • indexOf / lastIndexOf
      • isEmpty
      • replace
      • split
      • substring(切割)
      • toCharArray
      • toLowerCase / toUpperCase
      • trim
      • valueOf
      • 面试题
    • StringBuffer / StringBuilder 类库
      • 区别
      • 构造方法
      • append
    • Integer 类库
      • 基本数据类型包装类
      • 构造方法
      • 类型转换(装箱 / 拆箱)
      • MAX_VALUE / MIN_VALUE(上下限)
      • parseInt(String - int)
      • toBinaryString(二进制)
      • toHexString(八进制)
      • toOctalString(十六进制)
      • valueOf(转Integer)
    • Data / SimpleDateFormat 类库
      • 构造方法(获取时间)
      • 时间格式化
      • currentTimeMillis(获取距离毫秒数)
    • DecimalFormat 类库
      • 构造方法(数字格式化)
    • BigDecimal 类库
      • 构造方法
      • 四则运算
    • Random 类库
      • 构造方法
      • 生成随机数
    • File 类库
      • 构造方法
      • exists(判断存在)
      • createNewFile
      • mkdirs
      • 获取父路径
      • getName
      • isDirectory
      • isFile
      • lastModified
      • length
      • listFiles
      • toBinaryString(二进制)
      • toHexString(八进制)
      • toOctalString(十六进制)
      • valueOf(转Integer)
    • Data / SimpleDateFormat 类库
      • 构造方法(获取时间)
      • 时间格式化
      • currentTimeMillis(获取距离毫秒数)
    • DecimalFormat 类库
      • 构造方法(数字格式化)
    • BigDecimal 类库
      • 构造方法
      • 四则运算
    • Random 类库
      • 构造方法
      • 生成随机数
    • File 类库
      • 构造方法
      • exists(判断存在)
      • createNewFile
      • mkdirs
      • 获取父路径
      • getName
      • isDirectory
      • isFile
      • lastModified
      • length
      • listFiles

DOS 窗口常用命令


路径跳转

cd + 路径 改变当前目录

cd .. 返回上级目录

cd \ 返回根目录

列出当前目录下所有文件/子目录

dir

退出当前DOS命令窗口

exit

清屏

cls

内容复制

右键 - 标记 - 选中复制内容 - 右键

编译 .Java 文件

javac + .java源文件路径

运行 .class 文件

java + .class文件路径(只写文件名,不写后缀)

JDK 环境变量配置


在系统变量中增加 JAVA_HOME 赋值 C:\Program Files\Java\jdk1.8.0_202 JDK路径

Path 中增加 %JAVA_HOME%\bin

(选择性配置)CLASSPATH 赋值为 . 代表当前路径(与不配置效果一样) — 寻找 .class 文件路径

Java 基础


Java 三大模块

Java SE(Java标准版)

Java EE(Java企业版)

JavaME(Java微型版)

Java 术语

JDK : Java 开发工具包

JRE : Java 运行时环境(包括 JVM )

JVM : Java 虚拟机

OOA :面向对象的分析

OOD:面向对象的设计

OOP:面向对象的编程

GC:垃圾回收(机制)

IDE:集成开发环境

API:应用程序编程接口

cache:池,缓存机制

OCP:开闭原则,对扩展开放,对修改关闭

Java 注释写法

//	单行注释
/*
	多行注释
*/
/**
*	javadoc 注释
*	会被 javadoc.exe 解析提取并生成帮助文档
*/

Java 标识符规则与规范

  1. 只能由字母、数字、下划线_、美元符号$构成,不能以数字开头

  2. 严格区分大小写

  3. 不能使用关键字


遵循驼峰命名方式

  • 类名、接口名:首字母大写
  • 变量名、方法名**(动词)**:首字母小写
  • 常量名:全部大写

Java 编码方式

Java 语言源代码采用 Unicode 编码,支持中文(UTF-8 居多)

'0' - 48 'a' = 65 'A' = 97

Java 变量的分类

按声明位置分类

  • 成员变量:类变量 [ 实例变量、静态变量 ](属性)

  • 局部变量:方法体变量

按数据类型分类

  1. 基本数据类型

    • 整数型:byte(1)、short(2)、int(4)、long(8 L默认值0

    • 浮点型:float(4 F)、double(8)默认值0.0

    • 布尔型:boolean(1)默认值false

    • 字符型:char(2)默认值\u0000

    byte < short = char < int < long < float < double

  2. 引用数据类型

    • 字符串:String、Class 默认值null

Java 变量类型转换

  1. 大类型转小类型,强制类型转换,高位截掉(损失精度)
  2. 整数型超过原容量上限,就要进行强制类型转换

Java 进制

  1. 十进制:默认
  2. 八进制:以 0 开头
  3. 十六进制:以 0x 开头

Java 运算符注意点

  1. 逻辑运算符

不存在短路:&|!^ (异或,不同为真)

存在短路:&&||

  1. 计算运算符
byte i = 10;
i += 5;			//等价于 i = (byte)(i + 5)
i = i + 5		//等价于 i = i + 5	错误,i + 5 结果为 int 型

Java 中级


JVM 内存划分三块主要区域

最先有数据的是方法区内存、变化最频繁的是栈内存、垃圾回收(GC)机制针对堆内存

方法区内存

基础知识

  • 只能有一个方法区内存

存储内容

  • .class方法片段
  • 静态变量(类加载就开辟内存)

堆内存

基础知识

  • 只能有一个堆内存
  • Java 中没有指针,不可以直接操作堆内存,只能通过引用操作

存储内容

  • 引用数据类型 new 的**(实例对象、数组)**
  • 字符串常量池:存储字符串(JDK7从方法区移到堆内)

栈内存 (stack)

基础知识

  1. 一个线程一个栈内存
  2. 栈帧永远指向栈顶元素
  3. 栈顶元素处于活跃状态,其他元素静止
  4. 术语:
    • 压栈 / 入栈:push
    • 弹栈 / 出栈:pop
  5. 栈的存储结构特点
    • 先进后出、后进先出

存储内容

  • 执行中的方法、局部变量

面向对象的三大特征

类、对象、引用

类 — [ 实例化 ] — 对象(实例 instance)

对象 — [ 抽象 ] — 类

引用 — [ 保存 ] — 对象的地址

封装

访问类内属性不可以直接读写,通过get/set方法进行读写 (privet)

eclipse 中 右键 — Source — Generate Gerrers and Setters

继承

  • 基本语法

    [修饰符列表] class 类名 extends 父类名{ 
      //继承类
    }
    
  • Java 仅支持单继承,但是可以间接继承,默认继承 java.lang.Object

    1. 私有的不支持继承

    2. 构造方法不支持继承,调用 super() 调用父类构造方法

多态

上转型 / 下转型

  1. 上转型:子类型 — 父类型

    编译期参考父类型方法,执行期参考子类型方法

    继承中,多个子类型调用同一个父类型方法,即可传参子类型,方法接参父类型

    1. 下转型:父类型 — 子类型

    子类型转父类型,可再转回原子类型,但不可以转换为其他子类型 异常:java.lang.ClassCastException

    使用 instanceof 运算符避免异常 语法:引用 instanceod 类型名 返回 true(类型正确) / false(类型错误)

Java 数组相关知识

Array 的内存分配

数组为引用型数据,实际元素存储在内存堆中,引用存储在内存栈中

Array 优缺点

优:查询效率高

  • 内存空间地址是连续的,每一个元素类型相同,占用空间大小相同
  • 通过下标可以直接计算某个下标元素的内存地址

**缺:增删元素效率低:**元素位移

**缺:不适合存储大数据量:**内存空间很难存在特别大的连续内存空间

Array 的方法与属性

int[] a = {3,2,5,6,1,4}
a.length;	  	 //获取元素个数,输出 5
Arrays.sort(a); //排序数组

Array 扩容

当数组元素不足时,创建一个大数组,将小数组元素拷贝到大数组

拷贝方法:System.arraycopy(原数组, 原起始下标, 新数组, 新起始下标, 拷贝长度)

main 主方法 String[] args 作用

用于预留运行时传参,如DOS中 java .class文件名 参数1 参数2 参数3...

引用数组上/下转型

class test{
    public static void main(String[] args){
       A a_class = new a[new B(),new C()];
       for(int i = 0; i < a_class.length; i++){
         a_class[i].a();		//上转型
         /* 输出结果:
        子类B
        子类C */
       }
       for(int i = 0; i < a_class.length; i++){
         if(a_class instanceof B){		//下转型
           B b_class = (B)a_class[i];
           b_class.otherB();
         }else if(a_class instanceof C){
           C c_class = (C)a_class[i];
           c_class.otherC();
         }
         /* 输出结果:
      	子类其他方法B
      	子类其他方法C */
       }
    }
}
class A{
    public void a(){
       System.out.println("父类A");
    }
}
class B extends A{
    public void a(){
       System.out.println("子类B");
    }
    public void otherB(){
       System.out.println("子类其他方法B");
    }
}
class C extends A{
    public void a(){
       System.out.println("子类C");
    }
    public void otherC(){
       System.out.println("子类其他方法C");
    }
}

Java 方法相关知识

Java 方法的内存分配

  1. 方法只有在调用时,才会动态给方法分配内存空间
  2. 方法代码片段属于.class字节码的一部分,字节码文件在类加载的时候载入到方法区内存中,每次调用方法在栈内存中分配独立空间。
  3. 调用方法压栈,方法结束出栈

Java 构造方法

  1. 构造方法写法

    public class 类名 {
      public 类名(){
        //构造方法
        //eclipse 中 右键 — Source — Generate Constructor using Fields
      }
    }
    
  2. 直接调用构造方法 this()

Java 方法的重载(overload)

  1. 重载指同一类内方法重名
  2. 重载要求参数列表不同,其余必须完全一致

Java 方法的重写 / 覆盖(override)

  1. 重写指继承类方法重名
  2. 重写要求所有信息必须完全一致
  3. 重写方法访问权限不能更低,只能更高
  4. 抛出异常不能更过,只能更少

Java 方法的递归

递归必须有结束条件,否则必定会栈溢出,即便有条件也可能存在栈溢出

Java 静态方法(静态代码块)

Java 静态方法内不可以调用实例变量与方法(未被 static 修饰),不存在 this,需要实例化才可以调用

Java 方法代码块

静态代码块

public class 类名 {
    static{
       //类加载时刻执行
    }
}

实例代码块

public class 类名 {
    {
       //类实例时刻执行
    }
}

Java 修饰符相关知识

public static final 常量

public static final String 全部大写名字 =

final 修饰符

  • 修饰的类无法被继承
  • 修饰的方法无法被覆盖(重写)
  • 修饰的变量赋值后无法改变
  • 修饰的实例变量必须声明时赋值(或构造体)且不可改变
  • 修饰的引用赋值后无法改变,且无法被垃圾回收器回收

访问控制修饰符

修饰符名 使用权限
public 表示公开的,在任何位置都可以访问
protected 表示受保护的,同包、子类可以访问
default(缺省) 在同包可以访问
private 表示私有的,只能在本类中访问

类只能使用 public 与 default 修饰

Java 抽象类与接口

Java 抽象类

  • 基本语法

    [修饰符列表] abstract class 类名{
      // 继承抽象类 extends
      /*
        1. 抽象类无法被实例化
        2. final 与 abstract 不能联合使用,关键词是对立的
        3. 抽象类可以继承抽象类(实现接口)
        4. 抽象类有构造方法,供子类使用
        5. 抽象类不一定存在抽象方法,但有抽象方法一定在抽象类中
        6. 非抽象子类必须实现所有抽象方法,抽象子类可以不用写抽象方法
      */
      public abstract void 方法名();  //抽象方法
    }
    
  • 面试题:Java 语言中没有方法体的方法都是抽象方法(×)
    还存在 C++ 底层 native 等,表示调用 JVM 本地程序。

Java 接口

  • 基础语法

    [修饰符列表] interface 接口名{
      // 实现接口 implements (高扩展性,低耦合)
      /*
      	1. 接口是完全抽象的,抽象类是半抽象。接口是特殊的抽象类
      	2. 接口内部全部为抽象方法,public abstract 可以省略,常量 public static final 可以省略
      	3. 接口内部只能定义常亮、抽象方法
      */
      public abstract void 方法名();  //抽象方法
    }
    

Java 抽象类与接口

  • 基础语法

    class 类名 extends 父类 implements 接口1,接口2 {
      //类与接口没有继承关系,java 语法也允许上下转型
    }
    

Java 内部类

静态、实例、局部、匿名内部类

class Test{
  static class inner1{	//静态内部类
  }
  class inner2{		//实例内部类
  }
  public void test(){
    class inner3{		//局部内部类
    }
  }
  public static void main(String[] args){
    myMath m = new myMath();
    m.mysum(new math(){		//匿名内部类,直接实现接口
      public int sum(int a,int b){
        return a+b;
      }
    }, 200, 300);
  }
}

interface math{
  int sum(int a, int b);
}
class myMath{
  public void mysum(math c,int a,int b){
    return c.sum(a,b);
  }
}

Java 枚举类型

使用方法

public static void main(String[] args){
     Result re = a(9);		//Result.SUCCESS
     Result re = a(50);  //Result.FAIL
     Result re = a(99);	//Result.ON
}
public a(int x){
     if(x<10){
       return Result.SUCCESS
     }else if(x < 90){
       return Result.FAIL
     }else{
       return Result.ON
     }
}
enum Result{
     SUCCESS,FAIL,ON
}

Java 高级


类加载器

  1. 专门负责加载类的命令 / 工具(classloader)
  2. 类加载过程:加载 — 验证 — 准备 — 解析
  3. 三个类加载器(以此执行,全部找到不执行,双亲委派机制保障安全)
    • 启动类加载器:\jre\lib\rt.jarJDK核心类库
    • 扩展类加载器:\jre\lib\ext\*.jar扩展类
    • 应用类加载器:classpath

可变长度参数

类型... 数组名

  1. 可变长度个数0~N个
  2. 可变长度参数只能有一个,放在参数最后位置
  3. 可变长度参数当做一个数组看待

异常

异常分类

错误:Error 直接子类(发生错误,不可以处理,中止程序执行)

运行时异常(受检异常):Exception — RuntimeException 直接子类(在编写代码可以选择不处理)

编译时异常(非受检异常):Exception 直接子类(在编写代码必须处理)

Object
Throwable
Error
Exception
直接子类
RuntimeException
直接子类

异常处理方式

  • 在方法声明,使用 throws 关键字,抛给上一级
public class ExceptionTest{
    public static void main(String[] args){
       doSome();					//可能抛出异常但是未处理,报错(编译时异常)
    }
  
    /*public static void main(String[] args) throws ClassNotFoundException{
    doSome();					//解决办法,抛给JVM,程序终止
  }*/
  
    //ClassNotFoundException 未找到类异常,属于编译时异常
    public static void doSome() throws ClassNotFoundException{
       //若存在异常抛给上一级
    }
}
  • 使用 try…catch 语句进行异常捕捉
public class ExceptionTest{
    public static void main(String[] args){
       try{
         doSome();					//捕捉异常
       } catch(ClassNotFoundException e){
         e.printStackTrace();
       } catch(Exception e){
         // catch 拦截异常必须从小到大
       }
    }
    //ClassNotFoundException 未找到类异常,属于编译时异常
    public static void doSome() throws ClassNotFoundException{
       //若存在异常抛给上一级
    }
}

获取异常信息两个方法

public class ExceptionTest{
    public static void main(String[] args){
       NullPointerException e = new NullPointerException("空指针异常");
       String msg = e.getMessage();			//空指针异常,获取异常简单描述
       System.out.println(msg);
   
       e.printStackTrace();		//输出追踪信息(红字)打印异常堆栈信息,采用异步线程
    }
}

finally

try{
    return;		//即使有 return finally 也会执行
    System.exit(0);		//此时 finally 不执行
}catch{
}finally{
    //除了exit,代码一定执行
}

自定义异常

public class MyException extends Exception{		//自定义编译时异常
    public MyException(){};
    public MyException(String s){
       super(s);
    };
}
public class MyException extends RuntimeException{		//自定义运行是异常
    public MyException(){};
    public MyException(String s){
       super(s);
    };
}
public static void th() throws MyException{
    throw new MyException("手动抛出自定义异常")		//抛出自定义异常
}
public static void main(String[] args){
    try{							//捕捉自定义异常
       th();
    }catch{
       System.out.println(e.getMessage());		//抛出异常信息
    }
}

面试题

public int m(){			//返回结果100
    int i = 100;
    try{
       return i;
    }finally{
       i++;					//一定执行
    }
}
//反编译结果
public int m(){			//返回结果100
    int i = 100;
    int j = i;
    i++;
    return j;
}

集合

概念

  • java.util.* 所有集合与集合接口都在包下
  • 集合是一个容器,是一个载体,可以一次容纳多个对象
  • 集合不能直接存储基本数据类型,不能直接存储 java 对象,存储的是引用(内存地址)

集合的两大类

单个方式存储元素

  • 超级父接口:java.util.Collection
  • JavaSE 知识点梳理学习笔记【精华版】_第1张图片

键值对方式存储元素

  • 超级父接口:java.util.Map
  • JavaSE 知识点梳理学习笔记【精华版】_第2张图片

泛型

概念与构造方法

  1. 使用泛型后,List集合只允许存储对应引用数据类型数据,用泛型指定存储数据类型

    List<Integer> myList = new ArrayList<Integer>();
    Iterator<Integer> li = myList.iterator();		//泛型迭代器声明
    
  2. **优点:**统一存储元素数据类型,不需要大量下转型

  3. **缺点:**导致存储元素缺少多样性

自动类型推断机制

List<Integer> myList = new ArrayList<>();		//自动类型推断(钻石表达式)

自定义泛型

class MyIterator<T>{		//<>内部为标识符可以随意些,一般为E(element)和T(type)
    public T get(){
       return null;
    }
    public static void main(){
       MyIterator<Integer> it = new MyIterator<>();
       String s1 = it.get();			//泛型指定为Integer类型,可以调用泛型内部方法
    }
}

增强 for 的使用

基本语法

int[] arr = {100,200,300}
for(int i : arr){			//没有下标
    System.out.println(i);
}

集合使用

List<String> myList = new ArrayList<>();
myList.add("www");
myList.add("baidu");
myList.add("com");
for(String s : myList){
    System.out.println(s);
}

Collection(接口)

没有使用"泛型"可以存储Object所有子类型,使用"泛型"只能存储具体的类型

常用方法

  • boolean add(Object e)

    Collection c = new ArrayList();
    c.add(1230);			//增加元素
    c.add(new Object);
    c.add(true);
    
  • int size()

    c.size();				//返回集合中元素个数 3
    
  • void clear()

    c.clear();			//清空元素集合
    
  • boolean contains(Object e)

    c.add(123);
    c.contains(333);		//false
    
    //集合内部存储的是内存地址
    String s1 = new String("赵宗泽");
    c.add(s1);
    String s2 = new String("赵宗泽");
    c.contains(s2);		//本身不包含s2,但内部调用equals(重写过)方法,比较内容 结果为true
    
  • boolean remove(Object e)

    c.remove(123);		//移除元素
    
    //集合内部存储的是内存地址
    String s1 = new String("赵宗泽");
    c.add(s1);
    String s2 = new String("赵宗泽");
    c.remove(s2);		//重写equals两者都删除,不重写equals则删除s2
    
  • boolean isEmpty()

    c.isEmpty();		//true 判断是否为空
    
  • Object[] toArray()

    c.add(123);
    c.add(true);
    c.add(5.2);
    Object[] objs = c.toArray();		//{123,true,5.2}
    

Iterator(迭代器)

以下方式是 Collection 通用方式,Map 集合不可以使用

集合结构(包括增删元素)发生改变,迭代器必须重新获取,否则会报异常

获取迭代对象,相当于获取当前集合快照,所以改变会报异常

构造方法
Collection c = new ArrayList();
c.add(1230);			//增加元素
c.add(new Object);
c.add(true);

Iterator it = new Iterator();		//取得集合迭代器
迭代 / 遍历元素
boolean hasNext = it.hasNext();		//判断时候还有元素可以迭代
Object obj = it.next();		//取到指向元素

while(it.hasNext()){			//循环取出所有元素
    Sytem.out.println(it.next());
}
删除元素(迭代器)
it.remove();			//利用迭代器删除当前指向元素(迭代器不会报异常)

List(接口)

List 有下标可重复

常用方法

  • void add(int index,E element)

    List myList = new LinkedList();
    myList.add('a');		//下标从0开始
    myList.add('b');
    myList.add('c');
    myList.add(1,'d');
    myList.add('b');
    myList.add('f');	//{'a','d','b','c','b','f'}
    
  • void remove(int index)

    myList.remove(5);	//{'a','d','b','c','b'}
    
  • E get(int index)

    Object obj = myList.add(2);		//'b'
    
  • E set(int index,E element)

    myList.set(3,"c2");	//{'a','d','b','c2','b'}
    
  • int indexOf(Object o)

    int i =myList.indexOf('b');		//2
    
  • int lastIndexOf(Object o)

    int i =myList.lastIndexOf('b');		//4
    

ArrayList

  1. 默认容量为0,点击第一个元素初始化容量10,底层为Object[],可以指定初始化容量长度
  2. 容量不足扩容1.5倍,减少扩容
  3. 向数组末尾添加元素效率很高,最常用为ArrayList,检索操作更多。

构造方法

List l1 = new ArrayList();			//默认长度为0,添加第一个元素初始化容量为10
List l2 = new ArrayList(100);		//设置长度初始化

Collection c = new HashSet();
c.add(100);
c.add(200);
List l3 = new ArrayList(c);			//传出Collection类型初始化元素

LinkedList

LinkedList同样有下标,但是检索查找效率较低,因为内存地址不连续

Vector

  1. 默认容量为10,容量不足扩容2倍

  2. 不安全线程 ArrayList 转为安全线程,使用 java.util.collections 集合工具类

    List myList = new ArrayList();		//线程是不安全的
    Collections.synchronizedList(myLsit);		//变成线程安全的
    myList.add(1);
    myList.add(2);
    myList.add(3);
    

Map(接口)

常用方法

  • V put(K key, V value)

    Map<Integer, String> map = new HashMap<>();
    map.put(1,"zzz");				//添加键值对
    map.put(2,"ccc");
    map.put(3,"aaa");
    
  • V get(Object key)

    String a = map.get(2);		//"ccc" 通过key获取value
    
  • void clear()

    map.clear();				 //清空Map集合
    
  • boolean containsKey(Object key)

    //注意:contains方法内部调用equals进行比对,自定义类型重写equals方法
    map.containsKey(2); 			//判断Map中是否包含key,返回true与false
    
  • boolean containsValue(Object value)

    map.containsValue("ccc"); 		//判断Map中是否包含value,返回true与false
    
  • boolean isEmpty()

    map.isEmpty();			 //判断Map元素个数是否为0,返回true与false
    
  • V remove(Object key)

    map.remove(2);			//通过key删除键值对
    
  • int size()

    int a = map.size();		//获取Map集合中键值对数量
    
  • Set keySet()

    //获取Map集合所有的key,返回一个Set
    Set<Integer> keys = map.keySet();
    
  • Collection values()

    //获取Map集合中所以的value,返回一个Collection
    Collection<String> values = map.values();
    
  • Set> entrySet()

    //将Map集合转换为成Set集合,Map.Entry是Map中的静态内部类
    Set<Map.Entry<Integer,String>> set = map.entrySet();
    //遍历Map
    Iterator<Map.Entry<Integer,String>> it = set.iterator;
    while(it.hasNext()){
      Map.Entry<Integer,String> node = it.next();
      Integer key = node.getKey();			//Entry自带方法,适合大数据量
      String value = node.getValue();
    }
    

HashMap

  1. 无序(存放链表不定)不可重复(value覆盖)
  2. HashMap集合的key会调用两个方法,一个hasCode(),一个equals(),两个方法都要重写
  3. hasCode设定为同一个值,则形成单链表,称为散列分布不均匀;hasCode设定为不同值,则形成一维数组,也称为散列分布不均匀;保证hasCode值得到每一个下标的概率相同,称为散列分布均匀
  4. HashMap默认初始容量为16(必须是2的倍数,可以达到散列分布均匀,提高存储效率),默认加载因子为0.75(数组容量达到75%,数组扩容),扩容为原来的2倍
  5. HashMap允许key和value为null(Hashtable的key与value不可以为null,报异常)
  • equals方法重写,hasCode方法一定也要重写,且当equals为true,hasCode一定为true
  • 两个方法重写利用IDE直接生成

哈希表 / 散列表

哈希表是数组与单链表的结合体,发挥各自的优点

源代码

public class HashMap{
    //HashMap 底层是一位数组
    Node<K,V>[] table;
    //静态内部类 HashMap.Node
    static class Node<K,V>{
       final int hash;	//哈希值,通过 key 的 hasCode() 方法结果,hash值通过哈希函数/算法,可以转换成数组的下标
       final K key;//存储到Map集合中的key
       V value;//存储到Map集合中的value
       Node<K,V> next;//下一个节点的地址
    }
}

map.put 实现原理

  1. 将k,v封装到node对象中
  2. 底层调用k的hasCode()方法得出hash值,通过哈希算法,将hash值转换为数组下标
  3. 若下标无元素直接将Node添加到该位置,如下标存在链表,则用k与链表中每一个节点进行equals比较,如果无相同k节点,则插入到尾部,如存在相同k,则覆盖v值
  • 数组下标如果为null,不需要执行equals

map.get 实现原理

  1. 调用k的hasCode()方法得出hash值,通过hash算法转换为数组下标
  2. 如果数组下标无元素,返回null,如果下标存在链表,则用k与链表中每一个节点进行equals比较,如果无相同节点,返回null,如有相同节点,返回该节点v值
  • 数组下标只有一个元素,不需要执行equals

JDK8改进

如果哈希表单链表节点超过8个,将单链表转换为红黑树数据结构;当红黑树上节点小于6个,将红黑树转换为单链表数据结构。

Hashtable

  1. HashMap默认初始容量为11,默认加载因子为0.75(数组容量达到75%,数组扩容),扩容为原来的2倍+1
  2. Hashtable的key与value不可以为null,报异常(HashMap允许key和value为null)

Properties

  1. Properties是一个Map集合,key与value都是String类型,被称为属性类对象

常用方法

  • setProperty

    Properties pro = new Properties();
    pro.setProperty("url","ww.baidu.com");		//写键值对
    pro.setProperty("name","zzz");
    
  • getProperty

    String s = pro.getProperty("url");			//读键值对
    

TreeSet

  1. TreeSet集合底层是一个TreeMap,TreeMap底层集合是一个二叉树
  2. TreeSet集合中的元素,等同于放在TreeMap集合的key部分
  3. 二叉树采用中序排列

构造方法

TreeSet<String> ts = new TreeSet<>();
ts.add("wang");
ts.add("zhang");
ts.add("ayu");		//{"ayu","wang","zhuang"}	自动排序

自定义类排序

  1. Comparable是java.lang包下的,Comparator是java.util包下的
  2. 当规则不发生变化且只有一个的时候,建议实现Comparable接口;当比较规则有多个且切换比较频繁,建议使用Comparator接口
  3. Comparator 接口设计符合而OCP原则
  • 自定义类如何排序(方法一)

    class 类名 implements Comparable<比较类名>{
      int age;
      //接收参数 > 自身 返回正数为倒叙
      public int conpareTo(类名 o){		//实现接口方法
        if(this.age == o){
          return 0;						//相等返回0
        }else if(this.age > o){
          return 1;						//返回正数
        }else if(this.age < o){
          return -1;					//返回负数
        }
      }
    }
    
  • 自定义类如何排序(方法二)

    //比较器实现Comparator接口
    public class test{
      public static void main(String[] args){
        TreeSet<类名> ts = new TreeSet<>(new 类名比较器());		//构造器传参
      }
    }
    class 类名 implements Comparable<比较类名>{
      int age;
    }
    
    class 类名比较器 implemenets Comparator<比较类名>{		//比较器
      public int conpare(类名 o1, 类名 o2){
        if(o1 == o2){
          return 0;
        }else if(o1 > o2){
          return 1;
        }else if(o1 < o2){
          return -1;
        }
      }
    }
    

Collections(集合工具类)

常用方法

  • synchronizedList

    //将不安全线程变为安全线程
    List<String> list = new ArrayList<>();
    Collections.synchronizedList(list);
    
  • sort

    //元素排序(自定义类要实现Comparable接口)
    list.add("abc");
    list.add("adc");
    list.add("ebc");
    Collections.sort(list);
    
    //元素排序,传递比较器
    Collections.sort(List, 比较器);
    
    //对Set集合进行排序
    Set<String> set = new HashSet<>();
    set.add("abc");
    set.add("accc");
    set.add("eec");
    List<String> list = new ArrayList<>(set);		//将Set转化为List进行排序
    Collections.sort(list);
    

IO流

  1. java中所有流在java.io.*
  2. 所有流都实现了java.io.Closeable接口,都有close()方法,每次使用完关闭,不关闭会占用很多资源。
  3. 所有输出流都实现了java.io.Flushable接口,都有flush()方法,每次输出完刷新,将未输出完的剩余数据强行输出,管道清空。

分类

  1. 按照流的方向分类

    • 输入流:(读)InputStream
    • 输出流:(写)OutputStream
  2. 按照读取数据方式分类

    • 字节流:按照字节的方式读取数据,一次读取1字节byte,万能流什么文件都可以读取

      抽象类:java.io.InputStream 字节输入流、java.io.OutputStream字节输出流,以Stream结尾

    • 字符流:按照字符的方式读取数据,一次读取一个字符,只能读取普通文本文件(不包括word)

      抽象类:java.io.Reader字符输入流、java.io.Writer字符输出流,以Reader / Writer结尾

16个掌握的流

//文件专属
java.io.FileInputStream			//字节
java.io.FileOutputStream
java.io.FileReader					//字符
java.io.FileWriter
//转换流(字节流转换成字符流)
java.io.InputStreamReader
java.io.OutputStreamWriter
//缓冲流专属
java.io.BufferedReader			//自带缓冲区的数据流,不需要数组
java.io.BufferedWriter
java.io.BufferedInputStream
java.io.BufferedOutputStream
//数据流专属
java.io.DataInputStream		//写入数据与类型,文本文档打不开
java.io.DataOutputStream
//标准输出流
java.io.printWriter
java.io.printStream				//默认输出控制台
//对象流专属
java.io.ObjectInputStream		//反序列化 DeSerialize  文件恢复成java对象
java.io.ObjectOutputStream	//序列化	Serialize  java对象存储到文件

java.io.FileInputStream

public class FileInputStream{
    public static void main(String[] args){
       FileInputStream fis = null;
       try{
      //_创建流
         fis = new FileInputStream(路径);
      //_循环方法一
         int readData = 0;
         while((readData = fis.read()) != -1 ){
           System.out.println(readData);
         }
      //_循环方法二
         int readData = 0;
         byte[] bytes = new byte[4];
         while((readData = fis.read(bytes)) != -1){
           System.out.println(new String(bytes,0,readData));
         }
   
      //_构造方法一  
         int readData = fis.read(); 				//返回读到字节本身,失败返回-1
      //_构造方法二
         byte[] bytes = new byte[4];
         //如若剩余2字节,会覆盖01下标,23下标属于为上次数据
         int readData = fis.read(bytes);		//返回读到几个字节,失败返回-1

      //_转换读取内容
         new String(bytes,0,readData);		//字节数组指定位置转为字符串
      //_返回流中剩余的字节数量
         fis.available();
         byte[] bytes = new byte[fis.available()];	//可用于一次性读取(不适合大文件)
      //_跳过字节不读取
         fis.skip(3);
   
       }catch(FileNotFoundException e){		//此为创建流异常
         e.printStackTrace();
       }catch(IOException e){						//此为read异常
         e.printStackTrace();
       }finally{													//finally内部关闭流
         if(fis != null){							   //判断流是否为null
           try{
             fis.close();								//此为关闭流异常
           }catch(IOException e){
             e.printStackTrace();
           }
         }
       }
    }
}

java.io.FileOutputStream

public class FileOutputStream{
    public static void main(String[] args){
       FileOutputStream fos = null;
       try{
      //_创建流,文件不存在自动创建
         fos = new FileOutputStream(路径, true);		//true为末尾添加,false为覆盖
      //_写数据
         byte[] bytes = {97,98,99,100};
         fos.write(bytes);				//全部输出
         fos.write(bytes,0,2);		//输出一部分
      //_刷新
         fos.flush();
       }catch(FileNotFoundException e){		//此为创建流异常
         e.printStackTrace();
       }catch(IOException e){						//此为read异常
         e.printStackTrace();
       }finally{													//finally内部关闭流
         if(fos != null){							   //判断流是否为null
           try{
             fos.close();								//此为关闭流异常
           }catch(IOException e){
             e.printStackTrace();
           }
         }
       }
    }
}

文件拷贝(所有)

  1. 使用 FileInputStream + FileOutputStream 完成文件拷贝
  2. 拷贝过程一边读一边写,什么文件都可以拷贝
public class FileOutputStream{
  public static void main(String[] args){
    FileInputStream fis = null;
    FileOutputStream fis = null;
    try{
      fis = new FileInputStream(路径);
      fos = new FileOutputStream(路径, true);
//一边读一边写
      byte[] bytes = new byte[1024*1024]	//一次拷贝1MB
      int readCount = 0;
      while((readCount = fis.read(bytes)) != -1){
        fos.write(bytes,0,readCount);
      }

      fos.flush();
    }catch(FileNotFoundException e){
      e.printStackTrace();
    }catch(IOException e){
      e.printStackTrace();
    }finally{
      if(fis != null){			//分开try,避免其中一个出现异常,另一个无法关闭
        try{
          fis.close();
        }catch(IOException e){
          e.printStackTrace();
        }
      }
      if(fos != null){
        try{
          fos.close();
        }catch(IOException e){
          e.printStackTrace();
        }
      }
    }
  }
}

java.io.FileReader

FileReader reader = null;
try{
    reader = new FileReader(路径);

    int readData = 0;
    char[] chars = new char[4];			//把byte数组编程char数组即可
    while((readData = fis.read(chars)) != -1){
       System.out.println(new String(chars,0,readData));
    }
}

java.io.FileWriter

FileWrite write = null;
try{
    write = new FileWrite(路径, true);		

    char[] chars = {'我','中','国','人'};			//把byte数组编程char数组,且可写字符
    write.write(chars);
    write.write(chars,0,2);

    write.flush();
}

文本拷贝(文本)

  1. 使用 FileReader + FileWriter 完成文件拷贝
  2. 拷贝过程一边读一边写,只能拷贝普通文本
FileReader reader = null;
FileWrite write = null;
try{
  reader = new FileReader(路径);
  write = new FileWrite(路径, true);		

  int readData = 0;
  char[] chars = new char[1024*512];	//一次拷贝1MB
  while((readData = fis.read(chars)) != -1){
    write.write(chars,0,readData);
  }

  write.flush();
}

java.io.BufferedReader / InputStreamReader

public class BufferedReader{
     public static void main(String[] args) throws Exception{
       /*当一个流的构造方法中需要一个流的时
    被传进去叫:节点流;外部负责包装的流叫:包装流(处理流)
    FileReader是节点流,BufferedReader是包装流*/
       //_字节流传入
       FileReader reader = new FileReader(路径);
       BufferedReader br = new BufferedReader(reader);		//传入字符流,不能传字节流
       //_字符流传入
       FileInputStream in = new FileInputStream(路径);
       //_转换流
       InputStreamReader reader = new InputStreamReader(in);		//将字节流转为字符流
       BufferedReader br = new BufferedReader(reader);
 
       //_循环读取一行
       String s = null;
       while((s = br.readLine()) != null){
         System.out.println(s);
       }
   
       //_读一行    
       br.readLine();		//读取失败返回null
   
       //包装流关闭,节点流自动关闭
       br.close();
     }
}

java.io.BufferedWriter / OutputStreamWriter

public class BufferedWriter{
     public static void main(String[] args) throws Exception{
       //_字节流传入
       FileWriter writer = new FileWriter(路径);
       BufferedWriter out = new BufferedWriter(writer);		//传入字符流,不能传字节流
       //_字符流传入
       FileOutputStream ou = new FileOutputStream(路径);
       //_转换流
       OutputStreamWriter writer = new OutputStreamWriter(ou);		//将字节流转为字符流
       BufferedWriter out = new BufferedWriter(writer);

       out.write();

       out.flush();
       out.close();
     }
}

java.io.DataOutputStream

public class DataOutputStream{
     public static void main(String[] args) throws Exception{
       DataOutputStream dos = new DataOutputStream(new FileOutputStream(路径));

       byte b = 100;				//写入数据与数据类型
       int i = 50;
       boolean bo = false;
       char c = 'a';
       dos.writeByte(b);
       dos.writeInt(i);
       dos.writeBoolean(bo);
       dos.writeChar(c);
   
       dos.flush();
       dos.close();
     }
}

java.io.DataInputStream

public class DataInputStream{
     public static void main(String[] args) throws Exception{
       DataInputStream dis = new DataInputStream(new FileInputStream(路径));

       //读取与写入顺序要相同
       byte b = dis.readByte;				//写入数据与数据类型
       int i = dis.readInt;
       boolean bo = dis.readBoolean;
       char c = dis.readChar;
   
       dos.flush();
       dos.close();
     }
}

java.io.printStream

public class printStream{
     public static void main(String[] args) throws Exception{
       //_输出到控制台
       printStream ps = System.out;
       ps.println("Hello world");
       ps.println("Hello java");
       //标准输出流不需要关闭

       //_输出到文件
       printStream ps = new printStream(new FileInputStream(路径));
       System.setOut(ps);
       ps.println("Hello world");
       ps.println("Hello java");
     }
}

日志文件

public class Logger{
     public static void log(String msg){
       try{
         //指向日志文件
         printStream ps = new printStream(new FileInputStream(路径,true));
         //改变输出方向
         Sytem.setOut(ps);
         //获取日期
         Date nowTime = new Date(0);
         SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
         String strTime = sdf.format(nowTime);
   
         System.out.println(strTime + ":" + msg);
       }catch(FileNotFoundException e){
         e.printStackTrace();
       }
     }
}

ObjectOutputStream

public class ObjectOutputStream{
    public static void main(String[] args) throws Exception{
       //创建java对象
       Student o = new Student();
       //序列化
       ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(路径));
       //序列化对象
       oos.writeObject(s);

       //创建集合
       List<Student> st = new Student<>();
       st.add(new Student(1,"xxx"));
       st.add(new Student(2,"zzz"));
       st.add(new Student(3,"www"));
       //序列化集合
       oos.writeObject(st);

       oos.flush();
       oos.close();
    }
}
//序列化对象必须实现接口:Serializable 只是一个标志接口,起标识作用,JVM自动生成序列化版本号
//序列化版本号用于区分不同类,自动生成的序列化版本号存在不可更改代码的缺点,代码修改编译会重新生成,建议手动写序列化版本号。
class Student implements Serializable{
    //java虚拟机先识别类名,当类名一样识别序列号
    private static final long serialVersionUID = -11568497521542368L;
  
    public int no;
    public transient String name;			//transient 关键字,不参加序列化
    public Student(int no,String name){
       this.no = no;
       this.name = name;
    }
}

ObjectInputStream

public class ObjectInputStream{
    public static void main(String[] args) throws Exception{
       //创建java对象
       Student o = new Student();
       //反序列化
       ObjectInputStream ois = new ObjectInputStream(new FileInputStream(路径));
       //反序列化对象
       Object obj = ois.readObject();
   
       //反序列化集合
       List<Student> st = (List<Student>)ois.readObject();
       for(Student s : st){
         //输出s
       }

       oos.close();
    }
}
//序列化对象必须实现接口:Serializable 只是一个标志接口,起标识作用,JVM自动生成序列化版本号
class Student implements Serializable{
  
    private static final long serialVersionUID = -11568497521542368L;
  
    public int no;
    public transient String name;			//transient 关键字,不参加序列化
}

IO 流 + Properties

//写属性配置文件,建议以.properties结尾,Properties专门存属性配置的一个类
public class IoProperties{
    public static void main(String[] args){
       /*文件内容
    username=zzz
    root=xxx
    */
       FileReader reader = new FileReader(路径);		//新建一个输入流
       Properties pro = new Properties();		//新建一个Map集合
       pro.load(reader);		//调用load加载数据到Map,=左边为key,右边为value
       pro.getProperty("username")		//获取username值
    }
}

多线程

进程与线程的区别

  1. 进程
    • 进程是一个应用程序(软件)
    • 内存独立不共享
    • 一个进程可以启动多个线程
  2. 线程
    • 线程是一个进程中执行的场景 / 执行单元
    • 在Java中堆内存和方法区内存共享,栈内存不共享,一个线程一个栈互不干扰。

线程两大分类

  1. 用户线程:main方法

  2. 守护线程(后台线程):立即回收线程,一般是一个死循环,所有用户线程结束,守护线程自动结束。用于数据备份等。

    Thread t = new Thread();
    t.setDaemon(true);		//设置为守护线程,程序结束,自动终止
    t.start();
    

线程调度模型

  1. 抢占式调度模型

    线程优先级比较高,抢到CPU时间片的概率就会高一些,java采用抢占式调度模型

  2. 均分式调度模型

    平局分配CPU时间片,每个线程占有CPU时间片的时间长度一样

多线程并发安全问题

  1. 安全问题存在时机

    • 多线程并发
    • 有共享数据
    • 共享数据有修改行为(局部变量在栈中不共享,不存在线程安全问题)
  2. 解决线程安全问题

    线程排队执行(不能并发),这种机制被称为“同步机制”,会牺牲一部分效率。

    • 尽量使用局部变量代替实例变量和静态变量
    • 必须是实例对象,考虑创建多个对象,实例变量不共享
    • 不能使用局部变量,也不可以创建多个对象,使用synchronized线程同步机制
  3. 专业术语

    • 异步编程模型

      线程互不等待,多线程并发(效率较高)

    • 同步编程模型

      线程发生等待关系,线程排队执行(效率较低)

  4. synchronized

    //线程同步执行
    //锁代码块
    synchronized(多线程共享对象){
      //同步代码块,越小效率越高
    }
    
    public synchronized void 方法名(){
      //同步整个方法体,可能无故扩大同步范围,导致执行效率降低;锁对象只能是this;
    }
    
    public synchronized static void 方法名(){
      //synchronized出现在静态方法上为类锁,占据整个类
    }
    
  5. 安全性类

    • 局部变量推荐StringBuilder,不存在安全性问题,StringBuffer效率比较低
    • ArrayList是非线程安全的,Vector是线程安全的
    • HashMap / HashSet是非线程安全的,Hashtable是线程安全的
  6. 死锁

    • 例:线程a先锁1,再锁2,线程b先锁2,再锁1,造成相互等待
    • synchronized不要嵌套使用,容易造成死锁

实现多线程的方法

  • 方法一:继承java.lang.Thread父类,重写run方法

    public class Thread {
      public static void main(String[] args){
        //main方法属于主线程,在主栈中运行
    
        //创建分支线程
        MyThread myThread = new MyThread();
        /*调用start方法启动一个分支线程,在JVM中开辟一个新的栈空间,启动的线程自动调用run方法,并且run方法在栈底,相当于main方法,run与main平级*/
        myThread.start();	//瞬间结束,启动分支栈就结束,自上而下
        for(int i = 0; i < 1000; i++){
          System.out.println("主线程:"i);
        }
      }
    }
    class MyThread extends Thread{
      public void run(){			//继承Thread类,切重写run方法
        for(int i = 0; i < 1000; i++){
          System.out.println("分支线程:"i);
        }
      }
    }
    
  • 方法二:实现java.lang.Runnable接口,重写run方法

    public class Thread {
      public static void main(String[] args){
        //main方法属于主线程,在主栈中运行
    
        //创建一个可运行的对象
        MyRunnable r = new MyRunnable();
        //将可运行的对象封装成一个线程对象
        Thread t = new Thread(r);
        //启动线程
        t.start();
        for(int i = 0; i < 1000; i++){
          System.out.println("主线程:"i);
        }
      }
    }
    class MyThread implements Runnable{
      public void run(){			//继承Thread类,切重写run方法
        for(int i = 0; i < 1000; i++){
          System.out.println("分支线程:"i);
        }
      }
    }
    
  • 方法三:实现java.util.concurrent.FutureTask接口,重写call方法,可获取线程返回值

    FutureTask task = new FutureTask(new Callable(){
      public Object call() throws Exception{	//等同于run
        //线程执行任务可能存在执行结果
        return null;
      }
    });
    
    Thread t = new Thread(task);
    t.start();
    
    Object obj = task.get();		//获取线程返回值,等待线程结束返回结果,进入阻塞
    

线程的生命周期

JavaSE 知识点梳理学习笔记【精华版】_第3张图片

  • 五大生命周期状态(进入锁池可以理解为阻塞)

获取 / 修改线程名字

//当线程没有设置名字,默认名字为
//Thread-0
//Thread-1
//...
t.setName("名字");
String s= t.getName();

获取当前线程对象

static Thread currentThread();
//获取当前线程
Thread t = Thread.currentThread();

sleep(睡眠)

//static void sleep(long millis) 静态方法,参数为毫秒,使当前线程进入阻塞状态
//在哪调用,休眠哪个线程!!! 对象.sleep();不等同于休眠该对象
try{
    Thread.sleep(1000*5);			//休眠5秒
}catch(InterruptedException e){
    e.printStackTrace();
}

interrupt(唤醒)

t.interrupt();		//中止 t 线程的睡眠(抛出异常进入catch,依靠java的异常处理机制)

stop(强行终止)

t.stop();		//强行终止 t 线程,容易丢失数据,不建议使用

合理终止方式

public class Thread {
    public static void main(String[] args){
       MyRunnable r = new MyRunnable();
       Thread t = new Thread(r);
       t.start();
       r.run = false;		//终止线程
    }
}
class MyThread implements Runnable{
    boolean run = true;			//布尔值标记
    if(run){			//判断布尔终止标记
       public void run(){
         for(int i = 0; i < 1000; i++){
           System.out.println("分支线程:"i);
         }
       }
    }else{
       //终止线程,可以保存数据
       return;
    }
}

常用方法

  • getPriority / setPriority(实例方法)

    /*最低优先级1		Thread.MIN_PRIORITY
    	默认优先级5		Thread.NORM_PRIORITY
    	最高优先级10		Thread.MAX_PRIORITY*/
    int getPriority();			//获取线程优先级
    void setPriority(int newPriority);		//设置线程优先级
    
  • yield (静态方法)

    /*暂停当前执行的线程,执行其他线程
    	不是阻塞方法,从“运行状态”转为“就绪状态”
    */
    static void yield();		//让位方法
    
  • join(实例方法)

    void join();		//合并线程
    
    class MyThread1 extends Thread{
      public void doSome(){
        MyThread2 t = new MyThread();
        t.join();		//当前线程进入阻塞,t 线程执行,直到 t 线程结束,当前线程才开始执行
      }
    }
    class MyThread1 extends Thread{}
    

定时器

java.util.Timer

Timer timer = new Timer(true);		//设置true为守护线程
timer.schedule(定时任务,第一次执行时间,间隔时间);

class 类名 extends TimerTask{		//继承接口
    public void run(){
       //定时任务
    }
}

wait / notify(生产消费者模型)

//wait / notify方法建立在synchronized基础上
Object obj = new Object();
obj.wait();//对象上的当前线程进入无期限的等待状态,并且释放对象的锁,直到调用nodify方法
obj.nodify();	//唤醒对象上等待的线程

反射机制

概念

通过java反射机制可以操作字节码文件(可以读和修改字节码文件)

java.lang.reflect.*

  • java.lang.Class:代表整个字节码,代表一个类。
  • java.lang.reflect.Method:代表字节码中的方法字节码
  • java.lang.reflect.Constructor:代表字节码中的构造方法子字节码
  • java.lang.reflect.Field:代表字节码中的属性字节码

获取类的三种方法

  • 方法一:Class.forName静态方法

    /*1.静态方法
    	2.方法参数是一个字符串
    	3.字符串需要的是一个完整类名
    	4.完整类名必须带包名,java.lang包不能省略*/
    
    //c1代表String.class文件,或者说代表String类型
    Class c1 = Class.forName("java.lang.String");
    
  • 方法二:getClass实例方法

    String s = "abc";
    Class x = s.getClass(); //x代表String.class文件,或者说代表String类型
    
  • 方法三:.class属性

    Class z = String.class; //z代表String.class文件,或者说代表String类型
    

实例化对象

//实例化对象(会调用无参数构造方法与静态代码块[即类加载],若不存在无参构造方法会报异常)
Object obj = c1.newInstance();

获取绝对路径读配置

/*Thread.currentThread() 当前线程对象
	getContextClassLoader() 线程对象方法,获取当前线程类加载器对象
	getResource("") 类加载器对象方法,默认从类的根路径下加载资源
*/

//获取绝对路径读取
String path = Thread.currentThread()
                    .getContextClassLoader()
                    .getResource("根路径相对路径")
                    .getpath();
FileReader reader = new FileReader(path);
//以流的方式读取
InputStream reader = Thread.currentThread()
                    .getContextClassLoader()
                    .getResourceAsStream("根路径相对路径");
//读取内容
Properties pro = new Properties();
pro.load(reader);
reader.close();

资源绑定器(IO+Properties)

java.util包下提供一个资源绑定器,便于获取属性配置文件,调用绑定器,属性配置文件xxx.properties必须放在类的路径下(包含子目录,相对路径)

ResourceBundle bundle = ResourceBundle.get("配置名不带后缀,在类路径下");
String className = bundle.getString("key值");

Field 属性

public class S{
  public int no;
  protected float f;
  boolean i;
  private char sex;
}
public class Field{
  public static void main(String[] args) throws Exception{
    Class s = Class.forName("S");
    s.getName();			//获取完整类名
    s.getSimpleName();//获取简类名(不带包名)

    Field[] fields = s.getFields();		//取出 public 成员变量
    Field[] fields = s.getDeclaredFields();		//取出所有成员变量
    String fn = f[0].getName();	//取属性的名字

    Class ft = f[0].getType();	//取属性的类型
    String ftn = ft.getname();	//取属性的类型名字(带包名)
    String ftn = ft.getSimplename();	//取属性的类型名字(不带包名)

    int i = field.getModifiers();		//返回修饰符编号
    String s = Modifier.toString(i);

    /*—————————————————————————————— 反 编 译 ————————————————————————————*/
    Object obj = s.newInstance();
    Field noField = s.getDeclaredField("no");
    noField.set(obj, 2222);				//给属性赋值
    noField.get(obj);				//获取属性的值
    //若为私有属性,调用打破封装
    noField.setAccessible(true);
  }
}

Method 方法

Class s = Class.forName("S");
//获取所有method方法名
Method[] methods = s.getDeclaredMethods();
for(Method me : methods){
  Modifier.toString(method.getModifiers());	//取修饰符列表
  me.getReturnType().getSimpleName();		//取返回值类型
  me.getName();			//取方法名

  Class[] cl = method.getParameterTypes();		//获取所有参数类型
  for(Class c : cl){
    c.getSimpleName();			//获取参数类型
  }
}

/*—————————————————————————————— 反 编 译 ————————————————————————————*/
Object obj = s.newInstance();
Method me = s.getDeclaredMethod("方法名",类型名.class,...);	//获取方法
Object revalue = me.invoke(obj, 参数1, 参数2,...); //调用方法

Constructor 构造方法

Class s = Class.forName("S");
//获取所有method方法名
Constructor[] cos = s.getDeclaredConstructors();
for(Constructor co : cos){
  Modifier.toString(co.getModifiers());	//取修饰符列表
  co.getSimpleName();			//取构造方法名

  Class[] cl = co.getParameterTypes();		//获取所有参数类型
  for(Class c : cl){
    c.getSimpleName();			//获取参数类型
  }
}

/*—————————————————————————————— 反 编 译 ————————————————————————————*/
Constructor con = s.getDeclaredConstructor(类型名.class,...);	//获取构造方法
Object ob = con.newInstance(参数1, 参数2,...); //调用方法

父类与接口

Class s = Class.forName("java.lang.String");

Class superClass = s.getSuperclass();		//获取父类
superClass.getName();		//获取父类名字

Class[] interfaces = s.getInterfaces();		//获取接口
for(Class in : interfaces){
  in.getName();					//获取接口名字
}

注解

概念

注解类型:Annotation,是一种引用数据类型,会生成.class文件,可以出现在任何上方,注解是给编译器参考的,与运行阶段无关。

元注解:用来标注“注解类型”的“注解”,成为元注解。Tatget Retention

语法格式

[修饰符列表] @interface 注解名{
  //可包含属性,属性名为value时,调用可以省略名字
  //属性类型可以是基本数据类型,String,Class,枚举,数组(数组调用只有1个元素大括号可以省略)
}

JDK自带注解

@Override 只能注解方法,判断是否重写父类方法
@Target 标注注解可以出现哪个类型上
@Retention() 标注注解最总保存的位置
  RetentionPolicy.SOURCE:注解只保留在java源文件中
  RetentionPolicy.CLASS:注解保存在class文件中
  RetentionPolicy.RUNTIME:注解保存在class文件中,并且可以被反射机制读取
@Deprecated 注解表示已过时

反编译注解

Java 常用类库


Object 类库

clone

protected Object clone();		  //负责对象克隆
protected native Object clone() throws CloneNotSupportedException;

hasCode

int hasCode();							 //获取对象哈希值,可以看做内存地址
public native int hasCode();	//源代码

equals (重写)

boolean equals(Boject obj);
//判断两个对象是否相等(对象比较内存地址,建议重写),String 类已重写该方法
public boolean equals(Boject obj) {
    if(obj == null || !(obj instanceof 类型))	//地址为空或类型不同
       return false;
    if(this == obj)		//地址相同为同一元素
       return true;
    if(成员变量比较)
       return true;
    return false;
}

toString(重写)

String toString();
//将对象转换为字符串(建议重写),String 类已重写该方法
public String toString() {
    return 成员变量组合;
}

finalize(重写)

protected void finalize();
// 不需要手动调用,JVM垃圾回收器负责调用,在即将销毁时调用
protected void finalize() throws Throwable {
    System.out.println("即将被销毁");	//当即将被销毁时输出
}

System.gc();		//建议启动垃圾回收器(不一定启动)

Arrays 类库

binarySearch(二分法查找)

Arrays.binarySearch(a,'a');		//二分法查找前先排序,查找数组 a 中元素 'a'

sort

Arrays.sort(a);		//排序数组 a

String 类包

构造方法

//方法一:创造字符串(最常用)
String a = "Hello world";
System.out.println(a);		//结果为 Hello world
//方法二:传入byte数组
byte[] bytes = {97,98,99};
String b = new String(bytes);
System.out.println(b);		//结果为 abc
//方法三:传入byte数组,与起始下标和长度
byte[] bytes = {97,98,99};
String c = new String(bytes,1,2);
System.out.println(c);		//结果为 bc
//方法四:传入char数组
char[] chars = {'赵','宗','泽'};
String d = new String(chars);
System.out.println(d);		//结果为 赵宗泽
//方法五:传入char数组,与起始下标和长度
char[] chars = {'赵','宗','泽'};
String e = new String(chars,1,2);
System.out.println(e);		//结果为 宗泽
//方法五:传入字符串
String f = new String("Hello world");
System.out.println(e);		//结果为 Hello world

charAt(返回索引char值)

char a = "赵宗泽".charAt(1);		//宗

compareTo(比较字典序)

int a = "abc".compareTo("abc");	//0
int a = "aba".compareTo("abc"); //-1
int a = "abc".compareTo("aba"); //1

contains(包含)

"helloworld.java".contains(".java");	//true

endWith / startWith

"test.txt".endWith(".txt");		//true
"test.txt".startWith("te");		//true

equalsIgnoreCase(忽略大小写判断相等)

"aBc".equalsIgnoreCase("abc")		//true

getBytes(转为byte数组)

byte[] bytes = "abcde".getBytes();	//{97,98,99,100,101}

indexOf / lastIndexOf

"abcdecd".indexOf("cd");		//2
"abcdecd".lastIndexOf("cd");		//5

isEmpty

String a = "";
a.isEmpty();		//true
a = null;
a.isEmpty();		//空指针异常

replace

String newString = "www.baidu.com".replace("baidu","bilibili");		//www.bilibili.com

split

String[] a = "1980-10-11".split("-");		//{"1980","10","11"}

substring(切割)

"http://www.baidu.com".substring(7);	//www.baidu.com
"http://www.baidu.com".substring(7,10);	//www(左闭右开)

toCharArray

char[] chars = "赵宗泽".toCharArray();		//{'赵','宗','泽'}

toLowerCase / toUpperCase

"AbcdEFGh".toLowerCase();		//abcdefgh
"AbcdEFGh".toUpperCase();		//ABCDEFGH

trim

"    我是 中 国 人 ".trim()		//我是 中 国 人

valueOf

//String 中唯一的静态方法
String.valueOf(true);		//"true"
String.valueOf(new Object());		//没重写toString()方法之前返回对象内存地址

面试题

  • 判断数组长度是 length 属性,判断字符串长度是 length() 方法

StringBuffer / StringBuilder 类库

区别

StringBuffer中的方法都:synchronized关键字修饰,表示在多线程环境下是安全的

StringBuilder 中的方法都没有:synchronized关键字修饰,表示在多线程环境下是不安全的

构造方法

//StringBuffer 底层是以数组的方式存贮字符串
//优化:在创建时尽可能给定合适的初始容量,较少扩容次数
StringBuffer stringbuffer = new StringBuffer();		//创建一个初始化 16 个 byte[] 数组
StringBuffer stringbuffer = new StringBuffer(100);

StringBuilder stringbuilder = new StringBuilder();		//创建一个初始化 16 个 byte[] 数组

append

//底层数组追加,若数组已满,会自动扩容
stringbuffer.append("a");
stringbuffer.append(3.14);
stringbuffer.append(true);

Integer 类库

基本数据类型包装类

基本数据类型 包装类型 父类
byte java.lang.Byte Number
short java.lang.Short Number
int java.lang.Integer Number
long java.lang.Long Number
float java.lang.Float Number
double java.lang.Double Number
boolean java.lang.Boolean Object
char java.lang.Character Object

构造方法

Integer x = new Integer(100);				//传入int
Integer y = new Integer("200");			//传入String

类型转换(装箱 / 拆箱)

//装箱:基本数据类型 — 转为 — 引用数据类型
Integer i = new Integer(123);
//拆箱:引用数据类型 — 转为 — 基本数据类型
i.floatValue();		//123.0
i.intValue();		//123
//JDK 1.5 之后支持自动装箱 / 拆箱
Integer i =100;		//装
int y = i;		 	  //拆
// 注意:为提高程序执行效率,类加载[-128 ~ 127]自动存放到整数常量池中
Integer a = 127;		//提前存放,地址相同
Integer b = 127;
a == b; 						//true

Integer a = 128;		//后期创建,地址不同
Integer b = 128;
a == b 							//false

MAX_VALUE / MIN_VALUE(上下限)

Integer.MAX_VALUE;		//2147483647
Integer.MIN_VALUE;		//-2147483648

parseInt(String - int)

int a = Integer.parseInt("123")			//String 转为 int

toBinaryString(二进制)

toHexString(八进制)

toOctalString(十六进制)

valueOf(转Integer)

Data / SimpleDateFormat 类库

构造方法(获取时间)

import java.util.Date;
Date time = new Date();		//获取毫秒级系统当前时间

Date time2 = new Date(1);	//970年1月1日0时0分0秒0毫秒 + 1毫秒的时间
Date time2 = new Date(System.currentTimeMillis() - 1000*60*60*24);		//昨天的当前时间

时间格式化

//Date 转 String
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-mm-dd HH-mm-ss SSS");
String nowtime = sdf.format(time);
//String 装 Date
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss SSS");
Date datetime = sdf.parse("2020-02-04 23:24:56 888");		//格式对应

currentTimeMillis(获取距离毫秒数)

//获取1970年1月1日0时0分0秒0毫秒到当前系统时间的毫秒数
long timeMillis = System.currentTimeMillis();

DecimalFormat 类库

构造方法(数字格式化)

import java.text.DecimalFormat;
//#任意数字	,代表千分位 .代表小数点 0代表不够补0
DecimalFormat df = new DecimalFormat("###,####.0000");
String s = df.format(123456.89)		//123,456.900

BigDecimal 类库

构造方法

//用于财务系统,高精度
import java.math.BigDecimal;
BigDecimal a = new BigDecimal(100);
BigDecimal b = new BigDecimal(200);

四则运算

BigDecimal c = a.add(b);			//300

Random 类库

构造方法

import java.util.Random;
Random random = new Random();

生成随机数

int a = random.nextInt();		//产生一个int类型取值范围的随机数
int a = random.nextInt(101);		//产生一个1~100范围的随机数(不包括101)

File 类库

File是文件和目录路径的抽象表现形式

构造方法

File f = new File(路径);

exists(判断存在)

f.exists();		//存在返回true,不存在返回false

createNewFile

if(!f.exists()){
    f.createNewFile();		//以文件形式新建
}

mkdirs

if(!f.exists()){
    f.mkdirs();		//以目录形式新建
}

获取父路径

//方法一
String parentPath = f.getParent();
//方法二
File parentFile = f.getParentFile();
parentFile.getAbsolutePath();		//获取绝对路径

getName

f.getName();		//获取文件名

isDirectory

f.isDirectory();		//判断是否是一个目录

isFile

f.isFile();			//判断是否是一个路径

lastModified

long l = f.lastModified();		//文件最后修改时间,返回距离1970年的毫秒

length

f.length();			//获取文件大小,返回字节

listFiles

File[] files =  f.listFiles();		//获取文件夹下的子文件与目录

String - int)

int a = Integer.parseInt("123")			//String 转为 int

toBinaryString(二进制)

toHexString(八进制)

toOctalString(十六进制)

valueOf(转Integer)

Data / SimpleDateFormat 类库

构造方法(获取时间)

import java.util.Date;
Date time = new Date();		//获取毫秒级系统当前时间

Date time2 = new Date(1);	//970年1月1日0时0分0秒0毫秒 + 1毫秒的时间
Date time2 = new Date(System.currentTimeMillis() - 1000*60*60*24);		//昨天的当前时间

时间格式化

//Date 转 String
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-mm-dd HH-mm-ss SSS");
String nowtime = sdf.format(time);
//String 装 Date
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss SSS");
Date datetime = sdf.parse("2020-02-04 23:24:56 888");		//格式对应

currentTimeMillis(获取距离毫秒数)

//获取1970年1月1日0时0分0秒0毫秒到当前系统时间的毫秒数
long timeMillis = System.currentTimeMillis();

DecimalFormat 类库

构造方法(数字格式化)

import java.text.DecimalFormat;
//#任意数字	,代表千分位 .代表小数点 0代表不够补0
DecimalFormat df = new DecimalFormat("###,####.0000");
String s = df.format(123456.89)		//123,456.900

BigDecimal 类库

构造方法

//用于财务系统,高精度
import java.math.BigDecimal;
BigDecimal a = new BigDecimal(100);
BigDecimal b = new BigDecimal(200);

四则运算

BigDecimal c = a.add(b);			//300

Random 类库

构造方法

import java.util.Random;
Random random = new Random();

生成随机数

int a = random.nextInt();		//产生一个int类型取值范围的随机数
int a = random.nextInt(101);		//产生一个1~100范围的随机数(不包括101)

File 类库

File是文件和目录路径的抽象表现形式

构造方法

File f = new File(路径);

exists(判断存在)

f.exists();		//存在返回true,不存在返回false

createNewFile

if(!f.exists()){
    f.createNewFile();		//以文件形式新建
}

mkdirs

if(!f.exists()){
    f.mkdirs();		//以目录形式新建
}

获取父路径

//方法一
String parentPath = f.getParent();
//方法二
File parentFile = f.getParentFile();
parentFile.getAbsolutePath();		//获取绝对路径

getName

f.getName();		//获取文件名

isDirectory

f.isDirectory();		//判断是否是一个目录

isFile

f.isFile();			//判断是否是一个路径

lastModified

long l = f.lastModified();		//文件最后修改时间,返回距离1970年的毫秒

length

f.length();			//获取文件大小,返回字节

listFiles

File[] files =  f.listFiles();		//获取文件夹下的子文件与目录

你可能感兴趣的:(学习笔记)