2.常用类的学习

1.包装类的用途

八种基本类,每一种类对应一种包装类

byte,short,int,long
double float
char
boolean
基本数据地址放在栈,,对应地址数据在堆中
包装类的基本作用:在基本数据类型、包装类对象、字符串之间提供相互之间的转化。

【示例】初识包装类

public class WrapperClassTest {
    public static void main(String[ ] args) {
        Integer i = new Integer(10);    //从java9开始被废弃
        Integer j = Integer.valueOf(50); //官方推荐
    }
}

对于包装类来说,这些类的用途主要包含两种:

  1. 作为和基本数据类型对应的类型存在,方便涉及到对象的操作,如Object[ ]、集合等的操作。
  2. 包含每种基本数据类型的相关属性如最大值、最小值等,以及相关的操作方法(这些操作方法的作用是在基本数据类型、包装类对象、字符串之间提供相互之间的转化!)。

【示例】包装类的使用

public class Test {
    /** 测试Integer的用法,其他包装类与Integer类似 */
    void testInteger() {
        // 基本类型转化成Integer对象
        Integer int1 = new Integer(10);   //已废弃,不推荐使用
        Integer int2 = Integer.valueOf(20); // 官方推荐这种写法
        // Integer对象转化成int
        int a = int1.intValue();
        // 字符串转化成Integer对象
        Integer int3 = Integer.parseInt("334");
        Integer int4 = new Integer("999");
        // Integer对象转化成字符串
        String str1 = int3.toString();
        // 一些常见int类型相关的常量
        System.out.println("int能表示的最大整数:" + Integer.MAX_VALUE); 
    }
    public static void main(String[ ] args) {
        Test test  = new Test();
        test.testInteger();
    }
}

2.自动装箱和拆箱

自动装箱:

基本类型的数据处于需要对象的环境中时,会自动转为“对象”。

我们以Integer为例:

Integer i = 5

编译器会自动转成:Integer i = Integer.valueOf(5),这就是Java的自动装箱。

自动拆箱:

每当需要一个值时,对象会自动转成基本数据类型,没必要再去显式调用intValue()、doubleValue()等转型方法。

Integer i = Integer.valueOf(5);

int j = i;

编译器会自动转成:int j = i.intValue();

这样的过程就是自动拆箱。

自动装箱/拆箱的本质是:

自动装箱与拆箱的功能是编译器来帮忙,编译器在编译时依据您所编写的语法,决定是否进行装箱或拆箱动作。

【示例】自动装箱

Integer i = 100;//自动装箱
//相当于编译器自动为您作以下的语法编译:
Integer i = Integer.valueOf(100);//调用的是valueOf(100),而不是new Integer(100)

【示例】自动拆箱

Integer i = 100;
int j = i;//自动拆箱
//相当于编译器自动为您作以下的语法编译:
int j = i.intValue();

自动装箱与拆箱的功能是所谓的“编译器蜜糖(Compiler Sugar)”,虽然使用这个功能很方便,但在程序运行阶段您得了解Java的语义。如下所示的程序是可以通过编译的:

【示例】包装类空指针异常问题

public class Test1 {
    public static void main(String[ ] args) {
        Integer i = null;
        int j = i;
    }
}

运行结果之所以会出现空指针异常,是因为如上代码相当于:

public class Test1 {
    public static void main(String[ ] args) {
        /*示例8-5的代码在编译时期是合法的,但是在运行时期会有错误
因为其相当于下面两行代码*/
        Integer i = null; 
        int j = i.intValue();        
    }
}

3.包装类的缓存问题

整型、char类型所对应的包装类,在自动装箱时,对于-128~127之间的值会进行缓存处理,其目的是提高效率。

缓存原理为:如果数据在-128~127这个区间,那么在类加载时就已经为该区间的每个数值创建了对象,并将这256个对象存放到一个名为cache的数组中。每当自动装箱过程发生时(或者手动调用valueOf()时),就会先判断数据是否在该区间,如果在则直接获取数组中对应的包装类对象的引用,如果不在该区间,则会通过new调用包装类的构造方法来创建对象。

