文章目录

  • JAVA语言的初识
    • JDK的下载及安装
    • 简单的DOS命令
      • 1.打开cmd:
      • 2.常用的Dos命令
    • JDK、JRE、JVM
      • JDK
      • JRE
      • JVM
      • JDK、JRE、JVM三者之间的关系
      • JDK,JRE,JVM相关的面试题
      • Java程序运行机制
      • 编译型、解释型
  • 基础语法
    • 注释
      • javadoc生成jdk帮助文档
    • 关键字
    • 数据类型
      • 1.java是强类型语言
      • 2.Java的数据类型分为两大类
      • 3、常见的问题
    • 变量、常量、作用域
      • 1、变量
      • 2、自增自减
    • 命名规范
    • 运算符
      • 算数运算符
      • 赋值运算符
      • 关系运算符
      • 逻辑运算符
      • 位运算符
      • 条件运算符(三目运算符)
      • 扩展运算符
      • 运算符的优先级
  • 流程控制
    • 用户交互
    • 顺序结构
    • 选择结构
    • 循环结构
    • break && continue&&return
  • 方法
    • 何谓方法
    • 方法的定义和调用
    • 方法的重载
    • 可变参数
  • 面向对象
    • 类和对象的关系
    • 类和对象的创建
    • 构造器
    • 封装
    • 继承
    • 多态
    • instanceof
    • 抽象类
    • 接口
    • 内部类
      • 成员内部类
      • 静态内部类
      • 局部内部类
      • 匿名内部类
  • 常用类
    • 枚举类
      • 如何自定义枚举类
      • 如何使用enum定义枚举类
      • Enum类的主要方法
      • 实现接口的枚举类
    • 包装(Wrapper)类
    • String类
      • String类及常用方法
      • StringBuffer及StringBuilder
    • File类
    • 时间日期类
      • Date
      • Calendar
      • SimpleDateFormat
    • JDK8之后的时间日期类
      • Instant
      • DateTimeFormatter
    • System类
    • Math类
    • BigInteger及BigDecimal
    • 比较器
      • Comparable
      • Comparator
  • 集合
    • Collection
    • List
    • Set
    • Map
    • Collections工具类
    • 泛型<>
  • IO流
    • IO流原理及流的分类
    • 流的读写操作
      • 字符流
      • 字节流
      • 缓冲流
      • 转换流
      • 标准输入、输出流
      • 对象流
  • 多线程
    • 基本概念
    • 线程的创建和使用
    • java5.0新增的多线程创建方式
    • 线程的生命周期
    • 线程的同步
    • 线程通信
    • 经典案例:生产者消费者问题
  • 反射
    • Java反射机制
    • 理解Class类及获取Class实例
    • 类的加载与ClassLoader的理解
    • 创建运行时类的对象
    • 反射的运用:动态代理
  • 注解
    • 理解注解(Annotation)
    • jdk中的元注解
  • 注解
    • 理解注解(Annotation)
    • jdk中的元注解

JAVA语言的初识

JDK的下载及安装

官方下载路径

  1. 点击下载好的文件进行安装,尽量安装在固态硬盘中,一路下一步即可。

  2. 安装完成就配置环境变量

    新建CLASSPATH:

新建JAVA_HOME:

在path中加入:

  1. 环境变量配置完成,检查是否配置正确,启动命令窗口:win+R:cmd

    • 输入javajavacjava -version



Okay!至此jdk就配置完成~

简单的DOS命令

1.打开cmd:

  1. win+r:输入cmd;

  2. 文件地址栏输入cmd:

  3. 开始+系统+命令提示符:

管理员运行:

2.常用的Dos命令

  1. 盘符切换:d:

  1. 查看当前目录下的所有的文件:dir

  1. 切换目录:cd /d 路径

  2. 返回上一级:cd…

  3. 清除屏幕:cls

  4. 退出窗口:exit

  5. 查看本机ip:ipconfig

  1. ping命令:ping www.baidu.com

  2. 相关文件的操作:

    • md 创建文件夹
    • rd 移除文件夹
    • cd>a.txt 新建文件
    • del a.txt 删除文件

    文件的移除是不会移除至回收站中

JDK、JRE、JVM

JDK

  1. JDKJRE的超集,JDK包含了JRE的所有开发,调试和监视应用程序的工具。当要开发Java应用程序时,需要安装JDK.
  2. javac、java、javadoc、jar

JRE

Java运行时环境(JRE)是一个软件包,它捆绑了libraries(jar)和JVM,以及用Java编写的应用程序的其他组件。

JVM

JVM(JAVA虚拟机)是运行Java字节码的虚拟机,通过编译.java文件为.class文件得到字节码文件 . .class文件包含JVM可以理解的字节码。

JDK、JRE、JVM三者之间的关系

JDK,JRE,JVM相关的面试题

  • Java中的类加载有几种类型

    三种,分别是:Bootstrap,extendsion,application

  • 类加载器是如何工作的

    类加载器扫描它们预定义的jar文件和类的位置。它们扫描路径中的所有类文件并寻找所需的类。如果发现类则加载,链接并初始化类文件。

  • JREJVM的不同

    JVM是运行时环境的规范,它执行Java应用程序。Hotspot JVM就是这种规范的一种实现。它加载类文件,使用interpreterJIT Compiler将字节码转换成机器码并执行它。

  • interpreterJIT compiler的不同

    interpreter逐行解释字节码并按顺序执行。这会导致性能低下。JIT compiler通过在块中分析代码并在这个过程添加优化,然后准备(编译)为更优化的机器码。

Java程序运行机制

  1. 使用编辑器或IDE(集成开发环境)编写Java源文件.即.java文件
  2. 程序必须编译为字节码文件,javac(Java编译器)编译源文件为.class文件.
  3. 类文件可在任何平台/操作系统上由JVM(Java虚拟机)执行
  4. JVM将字节码文件翻译为机器可以执行的机器码(0,1二进制)

编译型、解释型

  1. JAVA 语言是一种编译型-解释型语言,同时具备编译特性和解释特性。其实,确切的说 Java 就是解释型语言,其所谓的(预)编译过程只是将 .java 文件编程成平台无关的字节码 .class 文件(生成的代码是介于机器码和Java源代码之间的中介代码),并不是向 C 一样编译成可执行的机器语言。作为编译型语言,JAVA 程序要被统一编译成字节码文件——>文件后缀是 .class 。此种文件在 Java 中又称为类文件。Java 类文件不能在计算机上直接执行,它需要被 JVM(Java 的虚拟机平台,可视为解释器)翻译成本地的机器码后才能执行,而Java 虚拟机的翻译过程则是解释性的过程。Java 字节码文件首先被加载到计算机内存中,然后读出一条指令,翻译一条指令,执行一条指令,该过程被称为 Java 语言的解释执行。而在现实中,Java 开发工具 JDK 提供了两个很重要的命令来完成上面的编译和解释(翻译)过程。两个命令分别是java.exejavac.exe,前者加载 Java 类文件,并逐步对字节码文件进行编译,而另一个命令则对应了 Java 语言的解释(javac.exe)过程。在次序上,Java 语言是要先进行编译的过程,接着解释执行。这样既保留了源代码的高抽象、可移植的特点,又已经完成了对源代码的大部分预编译工作,所以执行起来比“纯解释型”程序要快许多。

基础语法

注释

  1. 单行注释://
  2. 多行注释:/* */
  3. 文档注释:/** */ (可以通过javadoc生成帮助文档)

javadoc生成jdk帮助文档

IDEA 的 JavaDoc 生成功能在菜单 Tools->Generate JavaDoc 项里面。

关键字

Java关键字是电脑语言里事先定义的,有特别意义的标识符,有时又叫保留字,还有特别意义的变量。Java的关键字对Java的编译器有特殊的意义,他们用来表示一种数据类型,或者表示程序的结构等,关键字不能用作变量名、方法名、类名、包名和参数

abstract assert boolean break byte
case catch char class const
continue default do double else
enum extends final finally float
for goto if implements import
instanceof int interface long native
new package private protected public
return strictfp short static super
switch synchronized this throw throws
transient try void volatile while

数据类型

1.java是强类型语言

  1. 要求所有的变量严格符合规定,所有的变量都必须先定义后才能使用

2.Java的数据类型分为两大类

  1. 基本数据类型(8类)
  2. 引用数据类型(3类)
  • 位(bit):计算机中最小的存储单位;

  • 字节(byte):计算机中数据处理的基本单位,习惯使用B表示;

  • 单位转换:

    • 1B=8bit;
    • 1kb=1024b;
    • 1m=1024kb;
    • 1g=1024m;
  • 字符:指计算机中使用的字母、数字、字和符号

  • 电脑的32位和64位区别:

    • 32位的电脑只能使用4gb;
    • 64位电脑内存可以无限大;

3、常见的问题

  1. 银行业务的表示:

    不能使用浮点数,会有舍入误差,只能说接近,因为会有精度损失

  2. BigDecimal:数学工具类;

  3. a=97;A=65;

    • char c1=‘a’;System.out.println((int)c1);----->97;

变量、常量、作用域

1、变量

