【Java】JavaSE学习笔记

Python3.8

Python3.8

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

Dos命令

  1. 查看当前目录下文件(夹) dir
  2. 重定位 cd /d [对应目录(常用"\")]
  3. 退出 exit
  4. 查看ip ipconfig
  5. 文件操作
    • md 目录名
    • rd 目录名
    • cd> 文件名
    • del 文件名

基础概念

  1. JDK > JRE > JVM

    • JDK: Java Development Kit(JDK=JRE+开发工具)
    • JRE: Java Runtime Environment(JRE=JVM+核心类库)
    • JVM: Java Virtual Machine(真正运行Java程序的地方)
  2. Java运行机制

    • 编译型
    • 解释型
  3. IDE(Integrated Development Environment)

  4. 环境变量:在命令行寻找程序路径时的默认路径(类似于"JDK_HOME"使得能够在命令行任何位置执行默认程序)

对于Java,环境变量应该配置到java\jdk-xx\bin位置

  1. JAVA_HOME:告诉操作系统JDK安装在了哪个位置,JAVA_HOME应该配置到java\jdk-xx位置
  2. 一次编译,处处可用(由.java文件→.class文件后即可使用.class文件)
  3. Java项目代码结构:Project-Module-Package-Class

变量类型

float a = 50.1F; //float类型

long b = 10L; //long类型

boolean flag = true; 

不要用浮点数类型进行变量比较

类型转换

类型转换时采用直接舍入的方式

变量、常量

命名规范

类成员变量名、局部变量名、方法名:首字母小写 + 驼峰原则

类名:首字母大写 + 驼峰原则

常量:大写字母 + 间隔下划线

变量

boolean类型默认值是false

  1. 局部变量 从属于方法内部 可以直接在方法内访问
  2. 实例变量 从属于实例对象 需要创建实例后访问
  3. 类变量 从属于类(需要加static修饰)类内直接访问即可

常量

final 类型 常量名 = 值;

运算符

a=10;

b=20;
System.out.println(""+a+b);//输出1020
System.out.println(a+b+"");//输出30
  • 注意

==和equals()可以用于判断变量值是否相同,也可用于判断两个对象的的内存地址是否相同,但在String 类中,重写了 equals() 方法用于比较两个字符串的内容是否相等

逻辑运算符

  • & 逻辑与
  • | 逻辑或
  • ! 逻辑非
  • ^ 逻辑异或
  • && 短路与
  • || 短路或

可以有效防止命名空间重复

定义

package pkg1[.pkg2[.pkg3...]];  //通常采用域名倒置作为包名

导入

import pkg1[.pkg2...].(className|*);

JavaDoc

结合文档注释

/**

*@author:yabin

*/

命令行里 javadoc 参数 className.java 可以生成文档

输入输出

输入

需要用到Scanner类辅助输入

通常使用Scanner sc = new Scanner(System.in);定义并启用扫描器,使用sc.close();关闭扫描器

Scanner sc = new Scanner(System.in);

...

sc.close();

其中,使用sc.hasNext()/sc.hasNextLine()/sc.hasNextInt()/sc.hasNextDouble()来判断是否后续还有目标字符串/内容行/整数/浮点数

  • 区分

使用sc.next()[对空白符敏感] / sc.nextLine() / sc.nextInt() / sc.nextDouble() 来获取目标字符串/内容行/整数/浮点数

输出

通常情况下,要用到System.out中的方法

  • System.out.print(); 不带回车的输出
  • System.out.println(); 带回车的输出
  • System.out.printf()/format(); 格式化输出(类似C/C++)

程序流程

顺序结构

选择结构

  • if-else语句
  • switch-case语句

switch-case结构中存在“case穿透”的情况,所以需要根据情况加break语句

循环结构

  • while
  • do…while
  • for
  • 增强for(主要用于数组、集合的遍历访问)

for(类型 迭代变量:迭代对象){

}

数组

java中数组定义大小时,可以使用变量定义(区别于C/C++)

一维数组

数组声明
dataType[] arrayName;
数组初始化
  • 静态初始化
 arrayName = {val1, val2, val3, ...}
  • 动态初始化
 arrayName = new dataType[arraySize];
获取数组长度

数组的长度是确定的,不可变更。

如果越界会报异常ArrayIndexOutOfBounds

arrayName.length
内存分析

dataType[] arrayName = new dataType[arraySize]中:

变量arrayName存放在栈中,对应开辟的数组单元存放在堆中(数组是引用类型)

二维数组

数组声明
dataType[] arrayName;
数组初始化
  • 静态初始化
arrayName = {{val1, val2, val3, ...},...,{val1, val2, val3, ...}}
  • 动态初始化
arrayName = new dataType[arrayRowSize][arrayColSize];

Arrays类

  • Arrays.fill(); //填充数组
Arrays.fill(arr,4);//给所有值赋值4
Arrays.fill(arr, 0,3,-1);//给第下标为0到下标为2的元素赋值-1
  • Arrays.sort(); //数组排序,可以自定义比较方法
Arrays.sort(int[] a);//全部元素排序
Arrays.sort(int[] a, int fromIndex, int toIndex);//指定部分元素排序
Arrays.sort(T[] a, Comparator<? Super T> c);//用Comparator接口实现自定义排序规则
  • Arrays.toString(); //打印数组中的内容

  • Arrays.equals(); //比较数组元素是否相等

Arrays.equals(int[] a, int[] b); //比较数组元素是否相等
  • Arrays.copeOf() 、Arrays.copeOfRange(); //截取数组
int[] arr1 = Arrays.copyOf(arr, 3);//截取arr数组的前3个元素给新数组arr1
int[] arr1 = Arrays.copyOfRange(arr,1,3);//截取arr数组下标为1到下标为2的元素给新数组arr1

常用类

当前时间类

JDK8前:

Date now = new Date();

SimpleDateFormat sdf = new SimpleDateFormat sdf("yyyy/MM/dd HH:mm:ss EEE a");//显示格式

String date = sdf.format(now);

JDK8后:
在这里插入图片描述

在这里插入图片描述

格式化:DateTimeFormatter

LocalDateTime now = LocalDateTime.now();

DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss EEE a");//显示格式

String date = dtf.format(now);

字符串类

  • String形式的常量字符串被视为字面量,在修改内容时不会修改该字面量内容,而是指向新的字面量值
  • StringBuilder形式的字符串被视为容器,字符串是可以改变的,且支持链式编程,更适合操作字符串

在这里插入图片描述

浮点数运算类

  • BigDecimal:用于解决浮点型计算时结果失真的问题,得到有限位结果

在这里插入图片描述

包装浮点型变量多用于提高运算位数;包装字符串型变量多用于提高运算精度

在这里插入图片描述

值得注意的是,如果在进行除法运算时,结果是无限小数需要指定精确位数及舍入模式

随机数相关类

  1. Random类

int num = new Random().nextInt(n);//生成一个介于[0,n)的随机整型值

double num = new Random().nextDouble();//生成一个介于[0,1.0)的随机浮点值Math类

  1. Math类

double num = Math.random();//返回[0,1)的伪随机小数

  • 生成a-b之间的随机数
int num = nextInt(b-a)+a;

面向对象OOP(Object-Oriented Programming)

本质:以类的方式组织代码,以对象的方式组织(封装)数据

特性:

  • 封装
  • 继承
  • 多态

Java的“传递”特性

  • Java 只有值传递,无论是基本类型还是对象类型,传递的都是副本
  • 对于对象类型,传递的是对象的引用的副本,通过该引用仍然可以确定对象的内存位置,进而通过该引用修改对象的内部状态

Java 内存结构(JVM 内存布局)

主要由:方法区(由本地内存分配)、堆(对象)、栈(引用变量)部分组成

对象通过引用来操作:栈->堆

方法

重载:方法名称必须相同,参数列表必须不同(个数不同/类型不同/参数排列顺序不同等),返回类型可以不同

可变长参数:在方法中设置不定数量的参数,可变参数用三个点(…)表示,放置在方法参数的类型前。

可变参数实际上是一个数组,允许传递任意数量的参数值。可变参数只能作为方法的最后一个参数,且一个方法最多只能有一个可变参数。在编译时,Java的可变参数会被编译器转型为一个数组

public static void test(int x, int... i){
	for(int index=0; index<i.length; index++){
		System.out.print(i[index]+“ ”);
	}
}
test(1,2,3,4,5);//输出结果为2 3 4 5 
注意事项
  • 静态方法只能调用静态方法;

  • 非静态方法既可以调用静态方法,也可以调用非静态方法

(因为静态方法属于类,而非静态方法属于类的对象,可以从存在时间的早晚思考问题)

同样地,如果想要调用某个方法:要么创建实例,通过实例调用该方法;要么将该方法改为static类型,直接通过类调用该方法

创建对象及初始化

创建对象
  • new关键字

使用new关键字创建时,除分配内存空间外,还会给创建好的对象进行默认的初始化及对类中构造器的调用

使用new关键字的本质是在调用构造器

  • this关键字

通常this代表当前的类,用于本类中的方法使用本类中的属性等

初始化

使用构造器可以初始化对象的值(alt+insert快捷键)

要求
  • 构造器与类同名

  • 没有返回值(void也不行)

注意
  • 类本身自带无参构造器
  • 若在自行定义有参构造后还要使用无参构造,需要显示地定义一个无参的构造
  • 通常结合this关键字使用
public Person(){
	this.name = "Ben";
}

public Person(String name){
	this.name = name;
}

封装

关键:属性私有,get/set

目标:禁止直接访问一个对象中数据的实际表示,只允许通过操作接口来访问

好处:

  1. 安全性、可维护性高
  2. 接口统一
  3. 隐藏实现细节(可以在get/set方法内进行判断、处理)

注意:get/set方法也可以结合重载使用(不同的参数列表)

继承

子类(派生类) extends 父类(基类)

  • Java中的类只有单继承,没有多继承

  • Java中,所以的类都直接或间接地继承Object类

修饰符

public>protected>default>private

  • public 任何类均可访问
  • protected 同一个包中的类/子类可访问
  • default 同一个包中的类可访问
  • private 仅本类可访问
super关键字

super用于访问父类的属性或调用父类的(构造)方法

注意事项
  • super只能出现在子类的(调用)方法中,且调用父类的构造方法时必须放在构造方法最前面
  • 区别于this(没有继承也可以使用),super只有在实现继承后才可以使用

重写

当父类中的方法无法满足需求时,子类可以重写该方法去覆盖使用父类的此方法

注意
  • 重写要求具有继承关系,子类才能重写父类的方法
  • 要求重写方法的名称、参数列表必须相同,方法体内部不同,修饰符的范围只可以扩大不能缩小,抛出异常的范围只可以缩小不能扩大

多态

条件
  • 有继承关系
  • 子类重写父类方法
  • 父类引用指向子类对象

定义格式:父类类型 变量名 = new 子类类型();

只有方法才具有“多态”特性,属性不具备

Father father = new Son(); <编译看左边,执行看右边>

  • 属性:该Father类的引用变量father指向的Son类对象的属性仍然是Father类中的字段(不是多态)

  • 方法:该Father类的引用变量father指向的Son类对象能执行的方法取决于Father类中定义的方法类型,但调用时执行的是Son类的方法体内容(要求Son类中重写了该方法)

注意

final型常量、static方法、private方法都不适用于多态特性

instanceof

用于判断对象是否是某个类或其子类的对象

引用变量 instanceof//返回值是boolean类型

代码块

  • 静态代码块

与类一起加载执行,并且静态代码块仅执行一次,常用于类的初始化

static{
	...
}
  • 实例代码块(构造代码块)

与对象初始化一起加载,每次调用构造器初始化对象,实例代码块都要自动触发执行一次,并且在构造方法前执行

{
	...
}

抽象类

使用关键字abstract对类/方法进行约束:继承抽象类需要强制重写抽象方法,否则必须同样定义为抽象类

  • 抽象类中可以没有抽象方法
  • 有抽象方法的类一定要声明为抽象类
注意
  • 抽象类:不能使用new关键字来创建对象,它是用来被继承的(但抽象类同样有构造器,当子类继承该抽象类后可以调用抽象类的构造器来确保父类的成员变量被正确初始化,同时也满足构造器链)
  • 抽象方法:只有方法的声明,没有方法的实现,它是用来被实现的

接口

使用关键字interface、implements

  • 与抽象类的作用类似,用于规定约束,实现该接口的类需要重写接口中的方法
  • 与抽象类的“单继承”特性区别,接口具有“多继承”特性

接口中的方法默认是public abstract修饰

接口中的字段默认是public static final修饰

内部类

在这里插入图片描述

类型不同,访问权限不同

异常

类型
  • Error
  • Exception
    • 运行时异常RuntimeException:写代码时不会提示报错,运行时发现问题才会提示报错
    • 编译时异常:写代码时就会提示报错,需要当下解决

在这里插入图片描述

常规异常类均继承自Throwable类

作用
  • 定位程序Bug
  • 作为方法内部的特殊返回值,通知方法调用者以执行问题
异常处理
  • 抛出异常(把问题交给上层)
  • 捕获异常(在本层解决问题)
抛出异常

关键字throw、throws

throw: 用于在方法内部抛出异常

throws:用于在方法定义处指明方法可能抛出的异常(如果是编译时异常需要自行抛出解决,如果是运行时异常系统会自动抛出

public void method() throws OtherExceptionName{
	... throw new OtherExceptionName();
}//编译时异常

public void method() {
	... throw new RuntimeException();
}//运行时异常
捕获异常

关键字try、catch、finally

try{
   //用于包裹并检测可能会抛出异常的代码块
}catch(ExceptionType e1){
   //用于捕获并处理异常1的代码块
}catch(ExceptionType e2){
   //用于捕获并处理异常2的代码块
}finally{
   //用于包含无论是否发生异常都需要执行的代码块
}

catch捕获并处理异常时的规则:“先小(子类异常)后大(父类异常),不要覆盖”

try-with-resources

将资源类对象的定义放在try语句的"()"中,可以自动调用资源对象的close()方法
在这里插入图片描述

自定义异常
  1. 自定义异常类,并使其继承Exception或RuntimeException类
  2. 重写构造器
  3. 在自定义异常类中添加额外信息,以便抛出异常时提供更多的上下文信息
  4. 处理异常
常见的异常处理方案
  1. 底层不断向上抛出异常

2.1. 最上层调用者捕获异常并给出异常提示(如“您访问的页面不存在,即将返回首页”)

2.2. 最上层调用者捕获异常并尝试修复问题(常常结合循环与break关键字,如“直至输入内容为整数才继续运行后续代码”)

泛型

泛型的本质是变量类型参数化,是一种编译时类型安全检测机制

-相当于告诉编译器目标变量类型是什么,编译器在编译期就会做类型检查,告知是否插入了错误类型对象,使得程序更加安全,增强了程序的健壮性;在Java SE 1.5之前,通常需要用Object类型的引用来实现参数的“任意化”,“任意化”带来的缺点是要做显式的强制类型转换,但强制类型转换属于运行时异常,不会在编译阶段报错提醒

定义及使用

定义泛型时,数据类型被设置为一个抽象类型参数,通常使用通配符完成;

使用泛型时,外部调用会传入一个具体数据类型,数据类型如果不匹配,编译器就会直接报错

这种参数化类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法

通配符
  • E - Element(通常在集合中使用)
  • T - Type (Java类)
  • K - Key (键)
  • V - Value(值)
  • ? - 不确定的任意类型
    • <?>:无边界的通配符
    • <? extends E>:固定上边界的通配符(E及其子类)
    • <? super E>: 固定下边界的通配符(E及其父类)
注意事项及基本类型的包装类型

泛型参数可以有多个,但泛型类型必须是引用类型,因此Java为8种基本数据类型提供了包装类型:

在这里插入图片描述

包装类型的特性:

  • 通常通过valueOf方法将基本类型包装为引用类型
  • 自动装箱(基本类型->包装类型)
  • 自动拆箱(包装类型->基本类型)
  • toString()方法
泛型类、泛型接口、泛型方法

方法声明中定义的形参只能在该方法里使用,而接口、类声明中定义的形参则可以在整个接口、类中使用(包括接口、类中声明的其他方法)

  • 泛型类
public class 类名 <泛型类型1,...> {
	...
}
  • 泛型接口
public class 接口名 <泛型类型1,...> {
	...
}
  • 泛型方法
public <泛型类型> 返回类型 方法名(泛型类型 变量名) {
    ...
}

集合

  • Collection(单列集合)

    • List

      • ArrayList、LinkedList:有序、可重复、有索引
    • Set

      • HashSet:无序、不重复、无索引
      • LinkedHashSet:有序、不重复、无索引
      • TreeSet:按照大小默认升序排序、不重复、无索引
  • Map(双列集合:键值对)

    • HashMap:无序、不重复、无索引
    • LinkedHashMap:有序、不重复、无索引
    • TreeMap:按照大小默认升序排序、不重复、无索引
Collection
常用方法

在这里插入图片描述

其中,contains方法不仅可以用于对象包含判断,还可以用于String对象的子串判断,如:

Collection <String> myList  = new ArrayList();
myList.add("Hello");
for (String s : myList){
    if(s.contains("llo")){
        System.out.println(1);
    }
}//输出为1
遍历方式
  • 迭代器(“相对”适合增删元素)

区别于C++,没有start()和end(),但是可以通过hasNext()+while循环进行判断

在这里插入图片描述

  • 增强for循环(仅适合遍历)
for (集合元素类型 变量名: 集合名称){
	...
}
  • Lambda表达式+forEach方法(仅适合遍历)

在这里插入图片描述

集合遍历潜在问题:并发修改异常问题

并发修改异常问题是指在迭代的过程中对集合元素进行删除

  • 支持索引的集合(List类):
    • 使用基本for循环,但完成数据处理后,修改迭代索引变量-1
    • 倒序遍历(删除)
  • 所有集合:
    • 使用迭代器遍历,并用迭代器提供的remove()方法删除数据[增强for循环/Lambda表达式不能解决并发修改异常问题]

(如果是添加元素,也是类似的思想)

List
特有方法

主要是通过索引获取数据信息

在这里插入图片描述

ArrayList
  • 基于动态数组实现,内部维护一个Object数组,默认初始容量为10,当元素数量超过当前容量时会自动扩容
  • 随机访问效率高
  • 插入和删除效率低
LinkedList
  • 基于双向链表实现
  • 插入和删除效率高
  • 顺序访问效率低
Set
HashSet

底层原理:哈希表(初始默认数组长度为16,默认加载因子为0.75,通过Object类的hashCode()方法可以得到哈希值),由HashMap存储

  • JDK8之前:数组+链表(拉链法)

  • JDK8之后:数组+链表+红黑树

当数组中元素达到“数组长度*加载因子”时,会不断将数组长度扩充为2*数组长度(16->32->64->…)

JDK8以后:当有链表长度超过8且数组长度不小于64时,自动将对应链表转换为红黑树(相对平衡的二叉排序树)

  • 引用类型元素的去重:重写equals()和hashCode()方法
    1. 采用@Data注解自动重写
    2. 手动重写

为什么需要同时重写equals()和hashCode()方法?

  • 只重写hashCode()可能会因为哈希冲突而导致误判,故需要equals()另外比较对象中各字段的内容
  • 只重写equals()可能会在多元素场景(如比较集合中的元素)中效率太低,需要hashCode()通过哈希值处理实现快速比较
LinkedHashSet

底层原理:,由LinkedHashMap存储,数组+链表+红黑树

通过双链表记录每个元素的前后元素位置及链首、链尾

为什么是双链表不是单链表?

  • 更高效地实现删除操作
  • 更方便双向迭代
  • 更方便调整元素的前后关系

在这里插入图片描述

TreeSet

底层原理:红黑树

  • 对于数值类型(Integer、Double):按照数值本身大小进行升序排序
  • 对于字符串(String)类型:按照首字符编码顺序升序排序
  • 对于自定义类型:
    • 方式一:让自定义类(有待比较字段的类)实现Comparable接口,重写compareTo方法,指定比较规则
    • 方式二:调用TreeSet集合的有参构造器,设置Comparator对象,指定比较规则
public TreeSet(Comparator<? super E> comparator)//更优先的比较方式

如果要调用比较器,可以考虑Double.compare(ob1,ob2)和Integer.compare(ob1,ob2)方法实现值比较及值返回

Map
常用方法

在这里插入图片描述

另:entrySet()方法可以将Map中的各键值对当作Map.Entry<KeyType,ValueType>类型的元素,返回一个Set对象

遍历方式
  • 键找值

先通过keySet()方法获取Map中全部的键,再通过遍历键及get()方法获取值

在这里插入图片描述

  • 键值对

将键值对当作单独对象进行遍历,通过entrySet()方法获取键值对集合,通过getKey()和getValue()方法分别获取键和值

在这里插入图片描述
在这里插入图片描述

  • Lambda表达式

对map对象调用forEach()方法,通过方法中的形式参数k、v访问键和值

在这里插入图片描述
在这里插入图片描述

Collections工具类

在这里插入图片描述

Stream流

Stream流通过类似SQL的方式,结合Lambda的语法风格,提供一种对Java集合运算和表达的高阶抽象

Stream流的使用步骤:

  • 获取Stream流
  • 调用中间方法处理集合数据
  • 调用终结方法获取处理结果
获取Stream流

在这里插入图片描述

  • Stream.of(数组名);//得到数组对应的Stream流对象
调用中间方法处理集合数据

中间方法调用完成后会返回新的Stream流,能继续调用中间方法,即支持链式编程(使用Lambda表达式)

在这里插入图片描述

  • filter()方法中写条件判断语句
  • map()方法中写操作处理语句
调用终结方法获取处理结果

终结方法调用完成后会返回处理结果或将结果返回到集合或数组中

在这里插入图片描述
在这里插入图片描述

  • collect()方法中的参数写Collections.toList()/Collections.toSet()/Collections.toMap(字段1,字段2)

File

创建对象

直接使用文件路径创建File对象

在这里插入图片描述

常用方法
获取文件属性

在这里插入图片描述

文件路径:

  • 绝对路径:带盘符的从计算机初始位置开始定位的路径
  • 相对路径:不带盘符的从IDEA工程根目录位置开始定位的路径
创建、删除文件(夹)

在这里插入图片描述

遍历文件夹

每次只会列出当前目录下的一级文件(夹):

在这里插入图片描述

文件编码与解码
常用编码方式
  • ASCII
  • GBK
  • Unicode
编码与解码的方法

在这里插入图片描述

IO流

分类与体系

在这里插入图片描述

  • 字节流适合操作所有类型的文件,但字符流只适合操作纯文本类型的文件(以字符为单位进行处理)

  • 定义的IO资源类对象均可以使用try-with-resources方式定义,可以实现close()方法的自动调用

字节流

由于是字节流,使用到的数组都是Byte类型的

FileInputStream

在这里插入图片描述

在这里插入图片描述

InputStream is = new FileInputStream(FilePath);//多态

int val;
while((val = is.read()) != -1){
    System.out.print((char)val);
}

int len;
byte[] buffer = new byte[bufferSize];
while((len = is.read(buffer)) != -1){
    System.out.print(new String(buffer, 0 , len));//从字节数组的第0个开始读取len个字节
}
  • 可以考虑适当增大buffer大小,或用readAllBytes()方法来读取全部字节
OutputStream

增加了append选项:覆盖文件内容/文件内容追加

在这里插入图片描述

OutputStream os = new FileOutputStream(FilePath);
os.write("\r\n".getBytes());//写出换行,"\r\n"可以在不同操作系统稳定实现换行
字符流

由于是字符流,使用到的数组都是char类型的

FileReader

在这里插入图片描述

Reader fr = new FileReader(FilePath);//多态

int val;
while((val = fr.read()) != -1){
    System.out.print((char)val);
}

int len;
char[] buffer = new char[bufferSize];
while((len = fr.read(buffer)) != -1){
    System.out.print(new String(buffer, 0 , len));//从字符数组的第0个开始读取len个字符
}
FileWriter

在这里插入图片描述

增加了直接写入字符串的输出方式

Writer fw = new FileWriter(FilePath);
fw.write("\r\n");//写出换行,"\r\n"可以在不同操作系统稳定实现换行
缓冲流

缓冲流的实质是通过设置缓冲池,将原本的字节/字符流包装成性能更好的字节/字符流

缓冲池的容量通常大于用户定义的字节/字符数组,这样可以有效地减少IO次数(默认缓冲池大小为8KB)

在这里插入图片描述

字节流

在这里插入图片描述

InputStream is = new FileInputStream(FilePath);
InputStream bis = new BufferedInputStream(is);
OutputStream os = new FileOutputStream(FilePath);
OnputStream bos = new BufferedOutputStream(os);

int len;
byte[] buffer = new byte[bufferSize];
while((len = bis.read(buffer)) != -1){
    bos.write(buffer, 0 , len);//从字节数组的第0个开始读取len个字节写入指定文件
}
字符流

在这里插入图片描述

在这里插入图片描述

Reader fr = new FileReader(FilePath);
BufferedReader br = new BufferedReader(fr);//不使用多态定义引用变量,可以使用BufferedReader类的特有方法
Writer fw = new FileWriter(FilePath);
BufferedWriter bw = new BufferedWriter(fw);//不使用多态定义引用变量,可以使用BufferedWriter类的特有方法

String line;
while((line = br.readLine()) != null){
	bw.write(line);
}
其他流
  • InputStreamReader包装类:从字节流到字符流的桥接器:它使用指定的字符集读取字节并将它们解码为字符

在这里插入图片描述

  • DataOutputStream包装类:支持将数据及其类型一同写出

在这里插入图片描述

框架

commons-io-version.jar

在这里插入图片描述

在这里插入图片描述

流的刷新与关闭
  • flush(): 在写入内容后通过刷新流可以更新内容
  • close(): 关闭流(会自动刷新流)

GUI编程:Swing

编程思想

编辑页面时,通过自定义容器类并继承顶级容器JFrame,以系统化地设置容器属性、安排组件

public class FirstPage extends JFrame{
	public FirstPage(){//构造器
		...	//定义容器属性
    }
	...//安排组件
}

呈现页面时,通过调用构造器完成对象创建及初始化

new FirstPage();//调用构造器

“容器”概念

通常我们需要容器以容纳其他组件,通过容器嵌套进行布局,通过安置组件实现功能

容器本身也属于组件,用于组织、管理和显示其他组件

Swing 中容器可以分为两类:

  • 顶层容器

顶层容器是进行图形编程的基础,是任何图形界面程序都要涉及的主窗口,是显示并承载组件的容器组件

Swing中有三种可以使用的顶层容器:

  1. JFrame:用作框架窗口(基础)
  2. JDialog:用作对话框
  3. JApplet
  • 中间容器

中间容器也属于容器组件,可以承载其他组件,但中间容器不能独立显示,必须依附于其他的顶层容器或中间容器

Swing中常见的中间容器:

  1. JPanel:表示普通面板,是最灵活、最常用的中间容器

  2. JScrollPane:与 JPanel 类似,但它可在大的组件或可扩展组件周围提供滚动条

  3. JTabbedPane:表示选项卡面板,可以包含多个组件,但一次只显示一个组件,用户可在组件之间方便地切换

  4. JToolBar:表示工具栏,按行或列排列一组组件(通常是按钮)

组件

容器
JFrame

最外层的顶级容器

  • JFrame();//构造初始时不可见的新窗体
    JFrame(标题);//创建具有指定标题的不可见的新窗体
    
  • setSize(width, height);//设置宽高
    
  • setResizable(false);//设置无法修改窗口大小
    
  • setLocationRelativeTo(null);//设置窗口相对于屏幕居中显示
    
  • setAutoRequestFocus(false);//设置窗口初始不获得焦点(通常用于后续有组件使用FocusListener)
    
  • setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE / JFrame.DISPOSE_ON_CLOSE);//设置关闭窗口同时结束程序 / 设置仅关闭窗口
    
  • setVisible(true);//设置显示窗口(通常放在最后保证窗口得以完整地显示)
    
  • add(容器/组件);//将容器或组件放置到该容器中
    
JPanel

放置于顶级容器上的真正容纳组件的中间容器

  • JPanel();//使用默认的布局管理器FlowLayout创建新面板
    JPanel(LayoutManagerLayout layout);//创建指定布局管理器的 JPanel对象
    
  • setBackground(颜色);//设置容器背景颜色
    
  • add(容器/组件);//将容器或组件放置到该容器中
    
普通组件

基本通用的方法:

  • setBounds(x, y, width, height);//设置组件位置
    
  • setFont(字体);//设置文字字体
    
  • setForeground(颜色);//设置文字颜色
    
  • setBackground(颜色);//设置背景颜色
    
JTextField/JTextArea

单行/多行文本输入框

  • getText();//获取文本
    
  • setText(String);//设置文本
    
  • addFocusListener(new FocusListener() {
        @Override
        public void focusGained(FocusEvent e) {
      		//重写聚焦方法
        }
    
        @Override
        public void focusLost(FocusEvent e) {
        	//重写失焦方法
        }
    });//添加焦点监听器
    
JPasswordField

单行密码输入框

类似于JTextField

  • setEchoChar((char) 0/'*');//设置字符正常显示/显示为\*号
    
JLabel

标签

  • setIcon(图片);//设置图片标签
    
  • addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
      		//重写动作方法
        }
    });//添加动作监听器
    
