java语法进阶

在人生的道路上,不管是潇洒走一回,或者是千山独行,皆须是自己想走的路,虽然,有的人并不是很快就能找到自己的方向和道路,不过,只要坚持到底,我相信,就一定可以找到自己的路,只要找到路,就不必怕路途遥远了。

导读:本篇文章讲解 java语法进阶,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

java语法进阶

1. Objcet

1.1 概述

​ 在JDK的java.lang包下定义这个类。所有类直接或间接继承Objcet。任意类都可使用,但方法内部实现在不同子类中有不同重写。

​ 可空参构造Objcet对象,但一般不会,更多使用多态写法。

1.2 常用方法

1.2.1 toString方法:获取对象信息,返回对象的字符串表示。Object的toString方法返回值的是全类名和对象的hash值的拼接。

public String toString() {
    return getClass().getName() + "@" + Integer.toHexString(hashCode());
}

Object的toString方法意义不大,有需要的话在自己的类中重写。

1.2.2 equals方法:比较两个对象(引用类型)是否相同;==基本数据类型

public boolean equals(Object obj) {
    return (this == obj);   //两对象地址,属性相同也就相同
}

判断两个对象是否相同不能单纯的用==去判断。可以重写equals方法。实现自己的判断逻辑。

2. String

2.1 概述

2.2 对象创建

2.2.1 直接使用字面值 String s=‘xxx’;

2.2.2 使用构造方法

  • String()
  • String(char[] value)
  • String(byte[] bytes)

2.2.3 常用方法

String[] split(String regex)  //通过将该字符串围绕给定的正则表达式的匹配来计算的字符串数组 
public char[] toCharArray()  //将此字符串转换为新的字符数组。 
public byte[] getBytes()	//使用平台的默认字符集将此String编码为字节序列,将结果存储到新的字节数组中。
String substring(int beginIndex) //从beginIndex开始返回一个字符串,该字符串是此字符串的子字符串。 
String substring(int beginIndex, int cout) //从beginIndex开始cout个字符结束,返回一个字符串,该字符串是此字符串的子字符串。 
boolean equals(Object anObject)  //将此字符串与指定对象进行比较。 地址相同,为true/地址不同,内容相同为true
  • 分割时:对于 . + 这种符号需要转义,“\.” “\+” 两个\

  • 不用声明String x=“”; 直接xxx.getBytes();即可

  • 字符串一旦创建其内容是不变的

  • 字符串相当于char[]字符数组,底层是byte[]字节数组

2.2.4 科学编程法:

  • 如何寻找所需方法:参数类型、参数名称、返回值类型、方法名
  • 满足上面单词的方法后,对寻找到的方法进行编程验证。

3. 包装类

3.1 概述:oop思想,为每个基本数据类型提供一个包装类。char/Character

3.2 创建对象

3.2.1直接使用字面值

3.2.2使用构造方法

Integer i = new Integer("11");

3.2.3 使用静态方法valueOf

Integer i = Integer.valueOf("11");

3.3 常用方法

static Integer valueOf(int i) 把int转为Integer对象返回

static Integer valueOf(String s) 把String转为Integer对象返回,字符串的内容必须为纯数字

static int parseInt(String s) 把String 转换为int返回 字符串的内容必须为纯数字

3.4 自动装箱与拆箱

3.4.1 概述

JDK1.5中增加此功能。主要是让基本数据类型和包装类进行自动转换。

3.4.2 自动装箱:基本数据类型自动转换为包装类

3.4.3 自动拆箱:包装类自动转换为基本数据类型

 Integer i = new Integer(10);
 int ii = i;

3.4.4 原理:自动装箱通过包装类的静态方法valueOf来实现的转换;这个区域的值直接从缓存中取,节省内存空间。

