1. 为什么要使用泛型

  2. 使用

  3. 自定义泛型类

  4. 自定义泛型方法举例

  5. 泛型类与泛型方法的使用情景

  6. 泛型在继承方面的体现

  7. 通配符的使用

  8. 使用通配符后数据的读取和写入要求

  9. 有限制条件的通配符的使用

  10. 自定义泛型练习

  11. File类的实例化、

  12. File类常用方法

 

1,为什么要使用泛型

 

day25-泛型与File_泛型与File

    泛型使得定义类时类名由ArrayList变为ArrayList<E>,E用来接收一个类型,所以在引用一个存储String类型的ArrayList时,引用变量类型为ArrayList<String>

 

day25-泛型与File_泛型与File_02

 

2,使用

    在集合中使用泛型:
        1,集合接口或集合类在jdk5.0时都修改为带泛型的结构
        2,在实例化集合类时,可以指明具体的泛型类型,指明完以后,在集合类或接口中凡是定义类或接口时,内部结构(比如:方法、构造器、属性等)使用到类的泛型的位置,都指定为实例化的泛型类型。比如:add(E e) --->实例化以后:add(Integer e)
        3,泛型的类型必须是类,不能是基本数据类型。需要用到基本数据类型的位置,拿包装类替换
        4,如果实例化时,没有指明泛型的类型,默认传入的是java.lang.Object

 

package com.atguigu.java;

import org.junit.Test;

import java.util.*;

public class GenericTest {

    //出现泛型之前使用集合的情况:
    @Test
    public void test1(){
        ArrayList list = new ArrayList();
        list.add(78);
        list.add(76);
        list.add(89);
        list.add(88);
        list.add("Tom"); // 类型不安全,哪种类型都能放进集合里

        for(Object score : list){
            // 强转时,可能出现ClassCastException的异常
            int stuScore = (Integer) score;
            System.out.println(stuScore);
        }
    }

    // 在ArrayList中使用泛型:
    @Test
    public void test2() {
        // ArrayList<int> list = new ArrayList<int>(); // 给<>中传入的是一个类型,这个类型不能是基本数据类型
        ArrayList<Integer> list = new ArrayList<Integer>();
        list.add(78); // 凡是在ArrayList<E>中使用到E的地方,比如属性或方法,都会被实际传入的类型代替(这里是Integer)
        list.add(76); // 也就表明类似add(E e)的操作只能传入Integer类型的对象
        list.add(89);
        list.add(88);
        // list.add("Tom"); // 在编译时就会进行类型检查,当传入的是一个String类型时编译不通过

        // 方式一:
        for(Integer score : list) {
            int stuScore = score; // 给ArrayList<E>传入Integer同时也保证了集合存储的是Integer而不会是其他类型,所以不用进行强转
            System.out.println(stuScore);
        }
        // 方式二:
        Iterator<Integer> iterator = list.iterator(); // ArrayList<E>的iterator()创建并返回一个Iterator<E>类型的迭代器对象,
                            // 所以返回的是一个Iterator<Integer>类型。即Iterator<E>也使用了泛型,在创建Iterator对象时传入的就是Integer类型
        while(iterator.hasNext()) {
            int stuScore = iterator.next(); // Iterator<E>的next()返回的是E,在这里是Integer
            System.out.println(stuScore);
        }
    }

    // 在HashMap中使用泛型:
    @Test
    public void test3() {
        Map<String, Integer> map = new HashMap<String , Integer>(); // Map存储的是key-value,所以要传入两个类型

        map.put("Tom", 78);
        map.put("Jerry", 87);
        map.put("Jack", 67);
        // map.put(123, "ABC"); // 进行类型检查,编译不通过
        // !!!还需要深入到源码才能彻底理解要声明的类型
        Set<Map.Entry<String, Integer>> entry = map.entrySet(); // 调用的是HashMap中的entrySet(),该方法返回的是一个Set,Set中的每个元素由key-value组成。
                            // 该方法创建并返回的是一个Set<Map.Entry<K,V>>类型对象,所以在这里返回的是一个Set<Map.Entry<String, Integer>>类型对象
                            // 即Set<E>也使用了泛型,给E传入的是Map.Entry<K, V>,给K、V传入的是String和Integer,所以用Set<Map.Entry<String, Integer>>接收该Set对象
        Iterator<Map.Entry<String, Integer>> iterator = entry.iterator(); // Set中的iterator()创建并返回一个Iterator<E>类型的迭代器,上面提到的,创建Set<E>对象时给E传入的
                                                    // 是Map.Entry<String, Integer>类型,所以要用Iterator<Map.Entry<String, Integer>>类型的引用来接收该迭代器

        while(iterator.hasNext()) {
            Map.Entry<String, Integer> e = iterator.next(); // 上面在创建迭代器时给Iterator<E>的E传入的是Map.Entry<String, Integer>类型,next()返回的是E类型,所以
                                                // 该迭代器对象的next()返回的就是Map.Entry<String, Integer>类型
            String key = e.getKey(); // Entry<K, V>是Map内部定义的一个接口,接口中的getKey()返回K类型即String类型
            Integer value = e.getValue(); // 接口中的getValue()返回V类型即Integer类型
            System.out.println(key + "----" + value);
        }
    }
}
 
    在之前测试TreeSet的代码中加入泛型后的情况
    MyDate类

 