JButton

按钮

  • addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
      		//重写动作方法
        }
    });//添加动作监听器
    
JScrollPane、JTable、DefaultTableModel

滑轮容器-表格组件-数据模型

JScrollPane (具有滚动功能的容器)
——JTable (可视化表格组件)
——DefaultTableModel (数据模型,存储和管理表格数据)

DefaultTableModel
  • new DefaultTableModel(列名数组,行数);//列名数组长度定义了列数
    
  • setDataVector(数据二维数组, 列名数组);//填入表格数据
    
JTable
  • setRowHeight(行高值);//设置行高
    
  • getSelectedRow();//获取指定行
    
  • removeRow(行号);//根据行号移除指定行
    
  • add(数据模型);//向表格内添加数据模型
    
  • addMouseListener(new MouseAdapter() {
    	@Override
        public void mousePressed(MouseEvent e) {
    		//重写方法
        }
        @Override
        public void mouseReleased(MouseEvent e) {
        	//重写方法            
        }
    });//添加动作监听器
    
    /*为什么需要同时重写mousePressed和mouseReleased
    不同操作系统的右键点击行为可能有所不同:
    在Windows系统中,右键点击通常会在mouseReleased中触发isPopupTrigger()
    在macOS系统中,右键点击可能会在mousePressed中触发isPopupTrigger()
    因此,为了兼容不同平台的行为,通常会同时重写mousePressed和mouseReleased,确保无论在哪种平台上都能正确检测到右键点击事件*/
    

