专栏首页青柠小鱼Java第四周总结

Java第四周总结

第四后总结中的大部分知识点内容我之前都发过,这只是我的一个总结。

1. 集合

1.1 为什么使用集合

开发中会使用大量相同数据类型的情况。如果使用数组来解决问题 1. 数组能够使用的方法非常少,功能方法需要程序员自己完成。 2. 数据类型单一化,不支持多种情况。 3. 数组容量不可以更改。

集合为解决问题而生: 1. 方法多种多样,基本功能完善 2. 数据类型支持多样化,但是又不失数据类型一致要求 3. 容量可以变,并且不用开发者操心

1.2 集合架构

Java中集合的【总接口】Collection。Java中所有和集合有关的内容,都是Collection接口的子接口或者实现类

interface Collection –| interface List List接口,有序可重复 ----| class ArrayList 【重点】可变长数组结构 原码实现,了解其中的特征,性能… ----| class LinkedList 【重点】双向链表结构 ----| class Vector 【远古时代】JDK1.0 线程安全的ArrayList,如果不考虑线程安全问 题,建议使用ArrayList –| interface Set Set接口,无序不可重复 ----| HashSet 底层存储数据的方式是采用哈希表方式 ----| TreeSet 底层存储数据的方式一个平衡二叉树方式

以上这些东西我们之后会一一讲解,现在我们先来了解一下collection接口的常用方法

1.3 Collection<E>接口下的常用方法

增: boolean add(E e); 存入元素到当前集合对象中,这里要求的数据类型是E类型,也就是泛型对于 的具体数据类型 boolean addAll(Collection<? extends E> c); class Dog extends Animal class Cat extends Animal class Tiger extends Animal ==> ? extends E 泛型的上限 要求存入的集合c中,存储的元素要么是E类型,要么是E类的子类 删: void clear(); 清空整个集合 boolean remove(Object obj); 删除集合中的指定元素 boolean removeAll(Collection<?> c); 删除两个集合的交集 boolean retainAll(Collection<?> c); 保留两个集合的交集 查: int size(); 返回集合中有效元素个数 boolean isEmpty(); 判断当前集合是否为空 boolean contains(Object obj); 判断指定元素在当前集合中是否存在 boolean containsAll(Collection<?> c); 判断集合c是不是当前集合的子集合

以下是代码的实现: 注意导包,之前的部分代码也需要导包 就是这个: import java.util.ArrayList; import java.util.Collection;

public class Demo1 {
	public static void main(String[] args) {
		/*
		 * 因为Collection<E>是一个接口,接口没有自己的类对象
		 * 这里使用Collection接口的实现类来完成演示过程 ArrayList<E>
		 */
		Collection<String> c = new ArrayList<String>();
		
		c.add("82年的拉菲");
		c.add("82年的雪碧");
		c.add("82年的可乐");
		c.add("82年的老雪");
		
		System.out.println(c);
		
		Collection<String> c1 = new ArrayList<String>();
		
		c1.add("百威");
		c1.add("福佳白");
		c1.add("精酿啤酒");
		c1.add("修道院啤酒");
		
		c.addAll(c1);
		
		System.out.println(c);
		
		c.remove("82年的雪碧");
		System.out.println(c);
		
		//c.removeAll(c1);
		//System.out.println(c);
		
		//c.retainAll(c1);
		//System.out.println(c);
		
		System.out.println("size:" + c.size());
		System.out.println(c.isEmpty());
		
		System.out.println(c.contains("百威"));
		System.out.println(c.contains("哈尔滨"));
		
		System.out.println(c.containsAll(c1));
		
		c1.add("野格");
		System.out.println(c.containsAll(c1));
	}
}

1.4 迭代器

通过集合对象获取对应的Iterator迭代器 Iterator iterator();

常用方法: boolean hasNext(); 判断当前Iterator是否可以继续运行。 E next(); 获取Iterator当前指向元素,并且指向下一个元素。 void remove(); 删除 【注意】 1. remove方法有且只能删除通过next方法获取的元素 2. remove方法如果想要使用,必须紧挨着next方法

代码实现:

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

public class Demo1 {
	public static void main(String[] args) {
		Collection<String> c = new ArrayList<String>();
		
		c.add("星期一");
		c.add("星期二");
		c.add("星期三");
		c.add("星期四");
		c.add("星期五");
		c.add("星期六");
		c.add("星期日");
		
		System.out.println(c);
		
		/*
		 * 获取当前集合对应的Iterator迭代器对象
		 */
		Iterator<String> iterator = c.iterator();
		/*
		System.out.println("当前Iterator是否可以继续运行:" +iterator.hasNext());
		System.out.println("获取当Iterator指向元:" + iterator.next());
		System.out.println("获取当Iterator指向元:" + iterator.next());
		
		iterator.remove();
		System.out.println(c);
		iterator.remove();
		System.out.println(c);
		*/
		
		while (iterator.hasNext()) {
			iterator.next();
			iterator.remove();
		}
		
		System.out.println(c.isEmpty());
		
		
	}
}

1.5 Iterator使用注意问题

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

public class Demo2 {
	public static void main(String[] args) {
		ArrayList<String> c = new ArrayList<String>();

		c.add("烤羊排");
		c.add("油焖大虾");
		c.add("土豆牛肉");
		c.add("黄焖鸡米饭");
		c.add("麻辣香锅");
		c.add("孜然肉片");
		c.add("酸汤肥牛");
		
		Iterator<String> iterator = c.iterator();
		
		/*
		 * ConcurrentModificationException
		 * Iterator在创建的过程中,会对整个集合所有元素打招呼,记录每一个元素位置。
		 * Iterator在执行next方法过程中,会按照初始条件一个一个遍历
		 * 当前集合通过remove方法,删除已经被Iterator记录的元素时,是有可能导致
		 * Iterator一脸懵逼!!!元素不见了!!!
		 * 
		 * 这里就会发生冲突!
		 * 
		 * 这里因为集合中元素,对于集合本身和当前Iterator而言是一个共享资源
		 * 不管是哪一方操作元素,都存在影响对方操作的情况。【共享资源冲突问题】
		 * 
		 * ArrayList存储元素不是连续的吗,土豆牛肉删除了,他的位置不是会被后面的元素顶上来吗

		 */
		while (iterator.hasNext()) {
			System.out.println(iterator.next());
			
			// 这里通过集合删除土豆牛肉元素
			// 后期代码中会出现很多相同名字方法,这里一定要注意!!!
			// 调用当前方法的是哪一个
			c.remove("酸汤肥牛");
		}
	}
}

Iterator出现并发错误原因:

1.6 List<E>

1.6.1 List集合接口特征和方法

特征: 有序,可重复

有序: 添加顺序和存储顺序一致 可重复:相同元素可以同时添加

List接口下的实现类,存在一定的下标操作机制 ArrayList 底层数组形式操作,可以通过下标直接访问 LinkedList 底层是一个双向链表结构,下标 ==> 计数器

特定的方法: 增: add(E e); List接口下,当前方法是添加元素到集合的末尾,尾插法

addAll(Collection<? extends E> c); List接口下,当前方法是添加另一个集合到当前集合末尾,要求添加的 集合中保存的元素和当前集合保存元素一致,或者说是当前集合保存元 素的子类

add(int index, E e); 在指定的下标位置,添加指定元素

addAll(int index, Collection<? extends E> c); 在指定的下标位置,添加指定的集合,集合要求同上一个addAll方法

删: void clear(); 清空整个集合

remove(Object obj); 删除集合中的指定元素

removeAll(Colletion<?> c); 删除两个集合的交集

retainAll(Colletion<?> c); 保留两个集合的交集

E remove(int index); 删除集合中指定下标的元素。返回值是被删除的元素 改: E set(int index, E e); 使用指定元素替换指定下标index的元素,返回值是被替换掉的元素。

查: int size(); 有效元素个数

boolean isEmpty(); 判断当前集合是否为空

boolean contains(Object obj);

boolean containsAll(Collection<?> c);

int indexOf(Object obj); 找出指定元素在集合中的第一次出现位置

int lastIndexOf(Object obj); 找出指定元素在集合中最后一次出现位置

E get(int index); 获取指定下标的元素

List subList(int fromIndex, int endIndex); 获取当前集合的子集合 【特征】 获取数据的范围是 fromIndex <= n < endIndex 要头不要尾

1.7 ArrayList 可变长数组

特征: 数组形式的操作方式,查询效率高,但是删除,增加效率低。 数组: Object类型数组

方法: ArrayList使用的方法基本上都是从List接口中遵从实现的方法特征: ensureCapacity(int minCapacity); 判断当前容量是否足够 trimToSize(); 截断整个数组容量 ==> size有效元素个数 时间换空间,空间换时间

自定义实现的ArrayList Constructor构造方法

add(E e); add(int index, E e); addAll(自定义ArrayList e) addAll(int index,自定义ArrayList e) remove(Object obj); remove(int index); set(int index, E); E get(int index); int indexOf(); int lastIndexOf(); boolean contains(Object obj); boolean containsAll(自定义ArrayList类型 list) boolean isEmpty(); int size(); 自定义ArrayList subList(int fromIndex, int endIndex); Object[] toArray();

方法代码实现:

import java.util.Arrays;

/**
 * 自定义实现MyArraylist
 * @author Anonymous
 *
 * @param <E> 自定义泛型
 */