下面我们以Integer类为例,看一看Java为我们提供的源码,加深对缓存技术的理解,如示例所示。

【示例】Integer类相关源码

public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}
  1. 为Integer类的一个静态内部类,仅供Integer类使用。
  2. 一般情况下IntegerCache.low为-128IntegerCache.high为127

IntegerCache.cache为内部类的一个静态属性,如示例所示。

【示例】IntegerCache类相关源码

private static class IntegerCache {
    static final int low = -128;
    static final int high;
    static final Integer cache[ ];
    static {
        // high value may be configured by property
        int h = 127;
        String integerCacheHighPropValue =
                sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
        if (integerCacheHighPropValue != null) {
            try {
                int i = parseInt(integerCacheHighPropValue);
                i = Math.max(i, 127);
                // Maximum array size is Integer.MAX_VALUE
                h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
            } catch( NumberFormatException nfe) {
                // If the property cannot be parsed into an int, ignore it.
            }
        }
        high = h;
        cache = new Integer[(high - low) + 1];
        int j = low;
        for(int k = 0; k < cache.length; k++)
            cache[k] = new Integer(j++);
        // range [-128, 127] must be interned (JLS7 5.1.7)
        assert IntegerCache.high >= 127;
    }
    private IntegerCache() {}
}

由上面的源码我们可以看到,静态代码块的目的就是初始化数组cache的,这个过程会在类加载时完成。

下面我们做一下代码测试,如示例所示。

【示例8-9】包装类的缓存测试

public class Test3 {
    public static void main(String[ ] args) {
        Integer in1 = -128;
        Integer in2 = -128;
        System.out.println(in1 == in2);//true 因为123在缓存范围内
        System.out.println(in1.equals(in2));//true
        Integer in3 = 1234;
        Integer in4 = 1234;
        System.out.println(in3 == in4);//false 因为1234不在缓存范围内
        System.out.println(in3.equals(in4));//true
    }
}

总结

  • 自动装箱调用的是valueOf()方法,而不是new Integer()方法。
  • 自动拆箱调用的xxxValue()方法。
  • 包装类在自动装箱时为了提高效率,对于-128~127之间的值会进行缓存处理。超过范围后,对象之间不能再使用==进行数值的比较,而是使用equals方法。

4.自定义一个简单的包装类

public class MyInteger {


    private int value;
    private static MyInteger[] cache = new MyInteger[256];


    public static final int LOW = -128;
    public static final int HIGH = 127;




    static {
        //[-128,127]
        for(int i=MyInteger.LOW;i<=HIGH;i++){
            //-128,0;-127,1;-126,2;
            cache[i+128] = new MyInteger(i);
        }
    }


    public static MyInteger valueOf(int i) {
        if(i>=LOW&&i<=HIGH) {
            return cache[i+128];
        }
        return new MyInteger(i);
    }


    @Override
    public String toString() {
        return this.value+"";
    }

    public int intValue(){
        return value;
    }


    private MyInteger(int i) {
        this.value = i;
    }


    public static void main(String[] args) {
        MyInteger m = MyInteger.valueOf(30);
        System.out.println(m);


    }
}

5.自定义一个包装类完善

public class MyInteger {


    private int value;
    private static MyInteger[] cache = new MyInteger[256];


    public static final int LOW = -128;
    public static final int HIGH = 127;




    static {
        //[-128,127]
        for(int i=MyInteger.LOW;i<=HIGH;i++){
            //-128,0;-127,1;-126,2;
            cache[i+128] = new MyInteger(i);
        }
    }


    public static MyInteger valueOf(int i) {
        if(i>=LOW&&i<=HIGH) {
            return cache[i+128];
        }
        return new MyInteger(i);
    }


    @Override
    public String toString() {
        return this.value+"";
    }


    public int intValue(){
        return value;
    }


    private MyInteger(int i) {
        this.value = i;
    }


    public static void main(String[] args) {
        MyInteger m = MyInteger.valueOf(30);
        System.out.println(m);


    }
}

6.String类源码分析