另:JTableHeader可用于修改表头属性

JScrollPane
  • add(表格对象);//向容器内添加表格对象
    
JPopupMenu、JMenuItem

弹出菜单及菜单选项

JPopupMenu (弹出菜单窗体)
——JMenuItem (菜单选项)

JPopupMenu
  • add(菜单选项);//向菜单内添加选项
    
JMenuItem
  • addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
      		//重写动作方法
        }
    });//添加动作监听器
    
JOptionPane

对话框

  • showMessageDialog(null, 提示内容主体, 对话框标题, JOptionPane.WARNING_MESSAGE/PLAIN_MESSAGE);//警告对话框
    
  • showConfirmDialog(null, 提示内容主体, 对话框标题,  JOptionPane.YES_NO_OPTION);//选择对话框
    
  • UIManager.put("OptionPane.minimumSize", new Dimension(width, height));//设置对话框大小
    UIManager.put("OptionPane.messageFont", 字体);//设置文本字体
    UIManager.put("OptionPane.buttonFont", 颜色);//设置按钮颜色
    

多线程

线程:一个程序内部的一条执行流程

多线程:从软硬件上实现的多条执行流程的技术

多线程的创建

继承Thread类

在这里插入图片描述

  • 注意事项
    • 启动线程必须是调用start()方法,而非run()方法
    • 只有将子线程放在主线程(通常是main线程)前,才能实现多线程