package com.atguigu.exer;

public class MyDate implements Comparable<MyDate>{ // 实现Comparable<E>接口时给E传入的是MyDate,所以其中compareTo(E e)的形参也变为MyDate
    private int year;
    private int month;
    private int day;

    public MyDate(int year, int month, int day) {
        this.year = year;
        this.month = month;
        this.day = day;
    }

    public MyDate() {

    }

    public int getYear() {
        return year;
    }

    public void setYear(int year) {
        this.year = year;
    }

    public int getMonth() {
        return month;
    }

    public void setMonth(int month) {
        this.month = month;
    }

    public int getDay() {
        return day;
    }

    public void setDay(int day) {
        this.day = day;
    }

    @Override
    public String toString() {
        return "MyDate{" +
                "year=" + year +
                ", month=" + month +
                ", day=" + day +
                '}';
    }

    @Override
    public int compareTo(MyDate m) { // 没有给E传入具体类型时传入的Object类型,所以要先判断该对象是否是MyDate类型
                                    // 使用泛型后指明传入的数据类型必须是MyDate。接口中的泛型和类的泛型有所不同,
                                    // 接口使用泛型是在被类实现时传入一个类型,类使用泛型是在被实例化时传入一个类型
        int minusYear = this.getYear() - m.getYear();
        if(minusYear != 0){
            return minusYear;
        }

        int minusMonth = this.getMonth() - m.getMonth();
        if(minusMonth != 0){
            return minusMonth;
        }

        return this.getDay() - m.getDay();
    }
}
    Employee类

 

package com.atguigu.exer;

public class Employee implements Comparable<Employee>{
    private String name;
    private int age;
    private MyDate birthday;

    public Employee(String name, int age, MyDate birthday) {
        this.name = name;
        this.age = age;
        this.birthday = birthday;
    }

    public Employee() {

    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public MyDate getBirthday() {
        return birthday;
    }

    public void setBirthday(MyDate birthday) {
        this.birthday = birthday;
    }

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

    @Override
    public int compareTo(Employee o) {
        return this.name.compareTo(o.name);
    }
}
    测试类

 

package com.atguigu.exer;

import org.junit.Test;
import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;

public class EmployeeTest {
    // 自然排序
    @Test
    public void test1(){

        TreeSet<Employee> set = new TreeSet<>(); // JDK7中新加入,不需要在new时在<>中写类型。创建TreeSet<E>对象时
                                                // 给E传入Employee类型,TreeSet<E>类中使用到E的地方如add()、iterator()
                                                // 都被替换为Employee

        Employee e1 = new Employee("liudehua",55,new MyDate(1965,5,4));
        Employee e2 = new Employee("zhangxueyou",43,new MyDate(1987,5,4));
        Employee e3 = new Employee("guofucheng",44,new MyDate(1987,5,9));
        Employee e4 = new Employee("liming",51,new MyDate(1954,8,12));
        Employee e5 = new Employee("liangzhaowei",21,new MyDate(1978,12,4));

        set.add(e1);
        set.add(e2);
        set.add(e3);
        set.add(e4);
        set.add(e5);

        Iterator<Employee> iterator = set.iterator();
        while(iterator.hasNext()){
            Employee employee = iterator.next();
            System.out.println(employee);
        }
    }

