在实际开发工作中,我们会使用到一些操作,这些操作在Java中都已经封装好了相应的类包供我们使用。

包装类

包装类的定义

Java是面向对象的语言,但并不是“纯面向对象”的,因为我们经常用到的基本数据类型就不是对象。但是我们在实际应用中经常需要将基本数据转化成对象,以便于操作。

为了解决这个问题,Java在设计类时为每个基本数据类型设计了一个对应的类进行代表,这样八个和基本数据类型对应的类统称为包装类,以下就是每种基础数据类型所对应的包装类。

基础数据类型 包装类
byte Byte
boolean Boolean
short Short
char Character
int Integer
long Long
float Float
double Double

包装类的用途

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

以下例子归纳了包装类的常用用法,别的不常用的方法可以查看API文档:

public class Test {
    /** 测试Integer的用法,其他包装类与Integer类似 */
    public 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();
    }
}

自动装箱和拆箱

  • 自动装箱: 基本类型的数据处于需要对象的环境中时,会自动转为“对象”。自动装箱过程是通过自动调用包装类的valueOf()方法实现的。

  • 自动拆箱: 每当需要一个值时,对象会自动转成基本数据类型,没必要再去显式调用intValue()、doubleValue()等转型方法。自动拆箱过程是通过调用包装类的xxxValue()方法实现的(xxx代表对应的基本数据类型,如intValue()、doubleValue()等)。

    以下例子展示了自动装拆箱的使用:

public class TestAutoBox {
    public static void main(String[] args) {
        Integer a=123;  //自动装箱:Integer a=Integer.valueOf(123);
        int b=a;          //自动拆箱:int b=a.intValue();

        Integer c=null;
        if (c!=null) {  //检测c是否为空值,防止空指针异常
            int d=c;  //自动拆箱:调用了intValue();
        }
    }
}

包装类的缓存问题

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

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

public class Test {
    public static void main(String[] args) {
        //缓存[-128,127]之间的数字。实际就是系统初始的时候,创建了[-128,127]之间的一个缓存数组
        //当我们调用valueOf()的时候,首先检查是否在[-128,127]之间,如果在这个范围则直接从缓存数组中拿出已经建好的对象
        //如果不在这个范围,则创建新的Integer对象
        Integer in1=Integer.valueOf(-123);
        Integer in2=-123;
        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
    }
}

String类

在Java中没有内置的字符串类型,而是再标准Java类库中提供了一个预定义的类,这个类就是String类,String类对象代表不可变的Unicode字符序列,因此我们可以将String对象称为“不可变对象”。

String类的基本用法

public class TestString {
    public static void main(String[] args) {
        String s1=new String("abcdef");
        String s2=s1.substring(1, 5);
        System.out.println(s1);
        System.out.println(s2);
        System.out.println("#####################");
        //不是同一个对象
        System.out.println(Integer.toHexString(s1.hashCode()));
        System.out.println(Integer.toHexString(s2.hashCode()));
        System.out.println("#####################");

        //字符串的拼接
        String str01="abc";
        String str02=new String("def");
        String str03="abc"+"defg";
        String str04="18"+19;  //有一个字符串就不是加法,是字符串连接符,输出1819
        //编译器做了优化,直接在编译的时候将字符串进行拼接
        String str1="hello"+" java";
        String str2="hello java";
        System.out.println(str1==str2);  //true
        String str3="hello";
        String str4=" java";
        //编译的时候不知道变量中存储的是什么,所以没办法在编译的时候优化
        String str5=str3+str4;
        System.out.println(str2==str5);  //false
        System.out.println(str2.equals(str5));  //true,做字符串比较的时候,使用equals不要使用==
    }
}

String类的常用方法

以下展示了String类常用的几种方法,更详细的内容在需要使用时可以查看API文档:

public class TestStringClassVoid {
    public static void main(String[] args) {
        String str1="core Java";
        String str2="Core Java";
        System.out.println(str1.charAt(3));  //提取指定索引(3,从0开始)的字符
        System.out.println(str2.length());  //字符串的长度
        System.out.println(str1.equals(str2));  //比较两个字符串是否相等
        System.out.println(str1.equalsIgnoreCase(str2));  //比较两个字符串是否相等(忽略大小写)
        System.out.println(str1.indexOf("Java"));  //字符串str1中出现Java的位置(从0开始)
        System.out.println(str1.indexOf("apple"));  //字符串str1中出现apple的位置(从0开始,没有出现返回-1)
        String str=str1.replace(" ", "&");  //替换字符串里的字符
        System.out.println(str);

        System.out.println("###################");
        String s= "";
        String s1="How are you?";
        System.out.println(s1.startsWith("How"));  //是否以"How"开头
        System.out.println(s1.endsWith("you"));  //是否以"you"结尾
        s=s1.substring(4);  //提取子字符串:从下标为4开始到结尾为止(从0开始)
        System.out.println(s);
        s=s1.substring(4, 7);  //提取子字符串[4,7) 不包括7(从0开始)
        System.out.println(s);
        s=s1.toUpperCase(); //转大写
        System.out.println(s);
        s=s1.toLowerCase(); //转小写
        System.out.println(s);
        String s2="  How old are you?   ";
        s=s2.trim();  //删收尾空格(中间的空格不会删除)
        System.out.println(s);
        System.out.println(s2);  //因为String是不可变字符串,所以s2不变(仅将结果赋给s,所以s2不变)    
    }
}