实现Runnable()接口

在这里插入图片描述

  • 匿名内部类写法

在这里插入图片描述

  • 注意事项
    • 实现Runnable接口对象
实现Callable()接口

在这里插入图片描述
在这里插入图片描述

  • 注意事项
    • 调用start()方法用Thread类对象,调用get()方法用FutureTask类对象
    • FutureTask类间接实现了Runnable接口,创建出来的也是线程任务对象
方式启动过程返回值优点缺点
-Thread-简单无法继承其他类
-MyRunnable-Thread-可以继承其他类需要额外定义Runnable实现类对象
-Callable-FutureTask-Thread-可以继承其他类,可以获取返回值需要额外定义Callable实现类对象及FutureTask对象

Thread常用方法

在这里插入图片描述

线程安全和线程同步

线程安全

尽量保证“互斥”、“同步”地访问资源

线程同步
同步代码块

在这里插入图片描述

  • 注意事项
    • 如果是实例方法,通常选用this作为锁
    • 如果是静态方法,通常选用类名.class作为锁
同步方法

在这里插入图片描述

  • 注意事项
    • 是在方法定义处添加synchronized关键字,而非调用处

在这里插入图片描述

  • 注意事项
    • 通常,我们将锁对象用final关键字进行修饰,保证不被更改
    • 为保证同步、避免死锁,线程需要在关键操作前获得锁,在关键操作完成后释放锁