    // 定制排序
    @Test
    public void test2(){

        TreeSet<Employee> set = new TreeSet<>(new Comparator<Employee>() { // 创建Comparator<E>接口的匿名实现类的匿名对象时,给E传入
            // 的类型是Employee,要实现的抽象方法中使用到E的地方被替换为Employee
            @Override
            public int compare(Employee o1, Employee o2) {
                MyDate b1 = o1.getBirthday();
                MyDate b2 = o2.getBirthday();

                return b1.compareTo(b2);
            }
        });

        Employee e1 = new Employee("liudehua",55,new MyDate(1965,5,4));
        Employee e2 = new Employee("zhangxueyou",43,new MyDate(1987,5,4));
        Employee e3 = new Employee("guofucheng",44,new MyDate(1987,5,9));
        Employee e4 = new Employee("liming",51,new MyDate(1954,8,12));
        Employee e5 = new Employee("liangzhaowei",21,new MyDate(1978,12,4));

        set.add(e1);
        set.add(e2);
        set.add(e3);
        set.add(e4);
        set.add(e5);

        Iterator<Employee> iterator = set.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }
}

 

3,自定义泛型类

    Order<T>类

 

package com.atguigu.java;

/**
 * 可以自定义的泛型结构:泛型类、泛型接口;泛型方法
 */

public class Order<T> { // <>中的字符可以是任意字符,通常使用E、T,KV表示键值对

    String orderName;
    int orderId;

    // 在类的内部可以使用类的泛型
    T orderT;

    public Order() {}

    public Order(String orderName, int orderId, T orderT) {
        this.orderName = orderName;
        this.orderId = orderId;
        this.orderT = orderT;
    }

    public T getOrderT() {
        return orderT;
    }
    public void setOrderT(T orderT) {
        this.orderT = orderT;
    }

    @Override
    public String toString() {
        return "Order{" +
                "orderName='" + orderName + '\'' +
                ", orderId=" + orderId +
                ", orderT=" + orderT +
                '}';
    }
}
    测试

 

@Test
public void test1() {
    Order order = new Order(); // 将类定义为泛型但在实例化时没有指明要传入的类型,则默认泛型类型就是Object
    order.setOrderT(123); // 如果将类定义为泛型,则在实例化时就要指明具体类型,使得代码更严格
    order.setOrderT("ABC");

    Order<String> order1 = new Order<String>("orderAA", 1001, "order:AA");
    order1.setOrderT("AA:hello"); // 只能传入String类型对象
}
    Order<T>类的两个子类

 

package com.atguigu.java;

public class SubOrder extends Order<Integer> { // 在继承时就指明给父类中传入的类型,此时SubOrder不是泛型的
}
package com.atguigu.java;

public class SubOrder1<T> extends Order<T> {  // 在继承时没有给父类的泛型指明类型,则子类最好也加上泛型<T>,不然
                                // 在创建子类对象时无法给父类的泛型指明类型,此时子类是泛型的
}
    测试

 

@Test
public void test2() {
    SubOrder sub1 = new SubOrder();
    sub1.setOrderT(112); // SubOrder不是泛型的,但在继承时指明给父类的<E>中传入的是Integer,所以调用父类的该方法时传入的类型也是Integer

    SubOrder1<String> sub2 = new SubOrder1<>(); // 类型推断,在new中没有指明类型
    sub2.setOrderT("order2"); // 父类的该方法只能传入String类型,因为创建子类对象时给泛型传入的是String,这个String也
                            // 传给了父类Order<T>中的T
}
    其他注意点

 

day25-泛型与File_泛型与File_03

@Test
public void test3() {
    ArrayList<String> list1 = null;
    ArrayList<Integer> list2 = null;
    // list1 = list2; // 编译不通过
}

day25-泛型与File_泛型与File_04

    在Order<T>类中定义的静态方法

 

//    public static void show(T orderT) { // 静态方法中不能使用类的泛型,静态方法在类被加载时就有了,而
                                        // 类的泛型在创建对象时才指定,从生命周期角度看,前者不能调用后者
//        System.out.println(orderT);
//    }

day25-泛型与File_泛型与File_05

day25-泛型与File_泛型与File_06

 

4,自定义泛型方法举例

