目录
比较String、StringBuilder和StringBuffer的区别
使用套接字对象实现两个端点(Socket和ServerSocket)之间发送文件
String字符串
String是一个类,属于数据类型中的引用类型。
Java中一切使用""引起来的内容,都是这个类的实例,称为字符串对象。
字符串在定义后,值不可改变,是一个常量,实际是一个字符数组。
注意:如果频繁地将一个String类型变量的值进行更改时,会创建很多字符串对象。效率
低,浪费内存空间。所以在频繁更改字符串时,不要使用String类变量。如果要频繁更改字符串,使用StringBuilder类或StringBuffer类。
可变字符串
String字符串对象是一个常量,在定义后,值不可改变。
如果使用String类的对象,对其频繁更新时,就会不停地创建新的对象,不停引用给同一个变量。
如要执行10000次循环重新赋值的过程,就要创建10000个字符串对象,执行效率很低,这时就需要使用可变字符串对象。StringBuilder(线程不安全)StringBuffer(线程安全)。
StringBuilder类
用于表示可变字符串的一个类,是非线程安全的,建议在单线程环境下使用。
StringBuffer类
用于表示可变字符串的一个类,是线程安全的,建议在多线程环境下使用。
构造方法
常用构造方法 | 作用 |
StringBuilder() | 创建一个大小为16的字符串数组,表示一个空白字符。类似于String str=""; |
StringBuilder(String str) | 创建一个str长度+16的字符数组后,将str添加到其中。类似于String str="初始值"; |
普通方法
常用方法 | 作用 |
append(Object obj) | 将任意类型的参数添加到原可变字符串末尾 |
delete(int start,int end) | 删除[start,end)区间内的字符 |
deleteCharAt(int index) | 删除index索引上的字符 |
insert(int index,Object obj) | 在索引index上插入obj |
replace(int start,int end,String str) | 将[start,end)区间内的字符替换为str |
reverse() | 反转字符串 |
注意:以上表格中的方法都是在直接操作同一个字符串对象,每次调用方法后,原字符串都会发生变化。
StringBuffer和StringBuilder并没有重写equals方法,所以可变字符串的值是否相同时,调用的是
equals中原始的==判断。如果要判断两个可变字符串的值是否相同时,需要将其转换为String后调
用equals判断。
比较String、StringBuilder和StringBuffer的区别
相同点:
这三个类都可以表示字符串。都提供了一些操作字符串的方法。
这三个类中有相同的方法,如charAt()、indexOf()等。
这三个类都是被final修饰的类,不能被继承。
不同点:
String定义的字符串是一个常量。可变字符串定义的字符串是一个变量。
String类中的方法,调用后,不会改变原本字符串的值;可变字符串类中的方法,调用后,会改变
原本字符串的值。
StringBuilder是非线程安全的可变字符串类,StringBuffer是线程安全的可变字符串类,其中的方
法被synchronized修饰。
RunTime类
Runtime类的对象,表示程序运行时对象(程序运行环境对象)。
包含了程序运行环境相关的信息。常用于获取运行环境信息(如虚拟机内存)或执行某个命令。
特点
这个类不是一个抽象类,但不能创建对象,因为它的构造方法是私有的。
这个类提供了一个静态方法getRuntime(),通过这个方法,可以获取一个Runtime类的对象。
这是Java中的一种设计模式--单例模式(一个类只能有一个创建对象)
使用
public class RuntimeTest {
public static void main(String[] args) throws IOException,
InterruptedException {
//通过Runtime类的静态方法getRuntime()获取唯一的Runtime类的实例
Runtime runtime = Runtime.getRuntime();
System.out.println("当前虚拟机空闲内存" + runtime.freeMemory() / 1024 / 1024
+ "MB");
System.out.println("当前虚拟机实际最大内存" + runtime.totalMemory() / 1024 /
1024 + "MB");
System.out.println("当前虚拟机支持的最大内存" + runtime.maxMemory() / 1024 /
1024 + "MB");
//exec(String 指令名)运行某个指令,返回运行的进程对象
//在指定秒后关机
// Process process = runtime.exec("shutdown -s -t 300");
//取消关机任务
// Process process = runtime.exec("shutdown -a");
//mspaint画图 calc计算器 notepad记事本
Process process = runtime.exec("mspaint");
Thread.sleep(2000);
//通过进程对象调用销毁功能,从而关闭
process.destroy();
}
}
总结
参数只有是引用类型(类、数组、接口),并且方法中在直接操作该参数时,才会对实际参数造成影响。
fun3(Person p)参数为Person对象,方法中直接调用参数p的xxx方法,是在操作实际参数。
fun5(int[] list)参数为数组,方法中直接操作数组某个索引对应的元素,是在操作实际参数。
fun2(String str)和fun4(Person p)都在方法中创建了一个新的对象,是在操作方法中的参数,不影响实际参数。
Date类
用于表示日期时间的类,位于java.util包下
构造方法
常用构造方法 | 说明 |
Date() | 创建当前瞬间对应的日期对象 |
Date(long l) | 创建指定瞬间对应的日期对象 |
Date(int year,int month,int day) | 该构造方法已过时。创建指定年月日的日期对象(年是1900年起经过的 年数,月用0-11表示1到12月) |
常用方法
常用方法 | 作用 |
getTime() | 得到对应Date对象表示的毫秒数 |
setTime(long l) | 设置Date对象的毫秒数 |
after(Date when) | 判断调用日期对象是否在when之后 |
before(Date when) | 判断调用日期对象是否在when之前 |
SimpleDateFormat类
用于格式化日期的类。
SimpleDateFormat(String pattern); 来创建一个指定日期模板的格式化日期对象
格式:yyyy/MM/dd HH:mm:ss E ----2022/11/24 16:24:09 星期四
常用方法:format(Date date) 将Date对象按日期模板转换为字符串
parse(String str) 将满足日期模板的字符串转换为Date对象
异常
当程序没有按开发人员的意愿正常执行,中途出现错误导致程序中断,出现这种情况,就称为异常。学习异常就是认识异常的种类,如何处理异常和避免异常出现。异常在程序中以对象的形式存在。当代码执行过程中出现异常,虚拟机会自动创建一个异常对象,如果没有对象该异常对象进行处理,就会导致程序中断,不再执行后续代码。
运行时异常
NullPointerException | 空指 针异 常 | 用空对象null调用属性或方法 |
ArrayIndexOutOfBoundsException | 数组 下标 越界 异常 | 使用数组时,下标超出范围 |
NumberFormatException | 数字 格式 异常 | 使用包装类调用parse方法做转换时,无法 将参数转换。如String str="123abc";int i=Integer.parseInt(str) |
InputMismatchException | 输入 不匹 配异 常 | 使用Scanner接收控制台输入时,如果不 满足接收的类型。如int i = sc.nextInt(), 实际输入a |
ClassCastException | 对象 转型 异常 | Person p = (Person)Object obj; |
ArithmeticException | 算术 运算 异常 | 0当分母 |
编译时异常
如果一个异常类属于Exception异常类的子类,称为编译时异常,无法通过编译,必须处理异常后
才能编译运行。
SQLException | 数据库SQL相关异常 | 操作数据库时 |
IOException | 输入输出流异常 | 使用流对象时 |
FileNotFoundException | 文件未找到异常 | 方法的参数为文件时 |
处理异常
方式一:try-catch-finally语句
这种方式处理异常,无论会不会抛出异常,都能让程序正常执行。
try{
//可能出现异常的代码
}catch(异常类 异常对象){
//如果出现异常对象,且与catch小括号中的异常类型匹配,就会执行这里的代码
}catch(异常类 异常对象){
//如果出现异常对象,且与catch小括号中的异常类型匹配,就会执行这里的代码
}finally{
//无论程序是否会抛出异常,都要执行的代码
}
try-catch-finally使用时注意:
1.try、catch、finally都不能单独使用,try需要配合catch或finally或catch和finally一起使用。
2.执行try中的内容时,当某行代码抛出异常,不再执行try中该行代码后续的内容。
3.无论try中的代码是否会抛出异常,finally中的代码一定会执行。
4.如果代码会抛出多个异常,可以使用多个catch进行捕获,需要将异常子类放在最前,异常父类放在最后。
5.在try中定义的内容,无法在try之外的地方使用。
6.try中如果有return,不影响finally的执行,finally优先于return执行。
方式二:throws关键字
这种方式,可以让编译时异常通过编译。
在定义方法的时候,通过该关键字声明可能抛出的异常。
用法:方法的参数部分之后,添加"throws 异常类型1,异常类型2..."
public class Test{
public void fun() throws InterruptException{//这时该方法就会有一个声明:该方法可能
会抛出异常
//这句话直接写完后,会报错,因为sleep()方法可能会抛出InterruptException异常,属于
编译时异常,必须要处理
Thread.sleep(500);
}
}
throw和throws
throws表示用于声明方法有可能出现的异常。使用时写在方法的小括号之后
throw用于手动抛出异常对象。使用时,写在方法体中,常用于满足某种情况时,强制中断程序
用法:throw 异常对象;
自定义异常
如果需要在某种情况下中断程序, 可以自定义一个异常类,再通过throw关键字手动抛出。
自定义异常步骤
1.定义一个类,继承某个异常类
如果继承的是RuntimeException,表示自定义的异常类属于运行时异常,该异常对象可以不用处
理
如果继承的是非RuntimeException,表示自定义的异常类属于编译时异常,该异常对象必须要处
理
2.可选操作。定义带参构造方法,参数为异常信息,调用父类中的构造方法
/*
* 自定义一个异常类,用于密码输入次数过多时抛出该异常
* 这里继承的是RuntimeException,表示运行时异常,可以不用处理该类的对象
* */
public class PasswordErrorException extends RuntimeException{
/*
* 可选操作
* 定义无参数的构造方法,调用父类中无参数的构造方法
* */
public PasswordErrorException (){
super();
}
/*
* 可选操作
* 定义带参数的构造方法,调用父类中带参数的构造方法
* 参数为异常信息
* */
public PasswordErrorException(String msg){
super(msg);
}
}
Collection接口
该接口有两个核心子接口:List和Set。
这两个接口都可以保存一组元素,List接口保存元素时,是有序可重复的;Set接口保存元素时,是无序不重复的。
List接口
有序集合,元素可以重复,允许保存null,可以通过索引获取对应位置上的元素。
在该接口继承Collection接口的同时,又拓展了一些操作元素的方法,如添加到指定索引、根据索引删除、获取指定索引的元素、截取子集合的方法等。
ArrayList实现类
采用数组实现的集合。
可以通过索引访问元素,可以改变集合大小。如果要在其中插入或删除元素时,会影响后续元素
该集合中保存的都是引用类型,即便保存了数组123,也保存的是Integer类型的123,而不是int类
型的123。
该集合查询效率高,中途增加和删除元素效率低。
常用构造方法 | 说明 |
ArrayList() | 创建一个Object类型的空数组。在调用添加方法后,才会更改该数组 大小为10 |
ArrayList(int initialCapacity) | 创建一个指定容量的Object数组,如果参数为负,会抛出 IllegalArgumentException异常 |
LinkedList实现类
采用双向链表实现的集合。
集合中保存的每个元素也称为节点,除首尾节点外,其余节点都保存了自己的信息外,还保存了其
前一个和后一个节点的地址。
如果在双向链表的数据结构中插入和删除操作节点时,不会影响其他节点的位置。如添加时新节点
时,只需要重写定义新节点的前后节点位置即可。
如果要查询某个节点时,需要从头结点或尾结点开始一步步得到目标节点的位置。
双向链表在中间插入和删除的效率高,随机读取的效率低。
常用构造方法 | 说明 |
LinkedList() | 创建一个空链表 |
遍历集合中元素的方式
方式一:普通for循环
System.out.println("使用普通for循环遍历");
//方式一:普通for循环
for (int i = 0; i < nameList.size(); i++) {//从0遍历到size()
String name = nameList.get(i);//通过get(int index)获取指定索引的元素
System.out.println(name);
}
方式二:增强for循环
System.out.println("使用增强for循环遍历");
//方式二:增强for循环
for (String name : nameList) {
System.out.println(name);
}
方式三:迭代器
System.out.println("使用迭代器遍历");
//方式三:迭代器
//Collection类型的集合对象.iterator(),获取迭代器
Iterator<String> iterator = nameList.iterator();
// iterator.hasNext()判断集合中是否还有下一个元素
// iterator.next();获取下一个元素
while (iterator.hasNext()) {
String name = iterator.next();
System.out.println(name);
}
Map接口
Map称为映射,数据以键值对的形式保存。保存的是键与值的对应关系。
键称为Key,值称为Value,键不能重复,键允许出现一个null作为键,值无限制。
键和值都是引用类型。
HashMap实现类
HashMap() 创建一个空的映射集合,默认大小为16,加载因子为0.75
文件类File
Java中的File类,表示本地硬盘中的文件(文件和目录)的一个类。
通过这个类创建的对象,可以操作对应的文件。
构造方法
常用构造方法 | 说明 |
File(String pathName) | 根据文件的完整路径创建File对象 |
File(String parent,String child) | 根据文件的父目录路径和自身路径创建File对象 |
File(File parent,String child) | 根据文件的父目录对应的File对象和自身路径创建File对象 |
递归遍历文件夹
package com.hqyj.FileTest;
import java.io.File;
import java.util.Date;
public class Test3 {
//查看某个目录下的所有文件
public static void main(String[] args) {
File source = new File("E:\\adobe");
Test3 t = new Test3();
t.fun(source);
}
/*
* 递归遍历文件夹
* */
public void fun(File source) {
//输出某个目录中超过3个月未使用且大于500MB的文件
/*
long start = source.lastModified();
long end = System.currentTimeMillis();
if ((end - start) / 1000 / 3600 / 24 > 90 && source.length() / 1024 /
1024 > 500) {
System.out.println(source.getName() + "\t" + new
Date(source.lastModified()) + "\t" + source.length() / 1024 / 1024);
}*/
//判断是否为目录
if (source.isDirectory()) {
//将其展开
for (File child : source.listFiles()) {
//因为子文件有可能是目录,继续调用本方法
fun(child);
}
}
}
}
IO
I:Input输入
O:Output输出
流Stream
在Java中,流用于表示计算机硬盘与内存之间传输数据的通道。
将内存中的数据存入到硬盘中,称为写write,也称为输出Output。
将硬盘中的数据存入到内存中,称为读read,也称为输入Input。
流的分类
Java中将流定义为类,以对象的形式表现流。流有"四大家族",是所有流的父类。
字节输入流InputStream
字节输出流OutputStream
字符输入流Reader
字符输出流Writer
FileInputStream文件字节输入流
按字节读取硬盘中的文件。读取的文件必须存在。
构造方法
FileInputStream(String pathName) 根据文件名创建流对象
FileInputStream(File file) 根据文件对象创建流对象
常用方法
read() | 读取一个字节,返回读取到的字节 |
read(byte[] bytes) | 按字节数组读取,返回读取到的字节数量,读取到的内容保存在字节数组 中 |
close() | 关闭流对象 |
FileOutputStream文件字节输出流
按字节将内存中的数据写入到硬盘中。文件可以不存在,但父目录必须存在。
构造方法
FileOutputStream(String pathname) | 根据文件名创建输出流对象,写入时覆盖原内容 |
FileOutputStream(String pathname,boolean append) | 根据文件名创建输出流对象,第二个参数为true,写 入时追加在原内容之后 |
FileOutputStream(File file) | 根据文件对象创建输出流对象,写入时覆盖原内容 |
FileOutputStream(File file,boolean append) | 根据文件对象创建输出流对象,第二个参数为true, 写入时追加在原内容之后 |
常用方法
write(int i) | 写入一个指定字节 |
flush() | 将流中的数据冲刷到硬盘中 |
close() | 关闭流对象 |
网络编程
InetAddress类
表示IP对象的一个类
public static void main(String[] args) throws UnknownHostException {
//获取本机的ip对象
// InetAddress ip = InetAddress.getLocalHost();
//获取域名
// System.out.println(ip.getHostName());
//获取真实ip地址
// System.out.println(ip.getHostAddress());
//getByName(域名) 得到域名对应的ip对象
//localhost域名表示本机,对应的ip地址为127.0.0.1
InetAddress ip = InetAddress.getByName("localhost");
//获取域名
System.out.println(ip.getHostName());
//获取ip地址
System.out.println(ip.getHostAddress());
}
Socket类和ServerSocket类
都属于Socket(套接字)对象,表示网络中的某个端点。
Socket指普通端
ServerSocket指服务器端
使用套接字对象实现两个端点(Socket和ServerSocket)之间发送文件
服务器端
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
/*
* 使用套接字对象,实现客户端向服务端发送文件
*
* 定义服务端套接字对象
客户端
* */
public class Server {
public static void main(String[] args) throws IOException {
//以本机创建服务端套接字对象
ServerSocket server = new ServerSocket(8899, 100,
InetAddress.getLocalHost());
//等待客户端连接,返回连接的客户端套接字对象
Socket client = server.accept();
//定义要将读取到的数据写入到本地的文件字节输出流对象
FileOutputStream fos = new FileOutputStream("上传文件.md");
//获取客户端与服务端的输入流对象,读取发送的数据
InputStream is = client.getInputStream();
//定义读取的字节数组
byte[] bytes = new byte[1024 * 1024 * 8];
int count = is.read(bytes);
while (count != -1) {
//将读取到的数据写入到本地
fos.write(bytes, 0, count);
count = is.read(bytes);
}
fos.close();
is.close();
}
}
客户端
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
/*
* 定义客户端套接字对象
* */
public class Client {
public static void main(String[] args) throws IOException {
//创建客户端套接字对象,连接指定的服务端套接字对象
Socket client = new Socket("192.168.31.39", 8899);
//获取客户端与服务端的输出流对象
OutputStream os = client.getOutputStream();
//成功连接后,将某个文件发送给服务端
//定义要发送的文件对象
File file = new File("F:\\221001\\笔记\\面向对象部分回顾.md");
//读取要发送的文件
FileInputStream fis = new FileInputStream(file);
作业
//定义字节数组
byte[] bytes = new byte[1024 * 1024 * 8];
//循环读取要发送的文件
int count = fis.read(bytes);
while (count != -1) {
//将读取到的数据写入到客户端套接字与服务端套接字的通道中
os.write(bytes,0,count);
count = fis.read(bytes);
}
fis.close();
os.close();
}
}