String 类对象代表不可变的Unicode字符序列,因此我们可以将String对象称为“不可变对象”。 那什么叫做“不可变对象”呢?指的是对象内部的成员变量的值无法再改变。我们打开String类的源码,如图所示:

用finally定义的char数组

我们发现字符串内容全部存储到value[ ]数组中,而变量value是final类型的,也就是常量(即只能被赋值一次)。 这就是“不可变对象”的典型定义方式。

我们发现在前面学习String的某些方法,比如:substring()是对字符串的截取操作,但本质是读取原字符串内容生成了新的字符串。测试代码如下:

【示例】String类的简单使用

public class TestString1 {
    public static void main(String[ ] args) {
        String s1 = new String("abcdef");
        String s2 = s1.substring(2, 4);
        // 打印:ab199863
        System.out.println(Integer.toHexString(s1.hashCode()));
        // 打印:c61, 显然s1和s2不是同一个对象
        System.out.println(Integer.toHexString(s2.hashCode()));
    }
}

在遇到字符串常量之间的拼接时,编译器会做出优化,即在编译期间就会完成字符串的拼接。因此,在使用==进行String对象之间的比较时,我们要特别注意,如示例所示。

【示例】字符串常量拼接时的优化

public class TestString2 {
    public static void main(String[ ] args) {
        //编译器做了优化,直接在编译的时候将字符串进行拼接
        String str1 = "hello" + " java";//相当于str1 = "hello java";
        String str2 = "hellojava";
        System.out.println(str1 == str2);//true
        String str3 = "hello";
        String str4 = " java";
        //编译的时候不知道变量中存储的是什么,所以没办法在编译的时候优化
        String str5 = str3 + str4;
        System.out.println(str2 == str5);//false
    }
}

注意

String截取返回的是新字符串

7.StringBuffer和StringBuilder可变字符序列

StringBufferStringBuilder都是可变的字符序列。

  1. StringBuffer 线程安全,做线程同步检查, 效率较低
  2. StringBuilder 线程不安全,不做线程同步检查,因此效率较高。建议采用该类。

· 常用方法列表:

  • 重载的public StringBuilder append(…)方法

    可以为该StringBuilder 对象添加字符序列,仍然返回自身对象

  • 方法public StringBuilder delete(int start,int end)

    可以删除从start开始到end-1为止的一段字符序列,仍然返回自身对象

  • 方法public StringBuilder deleteCharAt(int index)

    移除此序列指定位置上的 char,仍然返回自身对象。

  • 重载的public StringBuilder insert(…)方法

    可以为该StringBuilder 对象在指定位置插入字符序列,仍然返回自身对象

  • 方法public StringBuilder reverse()

    用于将字符序列逆序,仍然返回自身对象。

  • 方法public String toString()返回此序列中数据的字符串表示形式。

  • 和 String 类含义类似的方法:

    public int indexOf(String str)
    public int indexOf(String str,int fromIndex)
    public String substring(int start)
    public String substring(int start,int end)
    public int length() 
    char charAt(int index)
    

    【示例】StringBuffer/StringBuilder基本用法

    public class TestStringBufferAndBuilder{
        public static void main(String[ ] args) {
            /**StringBuilder*/
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < 7; i++) {
                sb.append((char) ('a' + i));//追加单个字符
            }
            System.out.println(sb.toString());//转换成String输出
            sb.append(", I can sing my abc!");//追加字符串
            System.out.println(sb.toString());
            /**StringBuffer,下面的方法同样适用StringBuilder*/
            StringBuffer sb2 = new StringBuffer("北京尚学堂");
            sb2.insert(0, "爱").insert(0, "我");//插入字符串
            System.out.println(sb2);
            sb2.delete(0, 2);//删除子字符串
            System.out.println(sb2);
            sb2.deleteCharAt(0).deleteCharAt(0);//删除某个字符
            System.out.println(sb2.charAt(0));//获取某个字符
            System.out.println(sb2.reverse());//字符串逆序
        }
    }
    

8.不可变和可变字符序列使用陷阱

· String使用的陷阱

String一经初始化后,就不会再改变其内容了。对String字符串的操作实际上是对其副本(原始拷贝)的操作,原来的字符串一点都没有改变。比如:

String s ="a"; 创建了一个字符串

s = s+"b"; 实际上原来的a字符串对象已经丢弃了,现在又产生了另一个字符串s+"b"(也就是ab)。 如果多次执行这些改变串内容的操作,会导致大量副本字符串对象存留在内存中,降低效率。如果这样的操作放到循环中,会极大影响程序的时间和空间性能,甚至会造成服务器的崩溃。

相反,StringBuilder和StringBuffer类是对原字符串本身操作的,可以对字符串进行修改而不产生副本拷贝或者产生少量的副本。因此可以在循环中使用。

【示例】String和StringBuilder在字符串频繁修改时的效率测试

public class Test {
    public static void main(String[ ] args) {
        /**使用String进行字符串的拼接*/
        String str8 = "";
        
        long num1 = Runtime.getRuntime().freeMemory();//获取系统剩余内存空间
        long time1 = System.currentTimeMillis();//获取系统的当前时间
        for (int i = 0; i < 5000; i++) {
            str8 = str8 + i;//相当于产生了5000个对象
        }
        long num2 = Runtime.getRuntime().freeMemory();
        long time2 = System.currentTimeMillis();
        System.out.println("String占用内存 : " + (num1 - num2));
        System.out.println("String占用时间 : " + (time2 - time1));
        /**使用StringBuilder进行字符串的拼接*/
        StringBuilder sb1 = new StringBuilder("");
        long num3 = Runtime.getRuntime().freeMemory();
        long time3 = System.currentTimeMillis();
        for (int i = 0; i < 5000; i++) {
            sb1.append(i);
        }
        long num4 = Runtime.getRuntime().freeMemory();
        long time4 = System.currentTimeMillis();
        System.out.println("StringBuilder占用内存 : " + (num3 - num4));
        System.out.println("StringBuilder占用时间 : " + (time4 - time3));
    }
}

9.Date类用法_源码分析

“时间如流水,一去不复返”,时间是一维的。所以,我们需要一把刻度尺来表达和度量时间。在计算机世界,我们把1970 年 1 月 1 日 00:00:00定为基准时间,每个度量单位是毫秒(1秒的千分之一),如图所示。

我们用long类型的变量来表示时间,从基准时间前后几亿年都能表示。

这个“时刻数值”是所有时间类的核心值,年月日都是根据这个“数值”计算出来的。

我们工作学习涉及的时间相关类有如下这些:

在这里插入图片描述

Date时间类(java.util.Date)

在标准Java类库中包含一个Date类。它的对象表示一个特定的瞬间,精确到毫秒。

  • Date() 分配一个Date对象,并初始化此对象为系统当前的日期和时间,可以精确到毫秒)。

  • Date(long date) 分配 Date 对象并初始化此对象,以表示自从标准基准时间以来的毫秒数。

  • boolean equals(Object obj)比较两个日期的相等性。

  • long getTime()返回毫秒数。

  • String toString()把此 Date 对象转换为以下形式的 String:

    dow mon dd hh:mm:ss zzz yyyy 其中:dow 是一周中的某一天 。

【示例】Date类的使用

long  nowNum = System.currentTimeMillis();  //当前时刻对应的毫秒数


Date d = new Date();                //当前时刻的对象
System.out.println(d.getTime());    //返回时间对应的毫秒数


Date d2 = new Date(1000L * 3600 * 24 * 365 * 150);  //距离1970年150年
System.out.println(d2);

10.DateFormat时间格式化类

·DateFormat类的作用

把时间对象转化成指定格式的字符串。反之,把指定格式的字符串转化成时间对象。

DateFormat是一个抽象类,一般使用它的的子类SimpleDateFormat类来实现。