    在Order<T>中定义了泛型方法

 

public void setOrderT(T orderT) { // 不是说在方法中使用了泛型该方法就是泛型方法
    this.orderT = orderT;
}
// 泛型方法:在方法定义中出现了泛型的结构,与该方法所在类声明的泛型<T>是不一样的,且泛型类或非泛型类都可以定义泛型方法
public static <E> List<E> copyFromArrayToList(E[] arr) { // 数组arr的类型不确定,所以将它定义为泛型,所以创建ArrayList也
                                    // 要使用泛型,public后的<E>是必需的,否则E会被当做一个具体类型(而不是泛型)而报错
                                    // 泛型方法可以是static的,因为它里面的类型是在该方法被调用时确定,和创建对象无关,也就没有生命周期先后的问题
    ArrayList<E>  list = new ArrayList<>();
    for(E e : arr) {
        list.add(e);
    }
    return list;
}
    测试
@Test
public void test4() {
    Order<String> order = new Order<>();
    Integer[] arr = new Integer[]{1, 2, 3, 4};
    List<Integer> list = order.copyFromArrayToList(arr); // 给泛型方法传入一个数组时,就将该数组的类型传给了方法的泛型E,
    // 所以返回的list的类型是List<Integer>
    System.out.println(list);
}

 

5,泛型类与泛型方法的使用情景

    基础的DAO类
package com.atguigu.java1;

import java.util.List;

/**
 * DAO:database access object数据访问对象,用来定义操作数据库的通用操作
 * 数据库中的一张表可以对应到Java中的一个类,一行数据就是该类的一个对象
 * 数据库中的增删改查操作也可以对应到对Java对象的增删改查
 */

public class DAO<T> { // 要操作的表不确定(但对每张表要执行的操作是固定的),所以使用泛型,根据传进来的具体表做关于这张表的操作
    // 添加一条记录
    public void add(T t) {

    }
    // 删除一条记录
    public boolean remove(int index) {
        return false;
    }
    // 修改一条记录
    public void update(int index, T t) {

    }
    // 查询一条记录
    public T getIndex(int index) {
        return null;
    }
    // 查询多条记录
    public List<T> getForList(int index) {
        return null;
    }

    public <E> E getValue() { // 泛型方法
        return null;
    }
}
    表示数据库中某一张表的类

package com.atguigu.java1;

public class Customer { // 此类对应数据库中的customers表
    // 各种属性
}
    每张表都有自己对应的DAO类用于完成固定操作,而不是直接通过DAO<Customer>创建一个泛型对象来完成

package com.atguigu.java1;

public class CustomerDAO extends DAO<Customer> { // 将子类设计为只能操作某一张表(Customer表)的DAO
}
    测试

@Test
public void test1() {
    CustomerDAO dao1 = new CustomerDAO();

    dao1.add(new Customer());
    List<Customer> list = dao1.getForList(10);
}

 

6,泛型在继承方面的体现

// 类A是类B的父类,但G<A>和G<B>二者不是子父类关系,而是并列关系
@Test
public void test1() {
    Object obj = null;
    String str = null;
    obj = str; // String是Object的子类,所以String也是Object

    Object[] arr1 = null;
    String[] arr2 = null;
    arr1 = arr2; // String数组的每个元素也是Object类型的

    Date date = new Date();
    // str = date; // 编译不通过,因为Date与String没有子父类的关系,也就没有谁是谁的关系

    List<Object> list1 = null;
    List<String> list2 = null;
    // list1 = list2; // 编译不通过,因为list1和list2的类型不具有子父类关系
                // 假设可以成功赋值,list1的类型是List<Object>,但它引用的却是一个List<String>对象,
                // 当list1.add(123)时会出错

    // show(list2); // 所以在给方法传参时这样也是错误的
}
public void show(List<Object> list) {

}

// 类A是类B的父类,或类B实现接口A,则A<G>是B<G>的父类
@Test
public void test2() {
    AbstractList<String> list1 = null;
    List<String> list2 = null;
    ArrayList<String> list3 = null;

    list1 = list3;
    list2 = list3; // ArrayList继承AbstractList,实现List
}

 

7,通配符的使用

@Test
public void test3() {
    List<Object> list1 = null;
    List<String> list2 = null; // Object是String的父类,但List<Object>和List<String>没有继承关系
    List<?> list = null; // 使用通配符?,它匹配所有类型,所以可以认为List<?>是List<Object>和List<String>共同的父类

    list = list1;
    list = list2;
}
public void print(List<?> list) { // 可以传入List<Object>或List<String>,List<?>都能匹配
    Iterator<?> iterator = list.iterator();
    while(iterator.hasNext()) {
        Object obj = iterator.next(); // 不能写? obj。但能用Object接收所有类型对象
        System.out.println(obj);
    }
}

 

8,使用通配符后数据的读取和写入要求