StringBuffer和StringBuilder

StringBuffer和StringBuilder非常类似,均代表可变的字符序列。 这两个类都是抽象类AbstractStringBuilder的子类,方法几乎一模一样。

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

public class TestStringAndStringBuilder {
    public static void main(String[] args) {
        /**使用String进行字符串的拼接*/
        String str="";
        //本质上使用StringBuilder拼接,但是每次循环都会生成一个StringBuilder对象
        long num1=Runtime.getRuntime().freeMemory();  //获取系统剩余内存空间
        long time1=System.currentTimeMillis();  //获取系统当前时间
        for (int i = 0; i < 5000; i++) {
            str=str+i;  //相当于产生了10000个对象,每次i要加上去要产生一个i的字符串
        }
        long num2=Runtime.getRuntime().freeMemory();
        long time2=System.currentTimeMillis();
        System.out.println("String占用内存:"+(num1-num2));
        System.out.println("String占用时间:"+(time2-time1));

        /**使用StringBuilder进行字符串的拼接*/
        StringBuilder sb=new StringBuilder();
        long num3=Runtime.getRuntime().freeMemory();  //获取系统剩余内存空间
        long time3=System.currentTimeMillis();  //获取系统当前时间
        for (int i = 0; i < 5000; i++) {
            sb.append(i);
        }
        long num4=Runtime.getRuntime().freeMemory();
        long time4=System.currentTimeMillis();
        System.out.println("StringBuilder占用内存:"+(num3-num4));
        System.out.println("StringBuilder占用时间:"+(time4-time3));
    }
}

StringBuilder、StringBuffer的使用以及常用方法

StringBuilder和StringBuffer的方法几乎一样,所以以下用StringBuilder为例:

public class TestStringBuilderVoid {
    public static void main(String[] args) {
        String str;  //private final char value[];(不可变字符序列)

        //StringBuilder线程不安全,效率高(一般使用它);StringBuffer线程安全,效率低
        StringBuilder str1=new StringBuilder("abcdefg");  //char[] value;(可变字符序列)

        System.out.println(Integer.hashCode(str1.hashCode()));
        System.out.println(str1);
        System.out.println("##############");
        str1.setCharAt(2, 'S');
        System.out.println(Integer.hashCode(str1.hashCode()));
        System.out.println(str1);

        System.out.println("###########常用方法############");
        StringBuilder sb=new StringBuilder();
        for (int i = 0; i < 26; i++) {
            char temp=(char)('a'+i);
            sb.append(temp);  //在可变字符序列后加一个字符
        }

        System.out.println(sb);
        sb.reverse();  //倒序
        System.out.println(sb);
        sb.setCharAt(3, '王');  //改变可变字符序列指定位置的字符
        System.out.println(sb);
        //因为字符串的底层为数组,所以它的索引值从0开始
        //链式调用(可反复调用),核心就是:该方法调用了return this,把自己返回了.
        sb.insert(0, '6').insert(1, 5);  //在指定的位置插入一个字符
        System.out.println(sb);
        //同样支持链式调用
        sb.delete(0, 2).delete(3, 4);  //删除指定位置的字符
        System.out.println(sb);
    }
}

String、StringBuilder和StringBuffer的使用区别

  1. String:不可变字符序列。
  2. StringBuffer:可变字符序列,并且线程安全,但是效率低。
  3. StringBuilder:可变字符序列,线程不安全,但是效率高(一般用它)。

时间处理类

Date类(时间类)

public class TestDate {
    public static void main(String[] args) {
        Date d1=new Date(2000);
        System.out.println(d1);

        Date d2=new Date();
        System.out.println(d2.getTime());  //时间戳(输出自从1970 年 1 月 1 日 00:00:00 GMT以来的指定毫秒数)
        System.out.println(d1.after(d2));  //测试此日期是否在指定日期之后
        System.out.println(d1.before(d2));  //测试此日期是否在指定日期之前
        System.out.println(d1.equals(d2));  //比较两个日期的相等性

        //以后遇到时间处理:使用Candlendar类
        Date date=new Date(2020-1900,0,1);  //2020年1月1日
        System.out.println(date);
    }
}  