Integer i1 = 10;			  //自动装箱
Integer i2 = 10;
Integer i3 = 300;
Integer i4 = 300;
System.out.println(i1 == i2); //引用类型地址值  //true
System.out.println(i3 == i4); //引用类型地址值  //false
public static Integer valueOf(int i) {			//静态方法
						 //-128					//127
    if (i >= IntegerCache.low && i <= IntegerCache.high)
    	//索引从-128开始  这个范围的相等数值返回的静态区地址值相等
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

普通类无法用static修饰,内部类才可以。

4.StringBuilder

4.1概述:专门用来进行字符串拼接的。

  • String 中 +号拼接,字符串一旦创建不会改变,产生大量的中间变量,占用内存空间

4.2 创建对象:使用构造方法,有无参数都可以,对象内容相当于字符串

4.3 常用方法:

append

reverse //反转内容

toString //将StringBuilder转为String

链式编程new StringBuilder(“A”).append(“b”);

5.StringBuffer

5.1 StringBuffer 和 StringBuilder 的 3 个区别

a. StringBuffer:线程安全,StringBuilder:线程不安全。因为 StringBuffer 的所有公开方法都是 synchronized 修饰的,而 StringBuilder 并没有 synchronized 修饰。

b. 缓冲区

  • StringBuffer 代码片段:
private transient char[] toStringCache;

@Override
public synchronized String toString() {
    if (toStringCache == null) {
        toStringCache = Arrays.copyOfRange(value, 0, count);
    }
    return new String(toStringCache, true);
}
  • StringBuilder 代码片段:
@Override
public String toString() {
    // Create a copy, don't share the array
    return new String(value, 0, count);
}

可以看出,StringBuffer 每次获取 toString 都会直接使用缓存区的 toStringCache 值来构造一个字符串,过 StringBuffer 的这个toString 方法仍然是同步的。

而 StringBuilder 则每次都需要复制一次字符数组,再构造一个字符串。

c.性能

既然 StringBuffer 是线程安全的,它的所有公开方法都是同步的,StringBuilder 是没有对方法加锁同步的,所以毫无疑问,StringBuilder 的性能要远大于 StringBuffer。

所以,StringBuffer 适用于用在多线程操作同一个 StringBuffer 的场景,如果是单线程场合 StringBuilder 更适合。

5.集合

5.1 集合的概念:存储多个数据的容器。相对于相同功能的数组来说,集合的长度会更加灵活方便。

  • 数组缺点:一旦创建,长度固定

5.2 集合体系的结构

  • 两个顶层接口,Collection和Map

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zjk4QOVE-1648135317003)(E:\zkNote\2.语言学习\java\集合体系结构.png)]

5.3 常用list集合

5.3.1 List集合的特点 java.util

  • 有索引 ;0开始
  • 可以存储重复元素
  • 元素存入的顺序和实际存储的顺序相同;遍历

5.3.2 ArrayList

  • 创建对象:限定(存任意引用数据类型)和不限定集合中存储元素的数据类型。ArrayLIst
  • 常用方法:

void add(int index,E element) //E element ==创建对象时限定集合的数据类型,原来的数据往后挪

boolean remove(Object 0);删除元素/boolean add(E e);添加范型元素

E remove(int index) //删除指定索引位置的元素,返回值是被删除元素

E set(int index,E element) //修改指定索引位置的元素,返回值为修改之前的元素值

int size() //集合元素的个数

5.3.4 遍历

a. 使用索引遍历 原因:数据结构有索引

b. 单列集合Collection特有的遍历迭代器

Iterator<T> iterator = arrayList.iterator();
while (iterator.hasNext()){
	//Object next = iterator.next();
	System.out.println(iterator.next());
}
  • 并发修改异常,遍历时加值和删值,在使用迭代器遍历时会出现,数据结构次数发生变化。

if(“”.equals(s))

  • for循环(正向输出)也有问题,元素删了,使集合的数据结构变化了,往前挪,有元素没遍历上。

for循环倒序输出没问题

要删除数据多时在设置一个新数组,将old数据遍历时要删除的元素放到新数组中,遍历完毕后,在用old.removeAll(Collection c)方法删除掉

c.使用foreach遍历:java提供的语法糖,更方便的遍历集合和数组。实际上翻译为迭代器的形式。也会发生并发修改异常

d.转换为数组进行遍历 arrayList.toArray()

原因:有.toArray()成员方法

//范型,new String[0]参数[0]不重要,主要为是转为范型类型,而传递数据类型的。
String[] strings = arrayList.toArray(new String[0]);
for(String s:strings){
...
}

5.3.5 LinkedList

a. 创建对象:任意引用数据类型

LinkedList objects1 = new LinkedList<>();      //不限定存放类型参数
LinkedList<Object> objects = new LinkedList<>();//限定存放类型参数

b. 常用方法和ArrayList是相同的,都是List接口的实现类,有一些特有的方法

void addFirst(E e) //把元素添加到集合的最前面

addLast(E e) //把元素添加到集合的最后面

E removeFirst() //删除集合最前面的一个元素,返回值为被删除元素

E removeLast() //删除集合最后面的一个元素,返回值为被删除元素

c. 遍历同ArrayList,迭代器是List、Collection接口的方法