public class MyArrayList<E> {
	/**
	 * 准备一个底层数组,用于存储数据内容
	 */
	private Object[] elements;
	
	/**
	 * 初始化默认容量
	 */
	private static final int DEFAULT_CAPACITY = 10;
	
	/**
	 * 最大数组容量, -8是为了腾出一定的空间,保存数组的必要内容
	 */
	private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
	
	/**
	 * 当前底层数组中保存的有效元素个数
	 */
	private int size = 0;
	
	/**
	 * 无参数构造方法,但是需要提供给用户一个初始化容量来保存必要的数据
	 */
	public MyArrayList() {
		elements = new Object[DEFAULT_CAPACITY];
	}
	
	/**
	 * 用户指定保存元素容量的初始化过程,要求用户指定的容量范围是有效的
	 * 
	 * @param initCapacity 用户指定的初始化容量,但是不能小于等于0 ,不能大于
	 * 						MAX_ARRAY_SIZE
	 */
	public MyArrayList(int initCapacity) {
		// 用户传入参数的合法性判断过程
		if (initCapacity < 0 || initCapacity > MAX_ARRAY_SIZE) {
			// 抛出异常
			// IllegalArgumentException 是一个RuntimeException运行时异常的子类
			// 不需要强制声明抛出异常
			throw new IllegalArgumentException("IllegalArgumentException : " + initCapacity);
		}
		
		elements = new Object[initCapacity];
	}
	
	/*
	 * 增加方法
	 */
	/**
	 * 添加元素到当前集合的末尾
	 * 
	 * @param e 要求是符合泛型约束的指定数据类型
	 * @return 添加成功返回true, 否则返回false
	 */
	public boolean add(E e) {
		// 直接调用在指定下标位置添加元素的方法,只不过这里指定下标位置就是
		// 尾插法下标位置
		return add(size, e);
	}
	
	/**
	 * 在底层数组的指定下标位置保存对应的元素
	 * 
	 * @param index 指定下标位置,不能超出有效范围,0<= index <= size
	 * @param e 符合泛型约束的数据类型
	 * @return 添加成功返回true, 否则返回false
	 */
	public boolean add(int index, E e) {
		if (index < 0 || index > size) {
			throw new ArrayIndexOutOfBoundsException(index);
		}
		
		ensureCapacity(size + 1);
		
		for (int i = size; i > index; i--) {
			elements[i] = elements[i - 1];
		}
		
		elements[index] = e;
		size += 1;
		
		return true;
	}
	
	/*
	 * addAll方法
	 * 		1. 需要得到添加集合中元素内容,有效元素个数
	 * 		2. 确认容量问题
	 * 		3. size = srcSize + newSize
	 */
	/**
	 * 添加另一个集合到当前集合的末尾
	 * 
	 * @param list MyArrayList类型,自定义ArrayList,要求存储元素和当前集合一致,或者
	 * 				是其子类
	 * @return 添加成功返回true,添加失败返回false
	 */
	public boolean addAll(MyArrayList<? extends E> list) {
		Object[] array = list.toArray();
		int newSize = array.length;
		
		ensureCapacity(size + newSize);
		
		for (int i = 0; i < newSize; i++) {
			elements[i + size] = array[i];
		}
		
		size += newSize;
		return true;
	}
	
	/**
	 * Do yourself 作业
	 * @param index
	 * @param list
	 * @return
	 */
	public boolean addAll(int index, MyArrayList<? extends E> list) {
		return true;
	}
	
	/**
	 * 删除指定元素 
	 * 
	 * @param obj 指定删除的元素
	 * @return 删除成功返回true
	 */
	public boolean remove(Object obj) {
		int index = indexOf(obj);
		
		return null != remove(index);
	}
	
	/**
	 * 删除下标元素
	 * 
	 * @param index 指定的下标范围
	 * @return 删除成功返回对应元素,失败返回null
	 */
	public E remove(int index) {
		if (-1 == index) {
			return null;
		}
		
		E e = get(index);
		
		for (int i = index; i < size - 1; i++) {
			elements[i] = elements[i + 1];
		}
		
		// 原本最后一个有效元素位置上的内容赋值为null
		elements[size - 1] = null;
		size -= 1;
		
		return e;
	}
	
	/**
	 * 获取集合中指定下标的元素
	 * 
	 * @param index 指定下标的范围,但是不能超出有效下标范围
	 * @return 返回对应的元素
	 */
	@SuppressWarnings("unchecked")
	public E get(int index) {
		if (index < 0 || index > size) {
			throw new ArrayIndexOutOfBoundsException(index);
		}
		
		return (E) elements[index];
	}
	
	/**
	 * 查询指定元素在集合中的第一次出现下标位置
	 * @param obj 指定的元素
	 * @return 返回值大于等于0表示找到元素,否则返回-1
	 */
	public int indexOf(Object obj) {
		int index = -1;

		for (int i = 0; i < size; i++) {
			// equals 判断对象是否一致地方的方法
			if (obj.equals(elements[i])) {
				index = i;
				break;
			}
		}
		
		return index;
	}
	
	/**
	 * 查询指定元素在集合中的最后一次出现下标位置
	 * 
	 * @param obj 指定的元素
	 * @return 返回值大于等于0表示找到元素,否则返回-1
	 */
	public int lastIndexOf(Object obj) {
		int index = -1;

		for (int i = size - 1; i >= 0; i--) {
			// equals 判断对象是否一致地方的方法
			if (obj.equals(elements[i])) {
				index = i;
				break;
			}
		}
		
		return index;
	}
	
	/**
	 * 返回MyArrayList集合中所有有效元素的Object数组
	 * 
	 * @return 包含所有集合元素的Object类型数组
	 */
	public Object[] toArray() {
		// size是有效元素个数,通过该方法可以获取到一个只有当前数组中有效元素的数组
		return Arrays.copyOf(elements, size);
	}
	
	
	/**
	 * 替换指定下标的元素
	 * 
	 * @param index 指定下标元素,但是必须在有效范围以内
	 * @param e 符合泛型约束的对应数据类型
	 * @return 被替换的元素
	 */
	public E set(int index ,E e) {
		if (index < 0 || index >= size) {
			throw new ArrayIndexOutOfBoundsException(index);
		}
		
		E temp = get(index);
		elements[index] = e;
		
		return temp;
	}
	
	/**
	 * 判断指定元素是否存在 
	 * 
	 * @param obj 指定元素
	 * @return 存在返回true,不存在返回false
	 */
	public boolean contains(Object obj) {
		return indexOf(obj) > -1; 
	}
	
	/**
	 * 
	 * @param list
	 * @return
	 */
	public boolean containsAll(MyArrayList<?> list) {
		return false;
	}
	
	/**
	 * 判断集合是否是空的
	 * 
	 * @return 如果为空,返回true, 否则返回false
 	 */
	public boolean isEmpty() {
		return size == 0;
	}
	
	/**
	 * 获取当前集合中有效元素个数
	 * 
	 * @return 有效元素个数
	 */
    public int size() {
    	return size;
    }
    
    /**
     * 获取当前集合的子集合,截取范围是fromIndex <= n < endIndex
     * 
     * @param fromIndex fromIndex <= endIndex 不得小于0
     * @param endIndex endIndex >= fromIndex 小于等于size
     * @return 截取得到的一个MyArrayList子集合对象
     */
    public MyArrayList<E> subList(int fromIndex, int endIndex) {
    	if (fromIndex > endIndex || fromIndex < 0 || endIndex > size) {
    		throw new ArrayIndexOutOfBoundsException();
    	}
    	
    	MyArrayList<E> listTemp = new MyArrayList<E>(endIndex - fromIndex);
    	
    	for (int i = fromIndex; i < endIndex; i++) {
			listTemp.add(this.get(i));
		}
    	
    	return listTemp;
    }

    @Override
    public String toString() {
    	String str = "[";
    	for (int i = 0; i < size - 1; i++) {
			str += elements[i] + ", ";
		}
    	
    	return str + elements[size - 1] + "]";
    	
    }
	/*
	 * 这里需要类内使用的可以用于判定当前容量是否满足添加要求的方法
	 * 如果满足直接进入添加模式,如果不满足,需要执行grow方法,完成
	 * 底层数组的扩容问题。
	 */
	/**
	 * 每一次添加元素,都需要进行容量判断,如果满足可以进行添加操作
	 * 不满足需要制定grow方法
	 * 
	 * @param minCapacity 要求的最小容量
	 */
	private void ensureCapacity(int minCapacity) {
		if (minCapacity > elements.length) {
			// 完成一个底层数组的扩容方法
			grow(minCapacity);
		}
	}
	
	
	/**
	 * 底层数组的扩容方法,原理是创建新数组,移植数据,保存新数组地址
	 * 
	 * @param minCapacity 要求的最小容量
	 */
	private void grow(int minCapacity) {
		// 1. 获取原数组容量
		int oldCapacity = elements.length;
		
		// 2. 计算得到新数组容量
		int newCapacity = oldCapacity + (oldCapacity >> 1);
		
		// 3. 判断新数组容量是否满足要求
		if (newCapacity < minCapacity) {
			newCapacity = minCapacity;
		}
		// 新数组容量是大于允许的最大数组容量
		if (newCapacity > MAX_ARRAY_SIZE) {
			// 二次判断minCapacity是否小于MAX_ARRAY_SIZE
			if (minCapacity < MAX_ARRAY_SIZE) {
				// 最小要求是不大于MAX_ARRAY_SIZE,代码可以运行
				newCapacity = minCapacity;
			} else {
				throw new OutOfMemoryError("Overflow MAX_ARRAY_SIZE");
			}
		}
		
		/*
		 * 4. 使用数组工具类方法完成操作
		 * Arrays.copyOf(源数据数组,可以是任意类型,采用泛型约束, 指定的新数组容量);
		 * 		a. 根据指定的新数组容量创建对应泛型数据类型的新数组
		 *      b. 从源数据数组中拷贝内容到新数组中
		 *      c. 返回新数组首地址
		 */
		elements = Arrays.copyOf(elements, newCapacity);
	}

}

