1.常用类的学习方法(掌握) 类: 字段 重点掌握全局常量 方法(重重之重)
构造方法 学会查看api文档
2. 包装类(掌握)
3. String/StringBuffer/StringBuilder(掌握掌握掌握)
4.数字相关类(掌握)
5. System/Runtime/垃圾回收机制(了解)
实际开发中经常使用到一些类,比如数组的相关方法,字符串的相关方法等等,这些使用频率很高,Java就将常用的方法为我们封装好,为开发者省事、省时间,让开发者真正的去关心自己个人化的业务逻辑实现。所以我们需要学习常用类。
关键一点目的:要看懂人家这个类是干什么的,大致有哪些方法,知道怎么用。其次,可以借鉴人家的优秀思想和规范,进一步加强自己使用api的能力。
从类的成员入手:
构造方法 : 创建对象的,通过对象来调用方法
字段 : 重点关注全局常量
方法 : 重点中重点! 一个方法看成是一个功能
学习方法:api文档,注释,实例(看不懂就实际运行起来看结果帮助理解),互联网
就是基本数据类型对应的类。提供很多方法和字段,方便我们使用。
byte short int long float double char boolean==>都是小写,没有方法
Java语言是一个面向对象的语言,但是Java中的基本数据类型却是不面向对象的,这在实际使用时存在很多的不便,不能像对象一样拥有很对字段和方法。为了解决这个不足,在设计类时为每个基本数据类型设计了一个对应的类进行代表,这样八个类和基本数据类型对应的类统称为包装类(Wrapper
Class),包装类均位于java.lang包。先通过直观的代码看看int和Integer,演示一下Integer调用方法的方便性。
基本数据类型 | 包装类(可以在API文档中查询到) |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
装类型只是将对应基本数据类型封装成一个类而已。
包装类型比基本数据类型更方便操作,可以直接使用很多方法。
包装类型和其对应的基本数据类型表示的范围是一样的。
通过一个常用包装类Integer的学习,教会大家学习包装类的方法。主要是通过api文档来学习包装类的创建方式和常用方法的使用
Integer(int value)
Integer(String s)
为什么要提供这两种转换:
Integer i1 = **new** Integer(123);
Integer i2 = **new** Integer(“123”);
因为在项目很多时候从前台传输数据到后台几乎都是字符串的形式。比如:
我们本来想传一个字符串:”00”到后台,如果不是用字符串的形式的话,以数字传到后台的话,后台接收到的就是数字0,不是”00”.
排错方式2中
方式一:到API文档中查询什么意思 NumberFormatException
方式二:自己根据错误信息定位分析问题:
分析具体这行代码,哪些地方可能出错?
Integer integer = new Integer(“你给我转啊”);
1.为什么需要包装类?:
提供了很多方法和字段,方便我们开发中直接使用
2.基本数据类型和包装类对应关系?
包装类是基本数据类型的首字母大写,除了int和char ==》Integer Character
3.包装类的继承体系?
自己看图或者查文档,文档最为准确
4.解决错误两种方式?
①:通过exception的类名来定位代码
②通过自己的错误代码信息点击过去
把一个基本数据类型的数据赋值给一个其对应的包装类的过程
把一个包装类对象赋值给一个其对应的基本数据类型的变量的过程
1. 以int -- Integer为例
装箱
Integer i1 = new Integer(123);
拆箱
int i2 = i1.intValue();
Integer i1 = 123; 装箱
int i2 = new Integer(123); 拆箱
window—》preference—》javacompiler
Integer i1 = 123;
Double d1 = 123.0;
Integer integer1='a';; // 不行 ‘a’是char,对应的包装类是Character
String 是Java中写好的一个类: 描述一个字符串(一串字符)
很常用!!!
String s = “我是一个随便的字符串”;
通过调用String类的构造方法
String()
String(String str)
②String str2 = “”; //有一个对象,对象是空
③String str3 = new String();// 和②差不多
注意一下:在实际的开发中,我们会这样直接申明一个空的而不做任何事情么?绝对不会。所以呢,大家认识到这个就行了,主要是给大家演示加强一下==(值和地址都比较
)和equals(只关心值)。
System.out.println(str1==str2);
System.out.println(str1==str3);
System.out.println(*str1*.equals(str2));//尽量使用一个已知的值去和未知的值比较。尽可能的避免空指针异常。
System.out.println(str2==str3);
System.out.println(str2.equals(str3));
字符串对象引用都是存储在栈中的,如果是编译期已经创建好(直接用双引号定义的,表示这个值是已经确定的,已知的)的就存储在常量池中,如果是运行期(new出来的)才能确定的就存储在堆中。(注:编译期:就是我们的javac命令,运行期就是java。Eclipse是自动编译的,就是当我把代码写出来后,就运行了javac,生成了class文件。比如:Integer
i = new
Integer(“A”)这句代码,在我们的编译期不会出错,就是说写了这句代码没有报错(因为能够编译成class文件),但是运行起来后,就出错了。)
String str1=new String("abc");
String str2=new String("abc");
System.out.println(str1==str2);//true?false
System.out.println(str1.equals(str2)); //true?false
String str3="abc";
String str4="abc";
System.out.println(str3==str4); //true?false
System.out.println(str3.equals(str4)); //true?false
关于常量池的补充看代码:
String s="a";
String s1="b";
String str=s+s1;
String s2="a"+"b";//*ab*也在常量区
String s3="ab";
System.*out*.println(str==s3);//false
System.*out*.println(s2==s3);//true
解释:
分成两个部分来看。
String s2="a"+"b";//*a
和b都是确定的常量,在编译期就能确定就是字母a和字母b(确定的值不是只能是字母,只要是双引号引起来的,都是确定的)这句话编译期生成的class文件相当于String
s2=”ab”。如果这个时候常量池中没有ab,则在常量池中产生再将s2的引用指向常量池中ab,有就直接将s2的引用指向常量池中ab。所以不管怎么,结果就是常量池中有了ab这个常量*
String
s3="ab";//因为s2已经产生了ab常量,所以s3直接在常量池中就找到了,这个时候s2和s3都是指向了常量池中ab,所以s2==s3.
System.*out*.println(s2==s3);//true
String s="a";
String s1="b";//都是确定的值,所以在常量池中产生a和b两个常量。
String str=s+s1;
//因为String是一旦创建后就不可以改变的。这个+号操作就是说你在改变String
str=s,想把它改变成s+s1.
String s3="ab";//
System.*out*.println(str==s3);//false
最后记住一句话:这种对象的比较能懂就懂,不懂就算了,不要去想。实际开发中根本不会去想这些事情,没有一点用处。但是有些面试官喜欢(省略2个字)。放心,他们也说不清楚。
引用数据类型如果想比较值,使用equals
String类覆写了Object中的equals方法,比价的就是字符串的字面值
(对于实际开发没有一点意思)
将1到1000,1到10000,1到10w数字拼接起来,看看需要多少时间?
① 这3个类没有直接或者间接的继承关系(不是直系亲属)
StringBuffer sb = “1231432234455”; 报错
② 都表示字符序列(简单理解为字符串)
CharSequence (字符序列的接口)
|— String
|----StringBuffer
|----StringBuilder
③ 区别
String : 它的对象一旦被创建那么值和长度就固定不变了
StringBuffer : 它的对象内容是可以被改变的;
是线程安全的
版本是1.0
效率相对于比StringBuilder要低
StringBuilder : 它的对象内容是可以被改变的;
是线程不安全的
版本是 1.5
相当于StringBuffer效率更高一点
效率相对于比StringBuffer要高
① 这两个中的方法几乎是一样的;
② 上面3个都表示字符序列,因此有很多一样的方法(暂时就忽略)
③ 今天重点关注这两个中特有的方法: 更改对象中数据的方法
思考:
哪些操作可能会改变对象中的数据?
插入、替换、删除、追加。。。
================================
④ 构造方法:
StringBuilder()
构造一个不带任何字符的字符串生成器,其初始容量为 16 个字符。
初始容量什么意思?
StringBuilder(CharSequence seq)
构造一个字符串生成器,它包含与指定的 CharSequence 相同的字符。
new StringBuilder(“懂了吗?”)
new StringBuilder(new StringBuffer(“这下呢?”))
new StringBuilder(new StringBuilder(“。。。。”))
StringBuilder(int capacity)
构造一个不带任何字符的字符串生成器,其初始容量由 capacity 参数指定。
StringBuilder(String str)
⑤ 常用在方法:
StringBuilder append(....)
StringBuilder delete(int start, int end)
StringBuilder insert(插入点,插入的数据)
StringBuilder replace(int start, int end, String str)
StringBuilder reverse() 翻转
String substring(int start) 返回一个副本,本身的对象没有被改变
String substring(int start, int end) 返回一个副本,本身的对象没有被改变
类包含用于执行基本数学运算的方法,如初等指数、对数、平方根和三角函数
记住一点: 以后遇到1中的情况知道这里来找
能够表示比long更大的整数
long a=12333333333L;//没有超过大小
long a=1233333333333333333333333333333L;//超过大小了
它怎么去装更大的值(它是一个类啊)
是一个类,值太大了,你不能让我直接赋,就找构造方式创建
BigInteger b=new
BigInteger("9223372036854775807");//9223372036854775807是Long的最大值,new一个比它大1的数
两个BigInteger相加:
注意:在BigInteger中,不能直接使用+
-等运算符,已经写成了方法,请查看API文档。
BigInteger b1=new BigInteger("9223372036854775807");//
BigInteger b2=new BigInteger("9223372036854775807");//
System.out.println(b1.add(b2));//18446744073709551614
Integer 是int 的包装类,他们之间存在自动装箱拆箱,而和BigInteger没有任何关系
double
float浮点性小数,无限接近于结果,不精确。这个要看使用于什么场景,高科技呢?还有后面的单位呢?
double d1=0.02;
double d2=0.00002;
System.out.println(d1+d2);//0.02002
System.out.println(d1-d2);//0.01998
System.out.println(d1\*d2);//4.0000000000000003E-7
System.out.println(d1/d2);//999.9999999999999 不精确
BigDecimal 是一个对象,用new
BigDecimal d1=new BigDecimal(0.02);
BigDecimal d2=new BigDecimal(0.00002);
和BigInteger一样,不能直接使用±,已经定义成方法。请看API
BigDecimal d1=new BigDecimal(0.02);
BigDecimal d2=new BigDecimal(0.002);
System.out.println(d1.add(d2));//
System.out.println(d1.subtract(d2));//
System.out.println(d1.multiply(d2));//
System.out.println(d1.divide(d2));//
我们看到运算出来的结果也是不准确的,甚至直接出错了。为什么还是不精确的呢?怎么处理呢?
因为我们构造d1和d2的时候,就是传入的一个不精确的double值,结果肯定不精确。
我们可以采用传入精确的值:查看API构造方法,发现可以以字符串的形式传入:
BigDecimal d1=new BigDecimal("0.02");
BigDecimal d2=new BigDecimal("0.00002");
System.out.println(d1.add(d2));//0.02002
System.out.println(d1.subtract(d2));//0.01998
System.out.println(d1.multiply(d2));//4E-7
System.out.println(d1.divide(d2));//1E+3
1、基本数学运算的方法,如初等指数、对数、平方根和三角函数在哪里去找方法?
Math
2、BigInteger 和BigDecimal怎么运算?
①:是什么能干什么
BigInteger --》比long更大的数;
BigDecimal–》表示更精确的小数
②:怎么创建一个对象
都是通过构造函数;
BigDecimal–》想要结果精确,那么初始值就要精确–》new BigDecimal(String val)
③:怎么干
基本的+ - * /,要使用他们自身的方法
验证码,摇号,彩票,随机名字, 随机播放, 贪吃蛇的食物
5.2.2.1
Math类中有一个方法random
random()
返回带正号的 double 值,该值大于等于 0.0 且小于 1.0。
System.out.println(Math.random());//0.9468330747092099
如果要用这个方法,获取100以内的整数?乘以100得到0—100的小数,再取整。
5.2.2.2 Random类(有很多方法)
构造方法:
Random() 创建一个新的随机数生成器。 |
---|
Random(long seed) 使用单个 long 种子创建一个新的随机数生成器。 |
演示发现,如果使用了一个seed构造方法,每次得到的随机数是一样的。因为种子一样的嘛。那怎么办呢?我们是不是可以将种子搞成一个随机的呢?System.currentTimeMillis().其实看源码,发现无参的构造方法也是搞了一个随机的种子的。但是,即使这样,也可能会产生相同的值,计算机够快。
其他方法可以得到:nextInt(n)[0,n);
现在要获取x—y直接的int怎么办?我们关键是要确定这个n的值。n=y-x;
//获取3-7之间的随机整数
Random r=**new** Random();
//n=7-3=4
int m=r.nextInt(4);//得到m为0到n直接的值,最后再加上n-1
System.*out*.println(m+4-1);
问题:调用这个方法可以获得一个指定位数的随机字符串;其内容可以是 数字
大小写字母组成
4位随机数
分析思路:
①准备字符串:把所有数字和大小写字母放在一个字符串或者数组中
②在①中随机获取一个值
③遍历步骤②len次 ④返回结果
public static void main(String[] args) {
String random = getRandom(4);
System.out.println(random);
}
\* 思路分析: ①准备字符串:把所有数字和大小写字母放在一个字符串或者数组中
\* ②在①中随机获取一个值
\* ③遍历步骤②*len*次 ④返回结果
\* **\@param** len
\* **\@return**
public static String getRandom(int len) {
String s = "";
for (int i = 0; i \< len; i++) {
s += getOne();
}
return s;
}
private static String getOne() {
// ①准备字符串:把所有数字和大小写字母放在一个字符串或者数组中
String str="0123456789QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm";
// ②在①中随机获取一个值
//int r=ThreadLocalRandom.current().nextInt(0,str.length());
Random random = new Random();
int r=random.nextInt(str.length());
return String.valueOf(str.charAt(r));
}
闹钟,按照时间段来统计一些东西,支付订单上有时间,操作日志有时间
类 Date 表示特定的瞬间,精确到毫秒。在 JDK 1.1 之前,类 Date
有两个其他的函数。它允许把日期解释为年、月、日、小时、分钟和秒值。它也允许格式化和解析日期字符串。不过,这些函数的
API 不易于实现国际化.
闰秒. 格林威治标
5.3.2.1构造方法
Date(); 就表示当前系统时间对象
Date(long date) 根据指定的毫秒值创建一个指定的时间
Date d=new Date();
System.*out*.println(d);// Wed Apr 19 14:13:47 CST 2017
long time=System.*currentTimeMillis*();
Date d1=new Date(time);
System.*out*.println(d1);// Wed Apr 19 14:13:47 CST 2017
5.3.2.2普通方法
after(Date when) 测试此日期是否在指定日期之后。
before(Date when) 测试此日期是否在指定日期之前。
getTime() 返回自 1970 年 1 月 1 日 00:00:00 GMT 以来此 Date 对象表示的毫秒数。
setTime(long time) 设置此 Date 对象,以表示 1970 年 1 月 1 日 00:00:00 GMT 以后 time 毫秒的时间点。
5.3.2.3不直观的问题
直接打印Date对象 :Sat Apr 01 15:28:03 GMT+08:00
2017看起来不直观,用户体验不好。希望根据不同用户的需求显示不同的效果,怎么办?需要对结构进行格式化
2017-04-01 15:03:24
2017/04/01
2017年04月01日
作用一: 把一个Date对象可以转成我们希望的一个结果样式(字符串)
作用二: 也可以把一个字符串解析为一个Date对象
学习重点就是如何调用上面的提到的两个功能方法,注意怎么给他格式
SimpleDateFormat sdf=new SimpleDateFormat();
String p="yyyyMMdd HH:mm:ss";
sdf.applyPattern(p);
System.out.println(sdf.format(d1));
System.out.println(sdf.parse("20170420 14:33:26"));
日历:大家想到什么?可以看看我们电脑上的时间
日历,Calendar 类是一个抽象类,它为特定瞬间与一组诸如 YEAR、MONTH、DAY_OF_MONTH、HOUR 等 日历字段之间的转换提供了一些方法,并为操作日历字段(例如获得下星期的日期)提供了一些方法。
5.3.4.1字段:Calendar
类中有一些字段表示年 月 日 这些东西的标识
5.3.4.2常用方法:
①获取日历对象:static Calendar getInstance() 得一个日历。(是一个抽象类,外部和内部都不能new,不能创建对象。通过源码发现,是new 了一个子类赋值给Calendar中。)
② 获取指定字段值(年、月、日DAY_OF_MONTH等): int get(int field) 返回给定日历字段的值。
注意:月是从0—11,所以获取后需要+1
③ 设置指定字段值:set(int field,int value) 给指定的字段设置值。
这是一种重新赋值操作,会覆盖原来的值,会自动进位
④ 给指定字段增加或者减少值:add(int field,int amount) : 这个方法和set差不多,但是把amount的值累加到当前设置的字段原有的值之上
⑤使用指定时间创建一个Calendar: setTime(Date d) 可以直
接把一个Date设置进去
* 把 2033年3月4日 12:34:23 设置给日历:
* 分析:可以通过set方法一个个字段的设置,不建议。使用
* setTime(Date date)一个方法搞定。
* 步骤:
* ①把 字符串 "2033年3月4日 12:34:23" 转换成Date
* ②setTime设置
*/
String dateStr = "2033年3月4日 12:34:23";
SimpleDateFormat sdf = new SimpleDateFormat();
String pattern = "yyyy年MM月dd日 HH:mm:ss";
sdf.applyPattern(pattern);
Date date = sdf.parse(dateStr);
Calendar c = Calendar.getInstance();
c.setTime(date);
System.out.println(c.get(Calendar.YEAR) + "年"
+ (c.get(Calendar.MONTH) + 1) + "月"
+ c.get(Calendar.DAY_OF_MONTH) + "日"
+ c.get(Calendar.HOUR_OF_DAY) + ":" + c.get(Calendar.MINUTE)
+ ":" + c.get(Calendar.SECOND));
⑥ 获取一个Date对象:Date getTime() 可以获得日历对象中的当前日期对象
简单理解为,当我们对象失去所有的引用的时候
jvm回收垃圾是有自己的机制,不定时,随机的。说白了,就是你不知道jvm到底什么时候进行回收。但是我们也可以主动调用方法,但是呢,即使我们主动了,也不一定说jvm就马上进行垃圾回收,也是一个随机的事情,我们只是说自己去对垃圾回收这个事情进行了努力。
举一个例子:保洁机制。
源码时代,每天会产生很多烟头,纸屑等垃圾,有专门的保洁阿姨叔叔负责。他们有他们自己的一套保洁机制,比如早上大家上课前打扫一次,晚上大家下班打扫一次。
而此时此刻,就是now,现在,我们有一张纸屑没用了,丢地上了,它就变成了垃圾。也就是说,现在我们产生了垃圾,但是,现在保洁阿姨来收垃圾没有?没有!!!!也就是说,垃圾可能随时参数,但是不是产生垃圾了,马上就会被回收。但也有可能正好此时,保洁阿姨就在所清洁,马上就收走这个垃圾,所以垃圾的回收是不定时,随机的。
假如此时保洁阿姨没有来做,我们又继续产生了垃圾,哎呀,我自己都看不下去了。咋个办?此时,我们可以打电话给阿姨,主动请阿姨来进行保洁回收。也就是说,我们可以自己主动回收垃圾。
但是,是不是打了电话,阿姨就马上来回收垃圾了???不一定,可能这个时候阿姨在午休,需要2个小时后才来,可能阿姨在其他地方,需要更多时间后才来。只是说,我通知了阿姨,我努力了,至于到底什么时候回收垃圾,不确定!!!!
在Java中提供了两个方法和垃圾回收相关的
Object 中
finalize()
:所有的对象上都可以调用此方法,当这个对象被回收的时候就会调用此方法
System 中的 gc()
: 调用此方法表示我们做了一些努力来回收垃圾
怎么测试看效果?
创建一个GcTest类,覆写Object的finalize()方法,打印一些内容出来,便于我们看效果。然后创建另一个Test类,测试的时候循环创建多个GcTest匿名对象,看看会不会执行垃圾回收机制。我们也可以主动调用gc方法进行垃圾回收。
//覆写Object的finalize方法
public class GcTest {
public static Integer count = 0;
@Override
protected void finalize() throws Throwable {
// TODO Auto-generated method stub
super.finalize();
System.out.println("我被回收了。。。。"+count++);
}
}
Jvm自己回收
public class Test {
public static void main(String[] args) {
//参数垃圾
for (int i = 0; i < 100000; i++) {
new Test();
}}
}
人工主动回收
public class Test {
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Test();
System.gc();//主动回收
}
}
}
每个 Java 应用程序都有一个 Runtime
类实例,使应用程序能够与其运行的环境相连接。可以通过 getRuntime
方法获取当前运行时。
应用程序不能创建自己的 Runtime 类实例。为什么?请自己看源码
Runtime.getRuntime().exec(“notepad”);
可以指向字符串命令:必须放在c:\windows\system32
Runtime:不能实例化自己,构造函数私有化的。
可以指向字符串命令:必须放在c:\windows\system32
除了垃圾回收机制,Runtime,其它都是重点
没有,但是记得东西太多了,所以希望你们多去练习一下
public static void main(String[] args) {
String s1="AAA";
String s2="KKK";
StringBuffer sb1=new StringBuffer("QQQ");
StringBuffer sb2=new StringBuffer("JJJ");
change(s1,s2,sb1,sb2);
System.out.println("改变后s1="+s1);//
System.out.println("改变后s2="+s2);//
System.out.println("改变后sb1="+sb1);//
System.out.println("改变后sb2="+sb2);//
}
private static void change(String s1, String s2, StringBuffer sb1,
StringBuffer sb2) {
s1="XXX";
s2=s2.concat("666");
sb1.append("999");
sb2=sb2.append("777");
System.out.println("改变中s1="+s1);//
System.out.println("改变中s2="+s2);//
System.out.println("改变中sb1="+sb1);//
System.out.println("改变中sb2="+sb2);//
}