【示例】DateFormat类和SimpleDateFormat类的使用

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class TestDateFormat {
    public static void main(String[ ] args) throws ParseException {
        // new出SimpleDateFormat对象
        SimpleDateFormat s1 = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        SimpleDateFormat s2 = new SimpleDateFormat("yyyy-MM-dd");
        // 将时间对象转换成字符串
        String daytime = s1.format(new Date());
        System.out.println(daytime);
        System.out.println(s2.format(new Date()));
        System.out.println(new SimpleDateFormat("hh:mm:ss").format(new Date()));
        // 将符合指定格式的字符串转成成时间对象.字符串格式需要和指定格式一致。
        String time = "2049-10-1";
        Date date = s2.parse(time);
        System.out.println("date1: " + date);
        time = "2049-10-1 20:15:30";
        date = s1.parse(time);
        System.out.println("date2: " + date);
    }
}

代码中的格式化字符的具体含义见表:

格式化字符的含义

字母日期或时间元素表示示例
GEra 标志符TextAD
yYear1996; 96
M年中的月份MonthJuly; Jul; 07
w年中的周数Number27
W月份中的周数Number2
D年中的天数Number189
d月份中的天数Number10
F月份中的星期Number2
E星期中的天数TextTuesday; Tue
aAm/pm 标记TextPM
H一天中的小时数(0-23)Number0
k一天中的小时数(1-24)Number24
Kam/pm 中的小时数(0-11)Number0
ham/pm 中的小时数(1-12)Number12
m小时中的分钟数Number30
s分钟中的秒数Number55
S毫秒数Number978
z时区General time zonePacific Standard Time; PST; GMT-08:00
Z时区RFC 822 time zone0800

时间格式字符也可以为我们提供其他的便利。比如:获得当前时间是今年的第几天。

【示例】获取今天时本年度第几天

import java.text.SimpleDateFormat;
import java.util.Date;
public class TestDateFormat2 {
    public static void main(String[ ] args) {
        SimpleDateFormat s1 = new SimpleDateFormat("D");
        String daytime = s1.format(new Date());
        System.out.println(daytime);
    }
}

11.Calendar日历类的使用详解

Calendar 类是一个抽象类,为我们提供了关于日期计算的功能,比如:年、月、日、时、分、秒的展示和计算。

GregorianCalendar 是 Calendar 的子类,表示公历。

菜鸟雷区

注意月份的表示,一月是0,二月是1,以此类推,12月是11。 因为大多数人习惯于使用单词而不是使用数字来表示月份,这样程序也许更易读,父类Calendar使用常量来表示月份:JANUARY、FEBRUARY等等。

【示例】GregorianCalendar类和Calendar类的使用

import java.util.*;
public class TestCalendar {
    public static void main(String[ ] args) {
        // 得到相关日期元素
        GregorianCalendar calendar = new GregorianCalendar(2049, 9, 1, 22, 10, 50);
        int year = calendar.get(Calendar.YEAR); // 打印:2049
        int month = calendar.get(Calendar.MONTH); // 打印:9
        int day = calendar.get(Calendar.DAY_OF_MONTH); // 打印:1
        int day2 = calendar.get(Calendar.DATE); // 打印:1
        // 日:Calendar.DATE和Calendar.DAY_OF_MONTH同义
        int date = calendar.get(Calendar.DAY_OF_WEEK); // 打印:1
        // 星期几 这里是:1-7.周日是1,周一是2,。。。周六是7
        System.out.println(year);
        System.out.println(month);
        System.out.println(day);
        System.out.println(day2);
        System.out.println(date);
        // 设置日期
        GregorianCalendar calendar2 = new GregorianCalendar();
        calendar2.set(Calendar.YEAR, 2049);
        calendar2.set(Calendar.MONTH, Calendar.OCTOBER); // 月份数:0-11
        calendar2.set(Calendar.DATE, 1);
        calendar2.set(Calendar.HOUR_OF_DAY, 10);
        calendar2.set(Calendar.MINUTE, 20);
        calendar2.set(Calendar.SECOND, 23);
        printCalendar(calendar2);
        // 日期计算
        GregorianCalendar calendar3 = new GregorianCalendar(2049, 9, 1, 22, 10, 50);
        calendar3.add(Calendar.MONTH, -7); // 月份减7
        calendar3.add(Calendar.DATE, 7); // 增加7天
        printCalendar(calendar3);
        // 日历对象和时间对象转化
        Date d = calendar3.getTime();
        GregorianCalendar calendar4 = new GregorianCalendar();
        calendar4.setTime(new Date());
    }
    static void printCalendar(Calendar calendar) {
        int year = calendar.get(Calendar.YEAR);
        int month = calendar.get(Calendar.MONTH) + 1;
        int day = calendar.get(Calendar.DAY_OF_MONTH);
        int date = calendar.get(Calendar.DAY_OF_WEEK) - 1; // 星期几
        String week = "" + ((date == 0) ? "日" : date);
        int hour = calendar.get(Calendar.HOUR);
        int minute = calendar.get(Calendar.MINUTE);
        int second = calendar.get(Calendar.SECOND);
        System.out.printf("%d年%d月%d日,星期%s %d:%d:%d\n", year, month, day,  
                        week, hour, minute, second);
    }
}

