在实际开发工作中,我们会使用到一些操作,这些操作在Java中都已经封装好了相应的类包供我们使用。
包装类
包装类的定义
Java是面向对象的语言,但并不是“纯面向对象”的,因为我们经常用到的基本数据类型就不是对象。但是我们在实际应用中经常需要将基本数据转化成对象,以便于操作。
为了解决这个问题,Java在设计类时为每个基本数据类型设计了一个对应的类进行代表,这样八个和基本数据类型对应的类统称为包装类,以下就是每种基础数据类型所对应的包装类。
基础数据类型 | 包装类 |
---|---|
byte | Byte |
boolean | Boolean |
short | Short |
char | Character |
int | Integer |
long | Long |
float | Float |
double | Double |
包装类的用途
- 作为和基本数据类型对应的类型存在,方便涉及到对象的操作,如Object[]、集合等的操作。
- 包含每种基本数据类型的相关属性如最大值、最小值等,以及相关的操作方法(这些操作方法的作用是在基本数据类型、包装类对象、字符串之间提供相互之间的转化!)。
以下例子归纳了包装类的常用用法,别的不常用的方法可以查看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的使用区别
- String:不可变字符序列。
- StringBuffer:可变字符序列,并且线程安全,但是效率低。
- 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); } }
- 注意事项
- 注意月份的表示,一月是0,二月是1,以此类推,12月是11。 因为大多数人习惯于使用单词而不是使用数字来表示月份,这样程序也许更易读,父类Calendar使用常量来表示月份:JANUARY、FEBRUARY等等。
- 周日代表的是一周的第一天
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 }