1.异常
(1) 数组越界异常
public class Test{
public static void main(String [] args){
String[] strs = new String[]{"a","b","c"}
for(int i=0;i<4;i++){
System.out.println(strs[i]);
}
}
}
报错数组越界
java.lang.ArrayIndexOutOfBoundsException:3
(3表示第三个元素)
(2)空指针异常
public class Test{
public static void main(String [] args){
A a = new A();
A a = null;
System.out.println(a.i);//这里的a为空所以不能.i
}
}
报错:
java.lang.NullpointerExcption
(3)错误运算
public class Test{
public static void main(String [] args){
int=0;
System.out.println(3/i);
}
}
报错:
java,lang.ArithmeticException:/by zero
(4)
2.捕获异常
(1)
- java异常处理机制:抓抛模型
- Java 程序的执行过程中如出现异常,会自动生成一个异常类对象,该异常对象被提交给java运行时系统,这个过程称为抛出异常
- 如果一个方法内抛出异常,该异常会被抛到调用方法中。如果异常没有在调用方法汇总处理,它继续被抛给这个调用方法的调用者,这个过程将一直继续下去知道异常被处理,这个过程称为捕获异常。
try{//用try{}来括住一段有可能异常的代码段
System .out.println(3/i);
}catch(Exception e){//当不知道捕获的是什么类型时可以使用所有异常的父类Excption
e,.printStackTrace();
System.out.println( e.getMessage() );//输出异常
}
(2)程序员通过Excepion,而对Error无能为力
(3)
try{
System.out.println(1);
System .out.println(3/i);
System.out.println(2);
}catch(Exception e){
System.out.println(3);
}finally{//这个代码终止操作,可写可不写,默认存在
System.out.println(3);
}
//输出
1
3
4
//在 输出2 前发生异常不再执行try里的语句
(4)多个catch
try catch 是为了防止程序,可能出现的异常
String [] strs = new String [] {"a","b"};
A a = null;
try {
System.out.println(strs[2])};
System.out.println(a,i);
}catch(ArrayIndexOutOfBoundsEception e1){
System.out.println(e1.getMessage());
}catch(NullpointerException e2){
System.out.println(e2.getMessage());
}
System.out.println("====");
//输出
2//输出的时数组越界异常
=====
在捕获异常的代码块中(try{}里的代码),如果前面的代码出现异常了,就不会执行后面的了;
(5)
- getMessage() 方法,用力啊得到有关异常事件的信息。
- printStackTrace()用来跟踪异常事件发生时执行堆栈的内容
3. ## 抛出异常
(1)
public class Test1{
pulic static void main(String[] args){
//main方法抛出的异常直接抛到虚拟机上,在程序中不能处理
//一般异常需要在自己的程序中处理掉所以一半不在main中抛异常
B b = new B();
try{//throws 在代码这抛出的异常,在调用方去捕获处理
b.test();
}catch(Exception e){
e.printStackTrace();
}
b.test();
}
}
class B{
int i;
//可以使用throws在代码这抛出异常,在调用方去捕获处理
public void test() throws Exception{
B b = null;
System.out.println(b.i);
}
}
(2)抛出异常父子类关系
- 子类继承父类时,父类有抛出异常,则父类也必须抛出
- 子类重写父类的方法时,子类不能抛出比父类更大的异常;
例如
public class Test1{
pulic static void main(String[] args){
B b = new B();
try{
b.test();
}catch(Exception e){
e.printStackTrace();
}
b.test();
}
}
class B{
int i;
//NullpointerException的父类时Exception
//就是说Exception比NullpointerException范围大
public void test() throws NullpointerException{
B b = null;
System.out.println(b.i);
}
}
//继承B
class C extends B{
重写B的方法,并把范围扩大了
@Override
//此时就会报错;
public void test() throws Exception{
super.test();
}
}
(3)人工抛出异常
java 异常类对象除在程序中出现异常时由系统自动生成异常,并抛出,也可以根据需要人工创建并抛出;
首先要生成异常类对象,然后通过throw语句实现抛出操作(提交给java运行环境)
IOException e = new IOException();
throw e;
可以抛出异常必须是Throwable或者子类的实例。下面语句在编译时会产生语法错误
throw new String(“want to throw”);
public class Test1{
pulic static void main(String[] args){
B b = new B ();
try{
b.test1(-100);
} catch (Exception e){
e.printStackTrace();
}
}
}
class B{
int i;
public void test() throws Exception{
B b = null;
System.out.println(b.i);
}
int age;
public void test1(int age) throws Exception {
if(age >= 0 && age <= 150){
this.age = age;
System.out.println("年龄是"+ this.age);
}
else{
throw new Exception(“年龄在0到150之间”);
}
}
}
//继承B
class C extends B{
@Override
public void test() throws Exception{
super.test();
}
}
(4)使用用户自定义的异常类
- 用户自定义异常MyException,用于描述数据取值范围错误信息。用户自己的异常类必须继承现有的异常类。
class MyException extends Exception{
public MyException
}
4. java集合——HashSet集合
(1)
java集合类存放于java.util包中,是一个用来存放对象的容器。
- 集合只能存放对象,比如你存放一个int类型数据1放入集合中,其实他是自动准换成Integer类(封装类)后存入的,java中每一种基本类型都有对应的引用类型。
- 集合存放的是多个对象的引用,对象本身还是放在堆内存中。
- 集合可以存放不同类型,不限数量的数据类型。
java 集合可分为Set,List和Map 三种大体系
- Set:无序 不可重复的集合
- List:有序 可重复的集合
- Map:具有映射关系的集合
在JDK5之后,增加了泛型,java集合可以记住容器种对象的数据类型。
(2)
HashSet是Set接口的典型实现,大多数时候使用Set集合时都使用这个实现类。我们大多数时候说的set集合值得都是HashSet
HashSet按Hash 算法来存储集合中的元素,因此具有很好的存取和查找性能。
HashSet 具有以下特点:
-
不能保证元素的排列顺序(输入的元素不保证时按顺序的,存在哪由hashCode决定)
-
不可重复 (指的是hashCode不相同)
-
集合元素可以是 null
当向HashSet 集合中存入一个元素时,HashSet 会调用该对象的hashCode()方法来得到该对象的hashCde 值,然后会根据hashCode 值决定该对象在HashSet 中的存储位置。
如果两个元素的 equals()方法返回 true,但他们的hashCode()返回值不相等,hashSet 将会把他们存储在不同的位置,但依然可以添加成功。(一般情况下hashCode和equals()都是同时相等或不相等的)
(3)
很多接口用于操作set集合
(4)使用
//使用到的包
import java.util.hashSet;
import java.util.Iterator;
import java.util.Set;
public class Test3{
public static void main(String[] args){
Set set = new HashSet();
Set.add(1);
Set.add("a");
set.remove(1);//移除 元素 1
System.out.println(set.contains(1)) //检测1是否在集合中,返回布尔类型true和false
set.clear();//清空集合所有元素
System.out.println(set);//输出集合中的所有元素
System.out.println(set.size());//获取集合的个数
set.add("a");
set.add("a");
//此时集合中只有一个a,集合的不重复性
//遍历两种方式
//使用迭代器遍历集合
Iterator it = set.itertor();//调用迭代器
while(it.hasNext()){
System.out.println(it.nest());
}
//for each 迭代
//这个意思是把set的每一个值去除阿里,赋值给obj,知道循环set的所有值
for(Object boj :set){
System.out.println(obj);
}
}
}
(5)hashCode()方法
HashSet集合判断两个元素相等的标准:
- 两个对象通过equals()方法比较相等,并且来给你个对象的hasCode()方法返回值也相等。
- 如果两个对象通过 equals()方法返回true,这个对象的hashCode值也应该相同。
(6)泛型
如果想要让集合只能存相同类型的对象,需要使用泛型
//此时set1集合只能存String类型的
Set<String> set1 = new HashSet<String>();
当定义为Object类型的集合就可以存储所有类型的,因为Object是所有类的父类;
Set<Object> set = new HashSet<Object>();
5. java集合——TreeSet
(1)TreeSet 是SortedSet 接口的实现类,TreeSet 可以确保集合元素处于排序状态。TreeSet 支持两种排序方法:自然排序和定制排序。默认情况下,TreeSet采用自然排序。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210622221649144.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzUxNDk3MDQx,size_16,color_FFFFFF,t_70)
(2)自然排序
排序:TreeSet 会调用集合元素的 compareTo(Object obj)方法来比较元素之间的大小关系,然后将集合元素按升序排列;
必须放入同样类的对象,(默认会进行排序)否则可能会发生类型转换异常,我们可以使用泛型来进行限制;
import java.otil.Set;
public class Test4{
public static void main(String[] args){
//自然排序;
Set<Integer> Set = new TreeSet<Integer>();
set.add(4);
set.add(2);
set.add(5);
set.add(3);
System.out.println(set);
//遍历
//使用迭代器遍历集合
Iterator<Integer> it = set.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
//for each迭代集合,推荐使用
for(Integer i : set){
System.out.println(i);
}
}
}
(3)自定义类排序使用集合排序,(集合可以存储各种类型的)(定制排序)
import java.otil.Set;
public class Test4{
public static void main(String[] args){
Person p1 = new Person("张三",23);
Person p2 = new Person("李四",22);
Person p3 = new Person("王五",16);
Set<Person> set = new TreeSet<Person>(new Person());
set.add(p1);
set.add(p2);
set.add(p3);
//遍历输出
for(Person p : set){
System.out.println(p.name + " " + p.age);
}
}
}
class Person{
int age;
String name;
//构造
public person(){
}
public Person(String name,int age){
this.name = name;
this.age = age;
}
//实现方法
//负责排序,此时为大——>小,若反过来,把大于变小于就成
@Override
public int compare (Person o1,Person o2){
if (o1.age > o2.age){
return 1;
} else if{
return -1;
}else{
return 0;
}
}
}
6.List与ArrayList
- List代表一个元素有序。且可重复的集合,集合中的每个元素都有其对应的顺序索引
- List 允许使用重复元素,可以通过索引来访问指定位置的集合元素
- List 默认按元素的添加顺序设置元素的索引
- List 集合里添加了一些根据索引来操作的集合元素的方法
(2)
public class Test5 {
public static void main(String[] args){
Lict<List> list = new ArrayList<String>();
list.add("a");//第一个索引线标为0
list.add("b");//索引下标为1
list.add("c");
list.add("d");
System.out.println(list.get(2));
list.add("a");//允许使用重复元素
list.add(1,"f");//在指定元素插入数据,其他元素都会向后移
list<String> l = new SrrayList<String>();
l.add("123");
l.add("456");
list.addAll(2,1);//指定位置获取元素插入集合
System.out.println(list);
//获取指定元素在集合中第一次出现的索引下标
System.out.println(list.indexOf("d"));
System.out.println(list.lastIndexOf("d"));//最后一次
list.remove(2)//根据索引下标移除元素
list.set(1,"ff");//将下标为1的元素修改为ff
//截取索引为2到4的元素,不包含4 [2,4)
List<String> sublist = list.subList(2,4);
System.out.println(list.size());//获取长度
}
}
(3)
7 map——hashmap
(1)
- map 用于保存具有映射关系的数据,因此在map集合里板寸两组值,一组值用于保存map里的key,另外一组用于保存map里的value
- map 中的key 和 value 都可以是任何引用类型的数据map中的key不允许重复,即同一个对象的任何key通过equals 方法比较返回 false
- key 和 value 之间存在单向一对一关系,即通过指定的key总能找到唯一的,确定的value
(2)
hashmap类对map接口的经典实现
(3)
import java.util.HashMap;
import java.util.Map;
public class Test6{
public static void main(String [] args){
Map<String,Integer> map = new HashMap<>String,Integer();
map.put("b",1);//添加数据
map.put("c",2);//数据可以相同但键值不能相同
map.put("d",2);
System.out.println(map);//输出
System.out.println(map.get("b"));//根据key取值
map.remove("c");//移除键值对应的值
System.out.println(map);
System.out.println(map.size());//map集合的长度
System.out.println(map.containsKey("a"));//判断当前map集合是否包含指定的key
System.out.println(containsValue(10));
map.clear();//清空集合
Set<String> keys = map.keySet();
map.values();//获取map集合所有值value
//遍历map集合,通过map.keySet();
for(String key : key){
System.out.println("key :" + key + ", value"+ map.get(key));
}
//通过map.entrySet(); 需要导入一个包Import‘Entry’(java.util.Map)
//遍历map集合
Set<Entry<String,Integer>> entrys = map.entrySet();
for(Entry<String,Integer> en : entrys){
System.out.println("key:" + en.getKey());
}
}
}
(4)
(5)
一般情况下,不会使用过于复杂的对象坐key
很少使用定制排序
(6)
//TreeMap的自然排序是字典排序
Map<Integer,String> map = new TreeMap<Integer,String>();
map.put(4,"a");
map.put(2,"a");
map.put(3,"a");
map.put(1,"a");
System.out.println(map);
//自然排序使用因为字典排序
Map<String,String> map1 = new TreeMap<String,String>();
map1.put("b","b");
map1.put("c","b");
map1.put("s","b");
map1.put("a","b");
map1.put("ab","ab");
System.out.println(map1);
- 操作集合的工具类:Collections
Collections 是一个操作 Set List 和 Map 等集合类
Collections 中提供了大量的方法对集合元素进行排序,查询和修改等操作,还提供了对集合对象设置不变。对集合对象实现同步控制等方法
排序操作:
- reverse(List):反转List中元素的顺序
- shuffle(List):对List集合元素进行随机排序
- sort(List):根据元素的自然顺序对指定List集合元素按升序排序
- sort(List,Comparator):根据指定的Comparator 产生顺序对List集合元素进行排序
- swap(List,int,int):将指定list集合中的i出元素和j处元素进行交换
(2)
import java.util.ArrayList;
import java.util.List;
public class Test7{
public static void main(String[] args){
List<String> list = new ArrayList<String>();
list.add("b");
list.add("cd");
list.add("ca");
list.add("a");
list.add("l");
list.add("a");
System.out.println(list);
Collections.reverse(list);//反转List中元素的顺序
System.out.println(list);
Collections.shuffle(list);//随机排序List中元素的顺序
System.out.println(list);
Collections.sort(list);//List集合字典升序排列
System.out.println(list);
//返回指定元素出现的次数
System.out.println(Collections.frequency(list,"x"));
//替换指定元素(把a替换成了aa)
Collections.replaceAll(list,"a","aa");
/*
Collections.swap(list,0,4);//List中指定位置元素交换(0和4)
System.out.println(list);
*/
//这里需要把上面的个注释掉
Student s1 = new Student(14,"张三");
Student s1 = new Student(12,"李四");
Student s1 = new Student(13,"王五");
Student s1 = new Student(11,"小六");
List<Student> stus = new Arraylist<Student>();//创建集合
stus.add(s1);
stus.add(s2);
stus.add(s3);
stus.add(s4);
//输出集合里的对象最大值
Student s = Collections.max(stus,new Student());//有返回值
System.out.println(s.name + "," + s.age);
for(Student stu : strs){//遍历
System.out.println(stu.name + "," + stu.age);
}
Collections.sort(stus,new Student());//排序
System.out.println("升序排列后");
for(Student stu : strs){
System.out.println(stu.name + "," + stu.age);
}
}
}
class Student implements Compartor<Student>{
int age;
String name;
public Student(){
}
public Strdent (int age,String name){
this.age = age;
this.name = name;
}
@Override
public int compare(Student o1,Strdent o2){
if(o1.age > o2.age){
return 1;
}else if(o1.age < o2.age){
return -1;
}else{
return 0;
}
}
}
输出结果:
(3)
9.泛型
(1)介绍
java中的泛型,只在编译阶段有效。在编译过程中,正确检验泛型结果后,会将泛型的相关信息擦出,并且在对象进入和离开方法的边界出添加类型检查和类型转换的方法也就是说,泛型信息不会进入到运行阶段
(2)使用
(1.泛型类
对象实例化时不指定挡泛型,默认为object(所有父类都可调用)
import java.util.ArrayList;
import java.util.List;
public class Test{
public static void main(String[] args){
A<String> a1 = new A<String>(); //在new A的对象指定泛型的类型String
a1.serKey("XXXX");//对象使用serKey(T key )方法,中的key形参就是String
String s = a1.getKey();//T getKey(),返回值就有new对象确定值是String
A<Integer> a2 = new A<Integer>();
a2.serKey(1);
Integer i = a2.getKey();
A a3 = new A();//不指定泛型就相当于指定了一个Object类型
//A<Object> a3 = new A<object>();
a3.serKey(new Object());//这里猜测是创建的一个对象集合;
Object obj = a3.getKey();
//同样的类,但是在new对象时泛型指定不同的数据类型,这些对象不能互相赋值
//a1 = a2;//这样报错
}
}
//泛型类
/*
此处泛型可以任意取名 (尽量大写——类的类型)
一般使用T——type
*/
class A<T>{ //定义泛型
private T t;
public void serKey(T key){
this.key = key;
}
public getKey(){
return this.key;
}
}
(2.泛型接口;
/*
未传入泛型实参时,与泛型类的定义相同,在声明类的时候需要将泛型的声明也一起加到类中
即:class FruitGenerator implements Generator{}
如果不在声明泛型,如:class FruitGenerator implements Generator,编译器会报错:“Unknown class”
class FruitGenerator<T>
*/
public class Test1{
pubic static void main(String [] args){
B1<Object> b1 = new B1<Object>();
B1<String> b2 = new B1 <String>();
B2 b3 = new B2();
}
}
interface IB<T>{//定义泛型接口
T test(T t);
}
//未传入泛型实参时,与泛型类的定义相同,在声明类的时候需要将泛型的声明也一起加到类中
class B1 implements IB<T>{
@override
public T test(T t) {
return t ;
}
}
/*
如果实现接口时指定接口的泛型的具体数据类型
这个类实现接口所有方法的位置都要反省替换实际的具体数据类型
*/
class B2 implements IB<String>{
@Override
public String test(String t){
// TODO Auto-generated method stub
return null;
}
}
(3.泛型方法
方法,也可以被泛型化,不管此时定义在其中的类是不是泛型化的。在泛型方法中可以定义泛型参数,此时,参数的类型就是传入数据的类型。
泛型方法的格式:
public class DAO{
public void show (E e){
System.out.println(e.toStrin());
}
public T show1(T t){
return t;
}
}
/*
在类上定义的泛型,可以在普通的方法中使用;
假如class Cc<E>
private E e;
在之后的方法中可以使用
System.out.println(this.e);
//在静态方法中,不能使用类定义泛型,如果要使用泛型,只能使用静态方法自己定义的泛型
public static void test(this.e);
*/
/*
静态方法的泛型方法
这样就可以用了
public static <T> void test3(T t){
System.out.println(t);
}
*/
class Cc{
//无返回值
public <T> void test(T s){ //之前这里写的时String具体的类型现在设为T
T t = s ;
}
//有返回值的
public <T> String test1(String s){
return s;
}
//可变参数
//strs 为传过来多少个东西 然后用for接收;
public void test2(T… strs)
for(T s : strs){
System.out.println(s);
}
}
使用;
public class Test1{
public static void main(String[] args){
Cc<Sbject> c = new Cc<Object>();
c.test("xxx");
//泛型方法在调用之前没有固定的数据类型;
//在调用时传入的参数是什么类型,就会把泛型改成什么类型
//也就是说泛型方法会在调用时确定发逆行距离数据类型
Integer i = c.test1(2);//返回的参数为integer类型,泛型就固定成了Integer,返回值就是Integer
Boolean b = c.test2(true); //传递的参数是Boolean,泛型就固定成Boolean,返回值就是Boolean
}
}
10. 枚举类概述
在某些情况下,一个类的对象是有限的而且固定的,例如季节类,只能有4个对象
手动实现枚举类:
- private 修饰构造器
- 把属性使用private final修饰
- 把该类的所有实例都使用 public static final 来修饰
普通开发法方式:
单例模式
使用 enum 定义枚举类
- JDK 1.5 新增enum关键字用于定义枚举类
- 枚举类和普通类的区别:
- 使用enum定义的枚举类默认继承了java.lang.Enum类
- 枚举类的构造器只能使用private 访问控制符
- 枚举类的所有实例必须在枚举类中显示列出(, 分隔 ;结尾)列出的实例系统会自动添加 public static final 修饰
- 所有的枚举类都提供了一个values方法,该方法可以很方便的遍历所有的枚举值
- JDK1.5中可以在switch 表达式中使用枚举类的对象作为表达式,case子句可以直接使用枚举值的名字,无需添加枚举类作为限定
- 若枚举只有一个成员,则可以作为一种单子模式的实现方式
//枚举类
enum Season{
//这里SPRING相当于方法调用enum Season的构造方法
SPRING (“春天",“春暖花开”),
SUMMER(“夏天",”炎炎夏日”),
AUTUMN(“秋天",“秋高气爽”),
WINTER(“冬天",“寒风凛冽”);
//属性
private final String name;
private final String desc;
//Season的有参构造
private Season (String name,String desc){
this.name = name;
this.desc = desc;
}
public void showInfo(){
System.out.println(this.name + ":" + this.desc);
}
}
//调用
public class Test3 {
public static void main (String[] args){
//Season.SPRING 相当于枚举.构造 返回的还是枚举类型
//调用有参的私有构造
//Season.SPRING这个执行获取一个Season的对象
Season spring = Season.SPRING;
spring.showInfo();
……类推
Season spring1 = Season.SPRING;
每次执行 Season.SPRING获取相同的对象,枚举类中的每个枚举都是单例模式的
System.out.println(spring.equals(spring1));//返回true
}
}
枚举可以实现接口:
- 和普通的java类一样枚举类可以实现一个或多个接口
- 若需要每个枚举值在调用实现的接口方法呈现出的不同的行为方式,则可以让每个枚举值分别来实现该方法;
interface ITest{//接口
void test();
}
enum Season implements ITest{//枚举实现接口
@Override
public void test(){
System.out.println("这是实现的ITest接口的test方法");
}
}
//调用
public class Test3{
Season spring = Season.SPRING;
spring.test();
}
11.注解概述
- 从JDK 5.0开始,Java 增加了对元数据(MataData)的支持,也就是Annotation(注释)
- Annotation 其实就是代码里的特殊标记,这些标记可以在编译,类加载,运行时被读取,并执行相应的处理,通过使用Annotation,程序员可以在不改变原有逻辑的情况下,在源文件中嵌入一些补充信息
- Annotation 可以像修饰符一样被使用,可用于修饰包,类,构造器,方法,成员变量,参数,局部变量的声明,这些信息被保存在Annotation的“name = value”对中。
- Annotation 能被用来为程序元素(类,方法,成员变量等)设置元数据
使用Annotation时要在其前面增加@符号,并把该Anntation 当成一个修饰符使用,用于修饰它支持的程序元素;
三个基本Annotation(注解):
- @Override:限定重写父类的方法,该注释只能用于方法
- @Deprecated:用于便是某个程序元素(类,方法等)已过时
- @SuppressWarnings:抑制编译器警告
//当集合不写泛型时就会有警告
List LIst = new ArrayList();
//此时警告信息被抑制了
@SuppressWarnings(“rawtypes”)
List list = new ArrayList();
//方法已过时
@Deprecated
public void test1(){//
}
自定义Annotation(注解)
- 定义新的Annotation类型使用@interface关键字
- Annotation的成员变量在Annotation定义中以无参数方法的形式来声明,其方法名和返回值定义了该成员的名字和类型
- 可以在定义Annotation的成员变量时为其指定初始值,指定成员变量的初始值可使用default关键字
- 没有成员定义的Annotation 称为标记;包含成员变量的Annotation称为元数据Annotation
//创建属性的注解
@Target(ElementType.FIELD)//这个注解类给其他类的属性做注解
@Retention(RetentionPolicy.RUNTIME)//定义注解的声明周期
@Documented
@inteface TestAnn{
public int id()default 0;//不写时为0
poublic String desc()default “ ”;//不写为空字符串
}
//对属性的注解使用
class TestB extends TestA{
@TestAnn(id = 100,desc = "姓名")
String name;
}
12. IO流
主要内容
java.io.File 类的使用
IO原理及流的分类
文件类 //操作的都是文件(数据流的读写都是基于文件的操作)
FileInputStream / FileOutputStream / FileReader / FileWriter
缓冲流 //操作的是内存(数据流的读写都是基于内存的操作)
BufferedInputStream / BufferdOutputStream / BufferedReader / BufferedWriter
转换流
InputStreamReader / OutputStreamWriter
标准输入流/输出流
System.out.println
打印流
PrintStream / PrintWriter
对象流——涉及序列化,反序列化(把对象转化成一个数据流进行读写)
ObjectInputStream / DataOutputStream
随机存取文件流
RandomAccessFile
(随机解释:例如一个txt文件,其中有100行数据,可以直接读取第50行数据,也可以在第89行插入数据)
13. File类
java.io.File类:文件和目录路径名的抽象表达形式,与平台无关
File 能新建/删除/重命名文件和目录,但file不能访问文件内容本身。如果需要访问为念内容本身,则需要使用输入输出流;
File对象可以作为参数传递给流的构造函数
File类的常见构造方法:
public File(String pathname)
public File(String parent,String child)
import java.io.File;
public class Test{
public static void main(String[] args){
File f = new File {"D:\\test\\abc\\tt.txt"};//这个死后对象f就是tt.txt文件
//File f2 = new File ("D:/test/test/abc/tt.txt");
File f3 = new File("D:" + File.separator + "test\\abc\\tt,txt");
//File f1 = new File ("D:\\test","abc\\tt.txt");//这个f1也是tt.txt文件,这种式样相对比较少
//注意,\在文件中是路径的分隔符,但是在java变成中是一个\的意思是转移符,在java中\\或\才是文件的分割符
//也可以File.separator作为文件分隔符
}
}
file类只能操作文件本身,但不能操作文件内容
import java.io.File;
public class Test{
public static void main(String[] args){
File f = new File {"D:\\test\\abc\\tt.txt"};//这个死后对象f就是tt.txt文件
File f4 = new File ("D:\\test\\adc");
System.out.println(f.getName());//获取文件名
System.out.println(f4.getName());//获取当前文件名称
File f5 = new File("src/day12/jTest.ava")//使用相对路径来创建file对象
System.out.println(f.getPath());//获取文件或者文件路径
System.out.println(f..getAbsolutePath());//获取文件当前绝对路径
System.out.println(f5);
System.out.println(f5.getAbsoluteFile());//返回一个用当前的文件的绝对路径构建的file对象
System.out.println(f5。getParent());//返回当前文件或者文件夹的父级路径
f.renameTo(new File("D:\\test\\abc\\tt1.txt"));//给文件或文件夹重命名
//文件检测
File f6 = new File ("D:\\test\\abc\\tt1.txt");
System.out.println(f6.exists());//判断文件或者文件夹是否存在
File f7 = new File("D:\\test\\abc\\tt1.txt");
System.out.println(f7.canWrite());//判断文件是否可写
System.out.println(f7.canRead());//判断文件是否可读
System.out.println(f7.isFile());//判断当前的file对象是不是文件
System.out.println(f7.isDirectory());//判断当前的file对象是不是文件夹或者目录
System.out.println(f7.lastModified());//获取文件最后修改时间,返回是一个毫秒数
System.out.println(f7.length());//返回文件长度,单位是字节数
File f8 = new File("D:\\test\\abc\\tt2.txt");
System.out.println(f8,exists());//判断文件是否存在
if(!f8.exists()){
try{
f8.createNewFile()//创建新的文件
; } catch (IOException e){
e.printStackTrace();
}
}
f8.delete();//删除文件
File f9 = new File("D:\\test\\abc\\cc")
File f9 = new File("D:\\test\\abc\\cc\\dd")//在cc目录下创建个dd文件
f9.mkdir();//创建单层目录,如果使用这样的方法创建目录,就得一层一层的执行mkdir()
File f10 = new("D:\\test\\abc\\a\\b\\c");
f10,mkdirs();//这个方法是直接用来创建多层目录
File f11 = new File ("D:\\test");
String[] f1 = f11.list();//当前文件夹的子集,包括文件和目录
for(String s : f1){
system.out.println(s);
}
File [] fs = f11.listFiles();//返回当前文件夹的子集的file对象,包括文件夹和目录
for(File ff : fs){
System.out.println(ff);
}
}
}
遍历d盘下的test文件,把test文件下所有的目录与文件去哪不便利出来,不论层级又多深,要全部遍历出来。
//这个使用递归的方式来实现
//递归遍历文件
public void test (File file){
if(file.isFile()){
System.out.println(file.getAbsolutePath() + "是文件");
}else{
System.out.println(file.getAbsolutePath() + "是文件夹");
//如果是文件夹,这个文件夹里就可能又子文件夹或文件
File[] fs = file.list.listFiles();
if(fs != mull && fs.lenth > 0){
for(File ff :fs){
test(ff);//递归
}
}
}
}
//调用 (类)
File f = new Fle("D:\\test");
new Test().test(f);
- io与io流体系——java IO原理
- IO流用来处理设备之间的数据传输
- java程序中,对于数据的输入/输出操作以“流(stream)”的方式进行
- java.io包下提供了各种“流”类和接口,用以获取不同终类的数据,并通过标准的方法输入或输出数据
流的分类
- 按操作数据单位不同分为:字节流(8 bit),字符流(16 bit)
- 按数据流的流向不同分为:输入流和输出流
- 按流的角色不同分为:节点流 处理流
java的IO流共涉及40多个类,实际上非常的规则,都是从4个抽象基类派生的,由这四个类派生出来的子类名称都是以起父类名作为子类名后缀。
文件字节输入流
import java.io.FileInputStream
public class Test1 {
public static void main(String[] args){
Test1.testFileInputStream();
Test1.testFileOut.putStream();
}
===========================================
//文件字节输入流
//静态方法
Public static void testFileInputStream(){
try{
FileInputStream in = new FileInputStream("D:/test/abc/tt1.txt");
byte[] b = new byte[10];//设置一个byte数组接受读取文件内容
int len = 0;//设置一个读取数据的长度,防止读取的多了
in.read(b);//有一个返回值,返回的是读取的数据的长度,如果读取到最后一个数据,然后还会向后读一个,这时候返回值就是 -1
//也就意味着当in.read的返回值是-1的时候整个文件就读取完毕了
while((len = in..read(b)) != -1){
System.out.println(new String(b,0,len));
//new String(b,0,len),参数1是缓冲的数组,参数2是从数组的那个位置开始转化字符串,参数3是总共转化几个字节
}
System.out.println(new String(b));
in.close();//注意 流在使用完毕之后一定要关闭
}catch (Dxception e){
e.printStackTrace();
}
}
=========================================
//文件字节输出流FileOutputStream
public static coid testFileOutputStream(){
try{
FileOutputStream out = new FileOutputStream("D:/test/abc/tt1.txt");
String str = "knsasjadk";
out.write(str.getBytes());//把数据写到内存
out.flush();//把呢村中的数据刷写到硬盘
out.close();//关闭流
}catch(Dxception e){
e.printStackTrace();
}
}
}
缓冲字节流
文件字节流和文件字符流
FileInputStream , FileOutPutStream
FileReader , FileWriter
这些都是计算机与硬盘之间发生的io操作,基于硬盘的读写相对是比较慢的,这个操作的速度收到硬盘的读写速度的制约,未来能狗狗提供读写速度,一定程度上绕过硬盘的限制,java提供一种缓冲流来实现
为了提高数据读写的速度,java API提供了带缓冲功能的流类,在使用这些流时,会创建一个内部缓冲区数组
根据数据操作单位可以把缓冲流分为:
BufferedInputStream 和 BufferedOutputStream
BufferedReader 和 BufferedWriter
缓冲流要“套接”在相应的节点流之上,对读写的数据提供了缓冲的功能,提高了读写的效率,同时增加了一些心得方法
对于输出的缓冲流,写出的数据会先在内存中缓存,使用flush()将会使内存中的数据立刻写出
缓冲流基于内存,
缓冲流就是先把数据写入缓冲内存里,在内存中去做io操作,基于内存的io操作大概能比基于硬盘的io操作块75000多倍;
public class Test{
public static void main(String[] args){
try{//类抛出了异常在调用的地方就得捕获异常
Test.testBufferedInputStream();
Test.testBufferedOutputStream();
Test.copyFile();
} catch(Exception e){
e.printStackTrace();
}
}
===========================================
//缓冲字节输入流
//BufferedInputStream
public static void testBufferedInputStream() throws Exception{
//文件字节输入流对象
FileInputStream in = new FileInputStream("D:\\testdemo\\src\\day13\\tt.txt");
//把文件字节输入流放到缓冲字节输入流对象
BufferedInputStream br = new BufferedInputStream(in);
byte[] b = new byte[10];
int len = 0;
while((len = br.read(b) != -1)){//当读到最后一个字符后面后返回会是-1
System.out.println(new String(b,0,len));
}
//关闭流时,本着最晚开最早关的规则,依次关;
br.close();
in.close();
}
========================================
//缓冲字节输出流(写入文件)
//BufferedOutputStream
public static void testBufferedOutputStream() throws Exception{
//创建字节输出流对象
FileOutputStream out = new FileOutputStream("F:\\testdemo\\demo\\src\\day13\\tt1.txt");
//把字节输入流对象放到缓冲字节输出流中
BufferedOutputStream bo = new BufferedOutputStream(out);
String s = "hello world";
//这里需要把字符串转换成byte类型的数组
bo.write(s.getBytes());//写入内存中
bo.flush();//刷到硬盘上,*这时候才写到文件里*
//关闭流时,最晚开的最早关,一次关
bo.close();
out.close();
}
=================================
//缓冲流实现文件的复制(结果复制了一个txt文件)
public static void copyFile() throws Exception{
//缓冲输入流
bufferedInputStream br = new BufferedInputStream(new FileInputStream("D:\\testdemo\\demo\\src\\day13\tt1.txt"));
//缓冲输出流
BufferedOutputStream bo = new BufferedOutputStream(new FileOutStream("D:\\testdemo\\demo\\src\\day13\tt2.txt")"))
byte[] b= new byte[1024];//临时接受输入流的数组
int len = 0;\\设置一个没出读取道德数据的长度,知道br.read方法执行到最后;(例,文件中只有hello world,执行到最后一个就是读取d的后面,这个时候返回值就是-1)
while(len = br.read(b) != -1){
bo.write(b,0,len);//这时写到内存中
}
bo.flush();//刷到硬盘
bo.close();
br.close();
}
}
缓冲字符流
public class Test1{
public static void main(String[] args){
try{
Test.testBufferedReader();
Test1.testBufferedWriter();
Test1.copyFile();
}catch(Exception e){
e.printStackTrace();
}
}
========================================
//缓冲字符输入流
//BufferedReader
public static void testBufferedReader(){
FileReader r = new FileResder("D:\\testdemo\\demo\\src\\day13\tt.txt");
BufferedReader br = new BufferedReader(r);
char[] c = new char[100];
int len = 0;
while((len = br.read(c)) != -1){//br.read(c)读到文件最后一个字符的下一位,返回就是-1
System.out.println(new String(c,0,len));//c数组里面0开始len结束
}
br.close();
r.close();
}
===================================
//缓冲字符输出流
//BufferedWriter
public static void testBufferedWriter()throws Exception{
FileWriter fw = new FleWriter("D:\\testdemo\\demo\\demo\\src\\day13\\tt.txt");
BufferedWriterbw = new BufferedWriter(fw);
String s = "hello world!!!!!";
bw.write(s);
bw.flush();
bw.close();
fw.close();
}
================================
//缓冲字符流复制文件
public static void copyFile() throws Exception{
BufferedReader br = new BufferedReader (new FileReader(D:\\testdemo\\src\\day13\tt.txt));
BufferedWriter br = new BufferedWriter (new FileWriter(D:\\testdemo\\src\\day13\tt.txt));
char[] c = new char[100];
int len = 0;
while(len = br.read(c) != -1) {
bw.write(c,0,len);
}
bw.flush();
bw.close();
br.close();
}
}
注意:缓冲流是把数据缓冲到内存中;
轮转流
所有的文件都是由编码格式,对于我们来说,TxT和java文件一般来讲由三种编码。
iso8859-1,修编码是适用于重要和英文
GBK和UTF-8,这两种编码是适用于中文和英文
一般用UTF-8
转换流提供了在字节流和字符流之间的转换
java API提供了两个转换流:
InputStreamReader 和 OutputStreamWriter
字节流中的数据都是字符时,转成字符流操作更高效。
inputStreamReader
用于将字符流中读取道德字节按指定字符集解码成字符。需要和InputStream 套接
构造方法
InputStreamReader(InputStream in)
public InputSreamReader(InputStream in,String charsetName)
如:Reader isr = new InputStreamReader(System.in.“ISO5334_1”);
import java.io.FileInputStream;
Import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
//转换流可以把字节流转换为字符流,当字节流中的数据都是字符的时候,使用转换流转换为字符流处理效率更高;
public class Test2{
public static void main(String[] args) {
try{
Test2.testInputStreamReader();
Test2.testOutputStreamWriter();
} catch(Exception e){
e.printStackTrace();
}
=======================================
}
//转换字节输入流为字符输入流
//InputStreamReader
//注意在转换字符流的时候,设置的字符集的编码要与读取的文件的数据的编码一致,不然出现乱码
public static void testInputStreamReader() throws Exception{
FileInputStream fs = new FileInputStream("D:\\testdemo\\demo\\src\\day13\\tt5.txt");
//把字节流转换为字符流
InputStreamReader in = new InputStremReader(fs,“GBK”);//参数1是字节流,参数2是编码
char[] c = new char [100];
int len = 0;
while(len = in.read(c) != -1){
System.out.println(new String(c,0,len)) ;
}
in.close();
fs.close();
}
//输出 顶顶顶(输出的是汉字)
}
================================
//转换字节输出流为字符输出流
//OutputStreamWriter
public static void testOutputStreamWriter() throws Exception{
FileOutputStream out = new FileOutputStream("D:\\testdemo\\demo\\src\\day13\\tt5.txt");
OutputStreamWriter os = new new OutputStreamWriter(out,"GBK");
os.write("你好你好");
os.flush();
os.close();
out.close();
}
标准输入输出流
System.in和System.out分别代表了系统标准的输入和输出设备
默认输入设备是键盘,输出设备是显示器
System.in的类型是InputStream
System.out的类型是PrintStream,其是OutputStream的子类FilterOutputStream 的子类
//标准的输入流
public class Test3{
public static void main(String[] args){
try{
Test3.testSystemIn();
Test3.write2TXT();
} catch (Exception e){
e.printStackTrace();
}
}
=======================================
public static void testSystemIn(){
//创建一个接收键盘输入数据的输入流
InputStreamReader is = new InputStreamReader(System.in);
//把输入流放到缓冲流里
BufferedReader br = new BufferedReader(is);
String str = "";//定义一个临时接受数据的字符串
while((str = br.readLine()) != null){
System.out.println(str);
}
br.close();
is.close();
}
//结果:在控制台可以输入数据了
=====================================
//把控制台输入的内容写到指定的txt文件中,
//当接收到字符串over,就结束程序的运行
public static void write2TXT(){
InputStreamReader is = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(is);
BufferedWriter out = new BufferedWriter(new FileWriter("D:\\testdemo\\demo\\src\\day13\\tt5.txt"));
String line = "";
while((line = br.readLine()) != null){
//读取的每一行都写到制定的txt文件
if(line.equals("over")){
break;l
}
out.write(line);
}
out.flush();
out.close();
br.close();
is.close();
}
}
打印流和数据流
在整个IO包中,打印流时输出信息最方便的类。
PrintStream(字节打印流)和PrintWriter(字符打印流)提供了一系列重载的print和println方法,用于多种数据类型的输出
- PrintStream和PrintWriter 的输出不会抛出异常
- PrintStream和PrintWriter有自动flush功能
- System.out返回的是PrintStream的实例(System.out.这个后面返回PrintStream实例)
//数据流,专门用来做基本数据类型的读写的
import java.io.DataoutPutStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class Test4{
public static void main(String[] args){
try{
Test4.testDataOutputStream();
Test4.testDataInputStream();
} catch(Exception e){
e.printStackTrace();
}
}
//数据输出流
//用数据输出流写到文件中的基本数据类型的数据是乱码的,不能直接辨认出来需要数据输入流来读取
//DataOutputStream
public static void testDataOutputStream() throws Exception{
DataOutputStream out = new DataOutputStream(new FileOUtputStream("D:/testdemo/demo/src/day13/tt8.txt"));
//put.writeBoolean(true);
//out.writeDoule(1.35d);
out.writeInt(100);
out.flush();
out.close();
}
//数据输入流
//用数据输入流读取数据输出流写到是文件中的数据时,要保证使用和当时写的数据类型一直的类型来读取,也就是说如果写的时候是writeDouble,读的时候就得是readDouble
//DataInputStream
public static void testDatainput Stream(){
DataInputStream in = new DataInputStream(new FileInputStream("D:/testdemo/demo/src/day13.tt13/txt"));
System.out.println(in.readInt());
in.close();
}
}
对象流
正因为保存对象到硬盘(对象的持久化)和对象的网络传输,需要做这两件事,就产生了对象的输入与输出流
import java.io.Serializable;
//可以序列化与序列化的对象
//注意对象的序列化和反序列化使用的类要严格一致,包名,类名,类机构等等所有都要一致
public class person implements Seerializable{
//一个表示序列化版本标识的静态变量
//用来表明类的不用版本间的兼容性
private static final long serialVersionUID = 1L;
public Stringt name;
public int age;
}
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class Test5{
public static void main(String [] args){
try{
Test5.testSerialize();
Test5.testDeserialize();
} ccatch (Exception e){
e.printStackTrace();86r5tg
}
}
publc static void testSerialize() throws Exception{
//定义对象的输出流,把对象序列化之后的流放到知道你过的文件中
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("D:/testdemo/demo/src/day13.tt13/txt"));
Person p = new Person ();
p.name = "zhangsan";
p.age = 11;
out.writeObject
}
//反序列化
public static void testDeserialize() throws Exception{
//创建都西昂输入流的对象,从之地那个的文件中把对象
ObjectInputStream in = new objectInputStream(new FileInputStream(D:/testdemo/demo/src/day13.tt13/txt));
Object obj = in.readObject();
Person p = (Person) obj;
System.out.printIn(p.name);
System.out.printIn(p.age);
in.close();
}
}
随机存取流
RandomAccessFile类
RandomAccessFile类支持“随机访问”的方式,程序可以直接跳到文件的任意地方来读写文件
支持访问文件的部分内容
可以向已存在的文件后追加内容
RandomAccessFile对象包含一个记录指针,用以标示当前读写出的位置。
RanadomAccessFile类对象可以自由移动记录指针
long getFilePointer():获取文件记录指针的当前位置
void seek(long pos):将文件记录指针定位到pos位置
//文件随机读写
//程序可以直接跳到文件的任意位置地方读写文件
public classTest6 {
public static void main (String[] args){
try{
Test6.testRandomAccessFileRead();
Test6.testRandomAccessFileWrite();
}catch(Exception e) {
e.printStackTrace();
}
}
//==============================================
//随机文件
public static void testRandomAccessFileRead() throws Exception{
// RandomAccessFile的构造有两个参数,承诺书1是读写的文件路径
// 参数2是指定RandomAccessFile的范文模式
// r:以只读方式打开
// rw:打开以便读取和写入
// rwd:打开一边读取和写入;同步文件内容太的更新
// rws:打开一边读写和写入;同步文件内容和元数据的更新
//最常用的是r和rw
RandomAccessFile ra = new RandomAccessFile("D:/testdemo/demo/src/day13/tt10.txt","r");
ra.seek(0);//设置读取文件内容的起始点
byte[] b = new byte[1024];
int len = 0;
while ((len = ra.read(b)) != -1){
System.out.println(new String(b , 0, len));
}
ra.close();
}
//======================================
// 随机写
pubilc static void testRandomAccessFileWrite() throws Exception{
RandomAccessFile ra = new RandomAccessFile("D:/testdemo/demo/src/day13/tt10.txt","rw");
//注意:如果在文件的开头或中间的某个位置开始写的话,就会用写的内容覆盖掉等长度的原内容
ra.seek(0);//设置写的七十点,0代表从开头写
ra.seek(ra.length());//设置写的七十点,ra.length()代表从文件最后结尾写,也就是文件的追加
ra.write("你好".getBytes());
ra.close();
}
}
总结
- 流是用来处理数据的
- 处理数据时,一定要先明确数据源,与数据目的地
数据源可以实文件,也可以时键盘
数据目的地可以是文件 显示器或其他设备 - 而流只是咋i帮助数据进行传输,并对传输的数据进行处理,比如过滤处理,转换处理等;
字节流-缓冲流(重)
输入流 InputStream-FileInputStream-BufferedInputStream
输出 OutputStream-FileOutputStream-BufferedOutPutStream
字符流-缓冲流
输入流Reader-FileReader-BufferedReader
输出流Writer-FileWriter-BufferedWriter
转换流
InputSteamReader和OutputStreamWriter
对象流ObjectInputStream和ObjectOutputStream(难点)
序列化
反序列化
随机存取流RandomSAccessFile(掌握读取,写入)