1.8 ArrayList性能问题

增删慢

增加慢 1. 增加元素有可能出现调用grow方法,grow需要进行数组的扩容操作,操作过程中需要大 量的移动和拷贝过程,浪费时间 2. 在某一个指定位置添加元素,会导致从指定位置开始,之后的元素整体向后移动,涉及 移动复制操作,浪费时间。

删除慢: 1. 按照ArrayList可变长数组要求,删除元素之后,之后的内容都需要整体向前移动。

查询快

1.9 补充知识点【内存】

内存中的地址 1. 内存中的最小单元 字节 2. 计算机为了记录标记每一个字节的内存,给内存进行了编号 3. 航海中路60号,精确查询,唯一性 4. 计算机内存按照字节,一个字节对应一个地址,从0开始编号 到 34359738367 (32G 内存) 5. 计算机通过内存编号访问对应的内存,效率是非常高的!!! 6. 按照十进制表示地址编号,效果很差。 这里引入16进制 0x0 ~ 0x7 FFFF FFFF

null到底是谁? null ==> 0x0 内存中编号为0的地址 该地址受到系统保护,任何程序读取,写入0x0地址,系统直接杀死程序 一般用于在开发中初始化引用数据类型的变量,利用null报错。NullPointerException

1.10 LinkedList

1.10.1 1 LinkedList特征

底层是一个双向链表 链子 自行车链子 船锚 手链

自行车链子 维修很方便,前断,后断,链接搞定!!! 找到损坏的位置,需要一个一个来

链表结构 1. 增删快 2. 查询很慢很慢很慢

  1. 存储数据,非连续空间。
  2. 数据之间通过引用连接,方便遍历和使用
  3. 遍历效率较低,数据非连续空间存储,需要通过引用跳转过程来完成
  4. 删除插入操作效率高,但是注意地址的转移和保存问题。
  5. LinkedList链表当中的操作其实大部分都是和C语言指针一个概念
1.10.2 LinkedList需要了解的方法

LinkedList使用的方法,大部分都是从List接口中遵从实现的方法 但是有一些特征方法 addFirst(E e); addLast(E e); ==> add(E e);

E getFirst(); E getLast();

removeFirst(); removeLast();

以上方法组合可以完堆栈队列操作 先进后出 弹夹 addLast(E e); E getLast(); removeLast(); 队列 先进先出 addLast(E e); E getFrist(); removeFirst();

1.11 自定义完成MyLinkedList

1.11.1 节点

a. 向前的引用 b. 存储元素的引用 c. 向后的引用