package com.simon.demo01;public class Test01 {public static void main(String[] args) {//局部变量int a=100;//常量final int MAX_A=100;Test01 test01 = new Test01();System.out.println(test01.id);System.out.println(b);System.out.println(MAX_A);System.out.println(PI);System.out.println(a);}//实例变量int id;String name;int age;//类变量static int b;static final double PI=3.14;
}

2、自增自减

package com.simon.demo01;public class Test02 {public static void main(String[] args) {int a=3;System.out.println(a);int b=a++;//先赋值再+1System.out.println(a);//a=a+1System.out.println(b);int c=++a;//先+1,再赋值System.out.println(a);System.out.println(c);}
}

命名规范

1、项目名全部小写.
2、包名全部小写.
3、类名首字母大写,多个单词情况下使用驼峰命名规则.
4、变量名,方法名首字母小写,如果名称由多个单词组成,使用驼峰命名规则.
5、常量名全部大写.
6、所有命名规则必须遵循以下规则 :

  • 名称只能由字母、数字、下划线、$符号组成.
  • 不能以数字开头.
  • 名称不能使用Java中的关键字.
  • 尽量不使用中文及拼音命名.

包名命名方式

一般公司命名com.公司名.项目名.模块名....;

1.indi : 个体项目,指个人发起,但非自己独自完成的项目,可公开或私有项目,copyright主要属于发起者.

  • 包名 :indi.发起者名.项目名.模块名..

2.pers : 个人项目,指个人发起,独自完成,可分享的项目,copyright主要属于个人.

  • 包名 : pers.个人名.项目名.模块名…

3.priv : 私有项目,指个人发起,独自完成,非公开的私人使用的项目,copyright属于个人.

  • 包名 : priv.个人名.项目名.模块名…

4.onem : 与indi相同,推荐使用indi.

运算符

算数运算符

操作符 描述 例子
+ 加法 - 相加运算符两侧的值 A + B 等于 30
- 减法 - 左操作数减去右操作数 A – B 等于 -10
* 乘法 - 相乘操作符两侧的值 A * B等于200
/ 除法 - 左操作数除以右操作数 B / A等于2
取余 - 左操作数除以右操作数的余数 B%A等于0
++ 自增: 操作数的值增加1 B++ 或 ++B 等于 21
自减: 操作数的值减少1 B-- 或 --B 等于 19

赋值运算符

2 赋值运算符主要有两类:

一类是使用等号(=)赋值,它把一个表达式的值赋给一个变量或对象;

另一类是扩展的赋值运算符

3 赋值运算符的格式

variableName = expression;

这里,variableName为变量名,expression为表达式。其功能是将等号 右边表达式的值赋给左边的变量。

例如:

int x = 10;

int y = x + 20;

关系运算符

运算符 描述 例子
== 检查如果两个操作数的值是否相等,如果相等则条件为真。 (A == B)为假。
!= 检查如果两个操作数的值是否相等,如果值不相等则条件为真。 (A != B) 为真。
> 检查左操作数的值是否大于右操作数的值,如果是那么条件为真。 (A> B)为假。
< 检查左操作数的值是否小于右操作数的值,如果是那么条件为真。 (A <B)为真。
>= 检查左操作数的值是否大于或等于右操作数的值,如果是那么条件为真。 (A> = B)为假。
<= 检查左操作数的值是否小于或等于右操作数的值,如果是那么条件为真。 (A <= B)为真。

逻辑运算符

操作符 描述 例子
&& 称为逻辑与运算符。当且仅当两个操作数都为真,条件才为真。 (A && B)为假。
| | 称为逻辑或操作符。如果任何两个操作数任何一个为真,条件为真。 (A | | B)为真。
称为逻辑非运算符。用来反转操作数的逻辑状态。如果条件为true,则逻辑非运算符将得到false。 !(A && B)为真。

位运算符

操作符 描述 例子
如果相对应位都是1,则结果为1,否则为0 (A&B),得到12,即0000 1100
| 如果相对应位都是0,则结果为0,否则为1 (A | B)得到61,即 0011 1101
^ 如果相对应位值相同,则结果为0,否则为1 (A ^ B)得到49,即 0011 0001
按位取反运算符翻转操作数的每一位,即0变成1,1变成0。 (〜A)得到-61,即1100 0011
<< 按位左移运算符。左操作数按位左移右操作数指定的位数。左x2 A << 2得到240,即 1111 0000
>> 按位右移运算符。左操作数按位右移右操作数指定的位数。右/2 A >> 2得到15即 1111
>>> 按位右移补零操作符。左操作数的值按右操作数指定的位数右移,移动得到的空位以零填充。 A>>>2得到15即0000 1111

条件运算符(三目运算符)

表达式:

variable x = (expression) ? value if true : value if false

int a = 10;
int b = 20;//求最大值
int c = (a>b)? a:b;
System.out.println(c);//20

扩展运算符

操作符 描述 例子
+ = 加和赋值操作符,它把左操作数和右操作数相加赋值给左操作数 C + = A等价于C = C + A
- = 减和赋值操作符,它把左操作数和右操作数相减赋值给左操作数 C - = A等价于C = C - A
* = 乘和赋值操作符,它把左操作数和右操作数相乘赋值给左操作数 C * = A等价于C = C * A
/ = 除和赋值操作符,它把左操作数和右操作数相除赋值给左操作数 C / = A等价于C = C / A
(%)= 取模和赋值操作符,它把左操作数和右操作数取模后赋值给左操作数 C%= A等价于C = C%A
<< = 左移位赋值运算符 C << = 2等价于C = C << 2
>> = 右移位赋值运算符 C >> = 2等价于C = C >> 2
&= 按位与赋值运算符 C&= 2等价于C = C&2
^ = 按位异或赋值操作符 C ^ = 2等价于C = C ^ 2
| = 按位或赋值操作符 C | = 2等价于C = C | 2

运算符的优先级

类别 操作符 关联性
后缀 () [] . (点操作符) 左到右
一元 + + - !〜 从右到左
乘性 * /% 左到右
加性 + - 左到右
移位 >> >>> << 左到右
关系 >> = << = 左到右
相等 == != 左到右
按位与 左到右
按位异或 ^ 左到右
按位或 | 左到右
逻辑与 && 左到右
逻辑或 | | 左到右
条件 ?: 从右到左
赋值 = + = - = * = / =%= >> = << =&= ^ = | = 从右到左
逗号 左到右

流程控制

用户交互

import java.util.Scanner;

package com.simon.demo06;import java.util.Scanner;public class Test03 {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);System.out.println("请输入两个整数:");int i1 = scanner.nextInt();int i2 = scanner.nextInt();int add = add(i1, i2);System.out.println(add);//关闭输入流scanner.close();}public static int add(int a, int b){return a+b;}
}

顺序结构

顺序结构:就是从头到尾依次执行每条语句的操作。

选择结构

  1. 选择结构:也称条件控制,是指根据表达式的值有选择的执行。

  2. 在java中,选择结构分为if-else语句和 switch 语句。

    1. if-else结构:
    //单选择结构
    if(布尔表达式){语句或语句块
    }else{语句或语句块
    }//多选择结构
    if(布尔表达式){语句或语句块
    }else if(布尔表达式){语句或语句块
    }else{语句或语句块
    }

注意:

1)if括号里表达式的值返回的必须是布尔类型

2)如果条件体内只有一条语句需要执行,那么if后面的大括号可以省略。建议不要省略!

3)如果出现有多个if一个else的情况,else子句归属于最内层的if语句

​ 2. switch:

switch(表达式){case 常量值1:语句块;break;
case 常量值2:语句块;break;
case 常量值3:语句块;break;..
default:语句块;break;
}

注意:

1)switch中表达式的返回值只能是int,byte,char,short,枚举,字符串

2)case子句中的值必须是常量,且不能重复

3)default可有可无;

4)break作为某一个case代码段的结束句,使其跳出程序

循环结构

  1. 循环结构:也称回路控制,是根据循环初始条件和终结要求,执行循环体内的操作。

  2. 在java中,循环结构有三种,分别是while循环、do-while循环、for循环

    • while循环:循环条件为true,执行代码块,一直到循环条件为false 则跳出循环。
    while(循环条件){代码块
    }
    
    • do-while循环:先执行代码块,再判断循环条件,循环条件为true,则继续执行代码块,否则跳出循环。
    • **注意:**do-while循环的特点是无论循环条件是否为true,都会先执行一遍代码块
    do{代码块;
    }while(循环条件);
    
    • for循环:for循环可以用来重复执行某条语句,直到某个条件得到满足。
    for(表达式1;表达式2;表达式3){代码块;
    }
    