线程池

线程池是线程复用的技术,使得无需为每一个线程任务创建新的线程对象进行处理

创建方式

在这里插入图片描述

(更推荐方式一)

ThreadPoolExecutor

在这里插入图片描述
在这里插入图片描述

(在处理Callable任务时,使用Future类型对象来接收、获得返回值)
在这里插入图片描述

  • 可以根据任务类型(CPU密集/IO密集)确定具体参数值选择
Executors工具类

在这里插入图片描述

(这些方法底层都是通过通过ThreadPoolExecutor创建对象)

在这里插入图片描述

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

网络编程

基本通信架构

  • C/S架构:客户端、服务器端均需要程序员开发软件
  • B/S架构:仅服务器端需要程序员开发软件

获取IP地址

  • InetAddress类:代表IP地址

在这里插入图片描述

  • 本机IP:127.0.0.1/localhost
  • 查看本机IP:ipconfig
  • 查看网络连通情况:ping ipAddress

UDP通信

使用DatagramSocket类创建客户端、服务器端

使用DatagramPacket类创建数据包

在这里插入图片描述

C/S架构
单发单收
  • 客户端:

在这里插入图片描述

  • 服务器端:
    在这里插入图片描述
多发多收
  • 客户端:

在这里插入图片描述

  • 服务器端:

在这里插入图片描述

即:通过加入循环语句即可完成“多发多送”!

TCP通信

  • 客户端

在这里插入图片描述

通常需要用DataOutputStream类对象包装OutputStream类对象

  • 服务器端

在这里插入图片描述

通常需要用DataInputStream类对象包装InputStream类对象

  • 注意事项

采用DataOutputStream、DataInputStream类对象包装字节输出、输入类对象后,要保证客户端、服务器端的发送、接收方式相同(步调一致),如writeInt()对应readInt()

C/S架构
单发单收
  • 客户端

    ① 创建Socket对象,指定服务器IP及服务端端口

    ② 通过socket对象调用getOutputStream()方法得到字节输出流、完成数据的发送

    ③ 释放资源:关闭socket管道

  • 服务器端
    在这里插入图片描述

多发多收

采用多线程技术:

  • 客户端:保持不变
  • 服务器端:
    • 主线程定义循环接收客户端Socket管道连接
    • 每接收到一个Socket通信管道后,分配子线程负责处理
B/S架构
  • 注意
    • 无需编写客户端代码
    • 只需编写服务端代码,其代码和C/S架构的类似,但需要按照HTTP/HTTPS协议编写
    • 不适合UDP通信(HTTP/HTTPS是基于TCP协议的)