    写在test3()中

List<String> list3 = new ArrayList<>();
list3.add("AA");
list3.add("BB");
list3.add("CC");
list = list3;
// list.add("DD"); // 不能向List<?>类型的对象中添加数据
list.add(null); // 但可以添加null
Object o = list.get(0); // 可以读取数据,返回对象用Object接收
System.out.println(o);

 

9,有限制条件的通配符的使用

@Test
public void test4() {
    List<? extends Person> list1 = null; // ?可以匹配是Person或是Person的子类
    List<? super Person> list2 =null; // ?可以匹配是Person或是Person的父类

    List<Student> list3 = new ArrayList<Student>(); // Student继承Person
    List<Person> list4 = new ArrayList<Person>();
    List<Object> list5 = new ArrayList<Object>();

    list1 = list3; // 此时?匹配的是Student类型,List<Student>和List<Person>不具有子父类关系
    list1 = list4; // 此时?匹配的是Person类型,并不是说此时?就是Person类型
    // list1 = list5; // 编译不通过,因为不在?的匹配范围中
    // list2 = list3; // 编译不通过
    list2 = list4;
    list2 = list5;

    Person p = list1.get(0); // ?由匹配所有类型变为匹配Person或其子类,所以可以确定返回的一定是Person类型
    list1 = list3; // 并不是说此时给?赋值为Student类型,?没有改变,它还是匹配Person或其子类,只是它匹配的类型变了
    // Student s = list1.get(0); // 编译不通过,因为?表示一段范围,是不确定的,如果该get()返回Person
                                    // 类型,则不能用Student去接收,所以起码要用Person接收
    list2 = list4;
    // Person obj = list2.get(0); // 编译不通过,list2.get()返回的可能是Person或Object,所以要用Object接收

    // list1.add(new Student()); // 编译不通过。list1的类型中?既然能匹配Person的子类,那它就能匹配Student的子类
                                // ,向一个可能是存储子类对象的集合中添加父类(Student)对象是错误的
    list2.add(new Person());
    list2.add(new Student()); // list2的类型中?匹配Person或Object类,所以向其中添加Person或其子类是允许的
    // list2.add(new Object()); // 编译不通过
}

 

10,自定义泛型练习

package com.atguigu.exer1;

import java.util.*;

public class DAO<T> {

    // 创建一个HashMap,用于保存T类型的对象
    private Map<String, T> map = new HashMap<String, T>();

    public void save(String id, T entiry) {
        map.put(id, entiry);
    }

    public T get(String id) {
        return map.get(id);
    }

    public void update(String id, T entity) {
        if(map.containsKey(id)) {
            map.put(id, entity);
        }
    }

    public List<T> list() {
        // Collection<T> values = map.values(); // map.values()返回的就是一个Collection
        // return (List<T>)values; // 将一个子类对象赋值给父类引用,再将它强转为子类类型是可以的,但不能将一个父类对象的引用
                                // 强转为子类类型。所以这里试图将一个Collection强转为List也是错的
        ArrayList<T> list = new ArrayList<>();
        Collection<T> values = map.values();
        for(T t : values) {
            list.add(t);
        }
        return list;
    }

    public void delete(String id) {
        map.remove(id);
    }
}
package com.atguigu.exer1;

import java.util.Objects;

public class User {

    private int id;
    private int age;
    private String name;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public User() {
    }

    public User(int id, int age, String name) {
        this.id = id;
        this.age = age;
        this.name = name;
    }

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

    // User对象要加入到HashMap中,所以要重写equals()和hashCode()
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        return id == user.id &&
                age == user.age &&
                Objects.equals(name, user.name);
    }

    @Override
    public int hashCode() {

        return Objects.hash(id, age, name);
    }
}
package com.atguigu.exer1;

import java.util.List;

public class DAOTest {

    public static void main(String[] args) {
        DAO<User> dao = new DAO<>();

        dao.save("1001", new User(1001, 34, "Jack"));
        dao.save("1002", new User(1002, 20, "Rose"));
        dao.save("1003", new User(1003, 25, "Rob"));

        dao.update("1003", new User(1003, 30, "Jerry"));
        dao.delete("1002");

        List<User> list = dao.list();
        System.out.println(list);
    }
}

 