break && continue&&return

  1. break语句:

    ​ break语句刚刚在switch中已经见过了,是用来终止case的。实际上,break出现在while,do-while,for循环中,用于强行退出当前循环

  2. continue语句:

    ​ continue只能用于for,while,do-while循环语句中,用于让程序跳出本次循环,直接进入下次循环

  3. return语句:

    • 结束方法;
    public void show(){System.out.println("show---");return;//结束方法}
    
    • 返回值
    public static int add(int a, int b){return a+b;//返回值}
    

方法

何谓方法

  1. java方法是语句的集合,他们在一起执行一个功能;可以反复调用,增加代码的复用性。
  2. public static void main(String[] args){}
  3. System.out.println();

方法的定义和调用

  1. [修饰符] 返回值类型 方法名([参数类型 参数名],[…]){return 值}
public class Test03 {public static void main(String[] args) {test(3,5);//调用静态方法Test03 test03 = new Test03();System.out.println(test03.test01(1,2,3));//调用非静态方法}static void test(int a, int b){System.out.println(a+b);}int test01(int a,int b,int c){return a+b+c;}
}

方法的重载

  1. 方法名必须相同
  2. 参数列表必须不同(个数不同、参数类型不同、参数列表的顺序不同)
  3. 参数的返回值类型可以不同也可以相同
  4. 仅仅返回值类不同不足以构成方法的重载
public static void main(String[] args) {test(3,5);//调用静态方法Test03 test03 = new Test03();System.out.println(test03.test(1,2,3));//调用非静态方法System.out.println(test03.test(1.0,2.0));}static void test(int a, int b){System.out.println(a+b);}int test(int a,int b,int c){return a+b+c;}double test(double a,double b){return a+b;}
}

可变参数

  1. 类似于数组

  2. int test(int... a){for (int i = 0; i < a.length; i++) {System.out.print(a[i]+"\t");}return 0;}
    test03.test(1,2,3,4,5);//方法的调用

    输出结果:

面向对象

类和对象的关系

  1. 类是抽象的数据类型,并不能代表某一个具体的事物;类是对象的一个模板
  2. 对象是类的具体实例

类和对象的创建

构造器

  1. 方法名和类名相同;
  2. 无参构造器是默认存在的;
  3. 如果自己定义了一个有参构造器,那么无参构造器必须显示定义;
public class Student {String name;int age;//alt+insert自动生成//无参构造器public Student() {}//有参构造器public Student(String name, int age) {this.name = name;this.age = age;}void study(){System.out.println(this.name+"\t"+this.age+"\t"+"在学习!");}
}public class Application {public static void main(String[] args) {Student student1 = new Student("lscong",22);student1.study();}
}

封装

  1. 程序追求“高内聚、低耦合”,
  2. 高内聚:类的内部数据操作细节自己完成,不允许外部干涉;
  3. 低耦合:尽量暴露少量的方法给外部使用;
  4. 私有属性----定义set、get方法
public class Person {private String name;private int age;private int score;public Person() {}
//alt+insert选择getter、setterpublic String getName() {return name;}public int getAge() {return age;}public int getScore() {return score;}public void setName(String name) {this.name = name;}public void setAge(int age) {this.age = age;}public void setScore(int score) {this.score = score;}
}Person person = new Person();
person.setName("李思聪");
System.out.println(person.getName());

继承

  1. 关键字:extends
  2. java中只有单继承,没有多继承;
  3. 子类拥有父类所有的东西,但是私有的东西是不能被继承的;
  4. Object是所有类的父类,直接继承Object

  1. super关键字调用父类的属性及方法

    public Student() {//super();----默认调用父类的构造方法,且super必须放在第一行System.out.println("Student无参构造器!");}
    

  1. 重写:

    alt+insert

    • 需要有继承关系,子类重写父类
    • 方法名必须相同,方法体不同
    • 参数列表必须相同
    • 修饰符可以扩大:public>protected>default>private
    • 抛出的异常:可以缩小,但是不能扩大
    • 子类重写了父类,那么对象调用的就是执行重写的方法

    为什么重写:

    • 父类的功能,子类不一定需要,或者不一定能够满足

多态

  1. 可以实现动态编译

    //一个对象的实际类型是确定的
    new Student();
    new Person();//可以指向的引用类型就是不确定的,父类的引用指向子类
    Student s1=new Student();
    //父类不能调用子类独有的方法
    Person s2=new Student();Object s3=new Student();
    • 能不能调用,主要看左边类是否存在该方法
    • 如果子类重写了父类的方法,那么都是执行子类重写的方法
    • 可以强制转换,高->低
  • 注意事项:

    • 多态是方法的多态,属性是没有多态的

    • 存在的条件:继承关系,方法需要重写,父类的引用指向子类对象(Father f1=new Son();)

      不存在多态:

      • static 静态的方法 属于类,不属于实例
      • final 常量
      • private 私有的

instanceof

  1. 判断两边类型是否存在父子关系

  2. X instanceof Y

    Student s1=new Student();Person s2=new Student();Object s3=new Student();//Object>Person>Student
    //Object>Person>Teacher
    //Object>String
    s3 instanceof Student//true
    s3 instanceof Person//true
    s3 instanceof Object//true
    s3 instanceof String//false
    s3 instanceof Teacher//falses1 instanceof Student//true
    s1 instanceof Person//true
    s1 instanceof Object//true
    s1 instanceof String//编译错误
    s1 instanceof Teacher//编译错误s2 instanceof Student//true
    s2 instanceof Person//true
    s2 instanceof Object//true
    s2 instanceof String//编译错误
    s2 instanceof Teacher//false
    

抽象类

  1. abstract关键字
  2. 是一种约束,抽象方法,只有方法没有具体的实现
  3. 只能靠子类去实现方法
  4. 抽象类中可以存在非抽象类方法,但是非抽象类不能写抽象方法
  5. 子类继承抽象类,必须对其抽象方法进行重写

问题:

  1. 抽象类存在构造器吗?

    • 抽象类可以有构造方法,只是不能直接创建抽象类的实例对象而已。在继承了抽象类的子类中通过super()或super(参数列表)调用抽象类中的构造方法。

      abstract class Base{int a=7;public Base(){a=8;}public Base(int i){a=i;}
      }
      public class Demo01 extends Base {public Demo01(){super();}public Demo01(int i){super(i);}public static void main(String[] args) {Demo01 demo=new Demo01();System.out.println(demo.a);Demo01 demo1=new Demo01(9);System.out.println(demo1.a);}
      }
      
  2. 存在的意义?

    • 因为抽象类不能实例化对象,所以必须要有子类实现它之后才能使用。这样就可以把一些具有相同属性和方法的组件进行抽象,这样更有利于代码和程序的维护
    • 当又有一个具有相似的组件产生时,只需要实现该抽象类就可以获得该抽象类的那些属性和方法

接口

  1. implements:继承关键字

  2. interface:修饰符

  3. [public abstract] void run();

  4. 接口中定义的变量均为常量:[public abstract final ] AGE=100;

  5. 接口可以实现多继承

  6. 只有规范,自己无法写方法

  7. 以后均在面向接口编程

  8. 子类继承接口,子类必须对其方法进行重写

内部类

成员内部类

public class Outer{private String name;private int age;public void outer(){System.out.println("outer!");   }public class Inner{public void inner(){System.out.println("inner!");   }}
}//new
Outer outer=new Outer();
Outer.Inner inner=outer.new Inner();
inner.inner();

静态内部类

public class Outer{private String name;private int age;public void outer(){System.out.println("outer!");   }public static class Inner{public void inner(){System.out.println("inner!");   }}
}

局部内部类

public class Outer{private String name;private int age;public void outer(){public class Inner{private int score;void run(){System.out.println("run!");  }}System.out.println("outer!");   }
}

匿名内部类

public class Outer{private String name;private int age;public void outer(){System.out.println("outer!");   }
}
class Outer1{public void outer1(){System.out.println("outer1!");   }}//new,没有名字的初始化,不用将实例保存在变量中
new Outer1().outer();

常用类

枚举类

如何自定义枚举类

  1. 类的对象只有有限个,确定的

  2. 当需要定义一组常量时,强烈建议使用枚举类

package com.simon.demo06;//jdk5.0之前自定义枚举类public class Test01 {public static void main(String[] args) {Season summer = Season.SUMMER;System.out.println(summer);}
}//自定义枚举类
class Season {//声明Season对象的属性,private final修饰private final String seasonName;private final String desc;//类的构造器,并给类的对象赋值private Season(String seasonName, String desc) {this.seasonName = seasonName;this.desc = desc;}//提供当前枚举类的多个对象public static final Season SPRING = new Season("春天","春暖花开");public static final Season SUMMER = new Season("夏天","夏日炎炎");public static final Season AUTUMN = new Season("秋天","秋高气爽");public static final Season WINTER = new Season("冬天","凉风飕飕");//其他诉求,获取枚举类的对象属性public String getSeasonName() {return seasonName;}public String getDesc() {return desc;}//提供toString()@Overridepublic String toString() {return "Season{" +"seasonName='" + seasonName + '\'' +", desc='" + desc + '\'' +'}';}
}

如何使用enum定义枚举类

package com.simon.demo06;//jdk5.0之后enum定义枚举类public class Test01 {public static void main(String[] args) {Season summer = Season.SUMMER;System.out.println(summer);//SUMMERSystem.out.println(Season.class.getSuperclass());//class java.lang.Enum}}//自定义枚举类
enum  Season {//提供当前枚举类的多个对象;多个对象之间使用逗号隔开,最后使用分号SPRING("春天","春暖花开"),SUMMER("夏天","夏日炎炎"),AUTUMN("秋天","秋高气爽"),WINTER("冬天","凉风飕飕");//声明Season对象的属性,private final修饰private final String desc;private final String seasonName;//类的构造器,并给类的对象赋值;private Season(String seasonName, String desc) {this.seasonName = seasonName;this.desc = desc;}//其他诉求,获取枚举类的对象属性public String getSeasonName() {return seasonName;}public String getDesc() {return desc;}/*//提供toString()@Overridepublic String toString() {return "Season{" +"seasonName='" + seasonName + '\'' +", desc='" + desc + '\'' +'}';}*/
}

Enum类的主要方法

  1. values()

  2. valueOf()

  3. toString()

    //valuesOf(String name),根据提供的参数找到name
    Season winter = Season.valueOf("WINTER");
    System.out.println(winter);//WINTER//values:枚举类中存在哪些对象
    Season[] values = Season.values();
    for(Season s:values){System.out.println(s);//SPRING、SUMMER、AUTUMN、WINTER
    }
    //toString(),返回对象名
    System.out.println(summer.toString());//SUMMER
    

实现接口的枚举类

package com.simon.demo06;//jdk5.0之前自定义枚举类import javax.swing.*;public class Test01 {public static void main(String[] args) {Season summer = Season.SUMMER;//toString(),返回对象名System.out.println(summer.toString());//SUMMER//实现接口,使得每个对象可以调用不同的show()Season autumn = Season.AUTUMN;autumn.show();//秋天在哪里System.out.println(Season.class.getSuperclass());//class java.lang.Enum//values:枚举类中存在哪些对象Season[] values = Season.values();for(Season s:values){System.out.println(s);//SPRING、SUMMER、AUTUMN、WINTER}//valuesOf(String name),根据提供的参数找到nameSeason winter = Season.valueOf("WINTER");System.out.println(winter);//WINTER}}interface Season1{void show();
}
//自定义枚举类
enum  Season implements Season1{//提供当前枚举类的多个对象;多个对象之间使用逗号隔开,最后使用分号SPRING("春天","春暖花开"){@Overridepublic void show() {System.out.println("春天在哪里");}},SUMMER("夏天","夏日炎炎"){@Overridepublic void show() {System.out.println("夏天在哪里");}},AUTUMN("秋天","秋高气爽"){@Overridepublic void show() {System.out.println("秋天在哪里");}},WINTER("冬天","凉风飕飕"){@Overridepublic void show() {System.out.println("冬天在哪里");}};//声明Season对象的属性,private final修饰private final String desc;private final String seasonName;//类的构造器,并给类的对象赋值;private Season(String seasonName, String desc) {this.seasonName = seasonName;this.desc = desc;}//其他诉求,获取枚举类的对象属性public String getSeasonName() {return seasonName;}public String getDesc() {return desc;}/*//提供toString()@Overridepublic String toString() {return "Season{" +"seasonName='" + seasonName + '\'' +", desc='" + desc + '\'' +'}';}*/
}

包装(Wrapper)类

  1. 八种基本数据类型定义相应的包装类:

    基本数据类型 包装类
    byte Byte
    short Short
    int Integer
    long Long
    float Float
    double Double
    boolean Boolean
    char Character
  2. 基本数据类型、包装类、String之间的相互转换

    int nums = 10;Integer num = new Integer(nums);//装箱System.out.println(num);int i = num.intValue();//拆箱System.out.println(i);
    
  3. 与String之间的转换:

 //方式一
String str1 = nums + "";
//方式二
String str = String.valueOf(nums);//无论是基本数据类型还是包装类均可调用valueOf()
String str2 = String.valueOf(num);//String转换为基本数据类型
//没有关系的类是无法进行强转的
int i1 = Integer.parseInt(str);//Integer i2 = new Integer(Integer.parseInt(str));
Integer i3 = Integer.parseInt(str);String str3 = "true";
boolean bl = Boolean.parseBoolean(str3);
  1. 自动装箱和拆箱(新特性):
Integer in1 = nums;//自动装箱int in2 = in1;//自动拆箱

String类

String类及常用方法

  1. String的特性:

    1. String类代表字符串
    2. String是个final类,是个不可变的字符序列;
    3. 字符串是常量,使用“”来表示,他们的值创建了之后是不能被改变的
    4. String对象的字符内容是存储在一个**字符数组value[]**中的;
public class Test01 {public static void main(String[] args) {String s1="abc";String s2="abc";System.out.println(s1 == s2);//true}
}

在String常量池中,如果定义的String常量是相同的那么就是使用的同一个对象,如果不是相同的常量那么就会新建一个对象。

public static void test(){String str2 = new String("hello");String str1 = new String("hello");System.out.println(str1==str2);//false}

此时创建的是两个不同的对象,所有返回false

  • 问题:String str1 = new String(“hello”);在内存中创建了几个对象?

    答:2个,一个是在对空间中new的一个对象,另一个是在常量池中的数据"hello"

  1. 字符串的拼接

    public static void test2(){String s1="abc";String s2="def";String s3=s1+s2;String s4="abc"+"def";String s5=s1+"def";String s6="abc"+s2;String s7="abcdef";System.out.println(s4 == s7);//trueSystem.out.println(s5 == s7);//falseSystem.out.println(s6 == s7);//falseSystem.out.println(s3 == s7);//falseSystem.out.println(s3 == s4);//falseString s8=s5.intern();System.out.println(s7 == s8);//true}
    

    有变量参与的字符串拼接都是在对空间中new创建的对象,那么对象就是不同的;如果是字面量拼接的都是在常量池中创建的,如果结果是相同的,那么对象就是相同的;如果拼接调用了intern方法,那么该字符串对象就在常量池中,此时对象就是相他同的。

  2. String的常用方法

    1. public static void test3(){String s1="helloworld";System.out.println(s1.length());//长度System.out.println(s1.charAt(0));//字符索引System.out.println(s1.charAt(2));System.out.println(s1.charAt(4));System.out.println(s1.isEmpty());//是否为空String s2 = s1.toUpperCase();//大写System.out.println(s2);String s4="  helloWorld!   ";String s3 = s4.trim();//去除前后空格System.out.println(s3);System.out.println(s1.equals(s4));//比较字符串的值是否相同String s5="HelloWorld";System.out.println(s1.equalsIgnoreCase(s5));//忽略大小写的比较String s6="abc";String s7="abe";System.out.println(s6.compareTo(s7));//比较大小,依次比较System.out.println(s1.substring(5));//截取字符串System.out.println(s6.concat("def"));//连接字符串,等价于“abc”+“def”}
      
  3. String 与基本数据类型之间的转换

    public static void test4(){String s1="123";int s2 = Integer.parseInt(s1);System.out.println(s2);String s3 = String.valueOf(s2);System.out.println(s3);}
    
  4. String类型与char型数组之间的转化

    public static void test5(){String s1="helloworld";char[] chars = s1.toCharArray();for (int i = 0; i <chars.length ; i++) {System.out.print(chars[i]);}char[] c1={'h','e','l','l','o'};String s2 = new String(c1);System.out.println(s2);}
    

StringBuffer及StringBuilder

  1. String、StringBuffer、StringBuilder区别
  • String:不可变字符串序列;使用char[]存储

  • StringBuffer:可变的字符串序列;线程安全的效率偏低;使用char[]存储

  • StringBuilder:可变的字符串序列;线程不安全的效率高;使用char[]存储

  1. 常用方法

     public static void test6(){StringBuffer stringBuffer = new StringBuffer("abc");//char[] value=new char[16]System.out.println(stringBuffer.length());//0stringBuffer.append('d').append('e');//添加,可以反复调用append()abcdeSystem.out.println(stringBuffer.delete(0, 1));//删除bcdSystem.out.println(stringBuffer.replace(0, 1, "hello"));//替换hellocdestringBuffer.insert(2,"false");//插入hefalsellocdeSystem.out.println(stringBuffer.reverse());//翻转edcolleslafehSystem.out.println(stringBuffer.indexOf("l"));//字符出现的次数3stringBuffer.substring(2);//截取字符串olleslafeh}
    

    主要关注增删改查

  2. String、StringBuffer、StringBuilder执行效率

    String<StringBuffer<StringBuilder;String效率是极低的,在没有线程的时候就是用StringBuilder

File类

File类的使用

  1. 实例化

    • import java.io.File;
    • File file = new File("hello.txt");//相对于该项目的路径下
    • File file1 = new File("G:\\idea\\java\\java01\\src\\com\\simon\\demo03\\hello.txt");//绝对路径
    • 相对路径:相较于某个路径下,指明的路径;
    • 绝对路径:包含盘符,一个完整的路径;
  2. File类的常用方法

    System.out.println(file.getName());//hello.txt
    System.out.println(file.getAbsolutePath());//G:\idea\java\hello.txt
    System.out.println(file.getParent());//null
    System.out.println(file.getPath());//hello.txt
    System.out.println(file.length());//0 文件的字节长度
    System.out.println(file.lastModified());//0 最近一次修改时,时间戳!
    
    1. 创建文件或文件夹

      //创建文件或文件夹boolean newFile=false;try {newFile = file.createNewFile();} catch (IOException e) {e.printStackTrace();}finally {System.out.println(newFile);}//删除文件或文件夹boolean delete1 = file1.delete();System.out.println(delete1);boolean delete = file.delete();System.out.println(delete);//创建文件夹//mkdir 只能使用相对路径创建,此方法在上级目录存在的情况下才可以创建//mkdirs,在上级目录不存在的情况下也可以创建,此时就一并创建了boolean mkdir = file1.mkdir();System.out.println(mkdir);
      

时间日期类

Date

  1. import java.util.Date;
  2. java.sql.Date—数据库中的Date
  3. 两个构造器的使用
public static void test2(){//构造器一、空参构造器Date d1 = new Date();//import java.util.Date;//构造器二Date date = new Date(2020, 1, 1);//自己定义,但是这个构造器已经过时了Date date1 = new Date(1601802431564L);//Sun Oct 04 17:07:11 CST 2020/*@Deprecatedpublic Date(int year, int month, int date) {this(year, month, date, 0, 0, 0);*///java.sql.Datejava.sql.Date date2 = new java.sql.Date(1601802431564L);System.out.println(date2.toString());//2020-10-04}}
  1. 两个方法的使用

    //方法一
    System.out.println(d1.toString());//Sun Oct 04 17:05:05 CST 2020
    //方法二
    System.out.println(d1.getTime());//1601802431564,时间戳
    

Calendar

  1. import java.util.Calendar;

  2. 可变性

  3. 不能直接new Calendar();因为该类是抽象类

    1. 可以new 其子类

      Calendar c = new GregorianCalendar();

    2. 还可以调用其静态方法,进行new

      Calendar instance = Calendar.getInstance();

  4. 常用方法

    1. get()

      int i = c.get(Calendar.DAY_OF_MONTH);

    2. set()

      c.set(Calendar.DAY_OF_MONTH,22);

    3. add()

      c.add(Calendar.DAY_OF_MONTH,3);

    4. getTime()

      Date time = c.getTime();

    5. setTime()

      c.setTime(date);

SimpleDateFormat

  1. import java.text.SimpleDateFormat;

  2. SimpleDateFormat实例化

SimpleDateFormat simpleDateFormat = new SimpleDateFormat();//默认的构造器
  1. 两个操作

    1. 格式化:日期————>字符串
    Date date = new Date();
    System.out.println(date.toString());//Sun Oct 04 17:30:31 CST 2020//默认格式化
    String format = simpleDateFormat.format(date);
    System.out.println(format);//20-10-4 下午5:30//自己定义的格式化
    //格式化日期 yyyy-MM-dd HH:mm:ss
    //带参的构造器
    SimpleDateFormat simpleDateFormat1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    String format1 = simpleDateFormat1.format(date);
    System.out.println(format1);//2020-10-04 17:39:53
    
    1. 解析:格式化的逆过程;字符串—>日期

      String str="20-10-4 下午5:30";
      Date parse = null;
      try {parse = simpleDateFormat.parse(str);
      } catch (ParseException e) {e.printStackTrace();
      }
      System.out.println(parse);//Sun Oct 04 17:30:00 CST 2020
      

JDK8之后的时间日期类

  1. LocalDate、LocalDateTime、LocalTime

  2. 实例化:

    public static void test5() {//实例化LocalDate localDate = LocalDate.now();LocalTime localTime = LocalTime.now();LocalDateTime localDateTime = LocalDateTime.now();System.out.println(localDateTime);System.out.println(localDate);System.out.println(localTime);}
    
  3. 不可变性

  4. 常用方法

    System.out.println(localDateTime.getDayOfMonth());//4
    System.out.println(localDateTime.getDayOfWeek());//SUNDAY
    System.out.println(localDateTime.getDayOfYear());//278
    System.out.println(localDateTime.getMonth());//OCTOBER//操作,体现不可变性
    LocalDateTime localDateTime1 = localDateTime.withDayOfMonth(22);
    System.out.println(localDateTime);//2020-10-04T19:57:27.576
    System.out.println(localDateTime1);//2020-10-22T19:57:27.576//增加天数
    LocalDateTime localDateTime2 = localDateTime.plusDays(3);
    System.out.println(localDateTime2);//2020-10-07T19:57:27.576
    

Instant

  1. 时间线上的一个瞬时点
public static void test6() {//需要考虑时区,获取本初子午线对应的标准时间Instant instant =Instant.now();System.out.println(instant);//2020-10-04T12:02:45.416Z//根据时区去添加偏移量,+8OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.ofHours(8));System.out.println(offsetDateTime);//2020-10-04T20:05:48.240+08:00}

DateTimeFormatter

  1. 格式化日期
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
String format = dateTimeFormatter.format(LocalDateTime.now());
System.out.println(format);//2020/10/04 20:15:58

System类

public static void test1(){long l = System.currentTimeMillis();//时间戳System.out.println(l);//1601801988015自1970.1.1 00:00:00开始到现在的时间差msString s = System.getProperty("java.version");System.out.println(s);//1.8.0_202String s1 = System.getProperty("java.home");System.out.println(s1);//C:\Program Files\Java\jdk1.8.0_202\jre}

Math类

public static void test01(){int i = Math.abs(-1);//绝对值double v = Math.sqrt(16);//平方根double v1 = Math.pow(3, 3);//3*3*3double v2 = Math.log(27);//自然对数double v3 = Math.exp(2);//e为底的指数double v4 = Math.random();//0-1随机数System.out.println(i);//1System.out.println(v);//4.0System.out.println(v1);//27.0System.out.println(v2);//3.295836866004329System.out.println(v3);//7.38905609893065System.out.println(v4);//0.41071285585678285}

BigInteger及BigDecimal

一般的float和double在进行商业计算的时候会有精度的损失,所有一般不使用浮点数,因此就出现BigDecimal类来进行高精度的计算

import java.math.BigDecimal;

public static void test02(){BigDecimal bigDecimal = new BigDecimal(1635.16411);BigDecimal bigDecimal1 = new BigDecimal(515);//ROUND_CEILING四舍五入System.out.println(bigDecimal.divide(bigDecimal1,BigDecimal.ROUND_CEILING));//3.175075941747572693043587349572227996529885
}

比较器

  1. 由于对象只能使用==或者!=,不能使用>或者<;所以需要比较对象的大小,就有了以下两个比较类;

  2. 像String和包装类就实现了Comparable接口,重写了compareTo()方法,给出了比较两个对象大小的方式;

  3. 对于自定义类,如果需要进行排序,那么就需要自己实现Comparable接口和重写compareTo()。

    指明compareTo(obj)按照什么方式排序。

Comparable

Comparator

集合

Collection

  1. Collection类的常用方法

    public static void test03(){Collection<Object> objects = new ArrayList<>();//add()objects.add("123");objects.add(123);objects.add("aa");objects.add("bb");objects.add(new Date());System.out.println(objects.size());//5System.out.println(objects);//[123, 123, aa, bb, Sun Oct 04 21:31:28 CST 2020]System.out.println(objects.isEmpty());//falseSystem.out.println(objects.contains("123"));//trueSystem.out.println(objects.remove(123));//trueSystem.out.println(objects.hashCode());//1250521029Object[] objects1 = objects.toArray();//集合转换为数组StringBuilder stringBuilder = new StringBuilder();stringBuilder.append("[");for (int i = 0; i <objects1.length ; i++) {if(i<objects1.length-1){stringBuilder.append(objects1[i]+",");}else{stringBuilder.append(objects1[i]);}}stringBuilder.append("]");System.out.println(stringBuilder);//[123,aa,bb,Sun Oct 04 21:47:25 CST 2020]}}
    

    contains是比较内容,而不是比较的是对象。

  2. Iterator迭代器

    • 用于变量容器中的元素
    //初始化
    Iterator<Object> iterator = objects.iterator();//遍历元素
    //方式一for (int i = 0; i <objects.size() ; i++) {System.out.print(iterator.next()+"\t");//123    aa  bb  Sun Oct 04 21:59:40 CST 2020}//方式二while (iterator.hasNext()){System.out.print(iterator.next()+"\t");//123    aa  bb  Sun Oct 04 21:59:40 CST 2020}
    
  3. for-each(增强for循环)遍历集合或者数组

     for(Object obj:objects){System.out.print(obj+"\t");//123 aa  bb  Sun Oct 04 22:04:41 CST 2020}
    

List

List接口是Collection的子接口,存储有序的,可重复的数据。

ArrayList、LinkedList、Vector均是List接口的实现类

但是ArrayList是List接口的主要实现类,Vector是最老旧的,基本上是不用的

  1. 三者之间的区别:

    1. ArrayList:线程是不安全的,但是效率高
    2. LinkedList:对于频繁插入和删除操作,效率比ArrayList高
    3. Vector:线程是安全的,但是效率极低。
  2. 相同点:三者均实现List接口,存储数据的特点:存储有序可重复的数据。

  3. ArrayList常用方法:

    public static void test04(){List<Object> objects = new ArrayList<>();List<Object> objects1 = new LinkedList<>();List<Object> objects2 = new Vector<>();//添加数据objects.add(1);objects.add(2);objects.add(3);objects.add(4);System.out.println(objects.get(2));//3 获取索引2处的数据System.out.println(objects.set(2, 5));//3 修改数据System.out.println(objects);//[1, 2, 5, 4]System.out.println(objects.remove(3));//4 移除索引为3处的数据System.out.println(objects.indexOf(1));//0 数据第一次出现的位置//遍历Iterator<Object> iterator = objects.iterator();while (iterator.hasNext()){System.out.print(iterator.next());//125}}
    

Set

Set是Collection的另一个子接口,是存储无序的,不可重复的数据

Set的三个主要实现类:HashSet、LinkedHashSet、TreeSet

  1. 三者之间的区别:

    1. HashSet:作为Set的主要实现类,线程不安全的,可以存储null值
    2. LinkedHashSet:作为HashSet的子类,遍历其内部数据时可以按照添加的顺遍历
    3. TreeSet:存储数据必须是同一个类new的数据,可以根据添加对象的属性进行排序
  2. HashSet常用方法:

    全是Collection中存在的方法;

     HashSet<Object> objects = new HashSet<>();//添加数据objects.add(1);objects.add(3);objects.add(4);objects.add(6);objects.add("AA");//遍历Iterator<Object> iterator = objects.iterator();while (iterator.hasNext()){System.out.print(iterator.next());//AA1346}
    

    无序性不等于随机性;最终遍历的结果并不是按照插入的顺序遍历的,数据存储的顺序是按照哈希值存储的。

Map

存储双列数据,存储Key-Value对数据

Map的主要实现类:HashMap、HashTable、LinkedHashMap、TreeMap

  1. 实现类之间的区别:

    1. HashMap:Map的主要实现类,线程不安全的,但是效率是最高的;可以存储Null的键值对;
    2. HashTable:最古老的实现类,线程是安全的,但是效率是最低的;不能存储Null的键值对;
    3. LinkedHashMap:是HashMap的子类,在原有的HashMap基础上,添加了一堆指针,在频繁进行插入删除操作的时候,使用该类,效率较高;
    4. TreeMap:保证添加的键值对进行排序,实现排序遍历;是按照Key来排序的;
  2. Map中常用的方法

    public static void test06(){Map hashMap = new HashMap<>();System.out.println(hashMap);//{}//插入hashMap.put("name","李思聪");hashMap.put("age",22);hashMap.put("sex","男");//修改hashMap.put("name","李四");//移除hashMap.remove("name");System.out.println(hashMap);//{sex=男, age=22}System.out.println(hashMap.get("sex"));//男}
    

Collections工具类

Collection和Collections的区别

Collection是集合类的上级接口,继承与他有关的接口主要有List和Set,Collections是针对集合类的一个帮助类,他提供一系列静态方法实现对各种集合的搜索、排序、线程安全等操作

Collections常用方法:

public static void test07() {ArrayList list = new ArrayList();list.add(12);list.add(13);list.add(22);list.add(15);list.add(2);list.add(90);System.out.println(list);//[12, 13, 22, 15, 2, 90]Collections.reverse(list);//翻转System.out.println(list);//[90, 2, 15, 22, 13, 12]Collections.shuffle(list);//随机化System.out.println(list);//[2, 22, 15, 13, 90, 12]Collections.sort(list);//排序System.out.println(list);//[2, 12, 13, 15, 22, 90]Collections.swap(list, 1, 2);//交换制定索引数据System.out.println(list);//[2, 13, 12, 15, 22, 90]// ArrayList dest = new ArrayList();//  Collections.copy(dest, list);//"main" java.lang.IndexOutOfBoundsException: Source does not fit inList dest=Arrays.asList(new Object[list.size()]);//声明dest容器大小为list的大小Collections.copy(dest,list);//copylist至destSystem.out.println(dest);//[2, 13, 12, 15, 22, 90]}

synchronizedXxxx(),该方法解决了多线程并发访问集合时的线程安全问题

//返回的list1是线程安全的
List list1 = Collections.synchronizedList(list);
System.out.println(list1);

泛型<>

为什么要使用泛型?

泛型就是一种约束!因为有了泛型,就用不着强制类型转换,在编译期间,编译器就能对类型进行检查,杜绝了运行时由于强制类型转换导致的错误;提高java代码的安全性

 ArrayList<Integer> list = new ArrayList<>();
// ArrayList<Integer> list = new ArrayList<Integer>();//只能添加int类型数据list.add(12);list.add(13);list.add(22);list.add(15);list.add(2);list.add(90);for(int ints:list){//避免了强转int score=ints;System.out.println(score);}

IO流

IO流原理及流的分类

  1. 按照数据单位分为:字节流(8bit)、字符流(16bit=char(一个字符))

  2. 按照流的流向分为:输入、输出流

  3. 按照角色不同分为:节点流、处理流

    java中IO流涉及40多个类,但是都是从如下四个抽象基类派生的

抽象基类 字节流 字符流
输入流 InputStream Reader
输出流 OutputStream Writer
抽象基类 节点流(文件流) 缓冲流(处理流的一种) 转换流(处理流的一种)
InputStream FileInputStream BufferedInputStream InputStreamReader
OutputStream FileOutputStream BufferedOutputStream OutputStreamWriter
Reader FileReader BufferedReader
Writer FileWriter BufferedWriter

流的读写操作

字符流

  1. 读取一个文件中的内容:
 public static void test01(){//实例化对象,创建一个文件hello.txtFile file = new File("G:\\idea\\java\\java01\\src\\com\\simon\\demo04\\hello.txt");System.out.println(file.exists());//提供具体的流FileReader fileReader = null;try {fileReader = new FileReader(file);//数据的读入,如果没有数据则返回-1int read = 0;//遍历while ((read=fileReader.read()) != -1){System.out.print((char)read);//HelloWorld}} catch (IOException e) {e.printStackTrace();}finally {try {//关闭流操作fileReader.close();} catch (IOException e) {e.printStackTrace();}}}
  1. read()的理解:返回读入的字符,如果达到文件的末尾,则返回-1;

  2. 异常的处理:为了保证流资源一定可以执行关闭操作,所以就需要使用try—catch—finally去处理。

  3. 必须保证文件存在,如果不存在就会报异常。

另外一种方式读取内容:read(char[] cbuf)

public static void test02(){//实例化对象,创建一个文件hello.txtFile file = new File("G:\\idea\\java\\java01\\src\\com\\simon\\demo04\\hello.txt");System.out.println(file.exists());//提供具体的流FileReader fileReader = null;try {fileReader = new FileReader(file);//数据的读入,如果没有数据则返回-1//定义一个char类型的数组,长度=5char[] cbuf=new char[5];int read = 0;//使用read(char[] cbuf)方法//遍历while ((read=fileReader.read(cbuf)) != -1){//使用for()遍历for (int i = 0; i <read ; i++) {System.out.print(cbuf[i]);//HelloWorld123}}} catch (IOException e) {e.printStackTrace();}finally {try {//关闭流操作fileReader.close();} catch (IOException e) {e.printStackTrace();}}}
  1. 写出数据到文件中
public static void test03(){//实例化对象,创建一个文件hello.txtFile file = new File("G:\\idea\\java\\java01\\src\\com\\simon\\demo04\\hello1.txt");System.out.println(file.exists());//提供具体的流,FileWriterFileWriter fileWriter =null;try {fileWriter = new FileWriter(file,true);//写出数据fileWriter.write("Hello,Hi,are you okay?");//Hello,Hi,are you okay?Hello,Hi,are you okay?} catch (IOException e) {e.printStackTrace();}finally {//关闭流操作try {fileWriter.close();} catch (IOException e) {e.printStackTrace();}}}

说明:

  1. 如果写入的文件不存在,那么就会自动创建一个文件再写入;
  2. 如果存在的情况下,fileWriter = new FileWriter(file,true);如果是false那么就会对原有的文件进行覆盖;如果是true那么就会在后面持续的写入。

字节流

  1. 如果进行非文本文件的输入输出的话,那么字符流就不行了,这时就需要使用字节流来操作了

    public static void test05(){FileInputStream inputStream = null;FileOutputStream outputStream = null;try {//实例化file对象,File file1 = new File("G:\\idea\\java\\java01\\src\\com\\simon\\demo04\\timg.jpg");File file2 = new File("G:\\idea\\java\\java01\\src\\com\\simon\\demo04\\timg1.jpg");//创建流对象
    //            fileReader = new FileReader(file1);
    //            fileWriter = new FileWriter(file2);inputStream = new FileInputStream(file1);outputStream = new FileOutputStream(file2);//读写操作byte[] buffer=new byte[5];int data;while ((data=inputStream.read(buffer))!=-1){for (int i = 0; i <data ; i++) {//                    System.out.print(buffer[i]);
    //                    fileWriter.write(cbuf[i]);}outputStream.write(buffer,0,data);}} catch (IOException e) {e.printStackTrace();} finally {//关闭流操作try {outputStream.close();inputStream.close();} catch (IOException e) {e.printStackTrace();}}}
    

缓冲流

缓冲流是处理流的一种;

主要作用:提高流的读取、写入的效率;

  1. 缓冲字节流:
public static void test06(){FileInputStream inputStream = null;FileOutputStream outputStream = null;BufferedInputStream bufferedInputStream = null;BufferedOutputStream bufferedOutputStream = null;try {//实例化file对象,File file1 = new File("G:\\idea\\java\\java01\\src\\com\\simon\\demo04\\timg.jpg");File file2 = new File("G:\\idea\\java\\java01\\src\\com\\simon\\demo04\\timg2.jpg");//创建流对象
//            fileReader = new FileReader(file1);
//            fileWriter = new FileWriter(file2);inputStream = new FileInputStream(file1);outputStream = new FileOutputStream(file2);//创建缓冲流对象bufferedInputStream = new BufferedInputStream(inputStream);bufferedOutputStream = new BufferedOutputStream(outputStream);//读写操作byte[] buffer=new byte[5];int data;while ((data=bufferedInputStream.read(buffer))!=-1){//                for (int i = 0; i <data ; i++) {//                    System.out.print(buffer[i]);
//                    fileWriter.write(cbuf[i]);
//                }bufferedOutputStream.write(buffer,0,data);}} catch (IOException e) {e.printStackTrace();} finally {//关闭流操作try {bufferedInputStream.close();bufferedOutputStream.close();outputStream.close();inputStream.close();} catch (IOException e) {e.printStackTrace();}}}
  1. 缓冲字节流,调用方法,计算耗时:
public static void copyStream(String srcPath,String destPath){FileInputStream inputStream = null;FileOutputStream outputStream = null;BufferedInputStream bufferedInputStream = null;BufferedOutputStream bufferedOutputStream = null;try {//实例化file对象,File file1 = new File(srcPath);File file2 = new File(destPath);//创建流对象
//            fileReader = new FileReader(file1);
//            fileWriter = new FileWriter(file2);inputStream = new FileInputStream(file1);outputStream = new FileOutputStream(file2);//创建缓冲流对象bufferedInputStream = new BufferedInputStream(inputStream);bufferedOutputStream = new BufferedOutputStream(outputStream);//读写操作byte[] buffer=new byte[5];int data;while ((data=bufferedInputStream.read(buffer))!=-1){//                for (int i = 0; i <data ; i++) {//                    System.out.print(buffer[i]);
//                    fileWriter.write(cbuf[i]);
//                }bufferedOutputStream.write(buffer,0,data);}} catch (IOException e) {e.printStackTrace();} finally {//关闭流操作try {bufferedInputStream.close();bufferedOutputStream.close();outputStream.close();inputStream.close();} catch (IOException e) {e.printStackTrace();}}}public static void main(String[] args) {long l1 = System.currentTimeMillis();String srcPath="G:\\idea\\java\\java01\\src\\com\\simon\\demo04\\timg.jpg";String destPath="G:\\idea\\java\\java01\\src\\com\\simon\\demo04\\timg3.jpg";copyStream(srcPath,destPath);long l2 = System.currentTimeMillis();System.out.println(l2-l1);//10ms}
  1. 缓冲字符流,有一个新的读取方法:
public static void test07(){BufferedReader bufferedReader = null;BufferedWriter bufferedWriter = null;try {//创建缓冲流、字符流、实例化文件bufferedReader = new BufferedReader(new FileReader(new File("G:\\idea\\java\\java01\\src\\com\\simon\\demo04\\hello.txt")));bufferedWriter = new BufferedWriter(new FileWriter(new File("G:\\idea\\java\\java01\\src\\com\\simon\\demo04\\hello4.txt")));//读取数据char[] cbuf = new char[20];String data;//readLine()读取一行的方法while ((data=bufferedReader.readLine()) != null){bufferedWriter.write(data);bufferedWriter.newLine();//换行操作}} catch (IOException e) {e.printStackTrace();} finally {try {//关闭流操作bufferedWriter.close();bufferedReader.close();} catch (IOException e) {e.printStackTrace();}}}

转换流

字符集:

字符集 说明
ASCII 美国标准信息交换码,一个字节的七位可以表示
ISO8859-1 拉丁码表、欧洲码表,用一个字节的八位表示
GB2312 中国的中文编码表,最多2个字节编码所有的字符
GBK 中国的中文编码表的升级,融合更多的中文字符,最多2个字节编码
Unicode 国际编码表,融合目前人类所有的字符,为每一个字符分配唯一的字符码.
UTF-8 变长的编码方式,可以用1-4个字节来表示字符。
  1. 转换流提供字节和字符之间的转换;

  2. 也是属于处理流的一种;

    InputStreamReader:将InputStream转换为Reader

    OutputStreamWriter:将Writer转换为OutputStream

  3. 很多时候我们通过转换流来处理文件乱码的问题,实现编码和解码的功能;

  4. InputStreamReader:将InputStream转换为Reader:

 public static void test08(){FileInputStream fileInputStream = null;InputStreamReader inputStreamReader= null;try {fileInputStream = new FileInputStream(new File("G:\\idea\\java\\java01\\src\\com\\simon\\demo04\\hello.txt"));inputStreamReader = new InputStreamReader(fileInputStream,"UTF-8");char[] cbuf=new char[20];int data;while ((data=inputStreamReader.read(cbuf)) != -1){//                for (int i = 0; i < data; i++) {//                    System.out.print(cbuf[i]);
//                }String str = new String(cbuf,0,data);System.out.print(str);}} catch (IOException e) {e.printStackTrace();} finally {try {inputStreamReader.close();} catch (IOException e) {e.printStackTrace();}}}
  1. OutputStreamWriter:将Writer转换为OutputStream:
public static void test09(){InputStreamReader inputStreamReader = null;OutputStreamWriter outputStreamWriter = null;try {inputStreamReader = new InputStreamReader(new FileInputStream(new File("G:\\idea\\java\\java01\\src\\com\\simon\\demo04\\hello.txt")),"utf-8");outputStreamWriter = new OutputStreamWriter(new FileOutputStream(new File("G:\\idea\\java\\java01\\src\\com\\simon\\demo04\\hello5.txt")),"gbk");//读取操作char[] cbuf=new char[20];int len;while ((len = inputStreamReader.read(cbuf)) != -1){//            String str = new String(cbuf,0,len);outputStreamWriter.write(cbuf,0,len);}} catch (IOException e) {e.printStackTrace();} finally {try {outputStreamWriter.close();} catch (IOException e) {e.printStackTrace();}try {inputStreamReader.close();} catch (IOException e) {e.printStackTrace();}}}

标准输入、输出流

System.in

System.out

练习:要求键盘输入一串字符,使用System.in,然后在控制台输出对应的大写形式,当输入"e" OR "exit"退出程序!

public static void test01(){InputStreamReader isr = null;BufferedReader br = null;try {//将输入的字节转换为字符串isr = new InputStreamReader(System.in);//造流br = new BufferedReader(isr);//读取while (true){System.out.println("请输入字符串:");//读取操作String data = br.readLine();if (data.equalsIgnoreCase("e") || data.equalsIgnoreCase("exit")){System.out.println("程序结束!");break;}//转大写String str = data.toUpperCase();System.out.println(str);}} catch (IOException e) {e.printStackTrace();} finally {try {br.close();} catch (IOException e) {e.printStackTrace();}try {isr.close();} catch (IOException e) {e.printStackTrace();}}}

对象流

ObjectInputStream

ObjectOutputStream

作用:用于读取或存储基本数据类型数据或对象的处理流。他的强大之处在于能够将java中的对象写入到数据源中,也可以将对象从数据源中还原出来。

  1. 序列化:用ObjectOutputStream类保存基本类型数据或对象的机制
  2. 反序列化:用ObjectInputStream类读取基本类型数据或对象的机制

注意:

  1. ObjectInputStream和ObjectOutputStream不能序列化static和transient修饰的成员变量;

  2. 自定义序列化需要对序列化的类,实现Serializable接口方可进行序列化;

  3. 还需要定义一个全局常量:public static final long serialVersionUID = 586451352156L;

  4. 除了当前类需要实现Serializable接口,还需要保证其他内部所有的属性皆实现Serializable接口,才可进行序列化操作,(基本数据类型是底层已经实现Serializable接口,可直接序列化)。

序列化:使用ObjectOutputStream

public static void test02() {ObjectOutputStream oos = null;try {oos = new ObjectOutputStream(new FileOutputStream("hello6.txt"));oos.writeObject(new String("我的名字叫simon!"));//刷新操作oos.flush();oos.writeObject(new Person("李思聪",22,"man"));oos.flush();} catch (IOException e) {e.printStackTrace();} finally {try {oos.close();} catch (IOException e) {e.printStackTrace();}}}

反序列化:使用ObjectInputStream

public static void test03(){ObjectInputStream ois = null;try {ois = new ObjectInputStream(new FileInputStream("hello6.txt"));Object object = (String)ois.readObject();Object o = (Person)ois.readObject();System.out.println(object);System.out.println(o);} catch (IOException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();} finally {try {ois.close();} catch (IOException e) {e.printStackTrace();}}

多线程

基本概念

程序:为完成特定任务,用某种语言编写的一组指令的集合,及一段静态的代码,静态对象。

进程:程序的一次执行过程,或正在运行的一个程序。是一个动态的过程:有他自身的产生、存在和消亡 的过程——生命周期

  1. 如运行的QQ、运行的MP3播放器
  2. 程序是静态的,进程是动态的
  3. 进程是作为资源分配的单位:系统运行时会为每个进程分配不同的内存区域

线程:进程可以细化为线程,是程序内部的一条执行路径

  1. 若一个进程同一时间并行执行多个线程,就是支持多线程的
  2. 线程作为调度和执行的单位,每个线程拥有独立的运行栈和程序计数器(pc),线程切换的开销小
  3. 一个进程中多个线程共享相同的内存单元/内存地址空间——他们从同一堆中分配对象,可以访问相同的变量和对象。

并行和并发

  1. 并行:多个cpu同时执行多个任务
  2. 并发:一个cpu同时执行多个任务

多线程的优点

  1. 提高应用程序的响应,对图形化界面更有意义,可增强用户体验;
  2. 提高计算机系统cpu利用率;
  3. 改善程序结构,将进程分为多个线程,独立运行,便于理解和修改;

线程的创建和使用

多线程的创建(方式一)

  1. 创建一个继承Thread类的子类

  2. 重写Thread类中run()——>针对于此线程需要执行的操作写于run()中

  3. 创建Thread类子类的对象

  4. 通过此方法调用start()

    package com.simon.demo05;public class Test04 {public static void main(String[] args) {//创建对象Method method = new Method();Method1 method1 = new Method1();//调用start()method.start();method1.start();}}
    //1.继承Thread
    class Method extends Thread{//重写run()@Overridepublic void run() {//需要执行的操作for (int i = 0; i <1000 ; i++) {if(i%2==0){System.out.println(i);}}}
    }class Method1 extends Thread{@Overridepublic void run() {for (int i = 0; i <1000; i++) {if(i%2!=0){System.out.println(i);}}}
    }
    

注意:

  1. 不能使用实例化对象去调用run(),这样就没有开启新线程,此时还是主线程运行的。
  2. 不能使用同一个对象去调用多个start(),可以使用多个对象去调用start()。

Thread类中的常用方法

  1. start():启动当前线程,调用当前线程的run();
  2. run():重写Thread类的run(),将执行的操作放在里面;
  3. join():在线程a中调用b.join(),那么线程a就进入阻塞状态;直至b线程执行完毕;a线程才解除阻塞状态;
  4. yield():礼让,释放该线程的cpu执行权;
  5. currentThread():静态方法,返回当前代码的线程;
  6. getName():获取当前线程的名字;
  7. setName():设置当前线程的名字;
  8. sleep():让当前线程"睡眠"指定 的毫秒数,指定的睡眠时间内,该线程进入阻塞状态;
  9. stop():已过时,强制结束当前线程。
  10. isAlive():判断该线程是否存活。

sleep()和wait()的异同

相同:一旦执行线程均进入阻塞状态;

不同:

  1. 两个方法声明的位置不同;

  2. 调用的范围和要求不同;sleep()不限制,而wait()必须使用在同步代码块或同步方法中;

  3. 如果两个方法均使用在同步代码块或同步方法中,sleep()不会释放锁,但是wait()会释放锁‘

线程的调度(优先级)

  1. 优先级常量:

    public final static int MAX_PRIORITY = 10;
    public final static int NORM_PRIORITY = 5;
    public final static int MIN_PRIORITY = 1;
    
  2. 如何设置和获取当前线程的优先级

    myThread.setPriority(Thread.MAX_PRIORITY);
    int priority = myThread.getPriority();
    

注意:设置优先级之后,不一定一定先执行,只是从概率上讲,优先级高的先执行。

多线程的创建(方式二)

  1. 实现Runnable接口

    • 创建一个继承Runnable类的子类
    • 重写Runnable类中run()——>针对于此线程需要执行的操作写于run()中
    • 创建Runnable类子类的对象
    • 将此对象作为参数传递到Tread类的构造器中,创建Thread类的对象
    • 通过Thread类对象调用start()
package com.simon.demo05;public class Test06 {public static void main(String[] args) {//创建对象MyThread1 myThread1 = new MyThread1();//将myThread作为参数传递给Thread类的构造器,在调用start()//start():1.启动线程;2.调用当前线程的run()new Thread(myThread1).start();}
}//实现Runnable接口
class MyThread1 implements Runnable{//重写run()@Overridepublic void run() {for (int i = 0; i < 1000; i++) {if (i % 2 == 0) {System.out.println(Thread.currentThread().getName() + "---" + Thread.currentThread().getPriority()+ "---" + i);}}}
}

比较创建线程的两种方式

  1. 优先选择实现Runnable接口方式:

    • 实现方式没有类的单一继承的局限性;
    • 实现方式更适合来处理多个线程有共享数据的情况。
  2. 联系:

    • Thread类也是实现了Runnable接口;
    • 无论是哪种方式都需要重写run(),执行的操作均写在run()中。

java5.0新增的多线程创建方式

方式一

1. 实现Callable接口

与使用Runnable相比,Callable更加的强大:

  1. 相比run(),可以有返回值;
  2. 方法可以抛出异常;
  3. 支持泛型的返回值;
  4. 需要借助FutureTask类,比如获取返回结果;
package com.simon.demo05;import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;public class Test08 {public static void main(String[] args) {//创建对象MyThread3 myThread3 = new MyThread3();//创建FutureTask对象FutureTask futureTask = new FutureTask(myThread3);//启动线程new Thread(futureTask).start();try {//返回重写call()中的返回值sumObject o = futureTask.get();System.out.println("总和为"+o);} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}}
}
class MyThread3 implements Callable{@Overridepublic Object call() throws Exception {int sum=0;for (int i = 0; i <100 ; i++) {if (i % 2 ==0){sum += i;System.out.println(i);}}return sum;}
}

步骤:

 1. 创建实现Callable接口的类2. 实现call(),将此线程的执行操作写在call()中3. 创建实现类的对象4. 将此对象作为参数传递到FutureTack构造器中,创建FutureTack对象5. 将FutureTack对象作为参数传递到Thread类的构造器中,创建Thread类的对象,调用start()6. 获取返回值的方法:使用FutureTack对象去调用get()。

2. 使用线程池的方式

​ 思路:提前创建好多个线程,放入线程池中,使用时直接获取,使用完放回池中,可以避免频繁调用和销毁,实现重复利用。

​ 好处:

             1. 提高响应速度(减少创建线程的时间)2. 降低资源消耗(重复利用线程池中的线程,不需要每次创建)3. 便于线程管理
package com.simon.demo05;import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class ThreadPool {public static void main(String[] args) {//工具类,创建不同类型的线程池//此时可以 实现十个线程ExecutorService service = Executors.newFixedThreadPool(10);//new 实现Runnable接口对象MyThread4 myThread4 = new MyThread4();MyThread5 myThread5 = new MyThread5();//适合使用与Runnableservice.execute(myThread4);service.execute(myThread5);//        service.submit(Callable callable);//关闭线程池service.shutdown();//适合使用与Callable}
}
class MyThread4 implements Runnable {@Overridepublic void run() {for (int i = 0; i <100 ; i++) {if (i % 2 ==0){System.out.println(Thread.currentThread().getName()+"---"+i);}}}
}class MyThread5 implements Runnable {@Overridepublic void run() {for (int i = 0; i <100 ; i++) {if (i % 2 !=0){System.out.println(Thread.currentThread().getName()+"---"+i);}}}
}

步骤:

1. 使用Executors工具类创建指定数量的线程池:ExecutorService service = Executors.newFixedThreadPool(10);返回对象service
2. 创建实Runnable接口的类的对象
3. 将实现类对象作为参数传递到service.execute()中去,开启线程。

线程的生命周期

实现多线程,在他的完整的生命周期中通常往往经历了如下的五种状态:

  1. 新建:new Thread()之后,此线程对象就处于新建状态;
  2. 就绪:处于新建状态的对象,在调用start()之后,就处于就绪状态,等待cpu分配资源;
  3. 运行:就绪状态下的线程,被调度并分配了cpu资源,此时便进入运行状态;
  4. 阻塞:在某种特殊情形下,被人为的执行或挂起输入输出操作,就进入阻塞状态;
  5. 死亡:线程执行完毕便消亡,或者强制停止、异常导致终止也消亡。

线程的同步

主要就是解决线程安全的问题;

线程不安全出现的原因

当某个线程还未执行完毕,另一个线程就进来了,导致出现重票问题
解决:通过同步机制来解决线程安全问题

同步机制的两种方式:

  1. 同步代码块
    synchronized(同步监视器){
    //需要被同步的代码
    }
    说明:

    1. 操作共享数据的代码,即为需要被同步的代码
    2. 共享数据:多个线程需要共同操作的变量。比如ticket。
    3. 同步监视器:俗称"锁"。任何一个类的对象都可以充当锁。
      要求:多个线程必须共用同一个锁。
      我们可以考虑使用this充当同步监视器,此时的this对象唯一。
public class SaleTicket {public static void main(String[] args) {SaleTicketImp ticketImp = new SaleTicketImp();new Thread(ticketImp).start();new Thread(ticketImp).start();new Thread(ticketImp).start();}
}class SaleTicketImp implements Runnable {private int ticket = 100;//    Object obj = new Object();@Overridepublic void run() {//this指的是SaleTicketImp的对象ticketImp(此对象是唯一的)synchronized (this) {while (true) {try {Thread.currentThread().sleep(20);} catch (InterruptedException e) {e.printStackTrace();}if (ticket > 0) {System.out.println(Thread.currentThread().getName() + "抢到了第" + ticket + "张票");ticket--;} else {break;}}}}
}
  1. 同步方法
    如果需要执行的代码在一个方法中,那么就直接将此方法上锁
    注意:

    1. 同步方法依然还是使用的是同步监视器(this);
    2. 静态的同步方法,同步监视器指的是当前类本身。
    package com.simon.demo05;public class SaleTicket1 {public static void main(String[] args) {SaleTicketImp1 ticketImp = new SaleTicketImp1();new Thread(ticketImp).start();new Thread(ticketImp).start();new Thread(ticketImp).start();}
    }class SaleTicketImp1 implements Runnable {private int ticket = 100;@Overridepublic void run() {show();}//实际还是使用的是同步监视器(this)public synchronized void show(){while (true) {if (ticket > 0) {System.out.println(Thread.currentThread().getName() + "抢到了第" + ticket + "张票");ticket--;} else {break;}}}
    }
  2. 锁(Lock)

    jdk5.0后新特性:

    1. Lock锁:ReentrantLock lock = new ReentrantLock(true);

    问题:
    synchronized与lock的异同:

    相同:

    1. 二者均可以解决线程安全问题

    不同:

    1. synchronized机制在执行完相应的同步代码之后,自动的释放同步监视器

      1. Lock需要手动的去启动同步和释放同步:lock.lock();lock.unlock();

线程通信

线程通信实现交替打印

package com.simon.demo05;public class Test07 {public static void main(String[] args) {MyThread2 myThread2 = new MyThread2();new Thread(myThread2).start();new Thread(myThread2).start();new Thread(myThread2).start();}
}class MyThread2 implements Runnable{private int i=100;@Overridepublic void run() {while (true){synchronized (this) {//唤醒notifyAll();if(i>0){System.out.println(Thread.currentThread().getName()+"---"+i);i--;try {//进入阻塞wait();} catch (InterruptedException e) {e.printStackTrace();}}else {break;}}}}
}
  1. 涉及到的三个方法

    wait():一旦执行此方法,线程就进入阻塞状态,并释放同步监视器

    notify():一旦执行此方法,就会唤醒一个被wait()的线程;多个线程的话,就唤醒优先级高的线程

    notifyAll():一旦执行此方法,就会唤醒所有被wait()的线程

​ 说明:

  1. 上述三个方法必须使用在同步代码块或同步方法中,Lock()是不能使用的。
  2. 这三个方法的调用者必须是同步代码块中的同步监视器。

经典案例:生产者消费者问题

package com.simon.demo05;import static java.lang.Thread.sleep;public class ProductTest {public static void main(String[] args) {Clerk clerk = new Clerk();Producer p1 = new Producer(clerk);p1.setName("生产者");Customer c1 = new Customer(clerk);c1.setName("消费者");p1.start();c1.start();}
}//店员
class Clerk{//产品数量为0private int prodects = 0;//生产方法public synchronized void product() {if(prodects<20){//先加后输出prodects++;System.out.println(Thread.currentThread().getName()+"开始生产第"+prodects+"件产品");//唤醒notify();}else{//停止生产try {wait();} catch (InterruptedException e) {e.printStackTrace();}}}//消费者方法public synchronized void consume() {if(prodects>0){try {sleep(10);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+"开始消费产品第"+prodects+"件产品");//先输出后减prodects--;notify();//唤醒}else{//停滞try {wait();} catch (InterruptedException e) {e.printStackTrace();}}}
}
//生产者
class Producer extends Thread{//声明Clerk类变量clerkprivate Clerk clerk;//构造器public Producer(Clerk clerk) {this.clerk = clerk;}@Overridepublic void run() {System.out.println(getName()+":开始生产产品了----");while (true){//调用生产方法clerk.product();}}
}//消费者
class Customer extends Thread{//声明Clerk类变量clerkprivate Clerk clerk;//构造器public Customer(Clerk clerk) {this.clerk = clerk;}@Overridepublic void run() {System.out.println(getName()+":开始生消费产品了----");while (true) {//调用消费方法clerk.consume();}}
}

反射

Java反射机制

Java的反射(reflection)机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的,可以了解任意一个类的成员变量和方法可以调用任意一个对象的属性和方法。这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。反射被视为动态语言的关键

理解Class类及获取Class实例

  1. Class类:

    Class类(在java.lang包中,Instances of the class Classrepresent classes and interfaces in a running Javaapplication):

    在Java中,每个class都有一个相应的Class对象。也就是说,当我们编写一个类,编译完成后,在生成的.class文件中,就会产生一个Class对象,用于表示这个类的类型信息

  2. 获取Class实例的四种方式:

     @Testpublic void reflectTest(){//方式一,调用运行时类的属性,.classClass<Person> clazz1 = Person.class;System.out.println(clazz1);//class com.simon.demo04.Person//方式二,通过运行时类的对象调用getClass()Person p1 = new Person();Class clazz2 = p1.getClass();System.out.println(clazz2);//class com.simon.demo04.Person//方式三,调用Class的静态方法调用.forName(String Path)//此方式使用的多Class clazz3 = null;try {clazz3 = Class.forName("com.simon.demo04.Person");} catch (ClassNotFoundException e) {e.printStackTrace();}finally {System.out.println(clazz3);//com.simon.demo04.Person}//方式四,使用类加载器:ClassLoader()ClassLoader classLoader = Test01.class.getClassLoader();Class clazz4 = null;try {clazz4 = classLoader.loadClass("com.simon.demo04.Person");} catch (ClassNotFoundException e) {e.printStackTrace();}finally {System.out.println(clazz4);//com.simon.demo04.Person}
    

类的加载与ClassLoader的理解

  1. 类的加载:

    1、类的加载过程
    JVM将类的加载过程分为三个步骤:加载(Load),链接(Link)和初始化(Initialize)
    1)、加载:查找并加载类的二进制数据;
    2)、链接:验证:确保被加载类的正确性准备:为类的静态变量分配内存,并将其初始化为默认值解析:把类中的符号引用转换为直接引用
    3)、初始化:为类的静态变量赋予正确的初始值2、类的初始化,类什么时候才被初始化
    1)、创建类的实例,也就是new一个对象
    2)、访问某个类或接口的静态变量,或者对该静态变量赋值
    3)、调用类的静态方法
    4)、反射(Class.forName("com.vince.Dog"))
    5)、初始化一个类的子类(会首先初始化子类的父类)
    6)、JVM启动时标明的启动类,即文件名和类名相同的那个类3、类的加载器作用:
    值的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个这个类的Java.lang.Class对象,用来封装类在方法区类的对象。
    
  2. ClassLoader:

启动类加载器(Bootstrap ClassLoader):

这个类加载器负责将\lib目录下的类库加载到虚拟机内存中,用来加载java的核心库,此类加载器并不继承于java.lang.ClassLoader,不能被java程序直接调用,代码是使用C++编写的.是虚拟机自身的一部分.

扩展类加载器(Extendsion ClassLoader):

​ 这个类加载器负责加载\lib\ext目录下的类库,用来加载java的扩展库,开发者可以直接使用这个类加载器.

应用程序类加载器(Application ClassLoader):

这个类加载器负责加载用户类路径(CLASSPATH)下的类库,一般我们编写的java类都是由这个类加载器加载,这个类加载器是CLassLoader中的getSystemClassLoader()方法的返回值,所以也称为系统类加载器.一般情况下这就是系统默认的类加载器.

自定义类加载器

除此之外,我们还可以加入自己定义的类加载器,以满足特殊的需求,需要继承java.lang.ClassLoader类.

//自定义类,使用的是系统类加载器
ClassLoader classLoader = Test01.class.getClassLoader();//sun.misc.Launcher$AppClassLoader@18b4aac2
System.out.println(classLoader);
//其父类加载器是扩展类加载器
ClassLoader parent = classLoader.getParent();//sun.misc.Launcher$ExtClassLoader@8efb846
System.out.println(parent);
//无法获取引导类加载器
ClassLoader parent1 = parent.getParent();//null
System.out.println(parent1);

创建运行时类的对象

  1. 方法:

    newInstance()

Class<Person> clazz = Person.class;try {/*1. 调用newInstance(),创建对应的运行时类的对象2. 调用的还是类的空参构造器3. Person person = new Person();4. 创建的要求:1. 运行时类必须具备一个空参的构造器2. 空参的构造器的访问权限得够,通常情况下是public*/Person instance = clazz.newInstance();System.out.println(instance);//Person{name='null', age=0, sex='null'}} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}

反射的运用:动态代理

代理模式

为其他对象提供一个代理以控制对某个对象的访问。代理类主要负责为委托了(真实对象)预处理消息、过滤消息、传递消息给委托类,代理类不现实具体服务,而是利用委托类来完成服务,并将执行结果封装处理。

其实就是代理类为被代理类预处理消息、过滤消息并在此之后将消息转发给被代理类,之后还能进行消息的后置处理。代理类和被代理类通常会存在关联关系(即上面提到的持有的被带离对象的引用),代理类本身不实现服务,而是通过调用被代理类中的方法来提供服务。

静态代理

创建一个接口,然后创建被代理的类实现该接口并且实现该接口中的抽象方法。之后再创建一个代理类,同时使其也实现这个接口。在代理类中持有一个被代理对象的引用,而后在代理类方法中调用该对象的方法。

package com.simon.demo05;public class Test02 {public static void main(String[] args) {HelloProxy proxy = new HelloProxy();proxy.sayHello();}}//创建一个接口
interface Hello{void sayHello();
}//创建一个被代理类
class HelloImp implements Hello{@Overridepublic void sayHello() {System.out.println("Hello!");}
}//创建一个代理类
class HelloProxy implements Hello{HelloImp hello = new HelloImp();@Overridepublic void sayHello() {System.out.println("before sayHello");hello.sayHello();System.out.println("after sayHello");}
}

静态代理的缺点

使用静态代理很容易就完成了对一个类的代理操作。但是静态代理的缺点也暴露了出来:由于代理只能为一个类服务,如果需要代理的类很多,那么就需要编写大量的代理类,比较繁琐。

动态代理

利用反射机制在运行时创建代理类。
接口、被代理类不变,我们构建一个handler类来实现InvocationHandler接口。

动态代理底层实现

动态代理具体步骤:

  1. 通过实现 InvocationHandler 接口创建自己的调用处理器;
  2. 通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来创建动态代理类;
  3. 通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;
  4. 通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。

注解

理解注解(Annotation)

  1. jdk5.0新增的对元数据(MetaData)的支持,也就是Annotation;

  2. Annotation就是代码里的特殊标记,这些标记可以在编译、类加载、运行时被读取,并执行相应的处理;

  3. Annotation可以像修饰符一样被使用,可用于修饰包,类,构造器,方法,成员变量,参数,局部变量的声明。

  4. 实例一:生成文档的相关注解

    /*** @param* @throws**/
    /**** @return*/
    /***** @author* @since* @version***/
    
  5. 实例二:在编译时进行格式检查

    //抑制警告
    @SuppressWarnings(String[] value)
    //重写
    @Override
    //过时
    @Deprecated
    

    抑制警告的关键字:

    关键字 用途
    all to suppress all warnings
    boxing to suppress warnings relative to boxing/unboxing operations
    cast to suppress warnings relative to cast operations
    dep-ann to suppress warnings relative to deprecated annotation
    deprecation to suppress warnings relative to deprecation
    fallthrough to suppress warnings relative to missing breaks in switch statements
    finally to suppress warnings relative to finally block that don’t return
    hiding to suppress warnings relative to locals that hide variable
    incomplete-switch to suppress warnings relative to missing entries in a switch statement (enum case)
    nls to suppress warnings relative to non-nls string literals
    null to suppress warnings relative to null analysis
    rawtypes to suppress warnings relative to un-specific types when using generics on class params
    restriction to suppress warnings relative to usage of discouraged or forbidden references
    serial to suppress warnings relative to missing serialVersionUID field for a serializable class
    static-access to suppress warnings relative to incorrect static access
    synthetic-access to suppress warnings relative to unoptimized access from inner classes
    unchecked to suppress warnings relative to unchecked operations
    unqualified-field-access to suppress warnings relative to field access unqualified
    unused to suppress warnings relative to unused code

jdk中的元注解

概念:对现有的注解进行解释说明的注解

  1. @Retention:指明Annotation的生命周期,@Retention(RetentionPolicy.RUNTIME)

    • SOURCE
    • CLASS(默认)
    • RUNTIME,通过反射才能获取
  2. @Target:指明注解修饰的结构范围;
    • @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
  3. @Documented:修饰的Annotation类将被javadoc工具提取为文档,默认情况下,javadoc是不包含注解信息的
  4. @Inherited:使用了该注解,表明注解具有继承性了。

使用静态代理很容易就完成了对一个类的代理操作。但是静态代理的缺点也暴露了出来:由于代理只能为一个类服务,如果需要代理的类很多,那么就需要编写大量的代理类,比较繁琐。

动态代理

利用反射机制在运行时创建代理类。
接口、被代理类不变,我们构建一个handler类来实现InvocationHandler接口。

动态代理底层实现

动态代理具体步骤:

  1. 通过实现 InvocationHandler 接口创建自己的调用处理器;
  2. 通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来创建动态代理类;
  3. 通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;
  4. 通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。

注解

理解注解(Annotation)

  1. jdk5.0新增的对元数据(MetaData)的支持,也就是Annotation;

  2. Annotation就是代码里的特殊标记,这些标记可以在编译、类加载、运行时被读取,并执行相应的处理;

  3. Annotation可以像修饰符一样被使用,可用于修饰包,类,构造器,方法,成员变量,参数,局部变量的声明。

  4. 实例一:生成文档的相关注解

    /*** @param* @throws**/
    /**** @return*/
    /***** @author* @since* @version***/
    
  5. 实例二:在编译时进行格式检查

    //抑制警告
    @SuppressWarnings(String[] value)
    //重写
    @Override
    //过时
    @Deprecated
    

    抑制警告的关键字:

    关键字 用途
    all to suppress all warnings
    boxing to suppress warnings relative to boxing/unboxing operations
    cast to suppress warnings relative to cast operations
    dep-ann to suppress warnings relative to deprecated annotation
    deprecation to suppress warnings relative to deprecation
    fallthrough to suppress warnings relative to missing breaks in switch statements
    finally to suppress warnings relative to finally block that don’t return
    hiding to suppress warnings relative to locals that hide variable
    incomplete-switch to suppress warnings relative to missing entries in a switch statement (enum case)
    nls to suppress warnings relative to non-nls string literals
    null to suppress warnings relative to null analysis
    rawtypes to suppress warnings relative to un-specific types when using generics on class params
    restriction to suppress warnings relative to usage of discouraged or forbidden references
    serial to suppress warnings relative to missing serialVersionUID field for a serializable class
    static-access to suppress warnings relative to incorrect static access
    synthetic-access to suppress warnings relative to unoptimized access from inner classes
    unchecked to suppress warnings relative to unchecked operations
    unqualified-field-access to suppress warnings relative to field access unqualified
    unused to suppress warnings relative to unused code

jdk中的元注解

概念:对现有的注解进行解释说明的注解

  1. @Retention:指明Annotation的生命周期,@Retention(RetentionPolicy.RUNTIME)

    • SOURCE
    • CLASS(默认)
    • RUNTIME,通过反射才能获取
  2. @Target:指明注解修饰的结构范围;
    • @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
  3. @Documented:修饰的Annotation类将被javadoc工具提取为文档,默认情况下,javadoc是不包含注解信息的
  4. @Inherited:使用了该注解,表明注解具有继承性了。

JavaSE基础笔记(全)相关推荐

  1. JavaSE基础笔记——常用API、Lambda、常见算法

    日期与时间 时间日期是在任何一个程序系统里几乎都不可能忽略掉的数据量,而且大量的算法在底层都会使用到时间日期数据值作为算法的基本种子(随机数算法或加密算法都经常用到). 计算机里,时间日期的本质 作为 ...

  2. JavaSE基础笔记八

    第六章 异常处理 1.体系结构 java.lang.Object |----java.lang.Throwable |----java.lang.Error:错误,java程序对此无能为力,不显式的处 ...

  3. JavaSE基础笔记十二

    第十一章 多线程 理解程序.进程.线程的概念 程序可以理解为静态的代码. 进程可以理解为执行中的程序. 线程可以理解为进程的近一步细分,程序的一条执行路径. 2.如何创建java程序的进程(重点) 方 ...

  4. JavaSE基础笔记

    1.java 用==比较String 如果是基本类型,则比较值,如果是对象类型(引用类型),则比较内存地址 转载于:https://www.cnblogs.com/liboshi/p/4162715. ...

  5. [JavaSE基础笔记]Day10 石头迷阵实现

    目录 组件相关 其他 组件相关 对图片进行操作需要将图片的数据加载入数组中,即数组的数据作为图片的文件夹中的存放顺序 想要对源码加入新功能,可以采用继承技术(如:想要在JFrame中加入移动业务) t ...

  6. JavaSE基础笔记——不可变集合简介、Stream流体系、异常处理

    1.不可变集合简介 不可变集合,就是不可被修改的集合. 集合的数据项在创建的时候提供,并且在整个生命周期中都不可改变.否则报错. 为什么要创建不可变集合? 如果某个数据不能被修改,把它防御性地拷贝到不 ...

  7. JavaSE基础笔记——Javaoo(面向对象进阶:static与继承)

    1.Static: static是什么? 它是静态的意思,可以修饰成员变量和成员方法. static修饰成员变量表示该成员变量只在内存中只存储一份,可以被共享访问.修改. static修饰成员变量的用 ...

  8. JavaSE基础笔记—集合之Collection

    集合 数组的优缺点 1.集合.数组都是对多个数据进行存储操作的结构,简称Java容器. 说明:此时的存储,主要指的是内存层面的存储,不涉及到持久化的存储(.txt..jpg..avi.数据库). 2. ...

  9. javaSE基础——集合全面解析笔记

    javaSE基础--集合全面解析笔记 英文单词 一.容器定义 1.1.容器继承体系 二.Set--------容器类 部分方法数学集合意义 2.1 HashSet 2.1.1 基本用法 2.1.2 特 ...

最新文章

  1. 年仅 16 岁的黑客少年,竟是搅乱 IT 巨头的幕后主使?
  2. LINUX内核分析第四周——扒开系统调用的三层皮
  3. Nosql数据库之mongodb c++使用实例
  4. es head插件安装_ES笔记概述与安装
  5. mysql拆分字符串后行转列_mysql行转列(拆分字符串场景)
  6. jsoncpp判断Value中是否含有指定的key
  7. 杭州python爬虫招聘_python爬取招聘网站(智联,拉钩,Boss直聘)
  8. 小鹏汽车回应“侵犯消费者权益被罚3000元”:已于3月8日对购车协议内容进行调整...
  9. Nginx安装使用及与tomcat实现负载均衡
  10. c语言程序设计答案 第五版 谭浩强
  11. JS中动态创建元素的三种方法
  12. 使用vue-awesome-swiper制作H5动画页面
  13. [原创]python计算中文文本相似度神器
  14. 升级 glibc 到2.18版本
  15. 送礼蓝牙耳机哪款合适?2021最好的蓝牙耳机排行!
  16. 苹果电脑打印A4纸上纸盒的细线很浅
  17. 训练模型时候显存爆炸的一种可能性以及解决办法
  18. 霍兰德职业规划测试软件,发现你的职业兴趣——霍兰德职业兴趣测试
  19. 男生的头发,隔多长时间理一次发最适合
  20. Thymeleaf – Java静态页面模版框架

热门文章

  1. 敏捷宣言的内容及准则
  2. matlab乖离率计算,终于有人把“乖离率”说清楚了,看懂少走十年弯路!
  3. 滴滴云A100 GPU裸金属服务器性能及硬件参数详解
  4. 深入理解Java虚拟机小结
  5. 全志平台WiFi无法连接AP问题调试(1)问题分析
  6. 电路方案分析(十)2 端口 USB 3.0 集线器参考方案设计
  7. 阿里云应用身份服务IDaaS新升级,云原生、高安全,极致用户体验
  8. P1472 奶牛家谱 Cow Pedigrees
  9. java的虚引用_java虚引用的使用说明
  10. android os 1.5 下载地址,技德Remix OS 1.5发布 适配Android 5.0