其他技术

Junit

优点
  • 可以针对某个方法灵活地执行单元测试,也可以独立地一键完成对全部方法的自动化测试
  • 可以自动生成测试报告
具体步骤

在这里插入图片描述

  • 正常定义待测试类及方法
  • 额外定义测试类,声明测试方法
    • 声明@Test注解
    • 完成测试方法体,尝试不同测试用例以调用待测试方法(公共、无返回值、无参)
  • Junit运行测试方法,得到测试结果

反射

反射就是:加载类,并允许以编程的方式解析类中的各种成分(成员变量、方法、构造器)

在这里插入图片描述

获取类的元信息对象

类的元信息对象即类的class对象:

  • 是 JVM 在加载 .class 文件后,在 运行时内存中创建的对象
  • 它是 java.lang.Class 类的实例。
  • 用于表示类的结构信息,比如字段、方法、注解、构造器等
获取方式
  • 通过类名获得
Class className = 类名.class;
  • 通过Class类的静态方法获得
Class className = Class.forName(类的项目内定义路径);
  • 通过Object类的成员方法获得
Class className = 类的对象.getClass();

className.getName();//获取包含包路径的全类名
className.getSimpleName();//获取不包含包路径的简类名

获取类中的结构信息
构造器

需要先获取类,再获取类中成分