class Node { private Node prev; private Node next; private Object value;

// 构造方法存储元素,进入链接 }

1.11.2 管理节点的MyLinkedList

a. 链表头!!! b. 当前链表中有多少个元素。

class MyLinkedList { private Node first; private int size; }

要求实现的方法: add(E e); addFirst(E e); addLast(E e); E getFirst(); E getLast(): E get(int index); removeFirst(); removeLast(); remove(int index); remove(Object obj); E set(int index, E); size();

1.11.3 LinkedList实现

还需要补充的方法: add(int index,E e); addAll(MyLinkedList list); addAll(int index, MyLinkedList list); boolean isEmpty(); int indexOf(Object obj); int lastIndexOf(Object obj); boolean contains(Object obj); boolean containsAll(MyLinkedList<?> list); Object[] toArray();

1.12 Set集合

1.12.1 Set集合概述

特征: 无序,不可重复

无序:添加顺序和存储顺序不一致,【不代表有排序效果】 不可重复: 在一个Set集合中不能出现相同元素

interface Set –| class HashSet 底层是哈希表存储数据 –| class TreeSet 底层存储数据是一个二叉树

1.12.2 HashSet

底层结构

import java.util.HashSet;

public class Demo2 {
	public static void main(String[] args) {
		HashSet<Person> hashSet = new HashSet<Person>();
		
		Person p1 = new Person(1, "寝室长", 10);
		Person p2 = new Person(2, "队长", 15);
		Person p3 = new Person(3, "宇哥", 2);
		Person p4 = new Person(4, "老康", -5);
		Person p5 = new Person(5, "港儿子", 11);
		
		/*
		 * 当前这里两个元素,ID一样 ==> hashCode值是一致,会通过底层哈希表运算
		 * 保存到同一个单元格位置。
		 * 这里会通过equals方法,比较两个对象是否一致,来决定是否能够保存。
		 * 如果两个对象一致,无法保存。
		 * 
		 * 期望每一个哈希表单元格内保存的数据是唯一
		 */
		Person p6 = new Person(6, "康爷", 8);
		Person p7 = new Person(6, "康牙", 10);
		
		
		hashSet.add(p4);
		hashSet.add(p6);
		hashSet.add(p3);
		hashSet.add(p5);
		hashSet.add(p2);
		hashSet.add(p1);
		hashSet.add(p7);
		
		System.out.println(hashSet);
	}
}
1.13.2 TreeSet
Tree树形结构
TreeSet存储方式

没有比较方式无法存储

Comparable接口使用

interface Comparable { int compareTo(T t); }

方法参数为T类型,由实现类遵从接口时约束, compareTo方法,返回值类型int类型,0, 负数,正数 0 表示两个元素一致,如果在TreeSet中比较结果为0,表示同一个元素,无法存储第二个。

Comparable接口由存储元素对应的类遵从,完成该方法

Comparator接口使用

interface Comparator { int compare(T o1, T o2); }

需要完成一个自定义比较器类对象, int 返回值 0,负数,正数 0 表示两个元素一致,如果在TreeSet中比较结果为0,表示同一个元素,无法存储第二个。 Comparator使用要高于Comparable使用

2. Object类

2.1 Object类概述

Java中所有类的基类!!! Java中所有的类都是间接或者直接继承Object类。 Object类的引用数据类型变量可以保存Java中任意数据类型空间的首地址。

Object类内规定了一些方法: String toString(); 当前对象建议String类型描述。默认情况是当前类所属包名.类名@十六进制内存地址 如果对于数据类型展示有要求,可以重写toString方法,在展示的方法中会默认执行toString方法

int hashCode(); 内存中当前对象的唯一索引值,默认情况下是当前对象所处空间首地址的十进制展示。

boolean equals(Object obj); 比较方法,判断两个对象是否一致,Object类内默认情况下比较的方式是地址比较。 两个对象地址一致,表示肯定是相同对象。如果我们期望修改equals比较规则,可以在当前类内重写 【注意】 Java中规定,如果两个对象的equals比较方法结果为true,要求hashCode值必须一致。

下列方法之后再介绍:
线程有关方法
void wait();
void notify();
void notifyAll();

反射有关方法
Class<?> getClass();

2.2 toString方法:

食之无味,弃之可惜!!! 目前大家展示数据时,需要考虑使用的方法,可以通过Sout方法直接展示出对应的对象内 容。

使用DEBUG工具,一些辅助的可视化工具使用。

Eclipse Alt + Shift + S

2.3 equals方法

比较两个对象是否一致,在Object类内默认方式是比较两个对象的地址是否一致。

代码中存在一些情况,需要比较的是两个对象中保存的内容是一直,但是使用Object类内继承而来的equals方法,是不合理的!!! 【实现】 这里需要重写equals方法

代码实现:

/*                                                                   
 * 重写equals方法                                                        
 * 		1. 判断两个对象是不是同一个对象。如果调用方法的类对象和传入参数类对象    
 * 		地址一致,那就是同一个对象,返回true,搞定!!!         
 *                                                                   
 * 		2. equals方法参数是Object类型,那也就是说任何类型的数据都可以作为参数。   
 * 		两个数据类型不一致,是否需要进行比较操作。                               
 * 		判断数据类型是否一致                                                   
 * 		使用关键字 instanceOf,同数据类型继续运行,非同类型,结束判断返回false   
 * 		格式:                                                          
 * 			类对象 instanceOf 类名                                        
 *                                                                   
 * 		3. 判断对象中保存的数据                                                
 * 			Student中我们比较id, name, age, gender就可以了                    
 * 		                                                             
 */                                                                  
@Override                                                            
public boolean equals(Object obj) {                                  
	// 1. 判断是不是同地址对象                                                 
	if (this == obj) {                                               
		return true;                                                 
	}                                                                
	                                                                 
	// 2. 类型是否一致                                                     
	if (!(obj instanceof Student)) {                                 
		return false;                                                
	}                                                                
                                                            
	// 数据类型强制转换                                                      
	Student stu = (Student) obj;                                     
	return this.id == stu.id                                         
			// this.name.equals(stu.name) 该equals方法是String类equals方法  
			&& this.name.equals(stu.name)                            
			&& this.age == stu.age                                   
			&& this.gender == stu.gender;                            
	                                                                 
}   

2.4 hashCode方法

在Object类内,hashCode方法,返回的内容是当前对象的空间首地址十进制展示方式。

当前类重写equals方法之后,两个当前类对象比较结果为true,那么要求这两个对象的hashCode必须一致!!!

hashCode使用有一个唯一原则。 一般会参考参与equals比较的所有成员变量来组成对应的hashCode,这里会使用到一些Java中提供的计算哈希值的方法。

hashCode使用未进行重写的情况下,会使用地址作为hashCode对应的数据,重写之后,不再使用地址。重写之后hashCode 不对应当前对象所在地址。

代码:

@Override
public int hashCode() {
	// 这里通过Objects 工具类内的hash方法,传入所有参与equals比较的成员变量
	// 得到对应的hashCode值
	return Objects.hash(id, name, age, gender);
}

3.1 什么是Map

键(Key)值(Value)对 邓超 = 娘娘 贝克汉姆 = 维多利亚 黄磊 = 孙莉 吴京 = 谢楠

表格: 姓名:张三 年龄:23 性别:男

程序开发大部分数据都是键值对形式的 MySQL JSON XML 类对象成员变量和存储的数据 从前端发送的数据也可以转成Map格式 ==> 一键生成 ==> 类对象 ==> 一键存储 ==> 数据库

interface Map<K, V> –| class HashMap<K, V> 哈希表结构 –| class TreeMap<K, V> 底层是树形结构,存储要求K有对应的排序方式 Map双边队列中键(Key)是唯一的,但是值(Value)可以重复

3.2 Map<K, V>双边队列方法

增: put(K k, V v); 存入一个键值对类型,K和V都要符合泛型约束 putAll(Map<? extends K, ? extends V> map); 存入另一个Map双边队列,并且要求添加的Map双边对接中的K和V都要和当前Map中存储 的K和V一致 删: remove(Object k); 删除对应K的键(Key)值(Value)对 改: put(K k, V v); 对应当前K存在,修改对应内容 查: int size(); 当前Map双边队列中,有效键值对个数 boolean isEmpty(); 是否为空 boolean containsKey(Object key); 判断指定的Key是否存在 boolean containsValue(Object value); 判断指定Value是否存在 Set keySet(); 返回整个Map双边队列中所有Key对应的Set集合

【注意】 一个方法使用set结尾,表示该方法返回的是一个集合类型,大多是情况下都 是Set类型 Collection values(); 返回整个Map双边队列中所有Value对应的Collection集合 【注意】 方法名如果是一个复数,返回值类型集合或者是数组情况居多

3.3 EntrySet

Entry 可以认为是键值对对象 定义在Map类内 class Entry<K, V> { K k; V v; } K,V是完全依赖于Map约束的,这里可以Entry里面保存的是每一个键值对类对象

Map中提供了一个方法 Set<Entry<K, V>> entrySet 返回值是键值对类对象Set集合 Set集合中存储的是Entry类型 Entry类型是带有泛型的

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class Demo2 {
	public static void main(String[] args) {
		HashMap<String, String> map = new HashMap<String, String>();
		
		map.put("吴京", "谢楠");
		map.put("邓超", "娘娘");
		map.put("黄磊", "孙莉");
		map.put("王宝强", "XX");
		
		Set<Map.Entry<String, String>> entrySet = map.entrySet();
		
		System.out.println(entrySet);
	}
}

3.4 TreeMap<K, V> 以及Comparable和Comparator

K是需要有对应的比较方式,如果没有比较方式,无法存入。

推荐使用Comparator接口

import java.util.Comparator;
import java.util.TreeMap;

public class Demo3 {
	public static void main(String[] args) {
		TreeMap<String,String> map = new TreeMap<String, String>();
		
		map.put("李四", "1");
		map.put("王五", "1");
		map.put("赵六", "1");
		map.put("张三", "1");
		
		System.out.println(map);
		
		TreeMap<Dog,String> map2 = new TreeMap<Dog, String>(new Comparator<Dog>() {

			@Override
			public int compare(Dog o1, Dog o2) {
				return o1.getAge() - o2.getAge();
			}
		});
		
		map2.put(new Dog("王可可", 1), "111"); 
		map2.put(new Dog("八公", 2), "111"); 
		map2.put(new Dog("豆豆", 3), "111"); 
		map2.put(new Dog("老黄", 4), "111"); 
		map2.put(new Dog("旺财", 5), "111"); 
		
		System.out.println(map2);
		
	}
}

4. File

4.1 什么是File类

SUN公司提供给开发者操作文件和文件夹的一个类对象。 Java中万物皆对象,计算机中万物皆文件

获取File类有三种方式【Constructor 构造方法】 File(String pathName); 根据对应的文件路径创建获取对应的File类对象,可以是文件,可以是文件夹。

File(String parent, String child); 根据对应的父目录文件夹路径,以及子文件名或者子文件夹名,创建对应的File类对象

File(File parent, String child); 根据对应的父目录文件夹File类对象,以及子文件名或者子文件夹名,创建对应File类对象

路径: 相对路径 . 当前工作目录 … 父目录/上级目录 正对于当前工作目录和其他文件或者文件夹之间的最小路径

绝对路径 唯一的路径。 Windows操作系统 C D E F… 每一个盘符都是一个根目录开始 C:/Windows/System32 Linux UNIX macOS 存在一个 / 目录文件 /user/liuxiaolei/appliction

路径有一个很重要的东西 路径分隔符 Windows 分隔符 默认是\ Linux UNIX macOS 分隔符 默认是 /

Windows是支持Linux分隔符 / 没有任何问题

根据当前系统来区分不同的分隔符 File.separatorChar

代码演示:

import java.io.File;

/*
 * 创建File类对象
 */
public class Demo1 {
	public static void main(String[] args) {
		/*
		 * 1. 路径分隔符 \\ or / or File.separator
		 * 2. 操作文件必须带有文件的后缀名 1.txt 2.java ...
		 */
		File file = new File("C:\\aaa");
		File file1 = new File("C:" + File.separator + "aaa");
		File file2 = new File("C:/aaa", "1.txt");
		File file3 = new File(file, "bbb");
			
	}
}

4.2 创建文件和文件夹

boolean createNewFile(); 通过File类对象调用,创建对应File类对象中保存的路径的普通文件。 创建成功返回true,创建失败返回false 返回false的原因: 1. 路径不合法。 2. 对应的文件夹没有写入权限。 rwxr-xr-x 3. 对应当前的文件已经存在。

boolean mkdir(); 通过File类对象调用,创建对应File类对象中保存路径的文件夹 创建成功返回true,创建失败返回false 返回false的原因 1. 路径不合法。 2. 对应的文件夹没有写入权限。 3. 对应当前的文件夹已经存在。

boolean mkdirs(); 通过File类对象创建其中保存的文件目录的所有对应文件夹,包括中间路径 如果创建失败,返回false

boolean renameTo(File dest); 通过File类对象调用,转为目标File类对象dest 文件/文件夹移动,重命名

4.3 删除文件或者文件夹

boolean delete(); 通过File类对象调用,删除对应的文件或者文件夹 【要求】 1. 删除的文件或者文件夹都是直接抹掉数据,不是放入回收站 2. 无法删除非空文件夹,文件夹中存在其他内容无法整体删除。

void deleteOnExit(); 程序退出时删除对应的文件或者文件夹 用于删除程序运行过程中,留下的日志文件,缓冲文件,操作日志…

4.4 文件属性判断[有用]

boolean isFile(); 判断是否是一个普通文件

boolean isDirctory(); 判断是否是一个文件夹

boolean isAbsolute(); 判断是否使用了绝对路径

boolean isHidden(); 判断是否是隐藏文件

boolean exists(); 判断文件是否存在

4.5 获取文件属性

用处不大的方法 下面的方法和文件是否存在没有一分钱关系,都可以使用字符串操作直接得到我们想要的结果 String getPath(); 获取File类对象保存的路径 String getName(); 获取当前File类对象中保存的文件名或者文件夹名 String getParent(); 获取当前File类对象对应文件或者文件夹的父目录路径 String getAbsolutePath(); 获取当File类对象对应文件或者文件夹的绝对路径

有用方法: long lastModified() 获取文件的最后一次修改时间,返回值是一个时间戳类型。 从1970年01月01日 00:00:00到现在的秒数。计算机元年

long length(); 获取文件的大小,占用硬盘空间字节数。 如果操作的是文件夹,返回0L

4.6 列表方法

static File[] listRoots(); 通过File类调用,有且针对于Windows操作系统有效,获取当前电脑内所有根盘符对象,如果是Linux,UNIX,macOS是无效的。

File[] listFiles(); 通过File类对象调用,获取当前File类对象对应文件夹下的所有子文件或者子文件夹的File类对象数组

String[] list(); 通过File类对象调用,获取当前File类对象对应文件夹下的所有子文件或者子文件夹的String类型文件名或者文件夹名字数组

4.7 FilenameFilter文件名过滤器

interface FilenameFilter boolean accept(File dir, String name);

源码展示

@FunctionalInterface
public interface FilenameFilter {
    /**
     * Tests if a specified file should be included in a file list.
     *
     * @param   dir    the directory in which the file was found.
     * @param   name   the name of the file.
     * @return  <code>true</code> if and only if the name should be
     * included in the file list; <code>false</code> otherwise.
     */
    boolean accept(File dir, String name);
}

代码实现:

import java.io.File;
import java.io.FilenameFilter;

/*
 * FilenameFilter过滤器演示
 */
public class Demo8 {
	public static void main(String[] args) {
		File file = new File("C:\\aaa\\ddd");
		
		// 使用匿名内部类的匿名对象直接作为方法的参数
		File[] listFiles = file.listFiles(new FilenameFilter() {
			
			@Override
			public boolean accept(File dir, String name) {
				/*
				 * dir是当前操作的文件夹类对象
				 * name是当前文件夹下的子文件或者子文件夹名字
				 * 
				 * 获取对应的java文件
				 * 		1. 判断是不是普通文件
				 * 		2. 判断当前文件名是不是.java结尾
				 */

				return new File(dir, name).isFile()
						// endsWith字符串方法,判断当前字符串是不是已指定要求结尾
						&& name.endsWith(".java");
			}
		});
		
		// Lambda表达式 JDK1.8新特征 
		File[] listFile = file.listFiles((dir, name) -> 
			new File(dir, name).isFile() 
			&& name.endsWith(".java")
		);
		
		for (File file2 : listFile) {
			
			System.out.println(file2.getName());
		}
		
	}
}

5.String类

5.1 比较方式要求

5.2 获取方法

int length(); 获取字符串长度 “”

char charAt(int index); 获取String字符串中指定下标位置的char类型字符,如果index超出有效范围 StringIndexOutOfBoundsException

int indexOf(char ch); int indexOf(String str); int indexOf(char ch, int fromIndex); int indexOf(String str, int fromIndex); 这些方法都是获取指定元素所在的下标位置,元素可以是char类型字符,也可以是字符串。这里找出的是指定元素在字符串中第一次出现的位置,当然可以通过一定的约束,从哪个位置开始找fromIndex

int lastIndexOf(char ch); int lastIndexOf(String str); int lastIndexOf(char ch, int fromIndex); int lastIndexOf(String str, int fromIndex); 这些方法都是获取指定元素所在的下标位置,元素可以是char类型字符,也可以是字符串。这里找出的是指定元素在字符串中最后一次出现的位置,当然可以通过一定的约束,从哪个位置开始找fromIndex tips: 最后两个方法有坑!!!

5.3 判断方法

boolean endsWith(String str); 判断当前字符串是不是以指定字符串结尾

boolean isEmpty(); 判断字符串是否为空 ""空串 JDK1.6之后 null不能读取,不能写入,不能调用方法

boolean equals(Object obj); 继承重写Object类内的方法,完成字符串要求的比较方式

boolean equalsIgnoreCase(String str); 不区分大小写比较

boolean contains(String str); 判断指定字符串是否存在

5.4 转换方法

String(char[] arr); 使用字符数组中内容创建一个字符串对象

String(char[] arr, int offset, int length); String(char[] arr, int off, int len); String(char[] arr, int off, int cou); String(char[] arg0, int arg1, int arg2); 使用字符数组中内容创建一个字符串对象,offset是从char类型数组中指定下标位置开始获取数据,获取的数据长度是length

static String valueOf(char[] arr); 通过类名调用的静态方法,实际执行的是String(char[] arr);

static String valueOf(char[] arr, int offset, int length); 通过类名调用的静态方法,实际执行的是String(char[] arr, int offset, int length);

char[] toCharArray(); 返回当前字符串对应的字符数组

5.5 其他方法

String replace(char oldChar, char newChar) 替换,替换不会修改原始的字符串,会创建一个新字符串返回,并且替换效果是所有的对应 的oldChar全部替换成newChar

String[] split(String regex) 按照指定的字符串切割当前字符串 [00:00:15]XXXXXXX

String substring(int beginIndex) 从指定位置开始,截取子字符串,到字符串末尾

String substring(int beginIndex, int endIndex) 从指定位置开始beginIndex,到endIndex结束,要头不要尾

String toUpperCase() 转大写 字符串小写转大写

String toLowerCase() 转小写 字符串大写转小写

String trim() 去除空格 去除字符串两边的无用空格

5.6 字符串小问题

String str = "孜然肉片";
str += "麻辣香锅";
str += "番茄鸡蛋";
str += "土豆牛肉";
str += "烤羊排";
str += "金汤肥牛";
str += "蒜蓉油麦菜";

System.out.println("这里有几个字符串");

这里一共有几个字符串?

答案: 这里有14个字符串 使用双引号包含的字符串都是字符串常量!!!常量的概念中要求不可以修改。 双引号包含的字符串都是存在于内存的【数据区】

+ 在字符串常量操作时,使用原本的两个字符串拼接之后完成的一个新的字符串常量。

这里导致的字符串冗余问题,后期会使用StringBuffer StringBuilder来解决问题。

5.7 记录一个字符串中出现的英文字母个数【思考题】

小写a几次,大写A几次…

6. IO流

6.1 什么是IO流

I input 输入流 read 读取数据 O output 输出流 write 写入数据

一般情况下都是按照当前程序使用的内存为参照物来考虑数据的走向问题。 文件操作为例 从内存中保存数据到硬盘 output 从硬盘中读取数据到内存 input0

文件操作为例 1GB完整的文件拷贝过程,要远远高于1GB散文件的拷贝过程。 1. 打开文件,关闭文件消耗资源较少 2. 1GB散文件就需要不断的打开,关闭资源 操作时间的消耗和打开文件,关闭文件或者说打开硬盘,关闭硬盘有直接关系

IO流基类

InputStream 输入流基类 read

OutputStream 输出流基类 write

6.2 IO流分类

流向分类  输入输出

文件操作处理单元分类  字节流和字符流

FileInputStream  文件操作输入字节流 FileOutputStream  文件操作输出字节流

FileReader  文件操作输入字符流 FileWriter  文件操作输出字符流

6.3 文件操作字节流

6.3.1 文件操作输入字节流
FileInputStream 文件操作输入字节流

Constructor 构造方法
	FileInputStream(File file);
		这里是根据提供的File类对象创建对应的文件操作输入字节流。