5.3.5 ArrayList和LinkedList区别

  • 都是实现了List接口,不同点是底层存储数据结构不同。ArrayList底层使用数组来存储,而LinkedList使用链表。
  • ArrayList:查找快,增删慢(数组长度固定,增加元素,复制更大的数组,复制过来)
  • LinkedList:增删快,查找慢(从链表头到尾循环过去)

5.4 常用Set集合

5.4.1 Set集合的特点

  • 不能存储重复元素
  • 没有索引

5.4.2 HashSet 特点:

  • 底层数据结构是哈希表
  • 存储元素的顺序和遍历获取出来的顺序可能不一样
  • 没有索引
  • 集合中不能存重复元素

5.4.3 创建对象,同list

5.4.4 常见方法

boolean add(E e) //有重复元素,则添加不成功

boolean remove(Object o) //元素没有时删除不成功

用set的目的是去重。

5.4.5 遍历

  • 用迭代器遍历。(单列集合具有的遍历方法)
  • 转换为数组遍历。
  • 用foreach遍历,底层是迭代器。

5.5 泛型

5.5.1 概述:可以把类型明确的工作推迟到创建对象或调用方法的时候才去明确的特殊类型。相当于把数据类型作为参数来转换。

  • 注意:泛型只能是引用数据类型

5.5.2 使用

5.5.2.1 泛型类和泛型接口:的使用相同,泛型类是把泛型定义在类上,用户使用改类的时候,才把类型明确下来。

  • 定义泛型:在类名后加<>,在<>中定义泛型,<>中的内容相当于泛型名字,可任意写。在泛型类中我们把这个泛型的名字当做一个数据类型来使用。

5.5.2.2 使用泛型:在泛型类中可以使用类名后面定义的泛型。

public class ArrayList<E>{
	public boolean add(E e) {
		...
	}
}

5.5.2.3 泛型的确定

  • 创建对象时确定:在创建泛型类对象的时候确定之前定义的泛型代表什么数据类型。在定义泛型类对象的时候,在类名的后加<>,在其中写一个具体的数据类型

  • 定义子类时确定:

public class SubBox extends Box<Integer>{
}

SubBox subBox = new SubBox();
subBox.setE(2);			//自动添加Integer类型数据
  • 在定义子类时可以选择不确定泛型,让其在创建对象的时候在确定。
public class SubBox02<T> extends Box<T> {    //<T>可以不一样
}

5.5.3 泛型方法

5.5.3.1 定义泛型:在方法返回值前面加<>,在<>中内容相当于泛型的名字,可以任意写。在该泛型方法中我们可以把这个泛型的名字当做一个数据类型来使用。

public class SubBox02<E> extends Box<E> {
    public <T> T test(T t){
        System.out.println(t);
        return t;
    }
    public static <T> void getArr(T[] e){
        return;
    }
    
    public static <T>T[] getArr(T[] e){
        System.out.println(e.length);
        return e;
    }
}

5.5.3.2 使用泛型:在泛型方法中可以使用定义的泛型。并且我们一般在参数列表中或者是返回值类型上使用这个泛型。

5.5.3.3 在调用泛型方法的时候才真正确定之前定义的泛型代表什么数据类型。在调用泛型方法的时候。出现会根据调用自动推导泛型的具体类型

SubBox02<String> subBox02 = new SubBox02<>();
subBox02.setE("123");
String sdf = subBox02.test("sdf");
==========================================
String[] arr = {"123","456","789"};
SubBox02.getArr(arr);
===========================================
String[] arr = {"123","456","789"};
String[] arr1 = SubBox02.getArr(arr);
String[] arr2 = SubBox02.getArr(new String[0]);   //预定义数据

5.5.4 泛型上限&泛型下限

5.5.4.1 使用泛型时可以是任意的数据类型。某些场景我们要求泛型必须是某个子类或父类。这时需要泛型上限&泛型下限来限制泛型的范围

5.5.4.2 泛型上限:限制泛型是某个类或子类

<? extends 具体的类型>
  • 构造方法不会被继承,泛型不指出不会自动转型
public static void test(List<? extends Box> list){
    for (int i = 0; i < list.size(); i++) {
        Object e = list.get(i).getE();
        System.out.println(e);
    }
}
Box<String> box = new Box();
box.setE("zk");
SubBox subBox = new SubBox();
subBox.setE(2);
SubBox02<String> subBox02 = new SubBox02<>();
subBox02.setE("123");
ArrayList<Box> arrayList = new ArrayList<>();
arrayList.add(box);
arrayList.add(subBox02);
SubBox02.test(arrayList);
  • 调用子类或父类特有的方法