11,File类的实例化

    File类对象用来表示一个文件或文件目录,它的方法只和文件本身有关,不能影响文件内容,如果要读取写入文件内容,则需要使用IO流
    File类对象通常作为参数传递到流的构造器中,指明读取或写入的具体文件

day25-泛型与File_泛型与File_07

    File类的构造器

day25-泛型与File_泛型与File_08

// 创建File类的实例,需要提供文件的所在路径
@Test
public void test1() {
    // 构造器1
    File file1 = new File("hello.txt"); // 相对路径方式,在当前目录day25下查找
    File file2 = new File("D:\\java\\workspace_idea\\JavaSenior1\\day25\\he.txt"); // 绝对路径,从盘符写起,\\是为了
                                                            // 转义\,Windows下用\分隔
    System.out.println(file1); // hello.txt
    System.out.println(file2); // 即使没有这两个文件也不会报错,此时没有涉及到硬盘层面,只是在内存中创建了两个对象

    // 构造器2
    File file3 = new File("D:\\java\\workspace_idea", "JavaSenior1");
    System.out.println(file3); // D:\java\workspace_idea\JavaSenior1

    // 构造器3
    File file4 = new File(file3, "hi.txt");
    System.out.println(file4); // D:\java\workspace_idea\JavaSenior1\hi.txt
}
    路径分隔符的问题

day25-泛型与File_泛型与File_09

12,File类常用方法

@Test
public void test2() {
    File file = new File("hello.txt");

    System.out.println(file.getAbsolutePath()); // 获取绝对路径
    System.out.println(file.getPath()); // 获取路径
    System.out.println(file.getName()); // 获取文件名
    System.out.println(file.getParent()); // 获取上层文件目录路径。若无,返回null
    System.out.println(file.length()); // 获取文件长度(字节数,即文件大小),不能获取目录的长度
    System.out.println(file.lastModified()); // 获取最后一次的修改时间,毫秒值
}

// 获取指定目录下全部文件的两个方法
@Test
public void test3() {
    File file = new File("D:\\java\\workspace_idea\\JavaSenior1");

    String[] list = file.list();
    for(String s : list) {
        System.out.println(s);
    }

    File[] files = file.listFiles();
    for(File f : files) {
        System.out.println(f);
    }
}

// file1存在磁盘中,file2不在磁盘中才会返回true
@Test
public void test4() {
    File file1 = new File("hello.txt");
    File file2 = new File("D:\\io\\hi.txt");

    boolean renameTo = file2.renameTo(file1);
    System.out.println(renameTo);
}

@Test
public void test5() {
    File file1 = new File("hello.txt");
    File file2 = new File("d:\\io"); // 文件或目录存在调用以下方法才有意义
    // file1 = new File("hello1.txt"); // 文件或目录不存在,以下方法全部返回false

    System.out.println(file1.isDirectory());
    System.out.println(file1.isFile());
    System.out.println(file1.exists());
    System.out.println(file1.canRead());
    System.out.println(file1.canWrite());
    System.out.println(file1.isHidden());
}

// File类对象创建或删除文件
@Test
public void test6() throws IOException {
    File file1 = new File("hi.txt");
    if(!file1.exists()) {
        file1.createNewFile(); // 若指定路径的文件不存在,会创建该文件。可能抛出异常
        System.out.println("创建成功");
    }else {
        file1.delete();
        System.out.println("删除成功"); // 直接删除,没有放进回收站这一步
    }

    File file2 = new File("d:\\io\\io1");
    boolean mkdir = file2.mkdir(); // io目录存在才会创建io1
    boolean mkdirs = file2.mkdirs(); // 若io不存在,则递归创建io和io1
    
    File file3 = new File("D:\\io\\io1\\io2");
    file3 = new File("D:\\io\\io1");
    System.out.println(file3.delete()); //要想删除目录io2,io2下不能有子目录或文件
}
    练习

@Test
public void test1() throws IOException {
    File file1 = new File("D:\\io\\io1\\hello.txt"); // hello.txt文件存在
    File destFile = new File(file1.getParent(), "haha.txt"); // 目录(io1)+文件名的方式创建File对象
    boolean newFile = destFile.createNewFile();
    if(newFile) {
        System.out.println("创建成功");
    }
}

@Test
public void test2(){ // 找出目录下.jpg结尾的文件
    File srcFile = new File("d:\\code");

    String[] fileNames = srcFile.list();
    for(String fileName : fileNames){
        if(fileName.endsWith(".jpg")){
            System.out.println(fileName);
        }
    }
}