String是一个类,属于数据类型中的引用类型。
Java中一切使用""引起来的内容,都是这个类的实例,称为字符串对象。
字符串在定义后,值不可改变,是一个常量,实际是一个字符数组。
String字符串对象是一个常量,在定义后,值不可改变。
如果使用String类的对象,对其频繁更新时,就会不停地创建新的对象,不停引用给同一个变量。 如要执行10000次循环重新赋值的过程,就要创建10000个字符串对象,执行效率很低,这时就需要使 用可变字符串对象。
用于表示可变字符串的一个类,是非线程安全的,建议在单线程环境下使用。
用于表示可变字符串的一个类,是线程安全的,建议在多线程环境下使用。
注意:
方法一:String.valueOf(Object obj)方法
方法二:对象.toString();
方法三:
用于表示日期时间的类,位于java.util包下
用于格式化日期的类。
表示日历的类,包含了很多日历相关的信息。 是一个抽象类,无法创建对象。可以通过静态方法getInstance()获取该类的一个实例。
在Calendar类中,定义了很多被final和static修饰的常量,称为日历字段,实际一个数字,用于获取指 定信息
Java是纯面向对象语言,宗旨是将一切事物视为对象处理。但原始类型不属于对象,不满足面向对象的思想。但原始类型在使用时无需创建对象,保存在栈中,效 率高。 为了让原始类型也有对应的类类型,达到"万物皆对象"的理念,所以就有了包装类的概念 包装类就是原始类型对应的类类型。包装类通常用于字符串与原始类型之间的转换。在web应用中,从浏览器页面中获取到后台的数据,全部都是String类型,所以一定要使用转换为原始 类型的方法。
特点:
使用原始类型对应的包装类,调用parse原始类型(字符串)方法
当程序没有按开发人员的意愿正常执行,中途出现错误导致程序中断,出现这种情况,就称为异常。 学习异常就是认识异常的种类,如何处理异常和避免异常出现。
异常在程序中以对象的形式存在。当代码执行过程中出现异常,虚拟机会自动创建一个异常对象,如果 没有对象该异常对象进行处理,就会导致程序中断,不再执行后续代码。
异常在程序中以对象的形式存在,就有相应的类。 所有的异常类,组成了一个"异常家族"。
如果出现xxxxError,如StactOverFlowError,栈空间溢出,无法通过额外的代码解决,只能修改源码。
如果出现xxxxException,如NullPointerException,空指针异常,可以通过额外的代码去解决。
通常所说的处理异常,是指处理Exception类的子类异常。 处理异常的目的,就是保证程序正常执行。
这种方式处理异常,无论会不会抛出异常,都能让程序正常执行。
执行流程:先执行try中的代码,当出现异常,与后续catch中的异常类型进行匹配,如果匹配到对应的 类型或异常父类型,则执行大括号中的代码,最终一定执行finally中的内容。
try-catch-finally使用时注意
这种方式,可以让编译时异常通过编译。 在定义方法的时候,通过该关键字声明可能抛出的异常。 用法:方法的参数部分之后,添加"throws 异常类型1,异常类型2..."
如果需要在某种情况下中断程序, 可以自定义一个异常类,再通过throw关键字手动抛出。
1.定义一个类,继承某个异常类
2.可选操作。定义带参构造方法,参数为异常信息,调用父类中的构造方法
Collection还有父接口Iterable,但Iterable接口不算严格意义上的集合的根接口。它称为迭代器,是用 于遍历集合元素的一个工具接口。 所有集合的根接口为Collection接口和Map接口,位于java.util包中。
该接口有两个核心子接口:List和Set。
这两个接口都可以保存一组元素,List接口保存元素时,是有序可重复的;Set接口保存元素时,是无序 不重复的。
有序集合,元素可以重复,允许保存null,可以通过索引获取对应位置上的元素。 在该接口继承Collection接口的同时,又拓展了一些操作元素的方法,如添加到指定索引、根据索引删 除、获取指定索引的元素、截取子集合的方法等。
由于LinkedList既实现了List接口,又实现了Deque接口,所以还有Deque接口中的一些方法
无序集合,元素不可以重复,允许保存null,没有索引。 Set接口中没有自己定义的方法,都是继承于Collection接口中的方法
哈希表,也称为散列表,是一种数据结构,能更快地访问数据。 要保存的数据称为原始值,这个原始值通过一个函数得到一个新的数据,这个函数称为哈希函数,这个 新数据称为哈希码,哈希码和原始值之间有一个映射关系,这个关系称为哈希映射,可以构造一张映射 表,这个表称为哈希表。在哈希表中,可以通过哈希码快速地访问对应的原始值。
假设原本的数据为左侧的数组。 如果要查询10,需要遍历数组,效率不高。 通过一个特定的函数"原始值%5",得到一组新数据,让新数据重新对应元素,保存到“新数组”中,这个 “新数组”称为哈希表。 这时如果要查询10,由于哈希函数是通过%5得到了0,所以直接查询哈希表中0对应的元素即可。 整个过程中,这个函数称为哈希函数,得到的新数据称为哈希码,新数组称为哈希表,对应关系称为哈 希映射。 这个哈希函数,有一定的几率让多个原始值得到相同的哈希码,这种情况称为哈希冲突(哈希码一致,实 际值不同), 为了解决哈希冲突,可以使用"拉链法",将2这个哈希码所在的位置向链表一样进行延伸。
HashSet中没有属于自定义的方法,都是重写了父接口Set和Collection中的方法。这里参考Collection中 的方法即可。没有与索引相关的方法。
如果想要保存的对象保证不重复,且无关顺序,可以使用HashSet。如学生管理
Goods类
package com.hqyj.hashsetTest;
import java.util.Objects;
/*
* 定义商品类
* 品牌、名称、价格
* */
public class Goods {
private String brand;
private String name;
private int price;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Goods goods = (Goods) o;
return price == goods.price &&
Objects.equals(brand, goods.brand) &&
Objects.equals(name, goods.name);
}
/*
* 根据所有属性生成哈希码
* 如果两个对象的所有属性都一致,生成的哈希码就一致
* */
@Override
public int hashCode() {
return Objects.hash(brand, name, price);
}
@Override
public String toString() {
return "Goods{" +
"brand='" + brand + '\'' +
", name='" + name + '\'' +
", price=" + price +
'}';
}
public Goods(String brand, String name, int price) {
this.brand = brand;
this.name = name;
this.price = price;
}
public String getBrand() {
return brand;
Main类
}
public void setBrand(String brand) {
this.brand = brand;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
}
Main类
package com.hqyj.hashsetTest;
import java.util.HashSet;
import java.util.Iterator;
public class Main {
public static void main(String[] args) {
//创建一个HashSet集合
HashSet hs = new HashSet<>();
//创建几个Goods对象
//g1、g2、g3的属性不同,生成的hashcode不同,都能添加
Goods g1 = new Goods("康师傅", "冰红茶", 3);
Goods g2 = new Goods("康师傅", "红烧牛肉面", 5);
Goods g3 = new Goods("农夫山泉", "矿物质水", 2);
//g3与g4的属性相同,生成的hashcode相同,继续判断equals
Goods g4 = new Goods("农夫山泉", "矿物质水", 2);
//第一次添加,一定可以添加
hs.add(g1);
//第二次添加,对象的属性不同,hashcode不同,可以添加
hs.add(g2);
//第三次添加,对象的属性不同,hashcode不同,可以添加
hs.add(g3);
//第四次添加,对象的属性相同,hashcode相同,再判断equals结果,true,视为已存在,无法
添加
hs.add(g4);
/*
* HashSet没有可以通过索引获取对象的方法,所以无法使用普通for循环遍历
* 这里可以使用增强for循环
* */
for (Goods g : hs) {
System.out.println(g);
}
/*
* 可以使用迭代器遍历HashSet集合中的所有元素
* */
/*Iterator it = hs.iterator();
while (it.hasNext()) {
Goods goods = it.next();
System.out.println(goods);
}*/
}
}
Map称为映射,数据以键值对的形式保存。保存的是键与值的对应关系。 键称为Key,值称为Value,键不能重复,键允许出现一个null作为键,值无限制。 键和值都是引用类型。 如,yyds就是一个键key,代表了一个含义:“永远单身”即为值value。
一种规范,常用于限制集合中元素的类型,省去遍历元素时判断是否为对应类型和转型的过程
在定义集合遍历时,在类后面写上<引用数据类型>
集合类或接口 <引用数据类型>集合变量名 = new 集合实现类();
Java中的File类,表示本地硬盘中的文件(文件和目录)的一个类。 通过这个类创建的对象,可以操作对应的文件。
package com.hqyj.FileTest;
public class Test2 {
public static void main(String[] args) {
//兔子问题
//有一对兔子在第三个月开始,每个月都能生一对小兔子
//如果所有兔子不死亡,且每次生下的都是一雌一雄,问10个月后共有多少对兔子
//1月 2月 3月 4月 5月 6月 7月 8月 9月 10月
//1 1 2 3 5 8 13 21 34 55
//斐波那契数列
//f(n)=f(n-1)+f(n-2) n>2
Test2 t = new Test2();
System.out.println(t.f(20));
}
/*
* 递归方法
* */
public int f(int n) {
if (n > 2) {
return f(n - 1) + f(n - 2);
}
return 1;
}
}
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);
}
}
}
}
I:Input输入
O:Output输出
在Java中,流用于表示计算机硬盘与内存之间传输数据的通道。将内存中的数据存入到硬盘中,称为写write,也称为输出Output。将硬盘中的数据存入到内存中,称为读read,也称为输入Input。
Java中将流定义为类,以对象的形式表现流。流有"四大家族",是所有流的父类。
FileInpuStream、ObjectInputStream
FileOutputStream、ObjectOutputStream
FileReader、BufferedReader、OutputStreamWriter
FileWriter、BufferedWriter、InputStreamReader
按字节读取硬盘中的文件。
按字节将内存中的数据写入到硬盘中。
如有word.txt文件,其中保存aaabbbccc
FileInputStream fis = new FileInputStream("d:/word.txt");
FileOutputStream fos = new FileOutputStream("d:/copy.txt");
byte[] bytes = new byte[4];
//第一次读取4个字节,即aaab,count为4
int count=fis.read(bytes);
//写入数组中的全部内容
fos.write(bytes);
//第二次读取4个字节,即bbcc,count为4
count=fis.read(bytes);
//写入数组中的全部内容
fos.write(bytes);
//第三次读取1个字节c,覆盖数组中的第一个元素,即数组现在为cbcc,count为1
count=fis.read(bytes);
//写入数组中的全部内容
fos.write(bytes);//最终会写入aaabbbcccbcc
fos.write(bytes,0,count);//这样最后一次只会写入实际读取到的c
fos.close();
fis.close();
package com.hqyj.IOTest;
import java.io.*;
public class CopyFile {
public static void main(String[] args) throws IOException {
//定义原文件和目标文件
File source = new File("F:\\221001\\录屏\\FileInputStream和
FileOutputStream.mp4");
File target = new File("F:\\221001\\copy.mp4");
//定义文件字节输入流,用于读取原文件
FileInputStream fis = new FileInputStream(source);
//定义文件字节输出流,用于写入文件
FileOutputStream fos = new FileOutputStream(target);
/*
//调用无参的read()方法,表示读取一个字节,返回读取到的字节
int read = fis.read();
//如果能读取到内容
while (read > -1) {
//将读取到的内容写入到文件中
fos.write(read);
//继续读取
read = fis.read();
}
*/
//定义一个字节数组,大小为8MB
byte[] bytes = new byte[1024 * 1024 * 8];
//按字节数组读取,返回读取到的字节数量
int count = fis.read(bytes);
//循环读取写入
while (count > -1) {
//将读取的字节数组写入到文件中
// fos.write(bytes);//如果调用该方法,最后一次会多写入上一次残留的数据
fos.write(bytes,0,count);//如果调用该方法,实际读取到了多少字节就写入多少
count = fis.read(bytes);
}
fis.close();
fos.close();
if (target.exists()) {
System.out.println("复制成功");
}
}
}
package com.hqyj.IOTest;
import java.io.*;
public class CopyDirectory {
public static void main(String[] args) {
/*File source = new File("F:\\221001\\录屏\\流的基本概念.mp4");
File target = new File("F:\\221001\\copy.mp4");
copyFile(source, target);*/
File source = new File("F:\\221001\\笔记");
File target = new File("F:\\221001\\笔记副本");
/*
* source F:\221001\笔记
* target F:\221001\笔记副本
* 1.调用copyDir方法,判断发现source是一个文件夹,创建目标文件夹
target:“F:\221001\笔记副本”
* 2.遍历source,如其中有xxx.md文件,即child
* 此时的source是F:\221001\笔记\xxx.md,即child
* 此时的target是F:\221001\笔记副本\xxx.md,用File(File parent,String child)
构造方法表示这个目标文件
* 所以创建File newTarget = new File(target,child.getName())
*
* */
copyDir(source, target);
}
/*
* 定义复制文件夹的方法
* */
public static void copyDir(File source, File target) {
//如果是文件,调用单文件复制的方法
if (source.isFile()) {
copyFile(source, target);
} else {//如果是文件夹
//创建要复制的目标文件夹
target.mkdir();
//展开原文件夹
for (File child : source.listFiles()) {
//定义复制后的新目标文件
//如source为F:\221001\笔记\day1.md时,递归调用的target为F:\221001\笔
记副本\day1.md
File newTarget = new File(target, child.getName());//这里使用
File(File parent,String child)构造方法创建target对象
//递归调用的原文件依然是当前遍历出来的子文件,目标文件就是最终复制的
F:\221001\笔记副本\day1.md
copyDir(child, newTarget);
}
}
}
/*
* 定义单文件复制的方法
* */
public static void copyFile(File source, File target) {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
//创建用于输入输出的流对象
fis = new FileInputStream(source);
fos = new FileOutputStream(target);
//定义字节数组
byte[] bytes = new byte[1024 * 1024 * 8];
//按数组读取
int count = fis.read(bytes);
while (count != -1) {
fos.write(bytes, 0, count);
count = fis.read(bytes);
}
} catch (FileNotFoundException e) {
System.out.println("文件不存在" + e);
} catch (IOException e) {
System.out.println("读写异常" + e);
} finally {
try {
if (fis != null) {
fis.close();
}
if (fos != null) {
fos.close();
}
} catch (IOException e) {
System.out.println("关闭流对象异常" + e);
}
}
}
}
自带缓冲区(字符数组)的字符输入流。默认字符数组大小为8192,每次最多读取8192个字符。 在读取纯文本文件(txt或md)时,首选该类。
package com.hqyj.ReaderAndWriter;
import java.io.*;
public class Test2 {
public static void main(String[] args) throws IOException {
/*
File file = new File("F:\\221001\\笔记\\Java基础回顾.md");
//FileReader(File file)
Reader fr = new FileReader(file);
//BufferedReader(Reader in)
BufferedReader br = new BufferedReader(fr);
*/
//创建带有缓冲区的字符输入流对象
BufferedReader br = new BufferedReader(new FileReader("F:\\221001\\笔记
\\Java基础回顾.md"));
//循环判断是否还有字符
while (br.ready()) {
//读取整行
System.out.println(br.readLine());
}
//关闭最大的流对象即可
br.close();
}
}
自带缓冲区(字符数组)的字符输出流
package com.hqyj.ReaderAndWriter;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.logging.SimpleFormatter;
public class Test3 {
public static void main(String[] args) throws IOException {
File file = new File("221001.txt");
//创建缓冲字符输入流对象,读取文本
BufferedReader br = new BufferedReader(new FileReader(file));
//创建集合,保存读取到的姓名
ArrayList list = new ArrayList<>();
//循环读取文件中的所有字符
while (br.ready()) {
String name = br.readLine();
list.add(name);
}
//关闭
br.close();
//打乱集合中的元素
Collections.shuffle(list);
//创建日期字符串
String today = new SimpleDateFormat("yyyy.MM.dd").format(new Date());
//创建缓冲字符输出流,用于写文本,文件名为"日期+作业情况.txt",如果每次都是新建,这样
写
// BufferedWriter bw = new BufferedWriter(new FileWriter(today + "作业情
况.txt"));
//如果要追加,在new FileWriter("文件名",true)设置
BufferedWriter bw = new BufferedWriter(new FileWriter(today + "作业情
况.txt",true));
//写入字符串
bw.write("姓名\t\t是否完成");
//换行
bw.newLine();
Scanner sc = new Scanner(System.in);
//随机3个人
for (int i = 0; i < 3; i++) {
String name = list.get(i);
System.out.println(name + "完成情况:");
String str = sc.next();
//写入读取到的内容
bw.write(name + "\t\t" + str);
//换行
bw.newLine();
}
bw.close();
}
}
序列化:将对象转换为文件的过程 被序列化的对象,必须要实现Serializable接口。 这个接口是一个特殊的接口,没有定义任何方法,只是给该类加上标记,表示该类可以被序列化
反序列化:将文件转换为对象的过程
Person类,实现Serializable接口
package com.hqyj.ObjectStream;
import java.io.Serializable;
/*
* 如果希望该类的对象能序列化,写入对象到本地,必须要实现Serializable接口
* Serializable接口中没有任何方法,是一个标记接口,表示该类的对象可以被序列化
* */
public class Person implements Serializable {
private String name;
private int age;
private String sex;
//省略getter/setter和toString()
}
Main类
package com.hqyj.ObjectStream;
import java.io.*;
import java.util.ArrayList;
public class Test1 {
public static void main(String[] args) throws IOException,
ClassNotFoundException {
Person p1 = new Person("王海", 22, "男");
Person p2 = new Person("赵敏", 24, "女");
Person p3 = new Person("刘涛", 21, "女");
ArrayList list = new ArrayList<>();
list.add(p1);
list.add(p2);
list.add(p3);
//创建OutStream的实现类,设置写入的文件路径
OutputStream os = new FileOutputStream("F:\\221001\\person.p");
//创建对象输出字节流,参数为OutStream类型
ObjectOutputStream oos = new ObjectOutputStream(os);
//调用writeObject(Object obj)方法,将对象写入到硬盘中(序列化)
oos.writeObject(list);
oos.close();
//创建对象输入字节流,将上一步保存的文件进行反序列化
ObjectInputStream ois = new ObjectInputStream(new
FileInputStream("F:\\221001\\person.p"));
//使用readObject()方法,将写入的文件进行读取(反序列化)
ArrayList pList = (ArrayList) ois.readObject();
for (Person person : pList) {
System.out.println(person);
}
ois.close();
}
}
表示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(套接字)对象,表示网络中的某个端点
package com.hqyj.uploadTest;
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();
}
}
package com.hqyj.uploadTest;
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();
}
}
相同点:
不同点:
这个阶段的学习起来虽然比面对对象容易理解,但是内容很多,学到后面就不知道前面的就学了啥,还是要多花时间看一下笔记,温故而知新,加强一下记忆。