笔记为自学时随手记录,如有错误,欢迎指正,不胜感激!
笔记分享:自学it18大数据笔记-第一阶段Java-day09-day10-day11-day12--day13-day14-day15——会持续更新……
第一阶段Java-day03-day04见:http://t.cn/R65SR0f
第一阶段Java-day05-day06-day07-day08见:http://t.cn/R6cQpTt
day09笔记见下图:
day10笔记见下图:
day11笔记见下图:
day12笔记见下图:
day13笔记见下图:
day14笔记见下图:
day15笔记见下图:
day09
回顾:Tread 并发、每个线程就是一个栈、并发修改才加锁,synchronized是解决线程线程安全的
作业:100个馒头,40个工人吃,每个工人最多吃3个馒头,使用多线程给出所有工人吃馒头情况。
------------------------------------------------------------------------------------
class MantouDemo{
public static void main(String[] args){
Basket basket = new Basket();
for(int i = 1 ; i <= 40; i++ ){
new Worker("Worker-" + i, basket).start();
}
}
}
//工人
class Worker extends Thread{
private String name;
private static int MAX = 3;//工人最多能吃的数量
private int count;
private Basket basket;
public Worker(String name , Basket basket){
this.name = name;
this.basket = basket;
}
public void run(){
while(true){
if(count >= MAX){ //是否吃饱
return;
}
int no = basket.getMantou(); //取馒头
if(no == 0){
return;
}
count ++;
System.out.println(name + " : " + no);
}
}
}
//篮子
class Basket{
private int count = 100;
//同步方法,以当前对象作为锁旗标
public synchronized int getMantou(){
int temp = count ;
count --;
return temp > 0 ? temp : 0 ;
}
}
********************
注:同步函数中,当wiat()函数出现在if()函数的方法中的时候,注意由于wait()权限释放后,代码是直接从wait()后面开始运行,那么if语句条件判断可能在此时就失效,一般在wait()外套while循环,唤醒后再while循环判断一下,然后再执行后面的代码!
-----------------------------
代码有问题 ↓ ↓ ↓
class BeeDemo{
public static void main(String[] args){
Box box = new Box();
for(int i = 1 ; i <= 100 ; i ++ ){
new Bee("Bee-" + i , box).start();
}
Bear bear1 = new Bear("熊大",box);
bear1.start();
new Bear("熊二",box).start();
}
}
//蜜蜂
class Bee extends Thread{
private String name;
private Box box;
public Bee(String name, Box box){
this.name = name;
this.box = box;
}
public void run(){
while(true){
int n = box.add();
System.out.println(name + "生产了1蜂蜜!库存:" + (n + 1));
}
}
}
//熊
class Bear extends Thread{
private String name;
private Box box;
public Bear(String name, Box box){
this.name = name;
this.box = box;
}
public void run(){
while(true){
box.remove();
System.out.println(name + "吃掉5蜂蜜!");
}
}
}
//蜜罐
class Box{
private int MAX = 5;
private int count;
//加蜂蜜
public synchronized int add(){
while(count >= MAX ){ //这里最好不用if,wait()权限释放后问题导致!
try{
this.notify();
this.wait();
}catch(Exception e){
e.printStackTrace();
}
}
return count ++;
}
//吃蜂蜜
public synchronized void remove(){
while(count < MAX ){
try{
this.wait();
}catch(Exception e){
e.printStackTrace();
}
}
count = 0;
this.notify();
}
}
代码有问题 ↑ ↑ ↑
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
ava.lang.Runnable是接口 接口的目的是降低耦合度
---------------------------
java.lang.Runnable{ j
public.void run();
}
---------------------------
实现Runnable接口
class Car implements Runnable{…………} 一个类附加线程的特性,实现Runnable接口就好
使用Runnable对象创建线程:new Thread(Runnable r).start();
1,子类覆盖接口中的run方法。Runnable接口中仅仅有一个run()方法
2,通过Thread类创建线程,并将实现了Runnable接口的子类对象作为参数传递给Thread类的构造函数。
3,Thread类对象调用start()方法开启线程
>>>一个类实现了Runnable接口还不是“多线程”只有继承了Thread类才是,但是实现了Runnable接口就能传递给线程对象调用它的方法!!
---------------------------------------
利用匿名内部类 开个分线程 打印1-10个数↓↓↓
class RunnableDemo{
public static void main(String[] args){
//new Thread().start(); 开个线程直接运行
//下面都是匿名内部类对象创建
/*new Thread(new Runnable(){ //没有继承Thread,做了Runnable接口的实现类
public void run(){
for(int i = 1; i <= 10; i ++){
System.out.print(i + "\t");
}
}
}).start();*/
new Thread(){ //继承Thread,重写了run()方法
public void run(){
for(int i = 1; i <= 5; i ++){
System.out.print(i + "\t");
}
}
}.start();
}
}
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
线程安全问题
--------------------------
原因:多个线程访问出现延迟;线程随机性 。
注:线程安全问题在理想状态下,不容易出现,但一旦出现对软件的影响是非常大的。
同步synchronize 是解决线程安全问题的:加了同步synchronize关键字的好处:同一时刻只能有一个线程访问这段代码!
>>>静态同步方法是使用class作为锁。
>>>非静态同步方法是使用this(当前对象)作为锁。
停止线程
-------------------------------
>>>定义循环结束标记
因为线程运行代码一般都是循环,只要控制了循环即可。
>>>使用interrupt(中断)方法。简单粗暴,很少用
该方法是结束线程的冻结状态,使线程回到运行状态中来。
一般设置一个标记
注:stop方法已经过时不再使用。
线程类的其他方法
------------------------------------
setPriority(int num) 优先级
getPriority() 获得优先级数 最小是1 一般为5 最大是10
setDaemon(boolean b)
join()
自定义线程名称
toString()
>>>线程的四种状态
--------------------------------------
sleep方法需要指定睡眠时间,单位是毫秒。
一个特殊的状态:就绪。具备了执行资格,但是还没有获取资源。
IDE:继承开发环境 intergrate development environment
eclipse 日食 “挡住了sun的光芒”
------------------------------------------------------
netbeans;IDEA;borland Jbuilder
透视图 perspective eclipse -> windows -> perspective
视图 view eclipse -> windows -> show view -> other -> all view
>>Problems问题错误显示 javadoc网页型注释 console控制台
指定工作空间 eclipse --> file --> switch workplace --> other -> new……
src:源代码
JRE XXXX…:Java运行时环境
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
eclipse常用快捷键
-----------------------------------
提示所有快捷键的快捷键是 ctrl+shift+L 菜单是在: window-->preferences-->general-->keys
eclipse Ctrl +左键查看源代码
navigator导航器
Alt+/:代码提示、自动补全——main+alt+/,sout+alt+/
ctrl+f11:运行代码
格式化 ctrl+shift+f
导入包 ctrl+shift+o
注释 ctrl+/,ctrl+shift+/,ctrl+shift+\
ctrl+1:快速修复,提示代码错误原因以及处理办法。跟双击代码中的红叉一样的功能!!!
ctrl+2:修改变量名,定义变量
Ctrl+D: 删除当前行
Alt+↓ 当前行和下面一行交互位置(特别实用,可以省去先剪切,再粘贴了)>>代码上下移动 选中代码alt+上/下箭头 ctrl+alt+向下箭头:复制上面一行代码
查看源码 选中类名(F3或者Ctrl+鼠标点击)
java编辑器 显示工具提示描述 F2
outline:
--------------------------------
实心的代表方法 空心的代表属性
绿色的圆表示公有public
黄色的菱形表示保护protect
红色的方形表示私有private
蓝色的三角表示default
图形后加字母S代表该属性或方法为static静态的,加字母F代表它为final的,加字母A表示抽象abstract,加c表示构造方法construction。
方法后加蓝色三角代表它是继承至父类的方法
断点为蓝色小圆形
蓝色旗状图形代表书签
白底上加蓝色对钩代表task
------------------------------------------------
jar的使用:建Folder>>黏贴>>Build Path(构建路径)>>Add xxx>>>> 构建路径就是classpath
(...凡是带3个点的菜单将打开一个独立的窗口)
======================
调试debug,找虫子
------------------------------------
断点:代码运行到此处停住
单步跳过:进入下行代码…单步进入:进入行代码调用的函数,单步返回…继续运行:运行到下一个断点停住
==============================
线程状态 也成为状态机模型
------------------------------------------------
NEW 尚未运行
RUNNABLE 正在运行的状态
BLOCKED 阻塞状态,等待监视器的锁定权
synchronized(this){
}
WAITING 等待状态(无限等待),一个线程在等待另一个线程特定的操作
wait();
TTIMED_WAITING 限时等待 等待指定时间
wait(xxx);
TERMINATED 线程退出
Sleep 休眠
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
String
--------------------------
java.lang.String 常见的类一般都是 java.lang.Xxxx
java.lang.Integer 整数的包装类
字符串是一个特殊的对象。字符串一旦初始化就不可以被改变。
>>常量
String name = “xxx”;
name = “ddd” //这里xxx和ddd 才是string常量,它们没有改变
byte b = (int)1234; //强转,前提是基本数据类型相同或有继承关系(多态)
String str = 1234 + “”; String str = (String)1234;//错的,但可以使用加号“+”来转换;
Objiect o = new Dog();
Dog d = (Dog) o ;
>>创建String的区别
//一个对象(str1是指针,是引用,在栈区)
String str1 = “abc”; //字符串池里面的abc这个常量赋给str1
//2个对象:str2在栈区;new String在堆区;abc在串池里
String str2 = new String(“abc”); //在堆里面分配了空间
str.length(); //串长度=字符串的个数
charAt(x); //提取指定位置上的字符
toCharArray(); //复制String中的[ ]。产生新的数组,不会影响原来的数组!
indexOf(“world” , 7 );//返回子串在母串中的位置(索引值,以0为基础)——7是开始搜索的位置
boolean endsWith(String str);//判断是否以指定的字符结尾
boolean startsWith(String str);
String[] split(String reg);//切割字符串,形成String数组
“hello,,,,,,,world,”.split(“,”);以,号来拆分>>最后的,号不生效 中间的都生效
String substring(int index); //子串,beginIndex:int endIndex:int
“hello world”.substring(beginIndex,endIndex);
“hello world”.substring(6,10);//前包后不包 只有worl 没有d
String(char[] arr); //字符串内部就是用数组来存储的
编码表
-----------------------------
ASCII:美国标准信息交换码。
用一个字节的7位可以表示。
ISO8859-1:拉丁码表。欧洲码表
用一个字节的8位表示。无法存储汉字,或者只取了汉字的一半,使用?代替,即编码为63.
GB2312:中国的中文编码表。简体中文,2个字节
GBK:中国的中文编码表升级,融合了更多的中文文字符号。2个字节
Unicode:国际标准码,融合了多种文字。
所有文字都用两个字节来表示,Java语言使用的就是unicode
UTF-8:最多用三个字节来表示一个字符。
>>>>>>>实现:所有的文字都变成数字,映射到表中字符!
Java中的字符字节在运算是都变成int
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
day10
回顾:常用类都在Java.lang.包下 java.lang.String final 不可继承是个最终类
字符串其实就是字符
eclipse编辑器中F2 工具提示描述
---------------------
package com.it18zhang.day10demo;
public class YourNameDemo {
public static void main(String[] args) {
//输出你的名字在Unicode中的编码!
for (int i = 0;i < 0xffff ; i ++){
if((char)i == '潇'){
// System.out.println("潇:" + i);
System.out.println("潇0x:" + Integer.toHexString(i)); //十六进制
}
if((char)i == '洒'){
// System.out.println("洒:" + i);
System.out.println("洒0x:" + Integer.toHexString(i));
}
}
}
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
String
----------------
1.常量 immutable 不可变的
2.存在于字符串池中
3.”abc”+”def” 有加号操作
4.字符有编码,Charset
5.IDE下的默认字符集设置的就是项目编码,和字符集是一个概念
6.中文字符集(是字符和数字的对照表):GBK;GB2312;Big-5繁体字符集;iso-8859-1 西欧码表;utf-8 国际化编码,可以表示任意文字
7.字符在内存中存储都是unicode码
8.编码转换:乱码过程
9.字符串编码
编码(encode):String--->byte[]:字符串转换成字节数组:str.getBytes();
解码(decode):byte[]--->String:…… :new String(byte[] , Charset); Charset字符集
StringBuffer
------------------------------------
1.字符串缓冲区 StringBuffer是一个容器
2.StringBuffer可以对字符串内容进行增删,mutable 可变的
3.java.lang.StringBuffer继承java.lang.AbstractStringBuilder
4.线程安全的
5.很多方法与String相同
StringBuffer特有方法
------------------------------
StringBuffer append(xxx);//添加
StringBuffer delete(int start, int end );//前包后不包
StringBuffer insert(offset,String str);// 插入 offset 偏移量
StringBuffer reverse(); 反向操作;字符串翻转
JDK1.5出现一个StringBuilder,区别是StringBuffer是同步的,StringBuilder是非同步的。
StringBuilder 和StringBuffer很多相似,只是它不是同步的没有synchronized
-----------------------------------
字符构建器
StringBuffer可以对字符串内容进行增删,mutable 可变的
java.lang.StringBuilder继承java.lang.AbstractStringBuilder
不是线程安全的
很多方法与String相同
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Builder模式:构建器模式:方法链编程 builder模式:java设计模式之一
-----------------------------------------
source:[sɔ:rs] 源代码
====================
java基本数据类型对象包装类 wrapper包装类 包装器
-----------------------------------------
1,数字
byte Byte
short Short
int Integer <<<<<<
long Long
floa Float
double Double
2,boolean Boolean
3,char Character <<<<<<<<
临时:ctrl + shift + f 格式化代码
包装类上的值(value)只能赋值一次不能被修改(final)
----------------------
1.将基本数据类型封装成对象的好处在于可以在对象中定义更多的功能方法操作该数据。
2.常用的操作之一:用于基本数据类型与字符串之间的转换。
例:Integer的parseInt方法:把字符串转成整数,intValue方法。
基本类型和包装类型区别
-------------------------
1,基本类型(数值类型)有默认值0;包装类默认值null
2,基本类型无法表达null的概念
3,基本类型不是对象;包装类是对象
4,基本类型可以直接参与运算;包装类是对象,不能直接参与运算
自动装箱/自动拆箱 .>>将基本类型自动自动转换成包装类/ ……
---------------------------------
JDK1.5以后,简化了定义方式。
Integer x = new Integer(4);可以直接写成
Integer x = 4;//自动装箱。
x = x + 5;//自动拆箱。实际也是通过intVlaue方法(省略没显示)原来必须通过intValue方法。
需要注意:
在使用时,Integer x = null;上面的代码就会出现NullPointerException。
so: Integer x = null;
Integer x = null ? 0 : x + 5 ; //三元运算判断下先
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
回顾:数组
--------------------
1,元素类型必须相同:基本类型和引用类型都可以
2,长度固定(弊端)
3,地址连续
4,通过下标访问,以0为基址
5,2个常见错误:null指针异常/索引越界异常
集合
----------------------
1,容器
2,长度可变
3,只能存储对象
4,元素类型可以不同
>>为什么出现集合类?
面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,就对对象进行存储,集合就是存储对象最常用的一种方式。
>>数组和集合类同是容器,有何不同?
数组虽然也可以存储对象,但长度是固定的;集合长度是可变的。数组中可以存储基本数据类型,集合只能存储对象。
>>集合类的特点
集合只用于存储对象,集合长度是可变的,集合可以存储不同类型的对象。
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
(实框的是类,虚框的都是接口)
List
-------------------------
(java中的集合类 都在Java的工具包中java.util.Xxxx)
interface java.util.Iterable
/|\ 继承关系
|--------java.util.Collection
/|\ 在IDE(eclipse)中右击F4 查看等级树
|--------interface java.util.List
/\
---- 实现类
class java.util.ArrayList-----|
1,List(列表)可以存放重复元素
2,有序的
3,读快,写慢(查询快,存储慢)
list.add(....) list.get(int index) list.remove(int index) list.clear()
4, List<String> list = new ArrayList<String>();//集合为空,在堆中有地址
List<String> list = null;//集合不存在
(类似苹果箱子:集合有效就是有箱子还要有苹果,isEmpty()函数判断)
5,list.iterator() 迭代器
Iterator<String> it = list.iterator();
while (it.hasNext()) {
String s = it.next();
System.out.println(s);
}
------------------------------------------
package com.it18zhang.collection;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class ListDemo {
public static void main(String[] args) {
// 定义集合List
List<String> list = new ArrayList<String>();
list.add("hello");
list.add("hello");
list.add("world");
list.add("hello");
for (int i = 0; i < list.size(); i++) {
System.out.print(list.get(i) + "\t");
}
System.out.println();
System.out.println("--------------------------------------");
Iterator<String> it = list.iterator();
while (it.hasNext()) {
String s = it.next();
System.out.println(s);
}
}
}
---------------------------------------------
List<String> list = new ArrayList<String>();// 定义集合List
<E> :泛型,指描述性的东西,定义或声明类或方法时可以在里面加入一些约束性的东西 E:占位符 < >
查看↑ get()方法:操作Ctrl+单击它 弹出get()的各种实现,找到ArrayList.get()就是
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
常用到的集合:ArryList HashSet HashMap
没有一个是线程安全的
List接口中常用类
------------------------------------
Vector:线程安全,但速度慢,已被ArrayList替代。ArrayList是有类外衣的数组
ArrayList:线程不安全,查询速度快。
LinkedList:链表结构,增删速度快。“手拉手”通过指针关联的,里子不是数组
取出LIst集合中元素的方式:
get(int index):通过脚标获取元素。
iterator():通过迭代方法获取迭代器对象。
----------------------
LinkedList
链表
通过手拉手实现的对象引用,存储速度快,查询慢
String
------------
== 等号操作 判断的是对象的内存地址,不是对象的内容。
equals 判断对象的内容是否相同
String equals没出问题是其重写(override)了equals方法 override 重写
普通类 内容相等不出问题 要重写equals方法
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
迭代 Iterable可迭代的 迭代就是相当于循环,也是遍历
------------------------
迭代是取出集合中元素的一种方式。
因为Collection中有iterator方法,所以每一个子类集合对象都具备迭代器。
用法:
for(Iterator iter = list.iterator();iter.hasNext(); )
{
System.out.println(iter.next());
}
Iterator iter = l.iterator();
while(iter.hasNext())
{
System.out.println(iter.next());
}
迭代注意事项
迭代器在Collcection接口中是通用的,它替代了Vector类(向量)中的Enumeration(枚举)。
迭代器的next方法是自动向下取元素,要避免出现NoSuchElementException。
迭代器的next方法返回值类型是Object,所以要记得类型转换。
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Set
------------------
interface java.util.Iterable
/|\
|--------java.util.Collection
/|\
|--------interface java.util.Set
/\
----
class java.util.HashSet-----|
1,元素不能重复
2,元素无序
3,常用HashSet(hash:散列)
4,没有get()方法,它的元素在内存中是散列的
只能通过iterator(迭代器)遍历
Set接口中常用的类
------------
HashSet:线程不安全,存取速度快。
Set接口中常用的类
-----------------------------
HashSet:线程不安全,存取速度快。
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
day11
回顾:集合体系结构
java.util.Iterator
Java.util.Collection
java.util.List
>>>>>>>>>>>作业>>>>>>>>>>>>>>>>>
list nested 列表 嵌套 (nested 嵌套的) 考查 泛型使用
package com.it18zhang.collection;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class ListNestedDemo {
public static void main(String[] args) {
// 1, 班级是名单(String)集合 每个班60人
List<String> name = null;
// 2,年级是班级集合 每个年级10个班
List<List<String>> grade = new ArrayList<List<String>>();
// 3,学校是年级集合 每个学校6个年级
List<List<List<String>>> school = new ArrayList<List<List<String>>>();
// 6个年级
for (int i = 1; i <= 2; i++) {
// 创建每个年级,是班级的集合
grade = new ArrayList<List<String>>();
school.add(grade);
// 处理每个年级的班级组合
for (int j = 1; j <= 3; j++) {
// 创建班级名单
name = new ArrayList<String>();
grade.add(name);
for (int k = 1; k <= 9; k++) {
name.add("学生-" + i + "-" + j + "-" + k);
}
}
}
// 输出集合
outName2(school);
}
public static void outName(List<List<List<String>>> allName) {
// 年级集合
for (int i = 0; i < allName.size(); i++) {
// 取当前的年级集合
List<List<String>> grade = allName.get(i);
System.out.println((i + 1) + "年级");
// 每个年级是班级集合
for (int j = 0; j < grade.size(); j++) {
List<String> classes = grade.get(i);
System.out.println((j + 1) + "班");
for (int k = 0; k < classes.size(); k++) {
System.out.print(classes.get(k) + " ");
}
System.out.println();
}
System.out.println();
}
System.out.println();
}
/**
* 迭代器输出
*/
public static void outName2(List<List<List<String>>> allName) {
Iterator<List<List<String>>> it = allName.iterator();
while (it.hasNext()) {
// 每个年级
List<List<String>> grade = it.next();
// 班级
Iterator<List<String>> classesIt = grade.iterator();
while (classesIt.hasNext()) {
List<String> name = classesIt.next();
Iterator<String> nameIt = name.iterator();
while (nameIt.hasNext()) {
System.out.println(nameIt.next());
}
}
}
}
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
List
-------1,可重复 equals方法有关 如果是集合中的对象,但是equals方法返回了false,contains()返回false
2,有序
3,ArryList
查询快,储存慢
4,LinkedList
链表,手拉手,没有数组,无法定位:查询慢,写入快
重写toString()
--------java.lang.Object
==和equals区别:
------1,== 判断对象是否是同一个,也就是地址是否相同
2,equals 判断对象内容是否相同,但默认调用的Object的equals()方法,而此方法仍然是判断地址是否相同和==效果相同,大部分情况你要重写equals()方法
Set
--------------
1,不重复 无序
2,add 添加元素
3,HashSet的内部实现是通过hashMap实现的
TreeSet: 线程不安全,可以对Set集合中的元素进行排序。
Set集合元素唯一性原因
-----------------------------------
HashSet:通过hashCode ()方法、==和equals()方法来保证元素的是否相同。
TreeSet:通过Comparator.compareTo或者comparable.compare()方法中的来保证元素的是否相等。元素是以二叉树的形式存放的。
Map 映射(一个元素到另一个元素的映射)
----------------------------------------------------------------------------------------------------------
1,Key--value 对,称为Entry条目
2,map的size是entry的数目
3,Map接口是单独的接口,没有继承任何接口
4,put 放入元素 将key和value进行关联,如果key已经存在则value将被覆盖
5,get(Key) 提取元素
6,迭代
entrySet
keySet
7,HashMap.hash()方法的意义:将新hash值跟更多的特征值相关(移位来实现)
8,“桶”中是Node<K,V>
class Node<K,V>{
int hash; //新hash
final K key; //key不能修改
V value; //value
Node<K,V> next ; //
}
9,元素重复的判断标准
p.hash == hash && ((k = p.k) == key || (key != null && key.equals(k)))
顺序从前至后
10,内内部存储是“数组+链表”
拉链法,我们可以理解为“链表的数组”
Map与Collection不同
----------------------------------------------------
Map与Collection在集合框架中属并列存在
Map存储的是键值对
Map存储元素使用put方法,Collection使用add方法
Map集合没有直接取出元素的方法,而是先转成Set集合,在通过迭代获取元素
Map集合中键要保证唯一性
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
day12
作业:1,hashMap实现原理,为什么(取出hashCode值;取出高16位;抑或运算)
做法: 1,高16位无符号右移16位,与低16位做^运算
2,得到的数值与0xf做&运算
目的: 1,如果无第一步,直接将数值与0xf做&运算,那么高16位所表现的特征将被丢失。如果有第一步,那就将原始的哈希码值的高16位和低16位做了混合,那么在新计算出来的低16位数值中就掺杂了高16位的部分特征,高16位的信息就被保留下来。
采用^而不用 & | 的原因:
采用^ 运算能更好的保留各部分的特征,不至于向0或1靠拢
2,为了数值落在0~15之间,得到对应的下标,明确放在那个桶里
hashMap的核心存储机制就是:数组+链表:数组就是桶的数量,保证它能均匀的分布就通过hash(散列)
作业2,判断学生是不是同一个(年龄身高体重放在一起)重写equals和hashCode (code:准则,法则)
--------------------------------------------------------
package com.it18zhang.collection.homework;
public class Student {
private int age;
private int height;
private int weight;
public Student(int age, int height, int weight) {
super();
this.age = age;
this.height = height;
this.weight = weight;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
public int hashCode() {
/*
* int hash = 0; hash = this.age | this.height<<8 | this.weight<<16;
* return hash;
*/
return this.age | this.height << 8 | this.weight << 16;
}
public boolean equals(Object obj) {
if (obj == null)
return false;
if (obj == this)
return true;
if (obj instanceof Student) { //instanceof用来判断内存中实际对象A是不是B类型
return this.hashCode() == obj.hashCode();
}
return false;
}
}
**************************************
package com.it18zhang.collection.homework;
public class App {
public static void main(String[] args) {
Student s1 = new Student(12, 175, 66);
Student s2 = new Student(12, 176, 66);
System.out.println(s1.equals(s2));
}
}
作业3,
---------------------------------------------------------------------------------------------
package com.it18zhang.collection.homework;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
public class MapNestedDemo {
/**
* Map嵌套
*/
public static void main(String[] args) {
// 名单及合
Map<String, String> names = null;
// 班级集合
Map<String, Map<String, String>> classes = null;
// 年级集合,要初始化
Map<String, Map<String, Map<String, String>>> grades = new HashMap<String, Map<String, Map<String, String>>>();
int no = 0;
for (int i = 1; i <= 3; i++) {
classes = new HashMap<String, Map<String, String>>();
grades.put(i + "年级", classes);
for (int j = 1; j <= 4; j++) {
names = new HashMap<String, String>();
classes.put(i + "年级" + j + "班", names);
for (int k = 1; k <= 8; k++) {
names.put("No.310 " + i + " " + j + " " + k, "tom" + (no++));
}
}
}
// 迭代输出
for (Entry<String, Map<String, Map<String, String>>> entry : grades.entrySet()) {
String key = entry.getKey(); // 年级名称
// 班级集合
Map<String, Map<String, String>> classes0 = entry.getValue();
// 输出年级
System.out.println(key);
System.out.println("-----------------");
// 年级里的每个班
for (Entry<String, Map<String, String>> e : classes0.entrySet()) {
// 班级名称
String className = e.getKey();
// 学生名单
Map<String, String> sName = e.getValue();
// 输出班级
System.out.print("\t" + className + ": ");
// System.out.print("\t\t");
// 名单集合
for (Entry<String, String> e2 : sName.entrySet()) {
String stuNo = e2.getKey();
String stuName = e2.getValue();
System.out.print(stuName + ":" + stuNo + "\t");
}
System.out.println();
}
}
System.out.println("*******************");
// 迭代器输出
// 迭代年级
Iterator<Entry<String, Map<String, Map<String, String>>>> it1 = grades.entrySet().iterator();
while (it1.hasNext()) {
Entry<String, Map<String, Map<String, String>>> e1 = it1.next();
String k1 = e1.getKey(); // 年级名称
Map<String, Map<String, String>> v1 = e1.getValue();// 一个年级(班级集合)
System.out.println(k1);
System.out.println("-------------");
// 迭代班级
Iterator<Entry<String, Map<String, String>>> it2 = v1.entrySet().iterator();
while (it2.hasNext()) {
Entry<String, Map<String, String>> e2 = it2.next();
String k2 = e2.getKey(); // 班级名称
Map<String, String> v2 = e2.getValue(); // 一个班级(名单集合)
System.out.print("\t" + k2 + ": ");
Iterator<Entry<String, String>> it3 = v2.entrySet().iterator();
while (it3.hasNext()) {
Entry<String, String> e3 = it3.next();
String k3 = e3.getKey();
String v3 = e3.getValue();
System.out.print(v3 + "-" + k3 + "\t");
}
System.out.println();
}
}
}
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
集合框架中的常用接口
---------------------------------------------------------
Collection接口有两个子接口:
List(列表) ,Set(集)
List:可存放重复元素,元素存取是有序的。
Set:不可以存放重复元素,元素存取是无序的。
先判断hashcode是否相同,如果不同,可以存放,如果相同,再判断是否是同一对象(==),若是同一对象,则视为重复,否则再判断equals方法是否相同。
this.hash == obj.hash &&
(this==obj || this.equals(obj))
(== 是判断内存地址的。equals是判断对象内容是否一样的,但需要重写)
List
---------------------
ArrayList //不安全
LinkedList //不安全
Vector //线程安全的 vector向量
Set
-------------
HashSet(底层就是hashMap)和HashMap没有本质区别
TreeSet (二叉树)线程不安全,可以对Set集合中的元素进行排序。实现Comparable接口(Comparable可以比较的接口)来排序的
Set集合元素唯一性原因
-----------------------------------
HashSet:通过hashCode ()方法、==和equals()方法来保证元素的是否相同。
TreeSet:通过Comparator.compareTo或者comparable.compare()方法中的来保证元素的是否相等。元素是以二叉树的形式存放的。
TreeSet
-----------------------
排序的实现方式:
1,实现Comparable接口,interface Comparable(int compare(T t){……})
2,Comparator,对比器
reeMap:对键进行排序,排序原理与TreeSet相同。是key排序
Map
----------------------------
HashMap:key(键)-value(值) KV===Entry
Hashtable:线程安全,速度慢,不允许存放null键,null值,已被HashMap替代。
HashMap:线程不安全,速度快,允许存放null键,null值。
TreeMap:对键进行排序,排序原理与TreeSet相同。
集合框架中的工具类(集合的一些操作封装,都是静态方法,工具类基本上都是静态方法)
-----------------------------------
Collections 集合的工具类(加了s)
对集合进行查找
取出集合中的最大值,最小值
对List集合进行排序
……
Arrays 数组的工具类(加了s)
将数组转成List集合
对数组进行排序
对数组进行二分查找
为什么要将数组变集合呢?连增删操作都不可以用,有什么好处呢?
其实是:在用集合的思想来操作数组,可以方法很多比如:contains,indexOf…...
System.arraycopy(数组1,1,数组2,3):把数组1中的指针1到结尾的元素拷贝到数组2中,以数组2中指针3的位置为起始位
注意:如数组中的元素是基本类型的,拷贝后互不影响;如果数组中元素是对象,那么由于拷贝的是引用(对象在堆中的内存地址),拷贝后改变对象内容会对他们都有影响。
新增for语句 增强for循环 Pro增强版加强版
-----------------------------------------------
Collection在JDK1.5后出现的父接口Iterable就是提供了这个for语句。
格式:
for(数据类型 变量名 : 数组或Collection集合)
{
执行语句;
}
简化了对数组,集合的遍历。
可变参数,变长参数
-------------------------
返回值类型 函数名(参数类型… 形式参数) //3个点,
{
执行语句;
}
参数个数不固定,参数类型相同可以用变长参数
public void addTel(String... str){
for(String s : str){
tels.add(s);
}
}
其实接收的是一个数组,可以指定实际参数个数。
变长参数必须是防范的最后一个参数!!
----------------------------------------------------------------
public void addTel ( String s1 , String... str); //ok
public void addTel ( String... str, String s1 ) ; //不ok error
泛型的特点
--------------------------
提高了程序的安全性
将运行期遇到的问题转移到了编译期
省去了类型强转的麻烦
泛型类的出现优化了程序设计
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
IO流 Input / Output Stream流
-----------------------------
1,IO流用来处理设备之间的数据传输
2,Java对数据的操作是通过流的方式
3,Java用于操作流的对象都在IO包中
4,流类型:
[数据类型]
字节流:二进制文件,图片,mp3, 最根本的
抽象基类:InputStream ,OutputStream
字符流:操作文本有优势
抽象基类:Reader ,Writer
[流向] (我们和磁盘是对面:程序和磁盘或文件是相对的,输入输出是相对于我们来说的,读与写是相当于我们的动作,都是以程序(我们)来做主体,磁盘为操作对象)(注意身份转换)
输入流:读操作 磁盘输入-->到 程序(我们)-读操作-
输出流:写操作 程序(我们)-->输出 到磁盘--写操作
IO流常用基类
--------------------------------------------
字节流的抽象基类:
InputStream ,OutputStream。
字符流的抽象基类:
Reader , Writer。
注:由这四个类派生出来的子类名称都是以其父类名作为子类名的后缀。
如:InputStream的子类FileInputStream。
如:Reader的子类FileReader。
IO程序的书写
导入IO包中的类
进行IO异常处理
在finally中对流进行关闭
字符流——创建文件 写入
---------------------------------------------
创建流对象,建立数据存放文件
FileWriter fw = new FileWriter(“Test.txt”);//默认覆盖
FileWriter fw = new FileWriter(“Test.txt”,true);//追加 \r\n换行
调用流对象的写入方法,将数据写入流
fw.write(“text”);
关闭流资源,并将流中的数据清空到文件中。
fw.close();
**************
FileWriter fw = null;
try{ //异常,Ctrl+1 处理
fw = new FileWriter("Test.txt");
fw.write("text");
//fw.close();
}
catch (IOException e){
System.out.println(e.toString());
}
finally{
If(fw!=null)
try{
fw.close();
}
catch (IOException e){
System.out.println(e.toString());
}
}
flush
--------------------------
清理 区别:refresh刷新 clear清空
不写close方法会有什么结果呢? 内容写不到txt文件中
close()有个隐藏的flush操作,没有清理之前 内容一直驻留在内存中,清理把内容推送到目标文件上去!
直接调用flush()函数也可以不用close(),继续加数据 就用flush()
java.io.FileWriter
----------------------------------------
1,new FileWriter(String path);
2,write(String str);
写入字符数据到流中。
3,flush()
清理流,将流中的数据写到目标设备上。
4,close()
关闭流,隐含了flush()操作。
5,流在close之后,不能再写入数据了。可以重复关闭流
字符流——读取文件
-------------------------------------------
建立一个流对象,将已存在的一个文件加载进流。
FileReader fr = new FileReader(“Test.txt”);
创建一个临时存放数据的数组。
char[] ch = new char[1024];
调用流对象的读取方法将流中的数据读入到数组中。
fr.read(ch);
***********
FileReader fr = null;
try{
fr = new FileReader("c:\\test.txt");
char[] buf = new char[1024];
int len= 0;
while((len=fr.read(buf))!=-1){
System.out.print(new String(buf,0,len));
}
}
catch (IOException e){
System.out.println("read-Exception :"+e.toString());
}
finally{
if(fr!=null){
try{
fr.close();
}
catch (IOException e){
System.out.println("close-Exception :"+e.toString());
}
}
}
注意:
-----------------------
定义文件路径时,可以用“/”或者“\\”。
在创建一个文件时,如果目录下有同名文件将被覆盖。
在读取文件时,必须保证该文件已存在,否则出异常。
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
day13
作业:文本文件拷贝(字符流的操作)
---------------------------------------------
package com.it18zhang.io;
import java.io.FileReader;
import java.io.FileWriter;
public class FileCoyDemo {
public static void main(String[] args) {
FileReader fr = null;
FileWriter fw = null;
try {
fr = new FileReader("C:\\Users\\Administrator\\Desktop\\免费wifi.txt");
fw = new FileWriter("C:\\Users\\Administrator\\Desktop\\copywifi.txt",false);//覆盖模式
char[] buf= new char[10];
int len=-1;
while ((len=fr.read(buf))!=-1) {
fw.write(buf, 0, len);//有偏移量和长度参数保证了最后一次的不会把残留在缓冲区buf中的数据也推动到目标设备
}
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
if (fr!=null) {
fr.close();
}
if (fw!=null) {
fw.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
System.out.println("复制成功!");
}
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
java.io.FileReader
--------------------------------
1,核心类 : sun.nio.cs.StreamDecoder
2,read() 读取一个字符 是字符 不是字节
3,read(char[]) 读取多个字符
java.io.FileErtier
-------------------------------
1,核心类 : sun.nio.cs.StreamEncoder
字符流的缓冲区
-----------------------------
缓冲区的出现提高了对数据的读写效率。
对应类
BufferedWriter 等级树 Java.lang.Object
|---------java.io.Writer
|--------java.io.BufferedWriter
BufferedReader
缓冲区要结合流才可以使用。
在流的基础上对流的功能进行了增强。
适配器模式:匿名内部类那种情况,对接口加一个抽象类做预实现(抽象类实现接口所有方法)
构建器模式:builder模式(构造函数里)(return this)
装饰模式 decorator 流里面用最多 BufferedWriter Bufferedreader 都是装饰模式
--------------------------------------------------------------
锦上添花,核心功能已有,添加一些附加功能;对原有类进行了功能的改变,增强。
实现方式:
Buffered类继承Writer类,在类中添加Writer类型的成员变量,对应方法进行重写时,调用成员变量的方法进行完成。
实例:class BufferedWriter extends Writer{
Writer out ;
char[] cb = new char[8192];
public void writer(String str){
//1.先将数据写入缓冲区
cb.xxx
//2.如果cb已满,再写入到out中。
}
public void close(){
//1.清理cb
//2.关闭out
}
}
-----------------------------
junit
---------------
单元测试框架,不用借用于main函数来测试方法可以让某个方法单独执行:加注解@Test
方便进行测试使用的
方法签名:(不能有返回值,不能有参数,不能是静态的)
import orj.junit.Test;
@Test
public void xxx(){
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
字节流
------------------------
基本操作与字符流类相同
但它不仅可以操作字符,还可以操作其他媒体文件
例程
Copy一个Jpg文件。
字节流的缓冲区
-----------------------
同样是提高了字节流的读写效率。
BufferedInputStream BufferedOutputStream
字节流下的文件流
-------------------------------
1,FileInputStram 读取文件
支持skip() 方法,skip向后跳的时候不能超过文件头地址,可以超过文件末尾地址
2,FileOutputStram
不支持skip()方法
3,RandomAccessFile
随机访问文件,定位到文件的任意位置。
meta data
-----------------------------
描述数据的数据
文件开头的信息称为文件头(最为重要不可丢失)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
day14
作业:归档和解档
int FileInputStram.available()==文件长度
OOP:面向对象
-------------------------------------------------------------------------
package com.it18zhang.archive;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class ArchiverDemo {
/**
* 创建归档文件
*/
public void newArchivefile(String[] srcPaths, String yarPath) {
FileOutputStream fout = null;
try {
// 创建yar归档文件的输出流
fout = new FileOutputStream(yarPath);
for (String srcPath : srcPaths) {
// 向yar归档文件中添加文件
addFile(srcPath, fout);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (fout != null) {
fout.close();
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
}
/**
* 向yar归档文件中添加文件
*/
private void addFile(String srcPath, FileOutputStream fout) {
FileInputStream fin = null;
try {
// 1.取出srcPtch文件的类型和长度
int fType = getFileType(srcPath);
// 2.取出文件的长度
fin = new FileInputStream(srcPath);
int length = fin.available();
// 3.将文件类型fType写入到fout中
// fout.write(fType);
// 为了更加直观
byte bFtype = (byte) fType;
fout.write(new byte[] { bFtype });
// 4.将长度写如到yar中
byte[] bytes = Int2ByteArr(length);
fout.write(bytes);
// 5.写入文件的内容
int len = -1;
byte[] buf = new byte[1024];
while ((len = fin.read(buf)) != -1) {
fout.write(buf, 0, len);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (fin != null) {
fin.close();
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
}
/**
* 将整数 转换成字节数组
*/
private byte[] Int2ByteArr(int i) {
byte[] bytes = new byte[4];
bytes[0] = (byte) i;
bytes[1] = (byte) (i >> 8);
bytes[2] = (byte) (i >> 16);
bytes[3] = (byte) (i >> 24);
return bytes;
}
/**
* 得到文件类型 0-TXT 1-JPG 2-ppt 3-rar 4-exe
*/
private int getFileType(String srcPath) {
// 得到文件的扩展名
String ext = srcPath.substring(srcPath.lastIndexOf(".")).toLowerCase();
// 不用switch只能判断字符和数字;且字符串相等判断只能用equals
int type = -1;
if (".txt".equals(ext)) {
type = 0;
} else if (".jpg".equals(ext)) {
type = 1;
} else if (".ppt".equals(ext)) {
type = 2;
} else if (".rar".equals(ext)) {
type = 3;
} else if (".exe".equals(ext)) {
type = 4;
}
return type;
}
/**
* 先yar文件中追加文件
*/
public void appendFile(String srcPath, String yarPath) {
FileOutputStream fos = null;
try {
fos = new FileOutputStream(yarPath, true);
addFile(srcPath, fos);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (fos != null) {
fos.close();
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
/*
* try { FileOutputStream fos = new FileOutputStream(yarPath, true);
* addFile(srcPath, fos); fos.close(); } catch (Exception e) {
* e.printStackTrace(); }
*/
}
/**
* 接档文件
*/
public void unarchive(String yarPath, String destDir) {
try {
FileInputStream fin = new FileInputStream(yarPath);
// 循环读取下一个文件
int i = 0;
while (readNextFile(destDir, i + "", fin)) {
i++;
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 读取下一个文件
*/
private boolean readNextFile(String destDir, String fname, FileInputStream fin) {
try {
// 文件类型
int type = fin.read();
// 文件的扩展名
String ext = getFileExt(type);
// 如果文件到文件末尾,返回false
if (type == -1) {
return false;
}
/**
* 开始读取文件并写入到新的文件中
*/
// 0.构造文件输出流
FileOutputStream fout = new FileOutputStream(destDir + "/" + fname + ext);
// 1.读取文件长度
byte[] bytes = new byte[4];
fin.read(bytes);
// 2.将字节数组转换成int
int fileLength = byteArr2Int(bytes);
// 读取文件
byte[] buffer = new byte[1024];
// 计算读取文件的循环次数
int count = 0;
if (fileLength % buffer.length == 0) {
count = fileLength / buffer.length;
} else {
count = fileLength / buffer.length + 1;
}
// 开始循环读取
for (int i = 0; i < count; i++) {
// 不是最后一次
if (i != (count - 1)) {
fin.read(buffer);
fout.write(buffer);
} else {
// byte[] buf0 = new byte[fileLength - ((count - 1) *
// buffer.length)];
byte[] buf0 = new byte[fileLength % buffer.length];
fin.read(buf0);
fout.write(buf0);
}
}
fout.close();
// fin.close();
} catch (Exception e) {
e.printStackTrace();
}
return true;
}
/**
* 根据文件类型获得名称
*/
private String getFileExt(int type) {
String ext = ".tmp";
switch (type) {
case 0:
ext = ".txt";
break;
case 1:
ext = ".jpg";
break;
case 2:
ext = ".ppt";
break;
case 3:
ext = ".rar";
break;
case 4:
ext = ".exe";
break;
default:
ext = ".tmp";
break;
}
return ext;
}
/**
* 将长度为4的字节数组转换成int
*/
private int byteArr2Int(byte[] bytes) {
// return (bytes[3] << 24) | ((bytes[2] & 0xff) << 16);
int i0 = bytes[3] << 24;
int i1 = (bytes[2] & 0xff) << 16;
int i2 = (bytes[1] & 0xff) << 8;
int i3 = (bytes[0] & 0xff);
return i0 | i1 | i2 | i3;
}
}
***************************************
package com.it18zhang.archive;
import org.junit.Test;
public class App {
/**
* 新建归档文件
*/
@Test
public void newArchivefile() {
ArchiverDemo arc = new ArchiverDemo();
String[] srcPaths = { "C:/Users/Administrator/Desktop/it18/arc/07-IO.ppt",
"C:/Users/Administrator/Desktop/it18/arc/513253897_截图 .rar",
"C:/Users/Administrator/Desktop/it18/arc/day03.jpg",
"C:/Users/Administrator/Desktop/it18/arc/day04.jpg" };
String yarPath = "C:/Users/Administrator/Desktop/it18/arc/myyar.yar";
arc.newArchivefile(srcPaths, yarPath);
System.out.println("归档完成!");
}
@Test
public void appendFile() {
ArchiverDemo arc = new ArchiverDemo();
arc.appendFile("C:/Users/Administrator/Desktop/it18/arc/QQ截图20170215215043.jpg",
"C:/Users/Administrator/Desktop/it18/arc/myyar.yar");
System.out.println("追加文件完成!");
}
@Test
public void unarchive() {
ArchiverDemo arc = new ArchiverDemo();
arc.unarchive("C:/Users/Administrator/Desktop/it18/arc/myyar.yar",
"C:/Users/Administrator/Desktop/it18/arc/jidang");
System.out.println("解档文件完成!");
}
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
IO
-----------------------
1.流向
InputStram OutputStream
2.类型划分
a.字符流
Reader | Writer
FileReader | FileWriter
b.字节流
InputStream | OutputStream
FileInputStram | FileOutputStream
3.性能划分
BufferedWriter缓冲区流(装饰模式,flush清理) | 分缓冲区流
BufferedReader缓冲区,read(fill)
readline()读行函数 LineNumberReader
BufferedInputStream.read() == int
下一个整数
BufferedOutputStream
-------------------------------------------------------------------
……
/**
* 使用文档存储文件
*
* @throws Exception
*/
@Test
public void readTxt() throws Exception {
FileWriter writer = new FileWriter("C:/Users/Administrator/Desktop/it18/a.txt");
FileInputStream fis = new FileInputStream("C:/Users/Administrator/Desktop/it18/QQ截图20170215215043.jpg");
byte[] buffer = new byte[1024];
int len = -1;
while ((len = fis.read(buffer)) != -1) {
writeByteArrToFile(buffer, 0, len, writer);
}
writer.close();
fis.close();
}
//将字节数组中的字节写到fis中
private void writeByteArrToFile(byte[] arr, int startIndex, int len, FileWriter writer) {
try {
for (int j = startIndex; j < len; j++) {
writer.write(arr[j] + "\r\n");
}
} catch (Exception e) {
e.printStackTrace();
}
}
……
*******************************************
……
/**
* 读取文本文件内容然后存储成目标原文件(jpg)来回复图像数据
*/
@Test
public void readTxt2Jpg() {
try {
BufferedReader reader=new BufferedReader(new FileReader("C:/Users/Administrator/Desktop/it18/a.txt"));
FileOutputStream fos=new FileOutputStream("C:/Users/Administrator/Desktop/it18/b.jpg");
String line=null;
//循环读行
while ((line=reader.readLine())!=null) {
//byte b=(byte)Integer.parseInt(line);
//fos.write(b);
fos.write(Integer.parseInt(line));
//fos.write(new byte[]{b});
}
fos.close();
reader.close();
} catch (Exception e) {
e.printStackTrace();
}
}
……
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
转换流
--------------------------
字节流到字符流的桥梁,使用特定的字符集读取byte并解码成字符。
底层都是字节流,如果需要将其转换成字符内容处理的话,就可以使用转化流。
InputStreamReader
new InputStreamReader(InputStream is,charset);可以设置用哪种字符集来操作底层的字节流。
OutputStreamWriter
new OutputStreamWriter(Outputstream out, charset)
转换流的由来
字符流与字节流之间的桥梁
方便了字符流与字节流之间的操作
转换流的应用
字节流中的数据都是字符时,转成字符流操作更高效。
标准输入输出流
-----------------------------
standard Input 标准输入,默认是键盘,对应对象System.in(静态)System.setIn(…)
standard Output 标准输出 默认是控制台System.Out,静态System.setOut(xxx)
由于是静态的一旦改变 整个程序就会变成你所设置的那样
----------------------
Java静态对象和非静态对象有什么区别?
比对如下:
静态对象 非静态对象
拥有属性: 是类共同拥有的 是类各对象独立拥有的
内存分配: 内存空间上是固定的 空间在各个附属类里面分配
分配顺序: 先分配静态对象的空间 继而再对非静态对象分配空间,也就是初始化顺序是先静态再非静态.
java静态对象到底有什么好处?
A,静态对象的数据在全局是唯一的,一改都改。如果你想要处理的东西是整个程序中唯一的,弄成静态是个好方法。 非静态的东西你修改以后只是修改了他自己的数据,但是不会影响其他同类对象的数据。
B,引用方便。直接用 类名.静态方法名 或者 类名.静态变量名就可引用并且直接可以修改其属性值,不用get和set方法。
C,保持数据的唯一性。此数据全局都是唯一的,修改他的任何一处地方,在程序所有使用到的地方都将会体现到这些数据的修改。有效减少多余的浪费。
D,static final用来修饰成员变量和成员方法,可简单理解为“全局常量”。对于变量,表示一旦给值就不可修改;对于方法,表示不可覆盖。
你可以将方法和变量都声明为static。static 成员的最常见的 例子是main( ) 。声明为static的方法有以下几条限制(main也是??): ·
A,它们仅能调用其他的static 方法
B,它们只能访问static数据
C,它们不能以任何方式引用this 或super(this涉及到对象,super 与继承有关)
-----------------------
System.out.println();
System类中的字段:in,out。
它们各代表了系统标准的输入和输出设备。
默认输入设备是键盘,输出设备是显示器。
System.in的类型是InputStream.
System.out的类型是PrintStream是OutputStream的子类FilterOutputStream 的子类.
>>>>>>>>>>>>>>>>>>>>>
Scanner sc = new Scanner(System.in);
System.out.println(“请输入你的姓名:”);
String name = sc.nextLine();
System.out.println(“请输入你的年龄:”);
int age = sc.nextInt();
>>>>>>>>>>>>>>>>>>>>>
标准输入输出流示例
---------------------------------------
例:获取键盘录入数据,然后将数据流向显示器,那么显示器就是目的地。
通过System类的setIn,setOut方法对默认设备进行改变。
System.setIn(new FileInputStream(“1.txt”));//将源改成文件1.txt。
System.setOut(...);//将目的改成文件2.txt
因为是字节流处理的是文本数据,可以转换成字符流,操作更方便。
BfferedReader bufr =
new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufw =
new BufferedWriter(new OutputStreamWriter(System.out));
************
/*
* 从控制台读取输入字符打印在控制台上
*/
@Test
public void systemin() throws Exception {
BufferedReader reader=new BufferedReader(new InputStreamReader(System.in));//字节流转换成字符流
while (true) {
String line = reader.readLine();
if ("exit".equals(line)) {
System.exit(-1);
}
System.out.println(line);
}
}
流的基本应用小节
------------------------------------
流是用来处理数据的。
处理数据时,一定要先明确数据源(输入流),与数据目的地(输出流也叫数据汇)。
数据源可以是文件,可以是键盘。
数据目的地可以是文件、显示器或者其他设备。
而流只是在帮助数据进行传输,并对传输的数据进行处理,比如过滤处理.转换处理等。
字符流继承体系简图
-------------------------------------------------------------
字节流继承体系简图
-----------------------------------------------------------
File类
----------------------------
java.io.File
用来将文件或者文件夹封装成对象
方便对文件与文件夹的属性信息进行操作。
File对象可以作为参数传递给流的构造函数。
了解File类中的常用方法。
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
day15
回顾:归档和结归档,用的是Java中的IO流,就是把若干文件用流的方式写到一个文件里去,但要区分出来文件与文件的边界,需要设计每个文件头,由于文件在磁盘上最终是以字节数组呈现,所以要设计每个文件在流当中存在的形态,要设计文件头:文件扩展名(1个字节),文件长度(整型,4个字节),文件内容。
解文档:先读取文件头,1个字节得出扩展名,继续读4个字节得出文件长度,……
递归
---------------------------
//判断是否存在
//判断是否是文件-->输出文件路径
//文件夹.xxx();
**************************
package com.it18zhang.io;
import java.io.File;
public class FileRecur {
public static void main(String[] args) {
showFile("E:\\"); // 此路径不能含有隐藏受保护文件夹或文件
}
/*
* 显示文件+文件夹路径
*/
private static void showFile(String str) {
// 通过file路径构建file对象
File f = new File(str);
System.out.println(f.getAbsolutePath());
if (f.exists()) {
// 是否是目录
if (f.isDirectory()) {
// System.out.println(f.getAbsolutePath());
File[] chi = f.listFiles();
//防止list空指针异常
if (chi == null || chi.length == 0) {
return;
}
for (File ff : chi) {
String p0 = ff.getAbsolutePath();
showFile(p0);
}
}
// 是否是文件
// else if (f.isFile()) {
// System.out.println(f.getAbsolutePath());
// }
}
}
}
*******************
函数自己调用自己。
注意:递归时一定要明确结束条件。
应用场景:
当某一功能要重复使用时。
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++