在这里插入图片描述

Constructor[] cons = className.getDeclaredConstructors();//用于获取全部定义过的构造器
Constructor con = classNmae.getDeclaredConstructor(参数1类型.class,参数2类型.class,...);//用于获取指定的构造器,该构造器的首参数为类型1,次参数为类型2(固定写法)

con.setAccessible(true);//暴力反射,使得可以访问私有构造器
类名 object = (类名) con.newInstance();
字段

在这里插入图片描述

Field[] fields = className.getDeclaredFields();//用于获取全部定义过的字段
Field field = classNmae.getDeclaredField(字段名称);//用于获取指定名称的字段

field.setAccessible(true);//暴力反射,使得可以访问私有字段
field.set(字段所属的类的对象,字段修改值);
field.get(字段所属的类的对象);
方法

在这里插入图片描述

Method[] methods = className.getDeclaredMethods();//用于获取全部定义过的方法
Method method = classNmae.getDeclaredMethod(方法名,参数1类型.class,参数2类型.class,...);//用于获取指定名称的指定形参列表的方法

method.setAccessible(true);//暴力反射,使得可以访问私有方法
method.invoke(方法所属的类的对象,实参列表);
作用
  • 可以得到一个类的全部成员(构造器、字段、方法等)进行操作
  • 可以破坏封装性,访问到私有的构造器、字段、方法等
  • 可以绕过泛型(编译时)的限制[反射在运行时]
  • 适合做Java框架:通过对Java中某个对象进行反射分析,可以了解该对象所属类的性质及成员等

(人体解剖是猴体解剖的一把钥匙 | 从后往前分析)

注解

自定义注解

自定义注解(接口)内部可以定义属性,但其属性名后需要加"()",并可以标注默认值

在这里插入图片描述

在这里插入图片描述

元注解

放在注解上方,为自定义注解添加注解

在这里插入图片描述

  • @Target:括号内可以放多个参数,用“,”分隔
  • @Retention:通常使用Retention.RUNTIME延长保留期限
注解的解析

在这里插入图片描述

if(className/method/field.isAnnotationPresent(注解类名.class)){
	注解类名 注解对象 = (注解类名) className/method/field.getDeclaredAnnotation(注解类名.class);
	func(注解对象.属性值());//获取并处理注解的属性值
}
作用
  • 可以实现:结合反射中获取类内方法信息及其invoke()方法,仅批量执行有注解的方法(注解内的属性值可以用于限定执行次数等

动态代理

创建代理

通常把创建代理的方法设置为静态方法,放在工具类ProxyUtil中

在这里插入图片描述

  • loader用于确定类加载器去加载对应的代理类,通常选择工具类的类加载器,即ProxyUtil.class.getClassLoader()
  • interfaces用于确定代理类需要实现的接口,通常由原类对象调用getClass().getInterfaces()批量获取
  • h用于具体确定执行内容,通常使用匿名内部类创建InvocationHandler对象,重写invoke()方法
    • 在这里插入图片描述

    • 通过method确定执行方法,通过args获取运行参数

应用场景及好处

一种高效的设计模式

  • 实现代码复用:提高编程简洁性
  • 灵活扩展功能:在不修改原有类代码的情况下,增强功能(原对象→代理对象)
  • 解耦合:客户端只依赖接口,具体实现由代理动态生成,减少依赖关系
  • 支持AOP:代理机制是实现 AOP(面向切面编程)的核心基础

学习参考:https://www.bilibili.com/video/BV1gb42177hm/

您可能感兴趣的与本文相关的镜像

Python3.8

Python3.8

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ayaishere_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值