今天头痛,有可能感冒了,学的少了一点,但是应该坚持的学,一旦间断,有可能就停下啦。加油!
1、自动装箱、自动拆箱
这两个机制是为了减小程序员的压力吧。
有时候需要定义数值型的对象,以Int为例,可以用一个叫做Integer的类声明数值型的对象。感觉也比较简单,要理解的东西都放在注释里了。
public class TestAtuoBoxing {
public static void main(String[] args) {
Integer a=234;//Integer a=Integer.valueof(234)自动装箱
int b=a;//编译器会修改成int b=a.intValue();自动拆箱
Integer c=null;
//int d=c;//自动拆箱,调用了c.intValue();空指针
if (c!=null) {//加判断防止异常
int d=c;
}
//缓存[-128,127]之间的数字,实际就是系统初始的时候创建了[-128,127]之间的一个缓存数组
//当我们调用valueof()的时候,首先检查时候在[-128,127]之间,如果在这个范围则直接从缓存数组中拿出来已经缓存数组中拿出已经建好的对象
//如果不在这个范围,则创建新的Integer对象
Integer in1=-128;
Integer in2=-128;
System.out.println(in1==in2);//true,因为[-128,127]之间的数字是在缓存数组中,用的时候可以直接取
System.out.println(in1.equals(in2));//true
System.out.println("*******************************");
Integer in3=1234;
Integer in4=1234;
System.out.println(in3==in4);//false ,in3和in4是不同的对象。并且1234超出了[-128,127]的范围,不能直接从缓存数组中取出来
System.out.println(in3.equals(in4));//true
}
}
2、字符串
String类定义的字符串其实是放在一个char[]数组中,而这个数组被final修饰,所以String不能更改。之前,我写过这样的程序
String a="abc";
a="cbd";
这样不会报错,通过今天的学习,我发现,虽然不会报错,但是对象被更改了,在实验中,我打印出来地址,他俩是不一样的,证明是两个对象。
public class TestString {
public static void main(String[] args) {
String str="abcdefg";// private final char value[];有final,修饰,不能更改,要变得话没救新建对象
System.out.println(Integer.toHexString(str.hashCode()));
System.out.println(str);
str="hijklmn";//这样虽然不会出错,但是实际上已经将str的对象改变了,这样会给str一个新的对象
System.out.println(Integer.toHexString(str.hashCode()));//经过验证,地址改变了,说明对象变了
System.out.println(str);
String s1=new String("opqxyz");
String s2=s1.substring(2,4);
System.out.println(Integer.toHexString(s1.hashCode()));//hashcode :JDK根据对象的地址或字符串或数字算出来的int类型的数值
System.out.println(Integer.toHexString(s2.hashCode()));//返回的是不同的,表示这俩不是一个对象
//字符串比较的时候要用equals,尽量不用==
String str3="hello"+" java";//相当于str1="hello java";编译器做了优化,直接在编译的时候将字符串进行拼接
String str4="hello java";//这俩优化完了后,是一个对象
System.out.println(str3==str4);//true
String str5="hello";
String str6=" java";
//编译的时候,编译器不知道变量中存的是什么,所以没办法在编译的时候优化
String str7=str5+str6;
System.out.println(str4==str7);//false
//所以尽量使用equals,因为一般都是比较值,而不是比较对象是否是同一个
3、StringBuilder
StringBuilder定义的字符串没有用final修饰,也就是说,它是可变字符串。还有一个StringBuffer类,他俩的比较:StringBuilder线程不安全,效率高(一般用这个StringBuilder);StringBuffer线程安全,效率低。所以重点是Stringbuilder。
StringBuilder sb=new StringBuilder("abcdefg");//API文档:char[] value;没有finale修饰,可以更改
System.out.println(Integer.toHexString(sb.hashCode()));
System.out.println(sb);
sb.setCharAt(2, 'M');
System.out.println(Integer.toHexString(sb.hashCode()));
System.out.println(sb);//内容改变了,但是对象不会改变,还是这个对象,地址还是这个地址,所以内容可以随便修改
下面是StringBuilder的常用方法
StringBuilder sb=new StringBuilder();
for(int i=0;i<26;i++) {
sb.append((char)('a'+i));//字符串追加字符
}
System.out.println(sb);
sb.reverse();//将字符串倒叙
System.out.println(sb);
sb.setCharAt(2, '小');
System.out.println(sb);
sb.insert(4, '明');//插入字符
sb.insert(6, '爱').insert(8,'学').insert(10, '习');//因为insert()中存在return this;又将sb对象返回了,所以可以继续调用
System.out.println(sb);
sb.delete(20, 23).delete(10, 16);//delete();也使用了return this,所以也是可以继续调用的。删除区间的字符
System.out.println(sb);
4、字符串叠加的陷阱
直接使用字符串累加添加字符串的时候,会生成很多对象,有可能造成服务器崩溃
使用StringBuilder不会生成新对象,不对使用很多内存
首先用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对象和一个新的str的对象,所以是5000*2个对象
}
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));
结果
由此可见,之前我都是用错了。。。
5、Date类
Date是日期类,知道下面几种方法就行了
Date d=new Date();//什么都不传,返回当前时刻this(System.currentTimeMillis());
System.out.println(d);
Date d1=new Date(2000);//从1970年1月1日0:0:0:0后的2000ms
System.out.println(d1);
System.out.println(d.getTime());//获得从1970年1月1日0:0:0:0开始,到现在过去了多少ms
System.out.println(d1.after(d));//判断d1是不是在d后面
6、测试时间对象与字符串之间的转换
Date中一部分方法被停用了,但是有DateFormat类可以用,比如给时间给定“yyyy-MM-dd hh:mm:ss”这种格式。
但是DateFormat是抽象类,不能用new声明对象,所以用它的实现类SimpleDateFormat
DateFormat df=new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss");//因为DateFormat是抽象类,不能使用new创建对象,
//所以用它的实现类SimpleDateFormat
String str= df.format(new Date(400000000));//看一下从0时刻开始过400000000是什么时候
System.out.println(str);
DateFormat df2=new SimpleDateFormat("yyyy年MM月dd日 hh时mm分ss秒");
Date date=df2.parse("1983年06月01日 15时24分33秒");//这里必须跟上面的格式一致
System.out.println(date);
//测试其他的格式字符
DateFormat df3=new SimpleDateFormat("D");//今天是今年的多少天
//所以用它的实现类SimpleDateFormat
String str2= df3.format(new Date());//
System.out.println(str2);
7、日历类Calender
Calender也是个抽象类,所以要用他的实现类GregorianCalendar
//获得日期
Calendar calendar=new GregorianCalendar(2999,10,9,22,10,50);//2999年11月9日22时10分50秒
int year=calendar.get(calendar.YEAR);//获得这个对象year值
int month=calendar.get(calendar.MONTH);//获得月,10表示11月。0表示1月
int weekDay=calendar.get(calendar.DAY_OF_WEEK);//查看周几,1表示周日 2表示周一.。。。
System.out.println(year);
System.out.println(month);
System.out.println(weekDay);
System.out.println("********************************");
//设置日期
Calendar c2=new GregorianCalendar();//什么都不传,就生成当前的
System.out.println(c2);
c2.set(Calendar.YEAR, 8022);//设置到8022年
System.out.println(c2);
//日期的计算
Calendar c3=new GregorianCalendar();
c3.add(Calendar.DATE, 1000);//往后1000天
System.out.println(c3);
//日期对象和时间对象的转化
Date d4=c3.getTime();//日期类转时间对象
Calendar c4=new GregorianCalendar();
c4.setTime(new Date());//时间对象转日期类
printCalendar(c4);
写了一个将日历类对象打印成我们习惯的格式的方法
public static void printCalendar(Calendar c) {
int year=c.get(Calendar.YEAR);
int month=c.get(Calendar.MONTH)+1;
int date=c.get(Calendar.DAY_OF_MONTH);
int dayweek=c.get(Calendar.DAY_OF_WEEK)-1;
String dayweek2=dayweek==0?"日":dayweek+"";
int hour=c.get(Calendar.HOUR_OF_DAY);
int minute=c.get(Calendar.MINUTE);
int second=c.get(Calendar.SECOND);
System.out.println(year+"年"+month+"月"+date+"日 "+hour+":"+minute+":"+second+"秒 周"+dayweek2);
}