12.Math类和Random类

java.lang.Math提供了一系列静态方法用于科学计算;常用方法如下:

  • abs 绝对值
  • acos,asin,atan,cos,sin,tan 三角函数
  • sqrt 平方根
  • pow(double a, double b) a的b次幂
  • max(double a, double b) 取大值
  • min(double a, double b) 取小值
  • ceil(double a) 大于a的最小整数
  • floor(double a) 小于a的最大整数
  • random() 返回 0.0 到 1.0 的随机数
  • long round(double a) double型的数据a转换为long型(四舍五入)
  • toDegrees(double angrad) 弧度->角度
  • toRadians(double angdeg) 角度->弧度

【示例】Math类的常用方法

public class TestMath {
    public static void main(String[ ] args) {
        //取整相关操作
        System.out.println(Math.ceil(3.2));
        System.out.println(Math.floor(3.2));
        System.out.println(Math.round(3.2));
        System.out.println(Math.round(3.8));
        //绝对值、开方、a的b次幂等操作
        System.out.println(Math.abs(-45));
        System.out.println(Math.sqrt(64));
        System.out.println(Math.pow(5, 2));
        System.out.println(Math.pow(2, 5));
        //Math类中常用的常量
        System.out.println(Math.PI);
        System.out.println(Math.E);
        //随机数
        System.out.println(Math.random());// [0,1)
    }
}

Random类

Random类: 专门用来生成随机数。

import java.util.Random;
public class TestRandom {
    public static void main(String[ ] args) {
        Random rand = new Random();
        //随机生成[0,1)之间的double类型的数据
        System.out.println(rand.nextDouble());
        //随机生成int类型允许范围之内的整型数据
        System.out.println(rand.nextInt());
        //随机生成[0,1)之间的float类型的数据
        System.out.println(rand.nextFloat());
        //随机生成false或者true
        System.out.println(rand.nextBoolean());
        //随机生成[0,10)之间的int类型的数据
        System.out.print(rand.nextInt(10));
        //随机生成[20,30)之间的int类型的数据
        System.out.print(20 + rand.nextInt(10));
    }
}

注意

Random类位于java.util包下。

13File类的用法

File类的基本用法

java.io.File类:代表文件和目录,用于:读取文件、创建文件、删除文件、修改文件。

【示例】使用File类创建文件

File类的常见构造方法:public File(String pathname)

pathname为路径创建File对象,如果pathname是相对路径,则默认的当前路径在系统属性user.dir中存储。

import java.io.File;
public class TestFile1 {
    public static void main(String[ ] args) throws Exception {
        System.out.println(System.getProperty("user.dir"));
        File f = new File("a.txt"); //相对路径:默认放到user.dir目录下面
        f.createNewFile();//创建文件
        File f2 = new File("d:/b.txt");//绝对路径
        f2.createNewFile();
    }
}