5.5.4.3 泛型下限:限制泛型是某个类或父类

<? super具体的类型>

public static void test3(List<? super SubBox02> list){
    Object[] objects = list.toArray();
    for (int i = 0; i < objects.length; i++) {
        System.out.println(objects[i]);
    }
}
ArrayList<Box> arrayList = new ArrayList<>();
arrayList.add(box);
arrayList.add(subBox02);
//SubBox02.test2(arrayList);
SubBox02.test3(arrayList);

5.5.5 注意事项

  • 泛型上限可以定义泛型类和方法参数上使用,泛型类上不使用下限,无法知道其父类的内部定义。
public class subBox<E extends Box>{       //不是?,通配符无法作为参数的类型,可使用泛型类的方法
	E e;
}
  • 泛型下限用在方法参数上。

5.6 常用Map集合

5.6.1 Map集合的描述:双列集合的顶层接口。

interface Map<K,V>

key和value在Map集合中是一对一,key在Map中不会重复

5.6.2 HashMap特点:类似数组中加链表,根据key计算出的hashcode来放置到那块。

  • 底层数据结构是哈希表
  • 存储元素顺序和遍历取出来的顺序不一致
  • key不会重复,更新value值

5.6.2.1 创建对象

5.6.2.2 常用方法

V put(K key, V value) //key不存在则添加,返回null,存在则修改对应的value,并返回修改前的value

V get(Object key) //key不存在返回null

boolean containsKey(Object key) //key是否存在

void clear() //Removes all of the mappings from this map

5.6.2.3 遍历

  • 使用entrySet遍历:map集合的entry方法可以获取一个set集合,里面存放entry对象,一个Entry对象相当于一个键值对。可以遍历set集合拿到Entry对象,取出里面的键合值。
HashMap<String, String>  map = new HashMap<String, String>();
map.put("a", "123");
map.put("b","456");
Set<Map.Entry<String, String>> entries = map.entrySet();
Iterator<Map.Entry<String, String>> it = entries.iterator();
while (it.hasNext()){
    Map.Entry<String, String> next = it.next();
    System.out.println(next.getKey() + ":" + next.getValue());
}
Set<Map.Entry<String, String>> entries = map.entrySet();
for (Map.Entry<String, String> ent:entries ) {
    System.out.println(ent.getKey() + ":" + ent.getValue());
}
  • 使用keySet遍历:此方法可以获取到set集合,存放是所有的key,可以遍历set集合拿到key对象,然后通过key获取对应的value.
HashMap<String, String>  map = new HashMap<String, String>();
map.put("a", "123");
map.put("b","456");
Set<String> keySet = map.keySet();
for (String key: keySet ) {
	System.out.println(key + ":" + map.get(key));
}

5.7 HashMap的key去重原理:添加元素时会判断集合中key和本次存入的key相同,判断主要通过hashCode方法和equals方法来进行判断。hashCode相同,且equals相同就会认为是同一个key.

if (p.hash == hash &&
    ((k = p.key) == key || (key != null && key.equals(k))))
    e = p;

所以要存储到HashMap的key是一个自定义类型,就需要判断是否需要重写hashCode(new出来的对象地址值不同)和equals(自定义对象也是比较地址)方法。使用IDEA提示即可;需要重写的目的是让以属性值内容来代替地址。

@Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person persion = (Person) o;
        return age == persion.age &&
                Objects.equals(name, persion.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }

    @Override
    public String toString() {
        return "Persion{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

6.IO流-1

6.1 File

6.1.1 概述:File对象主要用来表示文件或目录的路径的。提供对文件或文件夹操作的方法

6.1.2 创建对象,仅仅是创建了对象,还未实际创建文件夹,用此方法mkdir实际创建文件夹。

  • 绝对路径:以磁盘名开头的路径。
  • 相对路径:不以盘符开头。相对项目(根目录)下的路径

File(String pathname)

File(String parent, String child) //通过父目录的路径(字符串类型)和文件夹名称来创建对象

File(File parent, String child) //通过父目录的路径(File类型)和文件夹名称来创建对象

6.1.3 常用方法

boolean createNewFile() //根据路径创建一个文件,返回值代表是否成功,已经有了就创建不成功了。

boolean mkdir() //根据路径创建文件夹,返回值代表是否创建成功

boolean mkdirs() //更安全根据路径创建文件夹,父目录不存在也会创建,返回值代表是否创建成功

boolean isFile() //是否是一个文件

boolean isDirectory() //是否是一个文件夹

boolean delete() //删除文件,若删除的是文件夹,则这个文件夹必须是空文件夹,正在占用的文件无法被删除

long length() //Returns the length of the file,对文件夹无效

String getName() //获取文件或文件夹名字

File getParentFile() //获取父类文件对象

String getAbsolutePath() //获取文件绝对路径

6.1.4 重要方法

File[] listFiles() //如果当前FIle对象是个文件夹,获取当前文件夹下所有文件或文件夹的file对象。不是文件夹或者是文件夹权限受限,则返回null.要对返回结果做非null判断

7.IO流-2

7.1 IO流:概述需要进行数据传输时可以使用IO流来进行。exp:把磁盘文件数据读取到内存中。把内存数据写入到磁盘中。把网络数据读取到内存中。防止内存溢出。

7.2 IO流分类:

  • 处理数据类型不同:字符流/字节流
  • 数据流向不同:输入流(只能读操作)/输出流(只能写操作)
数据类型 流向 父类
字节流 输入(读)java.io.InputStream
字节流 输出(写)java.io.OutputStream
字符流 输入(读)java.io.Reader
字符流 输出(写)java.io.Writer

7.3 字节输入流:以字节为单位

7.3.1 FileInputStream概述:用来读取文件数据的字节输入流

7.3.2 FileInputStream对象创建

//传入的是文件路径的String或者是File对象,文件夹不存储数据,文件才存储

File test = new File("E:\\software\\Chrome\\test\\test.txt");
FileInputStream fileInputStream = new FileInputStream(test);
catch (FileNotFoundException e) {
e.printStackTrace();
}

7.3.3 FileInputStream读取数据

7.3.3.1 FileInputStream读取文件中的字节数据,一次读取一字节。

int read() throws IOException //返回值字节数据,为-1时代表没有内容

7.3.3.2 一次读取一字节数组。

int read(byte b[]) throws IOException//传入字节数组并存储,最多一个字节,返回读取有效字节长度,返回值为-1时代表没有内容

FileInputStream实现了Closeable这个接口,即可写成一下格式,自动释放资源。

自己写的类实现了实现了Closeable这个接口,也可以写成这种格式。

File test = new File("E:\\software\\Chrome\\test\\test.txt");
FileInputStream fileInputStream = new FileInputStream(test);
//int read = fileInputStream.read();
byte[] b = new byte[1024];
int len = 0;
String str = "";
while ((len = fileInputStream.read(b)) != -1){
    str = new String(b, 0, len);
}
System.out.println(str);

7.3.4 资源释放:处理异常时可能导致出现异常导致资源没有被正确释放。

7.3.4.1 JDK6版本

finally {
    //释放资源
    if (fileInputStream!=null) {   //fileInputStream没new成功会出现空指针异常
        try {
            fileInputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

7.3.4.2 JDK7版本

使用try…catch…resource的写法,try后面加小括号,需要释放的资源在小括号中定义,就不需要手动释放资源,jvm会在最后调用close方法释放。

File test = new File("E:\\software\\Chrome\\test\\test.txt");
File copytest = new File("E:\\software\\Chrome\\copytest\\test.txt");
try(FileInputStream fileInputStream = new FileInputStream(test);){
    //int read = fileInputStream.read();
    byte[] b = new byte[1024];
    int len = 0;
    String str = "";
    while ((len = fileInputStream.read(b)) != -1){
        str = new String(b, 0, len);
    }
    System.out.println(str);
    FileOutputStream fileOutputStream = new FileOutputStream(copytest);
    FileReader testReader = new FileReader(test);
    FileWriter copytestWriter = new FileWriter(copytest);
} catch (FileNotFoundException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}

7.3.4.3 JDK9版本

资源定义可以不放在小括号中,只要在try的小括号中声明要释放的资源即可:

FileInputStream fileInputStream = new FileInputStream(test);
try(fileInputStream){
    //int read = fileInputStream.read();
    byte[] b = new byte[1024];

7.4 字节输出流:父类是java.io.OutputStream,以字节为单位

7.4.1 FileOutputStream:往文件中写入数据的字节输出流

7.4.2 FileOutputStream创建

File copytest = new File("E:\\software\\Chrome\\copytest\\test.txt");
FileOutputStream fileOutputStream = new FileOutputStream(copytest);

7.4.3 一次写一个字节

public void write(int b) throws IOException //传入一个字节数据,把字节数据写入文件

7.4.4 一次写一个字节数组,创建fos对象时把文件内容清空

public void write(byte b[]) throws IOException //传入一个字节数组,把字节数组中全部数据写入文件
public void write(byte b[], int off, int len) throws IOException//传入一个字节数组,把字节数组中从off索引开始den个元素数据写入文件

7.4.5 文件续写

用之前的构造方法写入文件是覆盖的形式,无法进行续写,得用新的构造方法。

public FileOutputStream(String name, boolean append)
    throws FileNotFoundException
public FileOutputStream(File file, boolean append)
        throws FileNotFoundException

7.4.6 文件复制

public static void main(String[] args){
    //要求定义一个方法,实现文件的复制
    //文件的复制是循环读写,直至操作完
    File test = new File("E:\\software\\Chrome\\test\\test.txt");
    File copytest = new File("E:\\software\\Chrome\\copytest");
    try {
        testInputStream(test,copytest);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

/**
 *
 * @param srcFile 源文件路径
 * @param dirFile 目标文件夹地址
 * @throws IOException
 */
private static void testInputStream(File srcFile,File dirFile ) throws IOException {
    //在dirFile目录下创建和srcFile同名的文件
    File destFile = new File(dirFile,srcFile.getName());
    //把读到的数据写入到目标文件destFile中
    FileInputStream fis = new FileInputStream(srcFile);
    FileOutputStream fos = new FileOutputStream(destFile,true);
    byte[] b = new byte[1024];
    int len = 0;
    while ((len = fis.read(b)) != -1){
        //把读到的数据写入新文件中
        fos.write(b,0, len);
    }
    //释放资源
    fis.close();
    fos.close();
    /*FileReader testReader = new FileReader(test);
    FileWriter copytestWriter = new FileWriter(copytest);*/
}

7.4.7 文件夹复制

public static void main(String[] args) {
    //定义一方法,实现文件夹的复制
    File srcDir = new File("E:\\software\\Chrome\\test");
    File dest = new File("E:\\software\\Chrome\\copytest");
    try {
        copyDirFile(srcDir,dest);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

/**
 *
 * @param srcDir 源文件夹
 * @param dest 目标目录
 * @throws IOException
 */
private static void copyDirFile(File srcDir,File dest) throws IOException {
    if(!srcDir.exists()&&srcDir.isDirectory()){
        throw new RuntimeException("源文件必须存在且必须是个文件夹");
    }
    if (!dest.isDirectory()) {
        throw new RuntimeException("目标文件必须是个文件夹");
    }
    //在目标文件夹下创建一个和源文件夹同名的destDir
    File destDir = new File(dest,srcDir.getName());
    destDir.mkdirs();
    //获取源文件夹下的所有子文件
    File[] files = srcDir.listFiles();
    if (files != null) {
        for (File file : files) {
            if (file.isFile()) {
                testInputStream(file,destDir);
            }else {
                copyDirFile(file,destDir);
            }

        }
    }

}
/**
 *
 * @param srcFile 源文件路径
 * @param dirFile 目标文件夹地址
 * @throws IOException
 */
private static void testInputStream(File srcFile, File dirFile ) throws IOException {
    //在dirFile目录下创建和srcFile同名的文件
    File destFile = new File(dirFile,srcFile.getName());
    //把读到的数据写入到目标文件destFile中
    FileInputStream fis = new FileInputStream(srcFile);
    FileOutputStream fos = new FileOutputStream(destFile,true);
    byte[] b = new byte[1024];
    int len = 0;
    while ((len = fis.read(b)) != -1){
        //把读到的数据写入新文件中
        fos.write(b,0, len);
    }
    //释放资源
    fis.close();
    fos.close();
    /*FileReader testReader = new FileReader(test);
    FileWriter copytestWriter = new FileWriter(copytest);*/
}

8.IO流-3

8.1 编码表—-字节数据==>字符数据

计算机要准确存储和识别各种字符集符号,需要字符编码。一套字符集至少有一套字符编码,编码和解码不是一个编码表就会出现乱码。

8.2 常见的编码表

  • ASCLL:显示现代汉语,包括控制字符、可显示字符,基本ASCLL字符集使用7位表示一个字符,共128字符,扩展字符集用8位标识一个字符共256位,支持欧洲常用字符

  • GBK:常用中文编码,在GB2312标准基础上扩展规范,用2字节收录21003个汉字,兼容GB2312标准支持繁体和日韩汉字

  • Unicode:UTF-8用来标识Unicode标准中任意字符,邮件、网页、存储和传送文字的首选。互联网工程工作小组(IETF)要求互联网协议支持UTF-8,使用4个字节为字符编码。

  • 规则:128个US-ASCLL字符,只用一个字节编码,拉丁文用两个字节,中文,使用3个字节,极少数Unicode辅助字符用4个字节编码

  • ANSI:不是具体编码表,系统默认编码表。简体中文win系统默认是GBK。

String s = new String(bytes,"GBK");

8.3 字符流:针对纯文本数据

8.3.1字符输入流:父类为java.io.Reader,以字符为单位的输入流

8.3.2 FileRead概述:从文件中读取数据的字符输入流

8.3.3 FileRead创建对象

//传入 文件 路径或文件路径File对象
File test = new File("E:\\software\\Chrome\\test\\test.txt");
FileReader testReader = new FileReader(test); //匿名对象的使用

8.3.4 读取数据

8.3.4.1一次读取一个字符

public int read() throws IOException  //一次读取一字符,文件末尾为-1
public int read(char cbuf[]) throws IOException  //一次读取一字符数组
File test = new File("E:\\software\\Chrome\\test\\test.txt");
FileReader fir = new FileReader(test);
int read = 0;
while ((read = fir.read())!=-1) {
    System.out.print((char) read);
}
fir.close();
File test = new File("E:\\software\\Chrome\\test\\test.txt");
File copytest = new File("E:\\software\\Chrome\\copytest\\test.txt");  //文件没有则自动创建
FileReader fir = new FileReader(test);
FileWriter fiw = new FileWriter(copytest);
int len = 0;
char[] c = new char[1024];
 while ((len = fir.read(c))!=-1) {
     fiw.write(c,0,len);
     System.out.print(c);
     System.out.println(new String(c).toString());
 }
fir.close();
fiw.close();

8.3.5 字符输出流:父类为java.io.Reader,以字符为单位的输出流

8.3.6 FileWriter概述:向文件中写入数据的字符输出流

8.3.7 FileWriter创建

8.3.8 写入数据

8.3.8.1 一次写入一个字符数据

public void write(int c) throws IOException //将一个字符写入到目的地
public void flush() throws IOException //将缓存区的数据写入硬盘

8.3.8.2 一次写入一个字符数组数据

public void write(char cbuf[]) throws IOException

8.3.8.3 一次写入一个字符串数据

public void write(String str) throws IOException

实际文件复制得能用子节流的复制,复制文件可以是任意类型的文件,字符流只能是纯文本格式的文件。

8.3.9 设置字符流编码表

FileReader fir = new FileReader(test2, Charset.forName("GBK"));

9.IO流-3

9.1 高效缓冲流:对硬盘进行数据的读取相比于内存中读取数据慢。所以jdk提供了高效缓冲流提高IO效率。借助内存缓冲区来减少硬盘IO的次数,提高性能。内存缓冲区4*1024

9.2 分类

9.2.1 字节流

  • 输入流:BufferedInputStream
  • 输出流:BufferedOutputStream

9.2.2 字符流

  • 输入流:BufferedReader
  • 输出流:BufferedWriter

9.3 对象的创建

FileInputStream fis = new FileInputStream(new File("E:\\software\\Chrome\\test\\test.txt"));
BufferedInputStream bis = new BufferedInputStream(fis);
FileOutputStream fos = new FileOutputStream(new File("E:\\software\\Chrome\\copytest\\test.txt"));
BufferedOutputStream bos = new BufferedOutputStream(fos);
FileReader fr = new FileReader(new File("E:\\software\\Chrome\\test\\test.txt"));
BufferedReader br = new BufferedReader(fr);
FileWriter fw = new FileWriter(new File("E:\\software\\Chrome\\copytest\\test.txt"));
BufferedWriter bw = new BufferedWriter(fw);

9.3.1 缓存字符流特殊方法

br.readLine();		//读取一行数据,读到内容不含换行符,文件末尾,返回null
bw.newLine();		//写入一个换行符,随系统变化
FileReader fr = new FileReader(new File("E:\\software\\Chrome\\test\\test.txt"));
BufferedReader br = new BufferedReader(fr);
String str;
while ((str = br.readLine() )!= null) {
    System.out.println(str);
}
br.close();
FileReader fr = new FileReader(new File("E:\\software\\Chrome\\test\\test.txt"));
BufferedReader br = new BufferedReader(fr);
FileWriter fw = new FileWriter(new File("E:\\software\\Chrome\\copytest\\test.txt"),true);
BufferedWriter bw = new BufferedWriter(fw);
String line;
while ((line = br.readLine() )!= null) {
    System.out.println(line);
    bw.write(line);
    bw.newLine();
}
br.close();
bw.close();

9.4 应用场景:想IO操作效率更高或想使用特有的方法(readLine/newLine)就可以使用高效缓存流。

9.5 转换流:字节转成字符流,就使用转换流

9.6 分类

  • 输入流:InputStreamReader。字节到字符的桥梁。将读取到的字节数据经过指定编码转换成字符
  • 输出里:OutputStreamWriter。字符到字节的桥梁。对读取到的字符数据经过指定编码转换成字节

9.7 使用:是字符流,有转换关系,构造方法需要传入字节对应的流对象。

  • 源和目的数据以子节流进行操作,中间操作使用文本,需要转换来提高效率
  • 操作文本指定编码需使用转换流。
public final class System {
	public static final InputStream in = null;  //字节输入流
	public static final PrintStream out = null; //字节输出流
}
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new FileWriter(new File("E:\\software\\Chrome\\copytest\\test.txt"),true));
String line;
while ((line=br.readLine())!= null){
    if ("end".equals(line)) {
        break;
    }
    bw.write(line);
    bw.newLine();
    bw.flush();
}
br.close();
bw.close();
InputStreamReader fr = new InputStreamReader(new FileInputStream(new File("E:\\software\\Chrome\\test\\test.txt")), Charset.forName("utf-8"));
BufferedReader br = new BufferedReader(fr);
BufferedWriter bw= new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new File("E:\\software\\Chrome\\copytest\\test.txt"),true),"utf-8"));
String line;
while ((line = br.readLine() )!= null) {
    bw.write(line);
    bw.newLine();
    bw.flush();
}
br.close();
bw.close();
BufferedReader br = new BufferedReader(new FileReader(new File("E:\\software\\Chrome\\copytest\\test.txt")));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
String line;
while ((line = br.readLine() )!= null) {
    bw.write(line);
    bw.newLine();
}
br.close();
bw.close();

10.Properties

10.1 对象创建,底层是个Map

public Properties()
public Properties(int initialCapacity)  //map容量

10.2 常用方法:

getProperty(String key)   在此属性列表中搜索具有指定键的属性。如果在此属性列表中找不到该键,则会检查默认属性列表及其默认值(递归)。如果未找到该属性,则该方法返回默认值参数。

setProperty(String key, String value) 致电 Hashtable方法 put 。

clear()  清除此哈希表,使其不包含任何键。

stringPropertyNames()  返回此属性列表中的一组键,其中键及其对应的值是字符串,如果尚未从主属性列表中找到相同名称的键,则包括默认属性列表中的不同键。键或键不是String类型的属性将被省略。

10.3 和流结合的方法:

list(PrintStream out)  将此属性列表打印到指定的字节输出流。此方法对于调试很有用。

list(PrintWriter out)  将此属性列表打印到指定的字符输出流

load(InputStream inStream)  从输入字节流中读取属性列表(键和元素对)。

load(Reader reader) 以简单的线性格式从输入字符流读取属性列表(关键字和元素对)。 并假定使用ISO 8859-1字符编码;即每个字节是一个Latin1字符。不在Latin1中的字符和某些特殊字符在使用Unicode转义符的键和元素中表示。 此方法返回后,指定的流仍保持打开状态。

store(OutputStream out, String comments) 将此Properties表中的此属性列表(键和元素对)以适合使用load(InputStream)方法加载到Properties表的格式写入输出流。 此Properties方法不会写出此Properties表的defaults表中的属性(如果有)。

store(Writer writer, String comments) 将此属性列表(键和元素对)写入此 Properties表中,以适合使用 load(Reader)方法的格式输出到输出字符流。 

storeToXML(OutputStream os, String comment, String encoding) 使用指定的编码发出表示此表中包含的所有属性的XML文档。

Properties properties = new Properties();
properties.put("1","123");
properties.setProperty("2","456");
Set<String> strings = properties.stringPropertyNames();
for (String string : strings) {
    System.out.println(string);
}
properties.list(System.out);

下一篇:java语法-02-多线程知识

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由半码博客整理,本文链接:https://www.bmabk.com/index.php/post/123980.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
半码博客——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!