java的常用类
基本数据类型的包装类
包装类基本知识
-
为什么需要 包装类(Wrapper Class)
JAVA并不是纯面向对象的语言。Java语言是一个面向对象的语言,但是Java中的基本数据类型却
是不面向对象的。但是我们在实际使用中经常需要将基本数据转化成对象,便于操作。比如:
集合的操作中。 这时,我们就需要将基本类型数据转化成对象! -
包装类均位于java.lang包,包装类和基本数据类型的对应关系:
基本数据类型 包装类 byte Byte boolean Boolean short Short char
Character
int
Integer
long Long float Float double Double -
Number类(抽象类,包含6个基本数据类型6个方法)
包装类的用途
对于包装类来说,这些类的用途主要包含两种
- 作为和基本数据类型对应的类型存在,方便涉及到对象的操作,如Object[]、集合等
的操作。 - 包含每种基本数据类型的相关属性如最大值最小值等,以及相关的操作方法(这些操作方法的作用是在基本数据类型、包装类对象、字符串之间提供相互之间的转化!)
public class TestWraperClass {
public static void main(String[] args) {
//基本数据类型转为对象
Integer i = new Integer(300);
Integer i2 = Integer.valueOf(20);//官方推荐这种写法
//包装类对象转为基本数据类型
double d = i2.doubleValue();
//将字符串数字转成包装类对象
Integer i3 = Integer.valueOf("2342");
Integer i4 = Integer.parseInt("334");
//将包装类对象转成字符串
String str = i3.toString();
//一些常用的常量
System.out.println(Integer.MAX_VALUE);
System.out.println(Integer.MIN_VALUE);
}
}
自动装箱和拆箱
- 自动装箱-boxing
- 基本类型就自动地封装到与它相同类型的包装中,如:
- Integer i = 100;
- 本质上是,编译器编译时为我们添加了:
- Integer i = Integer.valueOf(100);
- 自动拆箱autounboxing
- 包装类对象自动转换成基本类型数据。如:
- int a = new Integer(100);
- 本质上,编译器编译时为我们添加了:
- int a = new Integer(100).intValue();
public class TestWraperClass {
public static void main(String[] args) {
//自动装箱
Integer a = 300; //编译器帮你改成:Integer a = Integer.valueOf(300);
//自动拆箱
int b = a; //编译器帮你改成:a.intValue();
Integer c = null;
//int c2 = c; //编译器帮你改成:c.intValue();
// java.lang.NullPointerException:对象为null,我们调用了他的属性或方法
}
}
包装类的缓存问题
public class TestWraperClass {
public static void main(String[] args) {
//包装类的缓存问题
Integer d1 = 4000;
Integer d2 = 4000;
//当数字在[-128,127]之间的时候,返回缓存数组中的某个元素。
Integer d3 = 123;
Integer d4 = 123; //Integer.valueOf(123)
System.out.println(d1==d2); //两个不同的对象!
System.out.println(d3==d4); //两个不同的对象!
System.out.println(d1.equals(d2));
}
}
//结果:
//false
//true
//true
自定义一个包装类
/**
* 定义一个简单的包装类,并不难!!!
*/
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);
}
}
字符串相关类
String类、StringBuilder类、StringBuffer类 是三个字符串相关类。String类是的对象代表不可变的字符序列,StringBuilder类和StringBuffer类代表可变字符序列。关于这三个类详细的用法,在笔试面试以及实际开发中经常用到。
String类不可变,StringBuilder类(线程效率高,不安全)、StringBuffer类(线程效率低,安全) 可变
String类源码分析
-
Java字符串就是Unicode字符序列,例如串“Java”就是4个Unicode字符J,a,v,a组成的。
-
Java允许使用符号"+"把两个字符串连接起来
public static void main(String[] args){
//编译器做了优化直接在编译的时候将字符串进行拼接
String str1 = "hello" +" java";//相当于str1 = "hello java";
String str2 = "hello java";
System.outprintln(str1 == str2)://true
String str3 = "hello";
String str4 =" java";
//编译的时候不知道变量中存储的是什么所以没办法在编译的时候优化
String str5 =str3+str4;
System.outprintln(str2==str5)://false
}
- String类的常用方法1
方法 | 描述 |
---|---|
char charAt(int index) | 返回字符串中第index个字符 |
boolean equals(String other) | 如果字符串与other相等,返回true |
boolean equalsIgnoreCase(String other) | 如果字符串与other相等(忽略大小写),则返回true |
int indexOf(String str, int fromIndex) | 从当前fromIndex位置往从左往右查找最前一个 |
int lastIndexOf(String str, int fromIndex) | 从当前fromIndex位置往从右往左查找最后一个 |
int length() | 返回字符串的长度 |
String replace(char oldChar,char newChar) | 返回一个新串,它是通过用 newChar 替换此字符串中出现的所有oldChar而生成的 |
- String类的常用方法2
方法 | 描述 |
---|---|
boolean startsWith(String prefix) | 如果字符串以prefix开始,则返回true |
boolean endsWith(String prefix) | 如果字符串以prefix结尾,则返回true |
String substring(int beginIndex) | 从指定索引截取到结尾 |
String substring(int beginIndex,int endIndex) | 返回一个新字符串,该串包含从原始字符串beginIndex到串尾或endIndex-1的所有字符 |
String toLowerCase() | 返回一个新字符串,该串将原始字符串中的所有大写字母改成小写字母 |
String toUpperCase() | 返回一个新字符串,该串将原始字符串中的所有小写字母改成大写字母 |
String trim() | 返回一个新字符串,该串删除了原始字符串头部和尾部的空格 |
- 字符串相等的判断(一般使用equals方法)
public class StringTest3 {
public static void main(String[] args) {
String s1 = "abc";
String s2 = "abc";
String s3 = new String("abc");
String s4 = new String("abc");
System.out.println(s1==s2); //true
System.out.println(s1==s3); //false
System.out.println(s3==s4); //false
}
}
StringBuffer和StringBuilder
常用方法列表
- 重载的public StringBuilder append(…)方法
可以为该StringBuilder对象添加字符序列,仍然返回自身对象。 - 方法public StringBuilder delete(int startint end)
可以删除从start开始到end-1为止的一段字符序列,仍然返回自身对象。 - 方法public StringBuilder deleteCharAt(intindex)
移除此序列指定位置上的char,仍然返回自身对象。 - 重载的public StringBuilder insert(…)方法
可以为该StringBuilder对象在指定位置插入字符序列,仍然返回自身对象 - 方法 public StringBuilder reverse
用于将字符序列逆序,仍然返回自身对象。 - 方法publicStringtoString() 返回此序列中数据的字符串表示形式。
- 和String类含义类似的方法:
public int indexOf(String str)
public int indexOf(String str.int fromindexk public String substring(int start)
public String substring(int start,int end) public int length0
char charAt(int index)
public class TestString {
public static void main(String[] args) {
String str = "aabb"; //不可变字符序列
StringBuilder sb = null; //可变字符序列,线程不安全,效率高
StringBuffer sb2 = null; //可变字符序列,线程安全,效率低
sb = new StringBuilder("gao");
sb.append(123);
sb.append(456);
System.out.println(sb);
sb.append("aa").append("bb").append("cc");
for(int i=0;i<10;i++) {
sb.append(i);
}
System.out.println(sb);
/**StringBuffer,下面的方法同样适用StringBuilder*/
sb2 = new StringBuffer("zxlzxl");
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());//字符串逆序
}
}
不可变和可变字符序列使用陷阱
-
String使用陷阱
-
string s=“a”;//创建了一个字符串
s=s+“b”;//实际上原来的"a"字符串对象已经丢弃了,现在又产生了一个字符串s+“b”。如果多次执行这些改变串内容的操作,会导致大量副本字符串对象存留在内存中,降低效率。如果这样的操作放到循环中,会极大影响程序的性能。
-
package com.bjsxt.test;
/**
* 测试String和StringBuilder在频繁修改字符串时的效率问题
*/
public class TestString2 {
public static void main(String[ ] args) {
/**使用String进行字符串的拼接*/
String str8 = "";
//本质上使用StringBuilder拼接, 但是每次循环都会生成一个StringBuilder对象
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));
}
}
时间处理相关类
我们用long类型的变量来表示时间,从基准时间往前几亿年,往后几亿年都能表示,如果想后的现在时刻的“时刻数值”,可以使用:
long now = System.currentTimeMills();
public class TestDate {
public static void main(String[] args) {
long a = Long.MAX_VALUE/(1000L*3600*24*365);//加L避免1000*3600*24*365溢出
System.out.println(a); //大约表示到:2.9亿年后
long nowNum = System.currentTimeMillis(); //代表当前时刻的毫秒数
System.out.println(nowNum);
}
}
这个“时刻数字”是所有时间类的核心值,年月日都是根据这个“数值”计算出来的,我们工作学习涉及的时间相关类有如下这些:
Date时间类
public class TestDate {
public static void main(String[] args) {
Date d1 = new Date(); //如果没有传参,代表当前时刻
System.out.println(d1);
System.out.println(d1.getTime());//返回d1时间的毫秒数
Date d2 = new Date(1000L*3600*24*365*250);
System.out.println(d2);
}
}
-
Date类构造方法
Date() 分配 Date 对象并初始化此对象,以表示分配它的时间(精确到毫秒)。以本机时间为准。
Date(long date) 分配 Date 对象并初始化此对象,以表示自从标准基准时间(称为“历元(epoch)”,即 1970 年 1 月 1 日 00:00:00 GMT)以来的指定毫秒数。例:Date date1=new Date(10000000000L); 指历元后的10000000000毫秒所表示的时间。 -
Date类常用方法
方法 描述 boolean after(Date when) 测试此日期是否在指定日期之后。 boolean before(Date when) 测试此日期是否在指定日期之前。 int compareTo(Date anotherDate) 比较两个日期的顺序。 如果参数 Date 等于此 Date,则返回值 0;如果此 Date 在 Date 参数之前,则返回小于 0 的值;如果此 Date 在 Date 参数之后,则返回大于 0 的值。 boolean equals(Object obj) 比较两个日期是否相等。 long getTime() 返回自 1970 年 1 月 1 日 00:00:00 GMT 以来此 Date 对象表示的毫秒数。 void setTime(long time) 设置此 Date 对象,以表示 1970 年 1 月 1 日 00:00:00 GMT 以后 time 毫秒的时间点。 String toString() 把此 Date 对象转换为以下形式的 String: dow mon dd hh:mm:ss zzz yyyy
DateFormat类和SimpleDateFormat类
-
DateFormat类的作用
把时间对象转化成指定格式的字符串。反之,把指定格式的字符串转化成时间对象。DateFormat是一个抽象类,一般使用它的子类SimpleDateFormat类来实现。
import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; /** * 测试时间对象和字符串的互相转化 * 使用:DateFormat抽象类、SimpleDateFormat实现类 */ public class TestDateFormat { public static void main(String[] args) throws ParseException { // SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); SimpleDateFormat df = new SimpleDateFormat("yyyy年MM月dd日 hh时mm分ss秒"); //将字符串转成Date对象 // Date d1 = df.parse("1971-3-10 10:40:52"); Date d1 = df.parse("1971年3月10日 10时40分52秒"); System.out.println(d1.getTime()); //将Date对象转成字符串 Date d2 = new Date(1000L*3600*23); String str = df.format(d2); System.out.println(str); DateFormat df2 = new SimpleDateFormat("今年第w周,今年的第D天"); System.out.println(df2.format(d2)); } }
Calendar日历类
Calendar类是一个抽象类,为我们提供了关于日期计算的相关功能,比如:年、月、日、时、分、秒的展示和计算
GregorianCalendar是Calendar的一个具体子类,提供了世界上大多数国家/地区使用的标准日历系统
注意:
月份的表示,一月是0,二月是1,以此类推,十二月是11.因为大多数人习惯使用单词而不是使用数字来表示月份,这样程序也许更易懂,父类Calendar使用常量来表示月份:JANUARY、FEBRUARY表示
import java.util.*;
public class TestCalendar {
public static void main(String[ ] args) {
// 得到相关日期元素
GregorianCalendar calendar = new GregorianCalendar(2999, 10, 9, 22, 10, 50);
int year = calendar.get(Calendar.YEAR); // 打印:1999
int month = calendar.get(Calendar.MONTH); // 打印:10
int day = calendar.get(Calendar.DAY_OF_MONTH); // 打印:9
int day2 = calendar.get(Calendar.DATE); // 打印:9
// 日:Calendar.DATE和Calendar.DAY_OF_MONTH同义
int date = calendar.get(Calendar.DAY_OF_WEEK); // 打印:3
// 星期几 这里是: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, 2999);
calendar2.set(Calendar.MONTH, Calendar.FEBRUARY); // 月份数:0-11
calendar2.set(Calendar.DATE, 3);
calendar2.set(Calendar.HOUR_OF_DAY, 10);
calendar2.set(Calendar.MINUTE, 20);
calendar2.set(Calendar.SECOND, 23);
printCalendar(calendar2);
// 日期计算
GregorianCalendar calendar3 = new GregorianCalendar(2999, 10, 9, 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);
}
}
Math类
java.lang.Math提供了一系列静态方法用于科学计算;其方法的参数和返回值类型-般为double型。如果需要更加强大的数学运算能力,计算高等数学中的相关内容,可以便用apache commons下面的Math类库
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) 角度->弧度
Random类
Math类中虽然为我们提供了产生随机数的方法Mathrandom,但是通常我们需要的随机数范围并不是[0,1)之间的double类型的数据,这就需要对其进行一些复杂的运算。如果使用Math.random()计算过于复杂的话,我们可以使用例外一种方式得到随机数,即 Random类,这个类是专门用来生成随机数的,并且Math.random()底层调用的就是 Random的nextDouble()方法
import java.util.Random;
public class TestRandom (
public static void main(String[] args){
Random rand = new Random0;
//随机生成[0,1)之间的double类型的数据
System.outprintln(rand.nextDouble0);
//随机生成int类型允许范围之内的整型数据
System.outprintIn(rand.nextInt));
//随机生成[0,1)之间的float类型的数据
System.outprintln(rand.nextFloat());
//随机生成false或者true
System.outprintln(rand.nextBoolean0);
//随机生成[0,10)之间的int类型的数据
System.outprint(rand.nextlnt(10));
//随机生成[20,30)之间的int类型的数据
System.outprint(20 + rand.nextInt(10));
//随机生成[2030)之间的int类型的数据(此种方法计算较为复杂)
System.outprint(20+(int)(rand.nextDouble()*10));
}
}
File类
File类用来代表文件和目录
File类的基本用法
java.io.File类:代表文件和目录。 在开发中,读取文件、生成文件删除文件、修改文件的属性时经常会用到本类。
- File类的常见构造方法:public File(String pathname)
以pathname为路径创建File对象,如果pathname是相对路径,则默认的当前路径在系统属性user.dir中存储
import java.io.File;
import java.io.IOException;
import java.util.Date;
public class TestFile {
public static void main(String[] args) throws IOException {
File f1 = new File("d:/movies/功夫熊猫.mp4");
// File f1 = new File("d:\\movies\\功夫熊猫.mp4");
File f2 = new File("d:/movies");
System.out.println(System.getProperty("user.dir")); //项目的路径
File f3 = new File(System.getProperty("user.dir"));
f1.createNewFile();
System.out.println("File是否存在:"+f1.exists());
System.out.println("File是否是目录:"+f1.isDirectory());
System.out.println("File是否是文件:"+f1.isFile());
System.out.println("File最后修改时间:"+new Date(f1.lastModified()));
System.out.println("File的大小:"+f1.length());
System.out.println("File的文件名:"+f1.getName());
System.out.println("File的目录路径:"+f1.getPath());
File f4 = new File("D:/movies/大陆/学习/编程/java/朱相龙");
f4.mkdirs();
// f4.delete();
}
}
递归遍历目录结构和树状展示
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("-");
}
//输出文件名
//if(file.isDirectory()||file.getName().toLowerCase().endsWith(".md")) //{
//文件名字过滤
System.out.println(file.getName());
// }
//如果file是目录,则获取子文件列表,并对每个子文件进行相同的操作
if (file.isDirectory()) {
File[ ] files = file.listFiles();
for (File temp : files) {
//递归调用该方法:注意等+1
printFile(temp, level + 1);
}
}
}
}
枚举
enum 枚举名{
枚举体(常量列表);
}
所有的枚举类型隐形地继承自java.lang.Enum。枚举实质还是类!而每个被枚举的成员实质就是一个枚举类型的实例,他们默认都是public static final修饰的,可以直接通过枚举类型名使用它们。
import java.util.Random;
public class TestEnum {
public static void main(String[] args) {
System.out.println(Season.AUTUMN);
// 枚举遍历
for (Week k : Week.values()) { //values()返回的:Week[] 里面包含了所有的枚举元素
System.out.println(k);
}
Week[] ws = Week.values();
System.out.println(ws[1]);
int a = new Random().nextInt(4); //0,1,2,3 //(int)(Math.random()*4)
switch (Season.values()[a]){
case SPRING:
System.out.println("春天");
break;
case SUMMNER:
System.out.println("夏天");
break;
case AUTUMN:
System.out.println("秋天");
break;
case WINTER:
System.out.println("冬天");
break;
}
}
}
enum Season{
SPRING,SUMMNER,AUTUMN,WINTER
}
enum Week {
星期一,星期二,星期三,星期四,星期五,星期六,星期日
}