DateFormat类和SimpleDateFormat类(时间格式转换)

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

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

public class TestDateFormat {
    public static void main(String[] args) throws ParseException {

        //把时间对象按照“格式字符串指定的格式”转成相应的字符串
        DateFormat df1=new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        String str=df1.format(new Date(1500000));
        System.out.println(str);

        //把字符串按照“格式字符串指定的格式”转成相应的时间对象
        DateFormat df2=new SimpleDateFormat("yyyy年MM月dd日 hh时mm分ss秒");
        Date date =df2.parse("2020年1月1日 1时1分1秒");
        System.out.println(date);

        //测试其他的格式字符.例如:利用w和D,获得本时间对象所处年份的第几周,第几天.
        DateFormat df3=new SimpleDateFormat("第w周,第D天,E");
        String string=df3.format(new Date());
        System.out.println(string);
    }
}

格式字符串指定的格式如下图示例:

Calendar(日历类)

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

public class TestCalendar {
    public static void main(String[] args) {
        Calendar calendar=new GregorianCalendar(3000,0,1,1,1,1);
        int year=calendar.get(Calendar.YEAR);
        int month=calendar.get(Calendar.MONTH);  //0-11表示对应的月份.0是一月,1是二月.........11是12月.
        int day=calendar.get(Calendar.DATE);  //也可使用:DATE_OF_MONTH
        int weekday=calendar.get(Calendar.DAY_OF_WEEK);  //1-7表示对应周几.1是星期日,2是星期一......7是星期六
        System.out.println(year+"年"+month+"月"+day+"日");
        System.out.println(weekday);
        System.out.println("##############");

        //设置日期的相关元素
        Calendar c1=new GregorianCalendar();
        c1.set(Calendar.YEAR, 6666);
        System.out.println(c1);
        System.out.println("##############");

        //日期的计算
        Calendar c2=new GregorianCalendar();
        c2.add(Calendar.YEAR, 100);
        System.out.println(c2);
        System.out.println("##############");

        //日期对象和时间对象的转化
        Date date=c2.getTime();
        System.out.println(date);
        Calendar c3=new GregorianCalendar();
        c3.setTime(new Date(2000));
        System.out.println(c3);
        System.out.println("##############");

        printCalender(new GregorianCalendar());

    }


    public static void printCalender(Calendar c) {
        //打印:1918年10月10日 11:23:45 周四
        int year=c.get(Calendar.YEAR);
        int month=c.get(Calendar.MONTH)+1;  //0-11
        String monthString=month<10?"0"+month:month+"";
        int day=c.get(Calendar.DATE);
        String dayString=day<10?"0"+day:day+"";
        int hour=c.get(Calendar.HOUR);
        String hourString=hour<10?"0"+hour:hour+"";
        int minute=c.get(Calendar.MINUTE);
        String minuteString=minute<10?"0"+minute:minute+"";
        int second=c.get(Calendar.SECOND);
        String secondString=second<10?"0"+second:second+"";
        int dayweek=c.get(Calendar.DAY_OF_WEEK)-1;  //0-6
        String dayweekString="";
        switch (dayweek) {
        case 0:
            dayweekString=" 周日";
            break;
        case 1:
            dayweekString=" 周一";
            break;
        case 2:
            dayweekString=" 周二";
            break;
        case 3:
            dayweekString=" 周三";
            break;
        case 4:
            dayweekString=" 周四";
            break;
        case 5:
            dayweekString=" 周五";
            break;
        case 6:
            dayweekString=" 周六";
            break;
        }
        System.out.println(year+"年"+monthString+"月"+dayString+"日 "+hourString+":"+minuteString+":"+secondString+dayweekString);
    }
}
  • 注意事项
  1. 注意月份的表示,一月是0,二月是1,以此类推,12月是11。 因为大多数人习惯于使用单词而不是使用数字来表示月份,这样程序也许更易读,父类Calendar使用常量来表示月份:JANUARY、FEBRUARY等等。
  2. 周日代表的是一周的第一天

Math类

Math类的常用方法