	FileInputStream(String pathName);	
		这里是根据提供的String类型文件路径,创建对应的文件操作输入字节流。
	都会抛出异常:
		FileNotFoundException 文件未找到异常。

Method 成员方法	
	int read();
		从文件中读取一个字节数据返回到方法外。
		虽然返回值是一个int类型,但是在整个int类型当中存储的数据是一个byte类型,有
		且只有低8位数据有效
		
	int read(byte[] buf);
		读取文件的内容是存储在byte类型数组中,返回值是读取到的字节个数
		
	int read(byte[] buf, int offset, int count);
		读取文件的内容是存储在byte类型数组中,要求从byte数组offset位置开始,到
		count长度结束,返回值是读取到的字节个数
	
	以上三个方法如果读取到文件末尾,返回值都是 -1 EOF End Of File
	而且以上方法都要异常抛出
		IOException IO异常
6.3.2 使用演示
 	import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    
    /*
     * 文件操作输入字节流
     * 	1. 确认读取哪一个文件
     * 	2. 创建对应文件的FileInputStream
     * 	3. 读取数据
     * 	4. 关闭资源 【重点】
     */
    public class Demo1 {
    	public static void main(String[] args) {
    		long start = System.currentTimeMillis();
    		
    		readTest1();
    		
    		long end = System.currentTimeMillis();
    		System.out.println("Time : " + (end - start));
    	}
    