user.dir就是本项目的目录。上面代码执行后,在本项目和D盘下都生成了新的文件。

  • 通过File对象可以访问文件的属性:

    import java.io.File;
    import java.util.Date;
    public class TestFile2 {
        public static void main(String[ ] args) throws Exception {
            File f = new File("d:/b.txt");
            System.out.println("File是否存在:"+f.exists());
            System.out.println("File是否是目录:"+f.isDirectory());
            System.out.println("File是否是文件:"+f.isFile());
            System.out.println("File最后修改时间:"+new Date(f.lastModified()));
            System.out.println("File的大小:"+f.length());
            System.out.println("File的文件名:"+f.getName());
            System.out.println("File的目录路径:"+f.getAbsolutePath());
        }
    }
    

    【示例】使用mkdir创建目录

    import java.io.File;
    public class TestFile3 {
        public static void main(String[ ] args) throws Exception {
            File f = new File("d:/c.txt");
            f.createNewFile(); // 会在d盘下面生成c.txt文件
            f.delete(); // 将该文件或目录从硬盘上删除
            File f2 = new File("d:/电影/华语/大陆");
            boolean flag = f2.mkdir(); //目录结构中有一个不存在,则不会创建整个目录树
            System.out.println(flag);//创建失败
        }
    }
    
    

    【示例】使用mkdirs创建目录

    import java.io.File;
    public class TestFile4 {
        public static void main(String[ ] args) throws Exception {
            File f = new File("d:/c.txt");
            f.createNewFile(); // 会在d盘下面生成c.txt文件
            f.delete(); // 将该文件或目录从硬盘上删除
            File f2 = new File("d:/电影/华语/大陆");
            boolean flag = f2.mkdirs();//目录结构中有一个不存在也没关系;创建整个目录树
            System.out.println(flag);//创建成功
        }
    }
    

14.递归遍历目录结构

本节结合前面给大家讲的递归算法,展示目录结构。大家可以先建立一个目录,下面增加几个子文件夹或者文件,用于测试。

【示例】使用递归算法,以树状结构展示目录树

import java.io.File;
public class TestFile6 {
    public static void main(String[ ] args) {
        File f = new File("d:/电影");
        printFile(f, 0);
    }
    /**
     * 打印文件信息
     * @param file 文件名称
     * @param level 层次数(实际就是:第几次递归调用)
     */
    static void printFile(File file, int level) {
        //输出层次数
        for (int i = 0; i < level; i++) {
            System.out.print("-");
        }
        //输出文件名
        System.out.println(file.getName());
        //如果file是目录,则获取子文件列表,并对每个子文件进行相同的操作
        if (file.isDirectory()) {
            File[ ] files = file.listFiles();
            for (File temp : files) {
                //递归调用该方法:注意要+1
                printFile(temp, level + 1);
            }
        }
    }
}

15.枚举

JDK1.5引入了枚举类型。枚举类型的定义包括枚举声明和枚举体。格式如下:

enum  枚举名 {
      枚举体(常量列表)
}

枚举体就是放置一些常量。我们可以写出我们的第一个枚举类型,如示例所示:

【示例】创建枚举类型

enum Season {
    SPRING, SUMMER, AUTUMN, WINTER 
}

所有的枚举类型隐性地继承自java.lang.Enum。枚举实质上还是类!而每个被枚举的成员实质就是一个枚举类型的实例,他们默认都是public static final修饰的。可以直接通过枚举类型名使用它们。

老鸟建议

  • 当你需要定义一组常量时,可以使用枚举类型。
  • 尽量不要使用枚举的高级特性,事实上高级特性都可以使用普通类来实现,没有必要引入枚举,增加程序的复杂性!

【示例】枚举的使用

import java.util.Random;
public class TestEnum {
    public static void main(String[ ] args) {
        // 枚举遍历
        for (Week k : Week.values()) {
            System.out.println(k);
        }
        // switch语句中使用枚举
        int a = new Random().nextInt(4); // 生成0,1,2,3的随机数
        switch (Season.values()[a]) {
        case SPRING:
            System.out.println("春天");
            break;
        case SUMMER:
            System.out.println("夏天");
            break;
        case AUTUMN:
            System.out.println("秋天");
            break;
        case WINTER:
            System.out.println("冬天");
            break;
        }
    }
}
/**季节*/
enum Season {
    SPRING, SUMMER, AUTUMN, WINTER
}
/**星期*/
enum Week {
    星期一, 星期二, 星期三, 星期四, 星期五, 星期六, 星期日
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值