public class TestMath {
    public static void main(String[] args) {
        //取整相关操作
        System.out.println(Math.ceil(3.2));  //进1法
        System.out.println(Math.floor(3.2));  //去掉小数取整
        //四舍五入
        System.out.println(Math.round(3.4));
        System.out.println(Math.round(4.5));

        //绝对值、开方、a的b次幂等操作
        System.out.println(Math.abs(-50));  //取绝对值
        System.out.println(Math.sqrt(9));  //开方
        System.out.println(Math.pow(2, 3));  //a的b次幂
        System.out.println(Math.pow(3, 2));  //a的b次幂

        //Math类中常用的常量
        System.out.println(Math.PI);
        System.out.println(Math.E);

        //随机数
        System.out.println(Math.random());  //[0,1)
    }
}

Random类的常用方法

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

        System.out.println(20+(int)(rand.nextDouble()*10));  //随机生成[20,30)之间的int类型数据(此方法计算较为复杂)
    }
}

File类

路径的常用表达

public class TestPath {
    public static void main(String[] args) {
        String path="D:\\test\\test.txt";
        System.out.println(path);
        System.out.println(File.separator);

        /*路径的表达方式(常用)*/
        //1./
        path="D:/test/test.txt";
        System.out.println(path);

        //2.File.separator常量拼接
        path="D:"+File.separator+"test"+File.separator+"test.txt";
        System.out.println(path);
    }
}

File类的常用操作

public class TestFile {
    public static void main(String[] args) throws IOException {
        File file=new File("d:/a.txt");
//        File file=new File("d:\\a.txt");
        System.out.println(file);

        //文件重命名
        file.renameTo(new File("d:/bb.txt"));

        //加载当前用户目录
        System.out.println(System.getProperty("user.dir"));

        //创建新文件(默认是当前用户目录)
        File f=new File("gg.txt");
        f.createNewFile();

        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()));  //返回Date类
        System.out.println("File的大小:"+f.length());
        System.out.println("File的文件名:"+f.getName());  //获取对象的名称
        //获取对象的路径(构建时传入的是相对路径就返回相对路径,传入绝对路径就返回绝对路径)
        System.out.println("File的目录路径:"+f.getPath());  //仅显示文件名为当前目录路径
        System.out.println("File的绝对目录路径:"+f.getAbsolutePath());  //获取对象的绝对路径
        //获取对象的父路径(即文件名称前的路径),构建的时候有就返回,没有就返回null
        System.out.println(f.getParent());

        //文件状态判定
        File fileStatus=new File("D:/a.txt");
        if (null== fileStatus || !fileStatus.exists()) {
            System.out.println("文件不存在!");
        }else {
            if (fileStatus.isFile()) {
                System.out.println("文件操作");
            }else {
                System.out.println("文件夹操作");
            }
        }
        System.out.println("#################");
        //文件的创建以及删除
        File newFile=new File("newFile.txt");
        boolean flag=newFile.createNewFile();  //创建文件,如果文件已存在,则创建失败返回false
        System.out.println(flag);
        flag=newFile.delete();  //删除已经存在的文件
        System.out.println(flag);

        System.out.println("#################");
        //con和com3是操作系统的设备名,不能正确创建
        File newFileTest=new File("D:/con");
        flag=newFileTest.createNewFile();
        System.out.println(flag);

        //mkdir或mkdirs仅用来创建目录不能创建文件
        File f2=new File("d:/电影/华语/大陆");
        boolean flag1=f2.mkdir();  //目录结构中有一个不存在,则不会创建整个目录树
        System.out.println(flag1);  //创建失败

        File f3=new File("d:/电影/华语/大陆/");
        boolean flag2=f3.mkdirs();  //目录结构中有一个不存在也没关系,创建整个目录树
        System.out.println(flag2);  //创建成功

        System.out.println("#############");
        File dir=new File("D:/eclipse-workspace/");

        //list方法返回下级名称
        String[] subStrings=dir.list();
        for (String s : subStrings) {
            System.out.println(s);
        }

        System.out.println("#############");
        //listFiles返回下级的所有File对象
        File[] subFiles=dir.listFiles();
        for (File files : subFiles) {
            System.out.println(files);
        }

        //列出所有盘符
        File[] roots=dir.listRoots();
        for (File r : roots) {
            System.out.println(r.getAbsolutePath());
        }
    }
}

枚举类

public class TestEnum {
    public static void main(String[] args) {
        System.out.println(Season.SPRING);

        Season season=Season.AUTUMN;
        switch (season) {
        case SPRING:
            System.out.println("春天");
            break;
        case SUNMMER:
            System.out.println("夏天");
            break;
        case AUTUMN:
            System.out.println("秋天");
            break;
        case WINTER:
            System.out.println("冬天");
            break;
        }
    }
}

//枚举类型隐性地继承自java.lang.Enum,枚举实质上还是类
//每个被枚举的成员实质就是一个枚举类型的实例,默认都是public static final修饰的(常量)
enum Season{
    SPRING,SUNMMER,AUTUMN,WINTER
}