在实际开发工作中,我们会使用到一些操作,这些操作在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
}