    	public static void readTest2() {
    		// 1. 确定操作文件
    		File file = new File("C:\\aaa\\1.txt");
    
    		// 2. 字节输入流读取文件对象
    		FileInputStream fileInputStream = null;
    		
    		try {
    			// 3. 根据File类对象创建对应的字节输入流
    			fileInputStream = new FileInputStream(file);
    			
    			// 4. 准备一个8KB字节缓冲数组
    			byte[] buf = new byte[1024 * 8];
    			int length = -1;
    			
    			// 5. 读取数据
    			while ((length = fileInputStream.read(buf)) != -1) {
    				System.out.println(new String(buf, 0, length));
    			}
    			
    		} catch (IOException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		} finally {
    			// 在finally代码块中关闭资源
    			if (fileInputStream != null) {
    				try {
    					fileInputStream.close();
    				} catch (IOException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    			}
    		}
    	}
    
    	/*
    	 * low!!!
    	 */
    	public static void readTest1() {
    		// 1. 确定操作文件
    		File file = new File("C:\\aaa\\1.txt");
    		
    		// 2. 字节输入流读取文件对象 
    		FileInputStream fileInputStream = null;
    	
    		try {
    			// 3. 根据File类对象创建对应的字节输入流
    			fileInputStream = new FileInputStream(file);
    			
    			// 4. 读取文件 
    			int content = -1;
    			
    			while ((content = fileInputStream.read()) != -1) {
    				System.out.println((char)content);
    			}
    		} catch (IOException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		} finally {
    			// 用于处理代码中使用到资源,无法发生什么样的错误,finally中的代码一定会执行
    			// 这里发现fileInputStream不是null,证明已经打开了文件资源,关闭资源,捕获异常
    			if (fileInputStream != null) {
    				try {
    					fileInputStream.close();
    				} catch (IOException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    			}
    		}
    	}
    }
6.3.3 文件读取使用缓冲和非缓冲差距

内存的运作速度看做是火箭 硬盘就是一个自行车 以上代码中,使用缓冲之后,从硬盘中一口气读取8KB数据存储在内存中,供程序使用。

8KB固态硬盘,4KB对齐。固态硬盘中每一个扇区都是4KB。缓冲这里是要求CPU读取两个4KB数据,对于CPU而言没有太多压力。 如果是一个字节一个字节读取,CPU取出4KB数据,结果有4095无效。

6.3.4 文件操作输出字节流

FileOutputStream 文件操作输出字节流

Constructor 构造方法:

FileOutputStream(File file); 根据File类对象创建对应的文件输出字节流对象

FileOutputStream(String pathName); 根据String类型文件路径创建对应的文件输出字节流对象

以上两个构造方法,创建的FileOutputStream是删除写/清空写操作,会将原文件中的内容全部删除之后,写入数据。

FileOutputStream(File file, boolean append); 根据File类对象创建对应的文件输出字节流对象。创建对象时给予append参数为 true,表示追加写。

FileOutputStream(String pathName, boolean append); 根据String类型文件路径创建对应的文件输出字节流对象,创建对象时给予append参数为true,表示追加写。

FileOutputStream构造方法是拥有创建文件的内容,如果文件存在,不创建,文件不存在且路径正确,创建对应文件。否则抛出异常FileNotFoundException

Method 成员方法:

void write(int b); 写入一个字节数据到当前文件中,参数是int类型,但是有且只会操作对应的低八位数据

void write(byte[] buf); 写入字节数组中的内容到文件中

void write(byte[] buf, int offset, int length); 写入字节数组中的内容到文件中,从指定的offset开始,到指定长度length

以上方法会抛出异常:IOException

6.3.5 使用演示
import java.io.File;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    /*
     * 文件操作输出字节流
     * 		1. 确定文件
     * 		2. 创建FileOutputStream
     * 		3. 写入数据到文件中
     * 		4. 关闭资源 
     */
    public class Demo2 {
    	public static void main(String[] args) {
    		writeTest2();
    	}
    
    	public static void writeTest2() {
    		// 1. 确定文件
    		File file = new File("C:/aaa/中国加油.txt");
    		
    		// 2. 文件操作字节输出流对象
    		FileOutputStream fileOutputStream = null;
    		
    		try {
    			// 3. 创建FileOutputStream 
    			fileOutputStream = new FileOutputStream(file);
    			
    			// 4. 准备byte类型数组
    			byte[] bytes = "武汉加油!中国加油!".getBytes();
    			byte[] arr = {65, 66, 67, 68, 69, 70, 71};
    			
    			fileOutputStream.write(bytes);
    			fileOutputStream.write(arr, 2, 3);
    		} catch (IOException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		} finally {
    			// 关闭资源
    			if (fileOutputStream != null) {
    				try {
    					fileOutputStream.close();
    				} catch (IOException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    			}
    		}
    	}
    
    	public static void wrietTest1() {
    		// 1. 确定文件
    		File file = new File("C:/aaa/武汉加油.txt");
    		
    		// 2. 文件操作字节输出流对象
    		FileOutputStream fileOutputStream = null;
    		try {
    			// 3. 创建FileOutputStream
    			fileOutputStream = new FileOutputStream(file, true);
    			
    			// 4. 写入数据
    			fileOutputStream.write('D');
    			fileOutputStream.write('D');
    			fileOutputStream.write('D');
    			fileOutputStream.write('D');
    			fileOutputStream.write('D');
    			fileOutputStream.write('D');
    		} catch (IOException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		} finally {
    			// 关闭资源
    			if (fileOutputStream != null) {
    				try {
    					fileOutputStream.close();
    				} catch (IOException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    			}
    		}
    	} 
    }

6.4 文件操作字符流

6.4.1 字符流特征

字符流 = 字节流 + 解码过程 字节组合操作 ==> 对应当前环境编码集的一个字符 如果字符找不到,该数据无效,需要被删除。

如果是字符内容操作,效率还可以!!! 如果是非字符操作,凶多吉少!!!

字符流操作文件 个人建议,该文件可以使用notepad 记事本打开无乱码,可以使用字符流操作。 视频文件,图片文件,特定格式的文件,都无法使用字符操作。

6.4.2 文件操作输入字符流

FileReader 文件操作输入字符流

Constructor 构造方法 FileReader(File file) 根据File类对象创建对应的FileReader字符流输入对象

FileReader(String pathName) 根据String类型文件路径创建对应的FileReader字符流输入对象 如果文件不存在,抛出异常FileNotFoundException

Method 成员方法 int read(); 读取文件中的一个字符数据,通过返回值返回,返回值类型是int类型,但是在int类型中有且只有低16位数据有效

int read(char[] arr); 读取文件中的数据保存到字符数组中,返回值类型是读取到的字符个数

int read(char[] arr, int off, int len); 读取文件中的数据保存到字符数组中,要求从数组中下标offset开始,到len结束,返回值类型是读取到的字符个数

以上方法,如果读取到文件默认,返回值为-1 EOF End Of File 如果读取操作工作中,出现问题,抛出异常IOException

6.4.3 使用演示
  import java.io.File;
    import java.io.FileNotFoundException;
    import java.io.FileReader;
    import java.io.IOException;
    
    public class Demo4 {
    	public static void main(String[] args) {
    		long start = System.currentTimeMillis();
    		
    		readTest2();
    		
    		long end = System.currentTimeMillis();
    		System.out.println("Time : " + (end - start));
    	}
    
    	// 10
    	public static void readTest2() {
    		FileReader fileReader = null;
    		try {
    			fileReader = new FileReader(new File("C:/aaa/3.txt"));
    			
    			char[] buf = new char[1024 * 4];
    			int length = -1;
    			
    			while ((length = fileReader.read(buf)) != -1) {
    				System.out.println(new String(buf, 0, length));
    			}
    		} catch (IOException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		} finally {
    			if (fileReader != null) {
    				try {
    					fileReader.close();
    				} catch (IOException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    			}
    		}
    	}
    
    	// 300
    	public static void readTest1() {
    		FileReader fileReader = null;
    		try {
    			fileReader = new FileReader(new File("C:/aaa/3.txt"));
    			
    			int content = -1;
    			
    			while ((content = fileReader.read()) != -1) {
    				System.out.println((char) content);
    			}
    		} catch (IOException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		} finally {
    			if (fileReader != null) {
    				try {
    					fileReader.close();
    				} catch (IOException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    			}
    		}
    	}
    }
6.4.4 文件操作字符输出流
FileWriter文件操作输出字符流

Constructor 构造方法
	FileWriter(File file);
		根据File类对象创建对应文件的文件操作输出字符流
	FileWriter(String pathName);
		根据String类型文件路径创建对应文件的文件操作输出字符流
	FileWriter(File file, boolean append);
		根据File类对象创建对应文件的文件操作输出字符流,并要求为追加写
	FileWriter(String pathName, boolean append);
		根据String类型文件路径创建对应文件的文件操作输出字符流,并要求为追加写
	
	如果创建FileWrite对象时,这里文件不存在,路径合法,这里会创建对应的操作文件。如果路径不合法,抛出异常 FileNotFoundException 
	
Method 成员方法	
	void write(int ch);
		写入一个char类型数据到文件中
	void write(char[] arr);
		写入一个char类型数组到文件中
	void write(char[] arr, int offset, int length);	
		写入一个char类型数组到文件中,要求从offset下标位置开始读取数组数据,长度为
		length
	void write(String str);
		写入一个字符串到文件中
	void write(String str, int offset, int lenght);
		写入一个字符串到文件中,要求从指定字符串offset下标位置开始,长度为length
	如果写入数据操作过程中,发生问题,这里会有一个IOException
6.4.4 使用演示
 import java.io.File;
    import java.io.FileWriter;
    import java.io.IOException;
    
    /*
     * 文件操作字符输出流
     */
    public class Demo1 {
    	public static void main(String[] args) {
    		FileWriter fileWriter = null;
    		
    		try {
    			fileWriter = new FileWriter(new File("D:/aaa/5.txt"), true);
    			
    			char[] charArray = "现在美国全国缺少口罩2.7亿".toCharArray();
    			
    			fileWriter.write(charArray);
    			fileWriter.write("韩国目前疫情情况不容乐观");
    			fileWriter.write("\r\n");
    			fileWriter.write(charArray, 0, 5);
    			fileWriter.write("韩国目前疫情情况不容乐观", 0, 5);
    			
    		} catch (IOException e) {
    			e.printStackTrace();
    		} finally {
    			if (fileWriter != null) {
    				try {
    					fileWriter.close();
    				} catch (IOException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    			}
    		}
    		
    	}
    
    	private static void writeTest1() {
    		FileWriter fileWriter = null;
    		try {
    			fileWriter = new FileWriter(new File("D:/aaa/4.txt"), true);
    			
    			fileWriter.write('武');
    			fileWriter.write('汉');
    			fileWriter.write('加');
    			fileWriter.write('油');
    			fileWriter.write(',');
    			fileWriter.write('中');
    			fileWriter.write('国');
    			fileWriter.write('加');
    			fileWriter.write('油');
    			fileWriter.write(',');
    			fileWriter.write('世');
    			fileWriter.write('界');
    			fileWriter.write('加');
    			fileWriter.write('油');
    			
    			
    		} catch (IOException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		} finally {
    			if (fileWriter != null) {
    				try {
    					fileWriter.close();
    				} catch (IOException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    			}
    		}
    	}
    }
6.4.5 字符流文件拷贝
import java.io.File;
    import java.io.FileReader;
    import java.io.FileWriter;
    import java.io.IOException;
    
    /*
     * 使用文件操作字符流量拷贝非文本文件问题
     * 【要求】
     * 		禁止使用字符流操作非文本文件,记事本打开乱码文件都不可以
     */
    public class Demo2 {
    	public static void main(String[] args) {
    		FileReader fileReader = null;
    		FileWriter fileWriter = null;
    		
    		
    		try {
    			fileReader = new FileReader(new File("D:/aaa/logo桌面.jpg"));
    			fileWriter = new FileWriter(new File("D:/aaa/temp.jpg"));
    			
    			char[] buf = new char[1024 * 4];
    			int length = -1;
    			
    			while ((length = fileReader.read(buf)) != -1) {
    				fileWriter.write(buf, 0, length);
    			}
    		} catch (IOException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		} finally {
    			if (fileWriter != null) {
    				try {
    					fileWriter.close();
    				} catch (IOException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    			}
    			
    			if (fileReader != null) {
    				try {
    					fileReader.close();
    				} catch (IOException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    			}
    		}
    	}
    }

7. 缓冲流

7.1 缓冲流有什么作用

使用缓冲数组以后,整体的读取,写入效率提升很大!!! 降低了CPU通过内存访问硬盘的次数。提高效率,降低磁盘损耗。

字节输入缓冲 BufferedInputStream 字节输出缓冲 BufferedOutputStream 字符输入缓冲 BufferedReader 字符输出缓冲 BufferedWrite

【重点】 所有的缓冲流都没有任何的读取,写入文件能力,这里都需要对应的输入流和输出流来提供对应的能力。 在创建缓冲流流对象时,需要传入对应的输入流对象和输出流对象。 底层就是提供了一个默认大小的缓冲数组,用于提高效率

7.2 字节缓冲流

输入 BufferedInputStream(InputStream in); 这里需要的对象是一个字节输入流基类对象。同时也可也传入InputStream子类对象

输出 BufferedOutputStream(OutputStream out); 这里需要的对象是一个字节输出流基类对象。同时也可也传入OutputStream子类对象

以上传入的InputStream和OutputStream都是用于提供对应文件的读写能力。

7.2.1 字节输入流缓冲效率问题
  1. 在BufferedInputStream底层中有一个默认容量为8KB的byte类型缓冲数组。
  2. fill方法是一个操作核心 a. 从硬盘中读取数据,读取的数据容量和缓冲数组容量一致。 b. 所有的read方法,都是从缓冲数组中读取数据 c. 每一次读取数据之前,都会检查缓冲区内是否有数据,如果没有,fill方法执行,填充数据。
  3. 利用缓冲,fill方法,可以极大的降低CPU通过内存访问硬盘的次数。同时程序操作的数据是在内存中进行交互的。
7.2.2 字节输出流缓冲效率问题
  1. 在BufferedOutputStream类对象,默认有一个8KB的byte类型缓冲数组
  2. 数据写入文件时并不是直接保存到文件中,而是保存在内存8KB字节缓冲数组中
  3. 如果8KB空间填满,会直接flush缓冲区,数据保存到硬盘中,同时清空整个缓冲区。
  4. 在BufferedOutputStream关闭时,首先会调用flush方法,保存数据到文件,清空缓冲区,并且归还缓冲区占用内存,同时关闭缓冲流使用的字节输出流。
7.2.3 缓冲流拷贝和非缓冲拷贝时间效率区别
 import java.io.BufferedInputStream;
    import java.io.BufferedOutputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    public class Demo3 {
    	public static void main(String[] args) {
    		long start = System.currentTimeMillis();
    
    		copy();
    		
    		long end = System.currentTimeMillis();
    		// 总耗时
    		System.out.println("Time:" + (end - start));
    	}
    	
    	// 1716 ms
    	public static void useBuffered() {
    		BufferedInputStream bis = null;
    		BufferedOutputStream bos = null;
    		
    		try {
    			bis = new BufferedInputStream(new FileInputStream(new File("D:/aaa/2.txt")));
    			bos = new BufferedOutputStream(new FileOutputStream(new File("D:/aaa/buffered.txt")));
    			
    			int content = -1;
    			
    			while ((content = bis.read()) != -1) {
    				bos.write(content);
    			}
    		} catch (IOException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		} finally {
    			if (bos != null) {
    				try {
    					bos.close();
    				} catch (IOException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    			}
    			
    			if (bis != null) {
    				try {
    					bis.close();
    				} catch (IOException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    			}
    		}
     	}
    	
        // 531000
    	public static void copy() {
    		FileInputStream fis = null;
    		FileOutputStream fos = null;
    		
    		try {
    			fis = new FileInputStream("D:/aaa/2.txt");
    			fos = new FileOutputStream("D:/aaa/copy.txt");
    			
    			int content = -1;
    			
    			while ((content = fis.read()) != -1) {
    				fos.write(content);
    			}
    		} catch (IOException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		} finally {
    			if (fos != null) {
    				try {
    					fos.close();
    				} catch (IOException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    			}
    			
    			if (fis != null) {
    				try {
    					fis.close();
    				} catch (IOException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    			}
    		}
    	}
    }

7.3 字符缓冲流

7.3.1 方法

BufferedReader 字符缓冲输入流 BufferedReader(Reader reader);

BufferedWriter 字符缓冲输出流 BufferedWriter(Writer writer);

7.3.2 字符缓冲流效率问题
  1. 字符缓冲输入流,底层有一个8192个元素的缓冲字符数组,而且使用fill方法从硬盘中读取数据填充缓冲数组
  2. 字符缓冲输出流,底层有一个8192个元素的缓冲字符数组,使用flush方法将缓冲数组中的内容写入到硬盘当中。
  3. 使用缓冲数组之后,程序在运行的大部分时间内都是内存和内存直接的数据交互过程。内存直接的操作效率是比较高的。并且降低了CPU通过内存操作硬盘的次数
  4. 关闭字符缓冲流,都会首先释放对应的缓冲数组空间,并且关闭创建对应的字符输入流和字符输出流。
  5. 字符缓冲输入流中 String readLine(); 读取一行数据 字符缓冲输出流中 void newLine(); 换行

8. 序列化

8.1 序列化概述

Java中提供了一种序列化操作的方式,用一个字节序列化来表示一个对象,该字节序列化中保存了【对象的属性】,【对象的类型】和【对象的数据】。把字节序列化保存到文件中,就可以做到持久化保存数据内容。

从文件中读取字节序列化数据,可以直接得到对应的对象。

8.2 ObjectOutputStream类

将对象数据序列化,保存到文件中

构造方法 Constructor
	ObjectOutputStream(OutputStream out);
		输出字节流对象作为当前方法的参数
  import java.io.File;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.ObjectOutputStream;
    
    public class Demo1 {
    	public static void main(String[] args) {
    		
    		ObjectOutputStream objectOutputStream = null;
    		
    		try {
    			objectOutputStream = new ObjectOutputStream(new FileOutputStream("D:/aaa/person.txt"));
    			
    			// 序列化对象,并且写入到文件中
    			objectOutputStream.writeObject(new Person(1, "骚磊", 16));
    			
    		} catch (IOException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		} finally {
    			if (objectOutputStream != null) {
    				try {
    					objectOutputStream.close();
    				} catch (IOException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    			}
    		}
    	}
    }

8.3 ObjectInputStream类

从文件中读取被序列化之后的字节数据,提供反序列化操作,得到一个对象。

构造方法 Constructor
	ObjectInputStream(InputStream in);
	需要提供一个字节输入流对象来进行操作

【序列化注意事项】

  1. 如果一个类需要进行序列化操作,必须遵从。java.io.Serializable。不遵从无法进行序列化操作
  2. 序列化之后从文件中读取序列化内容,转换成对应的对象, ClassNotFoundException 对应类没有找到。 对应的类型没有导包,不存在… InvalidClassException 类型不一样 序列化之后的每一个类都会有一个serialVersionUID,该编号在使用过程中,序列化 和反序列化必须一致
  3. transient 修饰的成员变量不能被序列化

9.Java常用API

9.1. StringBuffer

9.1.1 StringBuffer概述

为了解决String字符串操作导致的内存冗余,提高效率,Java中提供了StringBuffer和StringBuilder来操作字符串,并且提供了很多方法,便于程序员开发。 StringBuffer和StringBuilder中都有char类型可变长数组作为字符串的保存空间。使用到的方法类型和ArrayList类似。

StringBuffer 线程安全,效率较低 StringBuilder 线程不安全,效率较高

9.1.2 StringBuffer构造方法

构造方法 Constructor StringBuffer(); 创建一个未存储任何字符串信息的空StringBuffer空间,底层初始化一个16个字符char类型数组

StringBuffer(String str); 根据提供的String类型字符串创建对应的StringBuffer空间,底层char类型数组的容量会根据str.length + 16决定,并且保存对应的str

9.1.3 添加方法

append(Everything) 在StringBuffer和StringBuilder对象中,添加另外的数据,并且当做字符串处理。 insert(int index, Everything) 在StringBuffer和StringBuilder对象中,在指定的下标位置,添加其他内容,并且当做 字符串处理

9.1.4 查看方法

String toString(); 将底层的char类型数组保存的字符内容转换成对应的String类型字符串返回 int length(); 返回底层char类型数组中有多少有效元素。 String substring(int begin); 从指定位置开始获取到char类型数组有效元素末尾对应的字符串,截取操作, String substring(int begin, int end); 从指定位置begin开始到end结束,获取对应的字符串,要头不要尾 int indexOf(String str); 指定元素字符串所在下标位置 int lastIndexOf(String str); 指定元素字符串最后一次所在下标位置

9.1.5 修改方法

replace(int start, int end, String str); 从指定位置start开始,到end结束,start <= n < end, 使用str替换

setCharAt(int index, char ch); 使用ch替换指定下标index对应的字符

9.1.6 删除和反序

delete(int start, int end); 删除指定范围以内的字符 start <= n < end deleteCharAt(int index); 删除指定下标的字符 reverse(); 逆序

9.2. Math数学类

Java中一些数学方法

public static double abs(double a); 返回值为绝对值 public static double ceil(double a); 向上取整 public static double floor(double a); 向下取整 public static double round(double a); 四舍五入 public static double random(); 随机数 0.0 <= n < 1.0

9.2.1 方法使用
package com.qfedu.b_math;

/*
 * Math工具类方法
 */
public class Demo1 {
	public static void main(String[] args) {
		// 绝对值
		System.out.println(Math.abs(1.5));
		System.out.println(Math.abs(-1.5));
		System.out.println(Math.abs(5));
		System.out.println(Math.abs(-5));
	
		System.out.println("--------------------------------");
		
		// 向上取整
		System.out.println(Math.ceil(1.5));
		System.out.println(Math.ceil(1.1));
		System.out.println(Math.ceil(-1.9));
		System.out.println(Math.ceil(-2.9));
		
		System.out.println("--------------------------------");
		
		// 向下取整
		System.out.println(Math.floor(10.5));
		System.out.println(Math.floor(10.1));
		System.out.println(Math.floor(-10.5));
		System.out.println(Math.floor(-10.1));
		
		System.out.println("--------------------------------");
		
		// 四舍五入
		System.out.println(Math.round(3.5)); // 4
		System.out.println(Math.round(3.4)); // 3
		System.out.println(Math.round(-2.5)); // -2
		System.out.println(Math.round(-2.4)); // -2
		System.out.println(Math.round(-2.6)); // -3
	}
}
9.2.2 抽奖小演示
package com.qfedu.b_math;

public class Demo2 {
	public static void main(String[] args) {
		for (int i = 0; i < 20; i++) {
			double num = Math.random() * 100;
			
			if (0.0 <= num && num < 50) {
				System.out.println("绿色普通卡");
			} else if (50 <= num && num < 80) {
				System.out.println("蓝色高端卡");
			} else if (80 <= num && num < 98) {
				System.out.println("紫色传说卡");
			} else {
				System.err.println("黄金史诗卡");
			}	
		}
	}
}

9.3. 日历时间格式

9.3.1 Date 时期类[逐渐淘汰]

获取当前系统时间 大部分构造方法已经过时

构造方法 Date(); 创建一个Date,对应当前时间,精度在毫秒值 Date(long date); 根据时间戳毫秒数,创建对应的Date对象,时间戳是从1970-01-01 00:00:00 GMT tips: 中国采用的东八区时间 1970-01-01 08:00:00 常用方法: long getTime(); 通过Date类对象获取对应当前时间的毫秒数 System.currentTimeMillis(); 可以获取当前系统时间戳毫秒数

9.3.2. DateFormat 日期格式类

DateFormat 是一个abstract修饰的类,用于转换时间格式。 DateFormat不能直接使用,一般使用DateFormat子类SimpleDataFormat来使用 SimpleDataFormat构造方法中需要的参数是一个String,String类型的参数有特定的要求

标识字母(区分大小写)

对应含义

y

M

d

H

时(24小时)

m

s

String format(Date date); 根据指定匹配要求,转换Date格式成为字符串

Date parse(String format); 按照指定的匹配规则,解析对应的字符串,返回一个Date数据

9.3.3 Calender日历类

Calender日历类,替换了很多Date类中的方法。把很多数据都作为静态的属性,通过一些特定的方法来获取。比Date处理日期数据更加方便。

Calender是一个abstract修饰的类,没有自己的类对象。这里通过特定的方法getInstance获取Calender日历类对象。

public static Calender getInstance(); 默认当前系统时区的Calender对象

常用方法: public int get(int field); 返回特定数据的数值 public void set(int field, int value); 设置特定字段对应的数据 public Date getTime(); 返回得到一个Date对象,从计算机元年到现在的毫秒数,保存在date对象中

字段名

含义

YEAR

MONTH

月(从0开始,使用时需要+1)

DAY_OF_MONTH

当前月的第几天

HOUR

小时(12小时制)

HOUR_OF_DAY

小时(24小时制)

MINUTE

分钟

SECOND

DAY_OF_WEEK

周几(周日为1)

9.4. System类

System类提供了大量的静态方法,操作的内容和系统有关。

可以获取当前时间戳 long currentTimeMillis() 获取系统属性的方法 Properties getProperties(); 退出当前程序 exit(int status)

数组拷贝方法 arrayCopy(Object src( 原数组), int srcPos(从原数组指定下标开始), Object dest(目标数组) , int destPos(目标数组从指定位置开始),int length( 读取数据的个数) )

9.5. Runtime类

Runtime当前程序运行环境类对象,只要程序启动就会有对应的Runtime存在。 获取Runtime对象的方法: Runtime Runtime.getRuntime(); 返回值是Runtime

需要了解的方法: gc(); JVM的GC机制,但是就算你调用了GC方法,也不会立即执行。 long totalMemory(); 目前程序使用的总内存 long freeMemory(); 目前程序使用的剩余内容 long maxMemory(); Java程序能过申请的最大内存 Process exec(String exePath); 开启一个程序

9.6. 包装类

Java中提供了两种数据类型 基本数据类型 byte short int long double float boolean char 引用数据类型 类对象,数组,字符串

Java中万物皆对象,Java中提供了包装类,让基本类型也可以当做类对象来处理。 包装之后的基本数据类型依然可以进行基本的操作和运算,但是多了一些特有的方法,增加了操作性。

问题: ArrayList中如果保存的数据类型是Integer类型 ArrayList元素: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 如果调用 remove(1); 删除的是谁???

基本类型

对应的包装类(java.lang)

byte

Byte

short

Short

int

Integer

long

Long

float

Float

double

Double

boolean

Boolean

char

Character

9.6.1 自动装箱和自动拆箱

基本类和包装类型之间进行转换的操作,这个过程就是"装箱"和"拆箱"。 装箱 从基本类型到包装类

拆箱 从包装类到基本类型

【不推荐】使用强制操作,太麻烦!!!

9.6.2 包装类和字符串数据转换过程

从文本中读取的数据很多都是字符串类型,例如 JSON XML Database 除了Character字符包装类之外,其他的包装类都有对应的解析方法

以下方法都是static修饰的静态方法 public static byte parseByte(String str); public static short parseShort(String str); public static int parseInt(String str); public static long parseLong(String str); public static float parseFloat(String str); public static double parseDouble(String str); public static boolean parseBoolean(String str); 以上方法都是对应的包装类调用,解析成对应的基本数据类型。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Java知识点——方法引用

    用户7073689
  • 知识点——初识java中File类

    SUN公司提供给开发者操作文件和文件夹的一个类对象。 Java中万物皆对象,计算机中万物皆文件

    用户7073689
  • Java知识点——NIO和BIO

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jvUiQgVM-1584882587306)(img/NIO图例.png)]

    用户7073689
  • mybatis的物理分页:mybatis-paginator

    文件分割与合并是一个常见需求,比如:上传大文件时,可以先分割成小块,传到服务器后,再进行合并。很多高大上的分布式文件系统(比如:google的GFS、taoba...

    菩提树下的杨过
  • java:快速文件分割及合并

    文件分割与合并是一个常见需求,比如:上传大文件时,可以先分割成小块,传到服务器后,再进行合并。很多高大上的分布式文件系统(比如:google的GFS、taoba...

    菩提树下的杨过
  • -1-4 java io java流 常用流 分类 File类 文件 字节流 字符流 缓冲流 内存操作流 合并序列流

    public void write(byte[] b,int off,int len)

    noteless
  • 基于RxJava2实现的简单图片爬虫的方法

    今年十月份以来,跟朋友尝试导入一些图片到tensorflow来生成模型,这就需要大量的图片。刚开始我只写了一个简单的HttpClient程序来抓取图片,后来为了...

    砸漏
  • 基于RxJava2实现的简单图片爬虫

    今年十月份以来,跟朋友尝试导入一些图片到tensorflow来生成模型,这就需要大量的图片。刚开始我只写了一个简单的HttpClient程序来抓取图片,后来为了...

    fengzhizi715
  • Java基础知识点面试手册(基础知识+集合)

    如果再深究一点呢,我们可以看看上面测试类的输出结果,或许对多态会有更深层次的认识。猜一猜上面 的结果是什么。

    Java3y
  • 每日一题(16)

    这是一个有点诡异的问题。程序并没有做什么特殊的事情,而是直接打印hello world。这里其实使用了java中一个鲜为人知的特性「语句标号」,可在任意语句前防...

    KEN DO EVERTHING

作者介绍

精选专题

活动推荐

扫码关注云+社区

领取腾讯云代金券