java零基础Ⅱ-- 4.常用类
一、包装类
包装类的分类
- 针对八种基本数据类型相应的引用类型 – 包装类
- 有了类的特点,就可以调用类中的方法
基本数据类型 | 包装类 |
---|---|
boolean | Boolean |
char | Character |
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
源码:
boolean --->Boolean
package java.lang;
public final class Boolean implements java.io.Serializable,
Comparable<Boolean>
{...
char ---> Character
package java.lang;
public final
class Character implements java.io.Serializable, Comparable<Character> {
byte ---> Byte
package java.lang;
public final class Byte extends Number implements Comparable<Byte> {
short ---> Short
package java.lang;
public final class Short extends Number implements Comparable<Short> {
int ---> Integer
package java.lang;
public final class Integer extends Number implements Comparable<Integer> {
long ---> Long
package java.lang;
public final class Long extends Number implements Comparable<Long> {
float ---> Float
package java.lang;
public final class Float extends Number implements Comparable<Float> {
double ---> Double
package java.lang;
public final class Double extends Number implements Comparable<Double> {
包装类和基本数据的转换
演示 包装类 和 基本数据类型的相互转换,这里以 int 和 Integer演示。
1)jdk5 前的手动装箱和拆箱方式,装箱:基本类型 --> 包装类型,反之,拆箱
2)jdk5 以后(含jdk5)的自动装箱和拆箱方式
3)自动装箱底层调用的是valueOf方法,比如:Integer.valueOf()
4)其它包装类的用法类似
演示
package com.zzpwdu.wrapper;
public class Integer01 {
public static void main(String[] args) {
//演示int <--> Integer 的装箱和拆箱
//jdk5前是 手动装箱和拆箱
//手动装箱 int --> Integer
int n1 = 100;
Integer integer = new Integer(n1);
Integer integer1 = Integer.valueOf(n1);
//手动拆箱
// Integer --> int
int i = integer.intValue();
//jdk5后(包含),就可以自动装箱和自动拆箱
int n2 = 200;
//自动装箱 int --> Integer
Integer integer2 = n2;//底层使用的是 Integer.valueOf(n2);
//自动拆箱 Integer --> int
int n3 = integer2;//底层仍然使用的是 integer2.intValue();
}
}
测试题
下面代码是否正确:
Double d = 100d;//ok,自动装箱 Double.valueOf(100d);
Float f = 1.5f;//ok,自动装箱 Float.valueOf(1.5f);
如下两个题目输出结果相同吗?各是什么?
Object obj1 = true? new Integer(1) : new Double(2.0);//三元运算符【是一个整体】
System.out.println(obj1);//1.0 因为后面有Double类型
Object obj2;
if(true){
obj2 = new Integer(1);
}else{
obj2 = new Double(2.0);
}
System.out.println(obj2);//1 ,分别计算
public class WrapperException01 {
public static void main(String[] args) {
Double d = 100d;//ok,自动装箱 Double.valueOf(100d);
Float f = 1.5f;//ok,自动装箱 Float.valueOf(1.5f);
Object obj1 = true? new Integer(1) : new Double(2.0);//三元运算符【是一个整体】
System.out.println(obj1);//1.0 因为后面有Double类型
Object obj2;
if(true){
obj2 = new Integer(1);
}else{
obj2 = new Double(2.0);
}
System.out.println(obj2);//1 ,分别计算
}
}
===========控制台输出=============
1.0
1
包装类型和String类型的相互转换
案例演示,以Integer 和 String 转换为例,其它类似:
// 包装类型 -------> String类型
Integer i = 100;
// 方式1
String s1 = i.toString();
// 方式2
String s2 = String.valueOf(i);
// 方式3
String s3 = i + "";
System.out.println(s3);
// String ------> 包装类
// 方式1
Integer j = new Integer(s1);
// 方式2
Integer j2 = Integer.valueOf(s2);
public class WrapperVSString {
public static void main(String[] args) {
//包装类(Integer) --> String
Integer i = 100;//自动装箱
//方式1
String str1 = i + "";
//方式2
String str2 = i.toString();
//方式3
String str3 = String.valueOf(i);
//String -> 包装类(Integer)
String str4 = "1234";
Integer i2 = Integer.parseInt(str4);//使用到自动装箱
Integer i3 = new Integer(str4);//构造器
System.out.println("ok~");
}
}
Integer类和Character类的常用方法
Integer 类和 Character 有些常用的方法,我们一起来使用一下
System.out.println(Integer.MIN_VALUE);//返回最小值 -2147483648
System.out.println(Integer.MAX_VALUE);//返回最大值 2147483647
System.out.println(Character.isDigit('a'));//判断是不是数字 false
System.out.println(Character.isLetter('a'));//判断是不是字母 true
System.out.println(Character.isUpperCase('a'));//判断是不是大写 false
System.out.println(Character.isLowerCase('a'));//判断是不是小写 true
System.out.println(Character.isWhitespace('a'));//判断是不是开个 false
System.out.println(Character.toUpperCase('a'));//转成大写 A
System.out.println(Character.toLowerCase('A'));//转成小写 a
Integer类面试题1
看看下面代码,输出什么结果?为什么?
public void method1(){
Integer i = new Integer(1);
Integer j = new Integer(1);
System.out.println(i == j);//false
Integer m = 1;//底层是 Integer.valueOf(1)
Integer n = 1;//底层是 Integer.valueOf(1)
//所以,这里主要看范围 -128 ~ 127 就是直接返回
/*
源码:
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)//-128 到 127
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
*/
System.out.println(m == n);//turn
//所以,这里主要看范围 -128 ~ 127 就是直接返回
//否则,就 new Integer(i);
Integer x = 128;//底层是 Integer.valueOf(1)
Integer y = 128;//底层是 Integer.valueOf(1)
System.out.println(x == y);//false
}
public class WrapperException02 {
public static void main(String[] args) {
Integer i = new Integer(1);
Integer j = new Integer(1);
System.out.println(i == j);//false
Integer m = 1;//底层是 Integer.valueOf(1)
Integer n = 1;//底层是 Integer.valueOf(1)
//所以,这里主要看范围 -128 ~ 127 就是直接返回
/*
解读源码:
1.如果i在 IntegerCache.low(-128)~IntegerCache.high(127),就直接从缓存数组返回
2.如果不在 -128~127,就直接 new Integer(i)
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)//-128 到 127
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
*/
System.out.println(m == n);//turn
//所以,这里主要看范围 -128 ~ 127 就是直接返回
//否则,就 new Integer(i);
Integer x = 128;//底层是 Integer.valueOf(1)
Integer y = 128;//底层是 Integer.valueOf(1)
System.out.println(x == y);//false
}
}
===========控制台输出=============
false
true
false
Integer类面试题总结
看看下面代码,输出什么结果
// 实例一
Integer i1 = new Integer(127);
Integer i2 = new Integer(127);
System.out.println(i1 == i2);//false
// 实例二
Integer i3 = new Integer(128);
Integer i4 = new Integer(128);
System.out.println(i3 == i4);//false
// 实例三
Integer i5 = 127;//底层是 Integer.valueOf(127)
Integer i6 = 127;//-128~127
System.out.println(i5 == i6);//true
// 实例四
Integer i7 = 128;
Integer i8 = 128;
System.out.println(i7 == i8);//false
// 实例五
Integer i9 = 127;//底层是 Integer.valueOf(127)
Integer i10 = new Integer(127);
System.out.println(i9 == i10);//false
// 实例六
Integer i11 = 127;
int i12 = 127;
//只要有基本数据类型,判断的是值是否相等
System.out.println(i11 == i12);//true
// 实例七
Integer i13 = 128;
int i14 = 128;
System.out.println(i13 == i14);//true
public class WrapperException03 {
public static void main(String[] args) {
// 实例一
Integer i1 = new Integer(127);
Integer i2 = new Integer(127);
System.out.println(i1 == i2);//false
// 实例二
Integer i3 = new Integer(128);
Integer i4 = new Integer(128);
System.out.println(i3 == i4);//false
// 实例三
Integer i5 = 127;//底层是 Integer.valueOf(127)
Integer i6 = 127;//-128~127
System.out.println(i5 == i6);//true
// 实例四
Integer i7 = 128;
Integer i8 = 128;
System.out.println(i7 == i8);//false
// 实例五
Integer i9 = 127;//底层是 Integer.valueOf(127)
Integer i10 = new Integer(127);
System.out.println(i9 == i10);//false
// 实例六
Integer i11 = 127;
int i12 = 127;
//只要有基本数据类型,判断的是值是否相等
System.out.println(i11 == i12);//true
// 实例七
Integer i13 = 128;
int i14 = 128;
System.out.println(i13 == i14);//true
}
}
===========控制台输出=============
false
false
true
false
false
true
true
二、String类
String类的理解和创建对象
1)String 对象用于保存字符串,也就是一组字符序列
2)字符串常量对象是用双引号括起的字符序列。例如:“你好”,“12.97”,"boy"等
3)字符串的字符使用Unicode字符编码,一个字符(不区分字母还是汉字)占两个字节
4)String类较常用构造器方法
- String s1 = new String();
- String s2 = new String(String original);
- String s3 = new String(char[] a);
- String s4 = new String(char[] a, int startIndex, int count);
- String s5 = new String(byte[] b);
- 说明
package com.zzpwdu.string_;
public class String01 {
public static void main(String[] args) {
//1.String 对象用于保存字符串,也就是一组字符序列
//2."jack" 字符串常量,双引号括起的字符序列
//3.字符串的字符使用Unicode字符编码,一个字符(不区分字母还是汉字)占两个字节
//4.String 类有很多构造器,构造器的重载
// 常用的有 String s1 = new String();
//String s2 = new String(String original);
//String s3 = new String(char[] a);
//String s4 = new String(char[] a, int startIndex, int count);
//String s5 = new String(byte[] b);
//5.String 类实例了接口 Serializable【String 可以串行化:可以在网络传输】
// 接口 Comparable【String 对象可以比较大小】
//6. String 是一个final 类,不能被其他类继承
//7. String 有属性 private final char value[];用于存放字符串内容
//8. 一定要注意:value 是一个final类型,不可修改(即:value不能指向新的地址,但是单个字符内容是可以变化的)
String name = "jack";
name = "tom";
final char value[] = {'a','b','c'};
char[] v2 = {'t','o','m'};
value[0] = 'h';
//value = v2;//错误 不可以修改 value地址
}
}
创建String对象的两种方式
1)方式一:直接赋值 String s = “zzp”;
2)方式二:调用构造器 String s2 = new String(“zzp”);
1、方式一:先从常量池查询看是否有"zzp"数据空间,如果有,直接指向;如果没有则重新创建,然后指向。s最终指向的是常量池的空间地址
2、方式二:先在堆中创建空间,里面维护了value属性,指向常量池的zzp空间。如果常量池没有"zzp",重新创建,如果有,直接通过value指向。最终指向的是堆中的空间地址。
3、画出两种方式的内存分布图
测试题
1)测试题1
String a = "abc";//在常量池查找
String b = "abc";
System.out.println(a.equals(b));//true
System.out.println(a == b);//true
public class StringExercise01 {
public static void main(String[] args) {
String a = "abc";
String b = "abc";
System.out.println(a.equals(b));//true
System.out.println(a == b);//true
}
}
==========控制台输出===========
true
true
2)测试题2
String a = new String("abc");//指向堆中对象 "abc"
String b = new String("abc");
System.out.println(a.equals(b));//true
System.out.println(a == b);//false
3)测试题3
String a = "zzp";//a 指向 常量池的 "zzp"
String b = new String("zzp");//b 指向推中的对象
System.out.println(a.equals(b));//true
System.out.println(a == b);//false
System.out.println(a == b.intern());//true
System.out.println(b == b.intern());//false
知识点:
当调用 intern 方式时,如果池子已经包含一个等于此 String 对象的字符串(用 equals(Object)方法确定),则返回池中字符串。否则,将此 String 对象添加到池子中,并返回此 String 对象的引用
解读:(1)b.intern() 方法最终返回的是常量池的地址(对象)
public class StringExercise03 {
public static void main(String[] args) {
String a = "zzp";//a 指向 常量池的 "zzp"
String b = new String("zzp");//b 指向推中的对象
System.out.println(a.equals(b));//true
System.out.println(a == b);//false
// b.intern() 方法返回常量池的地址
System.out.println(a == b.intern());//true
System.out.println(b == b.intern());//false
}
}
==========控制台输出===========
true
false
true
false
4)测试题4
String s1 = "zzp";//指向常量池 "zzp"
String s2 = "java";//指向常量池 "java"
String s4 = "java";//指向常量池 "java"
String s3 = new String("java");//指向堆中对象 "java"
System.out.println(s2 == s3);//false
System.out.println(s2 == s4);//true
System.out.println(s2.equals(s3));//true
System.out.println(s1 == s2);//false
5)测试题5
Person p1 = new Person();
p1.name = "zzp";//指向常量池 "zzp"
Person p2 = new Person();
p2.name = "zzp";//指向常量池 "zzp"
System.out.println(p1.name.equals(p2.name));//true
System.out.println(p1.name == p2.name);//true 都是指向常量池的地址
System.out.println(p1.name == "zzp");//true 都是指向常量池的地址
String s1 = new String("bcde");
String s2 = new String("bcde");
System.out.println(s1 == s2);//false
public class StringExercise05 {
public static void main(String[] args) {
Person p1 = new Person();
p1.name = "zzp";//指向常量池 "zzp"
Person p2 = new Person();
p2.name = "zzp";//指向常量池 "zzp"
System.out.println(p1.name.equals(p2.name));//true
System.out.println(p1.name == p2.name);//true 都是指向常量池的地址
System.out.println(p1.name == "zzp");//true 都是指向常量池的地址
String s1 = new String("bcde");
String s2 = new String("bcde");
System.out.println(s1 == s2);//false
}
}
class Person{
public String name;
}
==========控制台输出===========
true
true
true
false
字符串的特性
说明
1)String是一个final类,代表不可变的字符序列
2)字符串是不可变的。一个字符串对象一旦被分配,其内容是不可变的。
1、以下语句创建了几个对象?画出内存分布局图
String s1 = “hello”;//从常量池创建 hello
s1 = “haha”;//从常量池创建 haha
//创建了2个对象
面试题
1)题1
String a = "hello" + "abc";
创建了几个对象?===> 1个对象
>解读:String a = "hello" + "abc"; // ===> 优化等价 String a = "helloabc";
>分析:
>1、编译器不傻,做一个优化,判断创建的常量池对象,是否有引用指向
>2、String a = "hello" + "abc"; //==> 优化等价 String a = "helloabc";
2)题2
String a = "hello";//在常量池创建 a对象 hello
String b = "abc";//在常量池创建 b对象 abc
String c = a + b;//创建了几个对象? 3个对象
//关键就是要分析 String c = a + b; 到底是如何执行的
小结:
底层是 StringBuilder sb = new StringBuilder(); sb.append(a); sb.append(b); sb是在堆中,并且 append是在原来字符串的基础上追加的。
重要规则:
String c1 = “ab” + “cd”; 常量相加,看的是池。
String c1 = a + b; 变量相加,是在堆中。
public class StringExercise08 {
public static void main(String[] args) {
String a = "hello";
String b = "abc";
//解读:
//1.先创建一个 StringBuilder sb = StringBuilder();
//2.执行 sb.append("hello");
//3.sb.append("abc");
//4.String c = sb.toString()-->new String(value, 0, count);
//最后其实是 c 指向堆中的对象 (String)value[] -> 池中 "helloabc"
String c = a + b;
String d = "helloabc";
System.out.println(c == d);//false 一个是堆 另一个是常量池
String e = "hello" + "abc";//指向常量池中
System.out.println(d == e);//true
}
}
3)题3
下面代码输出什么,并说明原因
String s1 = "zzp";//s1 指向常量池中的 zzp
String s2 = "java";//s2 指向常量池中的 java
String s5 = "zzpjava";//s5 指向常量池中的 zzpjava
String s6 = (s1 + s2).intern();//s6 指向常量池中的 zzpjava
System.out.println(s5 == s6);//true
System.out.println(s5.equals(s6));//true
4)题4
下列程序运行的结果是什么,尝试画出内存布局图
public class Test1{
String str = new String("zzp");
final char[] ch ={'j','a','v','a'};
public void change(String str, char ch[]){
str = "java";
ch[0] = 'h';
}
public static void main(String[] args){
Test1 ex = new Test1();
ex.change(ex.str, ex.ch);
System.out.print(ex.str + " and ");
System.out.println(ex.ch);
}
}
//最终输出
zzp and hava
String类的常用方法
说明
String类是保存字符串的常量。每次更新都需要重新开辟空间,效率较低,因此 java设计者提供了 StringBuilder 和 StringBuffer 来增强String的功能,并提高效率。
//看看这段代码
String s = new String("");
for(int i = 0; i < 80000; i++){
s += "hello";
}
// 80000次开辟空间 消耗软件性能 浪费空间
String类的常用方法一览
equals
:将此字符串与指定对象进行比较。equalsIgnoreCase
:将此 String与其他 String比较length
:返回此字符串的长度indexOf
:返回指定字符第一次出现的字符串内的索引lastIndexOf
:返回指定字符的最后一次出现的字符串中的索引substring
:返回一个字符串,该字符串是此字符串的子字符串trim
:返回一个字符串,其值为此字符串,并删除任何前导和尾随空格charAt
:获取某索引处的字符(返回 char指定索引处的值)toUpperCase
:将所有在此字符 String使用默认语言环境的规则大写toLowerCase
:将所有在此字符 String使用默认语言环境的规则,以小写concat
:将指定的字符串连接到该字符串的末尾compareTo
:按字典顺序比较两个字符串toCharArray
:将此字符串转换为新的字符数组format
:使用指定的格式字符串和参数返回格式化的字符串
String类的常用方法应用实例1
equals
://区分大小写,判断内容是否相等equalsIgnoreCase
://忽略大小写的判断内容是否相等length
://获取字段的个数,字符串的长度indexOf
://获取字符在字符串中第1次出现的索引,索引从0开始,如果找不到,返回 -1lastIndexOf
://获取字符在字符串中最后1次出现的索引,索引从0开始,如果找不到,返回 -1substring
://截取指定范围的子串trim
://去前后空格charAt
:获取某索引处的字符:注意不能使用Str[index]这种方式【不能以数组方式截取,比如:String str = “hello”; str[0]–>错误】
//不能以数组方式截取,
String str = "hello";
//str[0] 错误
//str.charAt[0] => h
public class StringMethod01 {
public static void main(String[] args) {
//1.equals 比较内容是否相同,区分大小写
String str1 = "hello";
String str2 = "Hello";
System.out.println(str1.equals(str2));//false
//2.equalsIgnoreCase 忽略大小写的判断内容是否相等
String userName = "johN";
if("john".equalsIgnoreCase(userName)){
System.out.println("Success!");//Success!
}else {
System.out.println("Failure!");
}
//3.length 获取字符的个数,字符串的长度
System.out.println("zzp".length());//3
//4.indexOf 获取字符在字符串中第1次出现的索引,索引从0开始,如果找不到,返回 -1
String s1 = "wer@terwe@g";
int index = s1.indexOf('@');
System.out.println("index=" + index);//3
System.out.println("weIndex=" + s1.indexOf("we"));//0
//5.lastIndexOf 获取字符在字符串中最后1次出现的索引,索引从0开始,如果找不到,返回 -1
String s2 = "wer@terwe@g@";
int lastIndexOf = s2.lastIndexOf('@');
System.out.println("lastIndexOf=" + lastIndexOf);//11
System.out.println("weLastIndexOf=" + s1.lastIndexOf("we"));//7
//6.substring 截取指定范围的子串
String name = "hello,张三";
//下面 name.substring(6) 从索引6开始截取后面的所有内容
System.out.println(name.substring(6));//张三
//下面 name.substring(0,5) 从索引0开始截取,截取到索引 5-1=4 位置
System.out.println(name.substring(2,5));//llo
//7.trim 去前后空格
String str3 = " java ";
System.out.println(str3.trim());//java
//8.charAt 获取某索引处的字符:注意不能使用
String str4 = "hello";
System.out.println(str4.charAt(0));//h
}
}
=====控制台输出========
false
Success!
3
index=3
weIndex=0
lastIndexOf=11
weLastIndexOf=7
张三
llo
java
h
String类的常用方法应用实例2
toUpperCase
:将所有在此字符 String使用默认语言环境的规则大写toLowerCase
:将所有在此字符 String使用默认语言环境的规则,以小写concat
:将指定的字符串连接到该字符串的末尾replace
:替换字符串中的字符split
:分割字符串,对于某些分割字符,我们需要 转义,比如:| \\等
案例:
String poem = “锄禾日当午,汗滴禾下土,谁知盘中餐,粒粒皆辛苦”; 和 文件路径
compareTo
://比较两个字符串的大小,如果前者大,则返回正数,后者大,则返回负数,如果相等,返回0toCharArray
://转换成字符数组format
://格式字符串。%s 字符串 %c 字符 %d 整数 %.2f 浮点型
public class StringMethod02 {
public static void main(String[] args) {
//1.toUpperCase 将所有在此字符 String使用默认语言环境的规则大写
String s = "heLLo";
System.out.println("大写=" + s.toUpperCase(Locale.ROOT));//HELLO
//2.toLowerCase 将所有在此字符 String使用默认语言环境的规则,以小写
System.out.println("小写=" + s.toLowerCase(Locale.ROOT));//hello
//3.concat 将指定的字符串连接到该字符串的末尾
String s1 = "宝玉";
s1 = s1.concat("林黛玉").concat("薛宝钗").concat("together");
System.out.println("s1=" + s1);//宝玉林黛玉薛宝钗together
//4.replace 替换字符串中的字符
String s2 = "宝玉 and 林黛玉 林黛玉";
//在s2中,将 使用 林黛玉 替换成 薛宝钗
//解读:s2.replace() 方法执行后,放回的结果才是替换过的,
// 注意对 s2没有任何影响
String s3 = s2.replace("宝玉","tom");
System.out.println("s2=" + s2);//宝玉 and 林黛玉 林黛玉
System.out.println("s3=" + s3);//tom and 林黛玉 林黛玉
//5.split:分割字符串,对于某些分割字符,我们需要 转义,比如:| \\等
String poem = "锄禾日当午,汗滴禾下土,谁知盘中餐,粒粒皆辛苦";
//解读:
//1.以逗号, 为标准对 poem 进行分割,返回一个数组
//2.在对字符串进行分割时,如果有特殊字符,需要加入 转义符 \
String[] split = poem.split(",");
System.out.println("---poem 以逗号分割,如下----");
for (String str : split) {
System.out.println(str);
}
//我们需要 转义,比如:| \\等
poem = "E:\\aaa\\bbb";
split = poem.split("\\\\");
System.out.println("---poem 以转义\\\\字符分割,如下----");
for (String str : split) {
System.out.println(str);
}
//6.toCharArray 转换成字符数组
String s4 = "happy";
char[] chars = s4.toCharArray();
System.out.println("---s4.toCharArray()转换char数组,如下----");
for (char ch : chars) {
System.out.println(ch);
}
//7.compareTo 比较两个字符串的大小,如果前者大,则返回正数,
// 后者大,则返回负数,如果相等,返回0
//解读;
//(1) 如果长度相同,并且每个字符也相同,就返回 0
//(2) 如果长度相同或者不相同,但是在进行比较,可以区分大小
// 就返回 if (c1 != c2) {
// return c1 - c2;
// }
//(3) 如果前面的部分都相同,就返回 str1.len - str2.len
String s5 = "jchn";
String s6 = "jack";
//返回值是 'c' - 'a' = 2的值
System.out.println(s5.compareTo(s6));//2
//8.format 格式字符串
/*
占位符:
%s 字符串 %c 字符 %d 整数 %.2f 浮点型
*/
String name = "john";
int age = 20;
double score = 98.3 / 3;
char gender = '男';
//将所有的信息拼接在一个字符串
String info1 = "我的姓名是" + name + "年龄是" + age +
"性别是" + gender + ",成绩是" + score;
System.out.println("info1=" + info1);
//解读:
//1. %s, %c, %d, %.2f 称为占位符
//2. 这些占位符由后面的变量来替换
//3. %s 表示后面由 字符串替换
//4. %d 是整数来替换
//5. %.2f 表示后面由 小数来替换,替换后,只会保留小数点两位(四舍五入处理)
//6. %c 使用char类型替换
String formatSrt = "我的姓名是%s年龄是%d性别是%c,成绩是%.2f";
String info2 = String.format(formatSrt,name,age,gender,score);
System.out.println("info2=" + info2);
}
}
==============控制台输出================
大写=HELLO
小写=hello
s1=宝玉林黛玉薛宝钗together
s2=宝玉 and 林黛玉 林黛玉
s3=tom and 林黛玉 林黛玉
---poem 以逗号分割,如下----
锄禾日当午
汗滴禾下土
谁知盘中餐
粒粒皆辛苦
---poem 以转义\\字符分割,如下----
E:
aaa
bbb
---s4.toCharArray()转换char数组,如下----
h
a
p
p
y
2
info1=我的姓名是john年龄是20性别是男,成绩是32.766666666666666
info2=我的姓名是john年龄是20性别是男,成绩是32.77
三、StringBuffer和StringBuilder类
StringBuffer类
基本介绍
- java.lang.StringBuffer 代表可变的字符序列,可以对字符串内容进行增删
- 很多方法于String相同,但StringBuffer是可变长度的
- StringBuffer 是一个StringBuffer
package java.lang;
/**
* 1. StringBuffer 是final 类
* 2. 实现了 Serializable 接口,可以保存到文件,或者网络传输
* 3. 继承了抽象类 AbstractStringBuilder
* 4. AbstractStringBuilder 属性 byte[] value,保存的字符序列
*/
public final class StringBuffer
extends AbstractStringBuilder
implements java.io.Serializable, Comparable<StringBuffer>, CharSequence{
.....
}
package java.lang;
abstract class AbstractStringBuilder implements Appendable, CharSequence {
/**
* The value is used for character storage.
*/
char[] value
....
}
String VS StringBuffer
1)String保存的是字符串常量,里面的值不能更改,每次String类的更新实际上就是更改地址,效率低【private final char value[];】
2)StringBuffer 保存的是字符串变量,里面的值可以更改,每次StringBuffer的更新实际上可以更新内容,不用每次更新地址,效率高【char[] value; //这个存放在堆中】
public class StringBuffer01 {
public static void main(String[] args) {
//解读:
//1. StringBuffer 的直接父类是 AbstractStringBuilder
//2. StringBuffer 实现了 Serializable,即StringBuffer的对象可以串行化
//3. 在父类中 AbstractStringBuilder 有属性 char[] value,不是final
// 该 value 数组存放 字符串内容,引用存放在堆中的,不是常量池
//4. StringBuffer 是一个 final 类,不能被继承
//5. 因为StringBuffer 字符内容是存在 char[] value,使用在变化(增加/删除)
// 不用每次都更换地址(即不是每次创建新的对象),所以效率高于 String
StringBuffer stringBuffer = new StringBuffer("hello");
}
}
StringBuffer的构造器
public class StringBuffer02 {
public static void main(String[] args) {
//构造器的使用
//解读:
//1. 创建一个 大小为 16的 char[],用于存放字符内容
/*
public StringBuffer() {
super(16);
}
*/
StringBuffer stringBuffer = new StringBuffer();
//2. 通过构造器指定 char[] 大小
/*
public StringBuffer(int capacity) {
super(capacity);
}
*/
StringBuffer stringBuffer1 = new StringBuffer(100);
//3. 通过给一个String 创建 StringBuffer,char[] 大小就是 str.length + 16
/*
public StringBuffer(String str) {
super(str.length() + 16);
append(str);
}
*/
StringBuffer stringBuffer2 = new StringBuffer("hello");
}
}
String和StringBuffer相互转换
在开发中,我们经常需要将String 和 StringBuffer进行转换,看看然后实现
public class StringAndStringBuffer {
public static void main(String[] args) {
// String --> StringBuffer
String str = "hello";
//方式1 使用构造器
//注意:返回的才是StringBuffer对象,对str 本身没有影响
StringBuffer b1 = new StringBuffer(str);
//方式2 使用的是append方法
StringBuffer b2 = new StringBuffer();
b2.append(str);
//StringBuffer --> String
StringBuffer b3 = new StringBuffer("zzp");
//方式1 使用StringBuffer提供的 toString方法
String str2 = b3.toString();
//方式2 使用String构造器
String str3 = new String(b3);
}
}
StringBuffer类常见方法
1)增 append
2)删 delete(start, end)
3)改 replace(start, end, string)
//将start—end 间的内容替换掉,不含end
4)查 indexOf
//查找子串在字符串第1次出现的索引,如果找不到返回-1
5)插 insert
6)获取长度 length
public class StringBufferMethod {
public static void main(String[] args) {
StringBuffer s = new StringBuffer("hello");
//增
s.append(",");//hello,
s.append("张三丰");//hello,张三丰
s.append("赵敏").append(100).append(true).append(10.5);
System.out.println(s);//hello,张三丰赵敏100true10.5
//删
/*
* 删除索引为 >= start && < end 处的字符
* 解读:删除 11~14的字符【不包含14】 [11~14)
*/
s.delete(11,14);
System.out.println(s);//hello,张三丰赵敏true10.5
//改
//解读:使用 周芷若 替换 索引9~11的字符 [9~11)
s.replace(9,11,"周芷若");
System.out.println(s);//hello,张三丰周芷若true10.5
//查找指定的字符串第一次出现的索引,如果找不到返回-1
int indexOf = s.indexOf("张三丰");
System.out.println(indexOf);//6
//插
//解读:在索引为9位置插入 "赵敏",原来索引为9的内容自动后移
s.insert(9,"赵敏");
System.out.println(s);//hello,张三丰赵敏周芷若true10.5
//长度
System.out.println(s.length());//22
System.out.println(s);//hello,张三丰赵敏周芷若true10.5
}
}
=============控制台输出======================
hello,张三丰赵敏100true10.5
hello,张三丰赵敏true10.5
hello,张三丰周芷若true10.5
6
hello,张三丰赵敏周芷若true10.5
22
hello,张三丰赵敏周芷若true10.5
StringBuffer类测试题
1、看看下面代码输出什么?为什么?
String str = null;//ok
StringBuffer sb = new StringBuffer();//ok
sb.append(str);//看底层源码,底层调用的是父类的 AbstractStringBuilder.appendNull()方法
/* 源码方法
@Override
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
return this;
}
public AbstractStringBuilder append(String str) {
if (str == null)
return appendNull();
int len = str.length();
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;
return this;
}
//当传的参数为 null ==> 转成 "null"
private AbstractStringBuilder appendNull() {
int c = count;
ensureCapacityInternal(c + 4);
final char[] value = this.value;
value[c++] = 'n';
value[c++] = 'u';
value[c++] = 'l';
value[c++] = 'l';
count = c;
return this;
}
*/
System.out.println(sb.length());//4
System.out.println(sb);//null
StringBuffer sb1 = new StringBuffer(str);//null对象 看底层源码
/* StringBuffer 构造器,会抛出NullPointerException空指针异常
public StringBuffer(String str) {
super(str.length() + 16);//str=null ==> str.length 异常NullPointerException
append(str);
}
*/
System.out.println(sb1);
public class StringBufferExercise01 {
public static void main(String[] args) {
String str = null;//ok
StringBuffer sb = new StringBuffer();//ok
sb.append(str);//看底层源码,底层调用的是父类的 AbstractStringBuilder.appendNull()方法
/* 源码方法
@Override
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
return this;
}
public AbstractStringBuilder append(String str) {
if (str == null)
return appendNull();
int len = str.length();
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;
return this;
}
//当传的参数为 null ==> 转成 char[] = "null"
private AbstractStringBuilder appendNull() {
int c = count;
ensureCapacityInternal(c + 4);
final char[] value = this.value;
value[c++] = 'n';
value[c++] = 'u';
value[c++] = 'l';
value[c++] = 'l';
count = c;
return this;
}
*/
System.out.println(sb.length());//4
System.out.println(sb);//null
StringBuffer sb1 = new StringBuffer(str);//null对象 看底层源码
/* StringBuffer 构造器,会抛出NullPointerException空指针异常
public StringBuffer(String str) {
super(str.length() + 16);//str=null ==> str.length 异常NullPointerException
append(str);
}
*/
System.out.println(sb1);
}
}
2、输入商品名称和商品价格,要求打印效果示例,使用前面学习的方法完成;
商品名 商品价格
手机 123,456.59 //比如价格 3,456,789.88
要求:价格的小数点前面每三位用逗号隔开,在输出
public class StringBufferExercise02 {
public static void main(String[] args) {
/*
输入商品名称和商品价格,要求打印效果示例,使用前面学习的方法完成;
商品名 商品价格
手机 123,456.59 //比如价格 3,456,789.88
要求:价格的小数点前面每三位用逗号隔开,在输出
思路分析:
1. 定义一个Scanner 对象,接收用户输入的 价格(String)
2. 希望使用到 StringBuffer的 insert方法,需要将 String 转成 StringBuffer
3. 然后使用相关方法进行字符串的处理
代码实现
*/
//new Scanner(System.in);
String price = "1234567.59";
StringBuffer buffer = new StringBuffer(price);
//先完成一个最简单的实现 123,456.59
//找到小数点的索引,然后在该位置的前3位,插入,即可
// int i = buffer.indexOf(".");
// buffer = buffer.insert(i - 3, ",");
//上面的两步需要做一个循环处理,才是正确的
for(int i = buffer.lastIndexOf(".") - 3; i > 0; i -= 3){
buffer = buffer.insert(i, ",");
}
System.out.println(buffer);
}
}
========控制台输出========
1,234,567.59
StringBuilder类
基本介绍
1)一个可变的字符序列。此类通过了一个与 StringBuffer 兼容的 API ,但不保证同步(StringBuilder 不是线程安全)。该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓存区被单个线程使用的时候。如果可能,建议优先采用该类,因为大多数实现中,它比 StringBuffer 要快
2)在 StringBuilder 上的主要操作是 append 和 insert 方法,可重载这些方法,以接受任意类型的数据。
StringBuilder常用方法
StringBuilder 和 StringBuffer 均代表可变的字符序列,方法是一样的,使用使用和StringBuilder一样
StringBuilder 源码:
package java.lang;
/*
* 1. StringBuilder 是final
* 2. 继承 AbstractStringBuilder,属性 char[] value,内容存到 value
* 3. 实现了 Serializable 接口,序列化(所谓的序列化即可以保存类型和数据本身)
*/
public final class StringBuilder
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{....}
package java.lang;
abstract class AbstractStringBuilder implements Appendable, CharSequence {
/**
* The value is used for character storage.
*/
char[] value;
...
}
public class StringBuilder01 {
public static void main(String[] args) {
//解读:
//1. StringBuilder 继承了 AbstractStringBuilder 类
//2. 实现了 Serializable 接口,说明StringBuilder对象是可以串行化(对象可以网络传输,也可以保存到文件)
//3. StringBuilder 是final类,不能被继承
//4. StringBuilder 对象字符序列仍然是存放在其父类 AbstractStringBuilder的 char[] value;
// 因此,字符序列是对堆中
//5. StringBuilder 的方法,没有做互斥的处理,即没有synchronized 关键字,
// 因此在单线程的情况下使用 StringBuilder
StringBuilder stringBuilder = new StringBuilder();
}
}
String、StringBuffer 和StringBuilder的比较
1)StringBuffer
和 StringBuilder
非常类似,均代表可变的字符序列,而且方法也一样
2)String
:不可变字符序列,效率低,但复用率高
3)StringBuffer
:可变字符序列、效率较高(赠删)、线程安全
4)StringBuilder
:可变字符序列,效率最高、线程不安全
5)String使用注意说明:
String s = "a";//创建了一个字符串
s += "b";//实际上原来的 "a" 字符串对象已经丢弃了,现在又产生了一个字符串 s + "b"(也就是 "ab")。
//如果多次执行这些改变串的内容的操作,会导致大量副本字符串对象留在内存中,降低效率。
//如果这样的操作方法到循环中,会极大影响程序性能
// ==> 结论:如果我们对String 做大量修改,不要使用String
String、StringBuffer 和StringBuilder的效率测试
效率: StringBuilder > StringBuffer > String
public class StringVsStringBufferVsStringBuilder {
public static void main(String[] args) {
long startTime = 0l;
long endTime = 0l;
StringBuffer buffer = new StringBuffer("");
startTime = System.currentTimeMillis();
for (int i = 0; i < 20000; i++) {//StringBuffer 拼接 20000次
buffer.append(String.valueOf(i));
}
endTime = System.currentTimeMillis();
System.out.println("StringBuffer的执行时间:" + (endTime - startTime));
StringBuilder builder = new StringBuilder("");
startTime = System.currentTimeMillis();
for (int i = 0; i < 20000; i++) {//StringBuilder 拼接 20000次
builder.append(String.valueOf(i));
}
endTime = System.currentTimeMillis();
System.out.println("StringBuilder的执行时间:" + (endTime - startTime));
String text = "";
startTime = System.currentTimeMillis();
for (int i = 0; i < 20000; i++) {//String 拼接 20000次
text += String.valueOf(i);
}
endTime = System.currentTimeMillis();
System.out.println("String的执行时间:" + (endTime - startTime));
}
}
=========控制台输出=========
StringBuffer的执行时间:6
StringBuilder的执行时间:4
String的执行时间:1797
String、StringBuffer 和StringBuilder的选择
使用原则,结论:
- 如果字符串存在大量的修改操作,一般使用 StringBuffer 或 StringBuilder
- 如果字符串存在大量的修改操作,并在单线程的情况下,使用StringBuilder
- 如果字符串存在大量的修改操作,并在多线程的情况下,使用 StringBuffer
- 如果我们字符串很少修改,被多个对象引用,使用String,比如配置信息等
四、Math类
基本介绍
Math 类包含用于执行基本数学运算的方法,如初等指数、对数、平方根和三角函数。
方法一览(均为静态方法)
Math类常见方法应用案例
演示Math 类常见的方法
1)abs
:绝对值
2)pow
:求幂
3)ceil
:向上取整
4)floor
:向下取整
5)round
:四舍五入
6)sqrt
:求开方
7)random
:求随机数
思考:请写出获取 a-b之间一个随机整数,a,b均为整数
8)max
:求两数的最大值
9)min
:求两数的最小值
public class MathMethod {
public static void main(String[] args) {
//Math常用的静态方法
//1. abs 绝对值
int abs = Math.abs(-9);
System.out.println(abs);//9
//2. pow 求幂
double pow = Math.pow(2,4);//2的4次方
System.out.println(pow);//16
//3. ceil 向上取整,返回 >= 该参数的最小整数(转成double)
double ceil = Math.ceil(3.9);
System.out.println(ceil);//4.0
//4. floor 向下取整,返回 <= 该参数的最大整数(转成double)
double floor = Math.floor(4.01);
System.out.println(floor);//4.0
//5. round 四舍五入 Math.floor(该参数 + 0.5);
long round = Math.round(5.51);
System.out.println(round);//6
//6. sqrt 求开方
double sqrt = Math.sqrt(9.0);
System.out.println(sqrt);//3.0
System.out.println("-------------");
//7. random 返回随机数 [0 - 1)
// random 返回的是 0<= x < 1 之间的一个随机小数
//思考:请写出获取 a-b之间一个随机整数,a,b均为整数,比如:a=2,b=7
// 即返回一个数 x: 2<= x <= 7
//解读:Math.random() * (b-a) 返回的就是 0 <= 数 <= b-a
//(1) (int)a <= x <= (int)(a + Math.random() * (b-a +1))
//(2) 使用具体的数介绍 a=2 b=7
// (int)(a + Math.random() * (b-a+1)) = (int)(2 + Math.random() * 6)
// Math.random() * 6 返回的是 0 < x < 6 的一个小数
// 2 + Math.random() * 6 返回就是 2 <= x < 8 的小数
// (int)(2 + Math.random() * 6) = 2 < x <= 7
//(3) 公式就是 (int)(a + Math.random() * (b-a +1))
for (int i = 0; i < 10; i++) {
System.out.println((int)(2 + Math.random() * (7-2+1)) );
}
System.out.println("-------------");
//max,min 返回最大值 和 最小值
System.out.println("max="+ Math.max(12,20));//20
System.out.println("min=" + Math.min(12,20));//12
}
}
=======控制台输出========
9
16.0
4.0
4.0
6
3.0
-------------
4
2
4
4
6
4
3
6
4
4
-------------
max=20
min=12
练习题:获取 a - b 之间的一个随机整数
公式: (int)(a + Math.random() * (b - a +1))
五、Arrays类
Arrays类常见方法应用案例
Arrays里面包含了一系列静态方法,用于管理或操作数组(比如排序和搜索)。
1)toString
:返回数组的字符串形式
Arrays.toString(arr);
2)sort
:排序(自然排序和定制排序)
Integer arr[] = {1, -1, 7, 0, 89};
Arrays.sort(arr);
public class ArraysMethod01 {
public static void main(String[] args) {
Integer[] integers = {1,20,90};
//遍历显示数组
// for (int i = 0; i < integers.length; i++) {
// System.out.println(integers[i]);
// }
//直接使用Arrays.toString方法,显示数组信息
System.out.println(Arrays.toString(integers));//[1, 20, 90]
//演示 sort方法使用
Integer[] arr = {1,-1,50,20,24};
//进行排序
//1. 可以直接使用冒泡排序,也可以使用Arrays提供的sort方法排序
//2. 因为数组是引用类型,所以通过sort排序后,会直接影响到 实参 arr
// Arrays.sort(arr);//默认排序方法 从小到大
// System.out.println("Arrays.sort排序后=" + Arrays.toString(arr));//[-1, 1, 20, 24, 50]
//3. sort方法是重载的,也可以通过传入一个接口 Comparator 实现定制排序
//4. 调用 定制排序 时,传入两个参数 (1) 排序的数组 arr
// (2) 实现了 Comparator 接口的匿名内部类,要求实现 compare方法
//5. 这里体现了接口编程的方式 看源码
/* (1)Arrays.sort(T[] a, Comparator<? super T> c)
(2)TimSort.sort()方法
(3)再调用TimSort.binarySort方法,
会关键动态绑定机制,c.compare执行传入的匿名内部类的 compare()方法,
关键代码如下:
while (left < right) {
int mid = (left + right) >>> 1;
//在binarySort方法底层,会通过匿名内部类的compare方法来决定排序的顺序
if (c.compare(pivot, a[mid]) < 0)
right = mid;
else
left = mid + 1;
}
(4)public int compare(Object o1, Object o2) 返回的值>0 还是 <0 会影响这个排序的结果
这里充分体现了 接口编程+动态绑定+匿名内部类的综合使用
*/
//定制排序
Arrays.sort(arr, new Comparator() {
@Override
public int compare(Object o1, Object o2) {
Integer i1 = (Integer) o1;
Integer i2 = (Integer) o2;
return i2 - i1;
}
});
System.out.println("Arrays.sort定制排序后=" + Arrays.toString(arr));
}
}
===========控制台输出=========
[1, 20, 90]
Arrays.sort定制排序后=[50, 24, 20, 1, -1]
结合冒泡 + 定制(使用Comparator接口) 排序方法,演示
public class ArraysSortCustom {
public static void main(String[] args) {
int[] arr = {1,0,-2,12,3};
//bubble01(arr);
bubble02(arr, new Comparator() {
@Override
public int compare(Object o1, Object o2) {
Integer i1 = (Integer) o1;
Integer i2 = (Integer) o2;
return i1 - i2;//从小到大
// return i2 - i1;//从大到小
}
});
System.out.println("排序后=" + Arrays.toString(arr));
}
//使用冒泡排序完成 从小到大排序
public static void bubble01(int[] arr){
int temp = 0;
for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length - i -1; j++) {
if(arr[j] > arr[j + 1]){
temp = arr[j + 1];
arr[j + 1] = arr[j];
arr[j] = temp;
}
}
}
}
//结合冒泡 + 定制
public static void bubble02(int[] arr, Comparator c){
int temp = 0;
for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length - i -1; j++) {
//数组的排序由这 c.compare(arr[j], arr[j+1])返回的值决定
if(c.compare(arr[j], arr[j+1]) > 0){
temp = arr[j + 1];
arr[j + 1] = arr[j];
arr[j] = temp;
}
}
}
}
}
3)binarySearch
:通过二分搜索法进行查找,要求必须排好序
int index = Arrays.binarySearch(arr, 3);
4)copyOf
:数组元素的复制
Integer[] newArr = Arrays.copyOf(arr, arr.length);
5)fill
:数组元素的填充
Integer[] num = new Integer[]{9, 3, 2};
Arrays.fill(num, 99);
6)equals
:比较两个数组元素内容是否完全一致
boolean equals = Arrays.equals(arr, arr2);
7)asList
:将一组值,转换成list
List<Integer> asList = Arrays.asList(2,3,4,5);
System.out.println(“asList=” + asList);
public class ArraysMethod02 {
public static void main(String[] args) {
Integer[] arr = {1, 2, 90, 123, 567};
//binarySearch:通过二分搜索法进行查找,要求必须排好序
//解读:
//1. 使用 binarySearch 二叉查找
//2. 要求该数组是有序的。如果该数组是无序的,不能使用 binarySearch
//3. 如果数组中不存在该元素,就返回 -(low + 1); // key not found.
int index = Arrays.binarySearch(arr, 123);
System.out.println("index=" + index);
//copyOf 数组元素的复制
//解读:
//1. 从 arr 数组中,拷贝 arr.length个元素到 newArr数组中
//2. 如果拷贝的长度 > arr.length 就在数组后面 增加 null
//3. 如果拷贝长度 <0 就抛出异常 NegativeArraySizeException
//4. 该方法的底层使用的是 System.arraycopy()
Integer[] newArr = Arrays.copyOf(arr, arr.length +1);
System.out.println("newArr=" + Arrays.toString(newArr));//[1, 2, 90, 123, 567, null]
//fill 数组元素的填充
Integer[] num = new Integer[]{9, 3, 2};
//解读:
//1. 使用 99 去填充 num数组,可以理解成是替换原来的元素
Arrays.fill(num, 99);
System.out.println("填充后的数组=" + Arrays.toString(num));//[99, 99, 99]
//equals 比较两个数组元素内容是否完全一致
Integer[] arr2 = {1, 2, 90, 123, 567};
//解读:
//1. 如果arr 和 arr2 数组的元素一样,则返回true
//2. 如果不是完全一样,就返回 false
boolean equals = Arrays.equals(arr, arr2);
System.out.println("equals数组比较=" + equals);//true
//asList:将一组值,转换成list
//解读:
//1. asList方法,会将 (2,3,4,5)数据转成一个List集合
//2. 返回的 asList 编译类型 List
//3. asList 运行类型 class java.util.Arrays$ArrayList
// ArrayList 是Arrays类的静态内部类
// private static class ArrayList<E> extends AbstractList<E>
// implements RandomAccess, java.io.Serializable
List asList = Arrays.asList(2,3,4,5);
System.out.println("asList=" + asList);
System.out.println("asList的运行类型:" + asList.getClass());
}
}
===========控制台输出=========
index=3
newArr=[1, 2, 90, 123, 567, null]
填充后的数组=[99, 99, 99]
equals数组比较=true
asList=[2, 3, 4, 5]
asList的运行类型:class java.util.Arrays$ArrayList
Arrays类练习
案例:自定义Book类,里面包含name和price,按price排序(从大到小)。要求使用两种方式排序,有一个 Book[] books = 4 本书对象。
使用前面学习过的传递 实现Comparator接口匿名内部类,也称为定制排序。可以按照 price (1)从大到小(2)从小到大(3)按照书面长度从大到小
Book[] books = new Book[4];
books[0] = new Book("红楼梦", 100);
books[1] = new Book("西游记~", 120);
books[2] = new Book("青年文摘~", 10);
books[3] = new Book("java从入门到放弃~", 300);
public class ArraysExercise {
public static void main(String[] args) {
/*
自定义Book类,里面包含name和price,按price排序(从大到小)。
要求使用两种方式排序,有一个 Book[] books = 4 本书对象。
使用前面学习过的传递 实现Comparator接口匿名内部类,也称为定制排序。
可以按照 price (1)从大到小(2)从小到大(3)按照书面长度从大到小
*/
Book[] books = new Book[4];
books[0] = new Book("红楼梦", 100);
books[1] = new Book("西游记~", 120);
books[2] = new Book("青年文摘~", 10);
books[3] = new Book("java从入门到放弃~", 300);
//(1)price从大到小
Arrays.sort(books, new Comparator() {
//这里是对Book数组排序,因此 o1,o2就是Book对象
@Override
public int compare(Object o1, Object o2) {
Book book1 = (Book) o1;
Book book2 = (Book) o2;
double priceVal = book2.getPrice() - book1.getPrice();
//这里进行了一个转换
//如果发现返回结果和我们输出的不一致,就修改 1 和 -1 的位置
if(priceVal > 0){
return 1;
}else if(priceVal < 0){
return -1;
}else {
return 0;
}
}
});
System.out.println(Arrays.toString(books));
//(2)price从小到大
Arrays.sort(books, new Comparator() {
//这里是对Book数组排序,因此 o1,o2就是Book对象
@Override
public int compare(Object o1, Object o2) {
Book book1 = (Book) o1;
Book book2 = (Book) o2;
double priceVal = book2.getPrice() - book1.getPrice();
//这里进行了一个转换
//如果发现返回结果和我们输出的不一致,就修改 1 和 -1 的位置
if(priceVal > 0){
return -1;
}else if(priceVal < 0){
return 1;
}else {
return 0;
}
}
});
System.out.println(Arrays.toString(books));
//(3)按照书面长度从大到小
Arrays.sort(books, new Comparator() {
//这里是对Book数组排序,因此 o1,o2就是Book对象
@Override
public int compare(Object o1, Object o2) {
Book book1 = (Book) o1;
Book book2 = (Book) o2;
//按照书面的长度排序
return book2.getName().length() - book1.getName().length();
}
});
System.out.println(Arrays.toString(books));
}
}
class Book{
private String name;
private double price;
public Book(String name, double price) {
this.name = name;
this.price = price;
}
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public double getPrice() { return price; }
public void setPrice(double price) { this.price = price; }
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", price=" + price +
'}';
}
}
===========控制台输出=========
[Book{name='java从入门到放弃~', price=300.0}, Book{name='西游记~', price=120.0}, Book{name='红楼梦', price=100.0}, Book{name='青年文摘~', price=10.0}]
[Book{name='青年文摘~', price=10.0}, Book{name='红楼梦', price=100.0}, Book{name='西游记~', price=120.0}, Book{name='java从入门到放弃~', price=300.0}]
[Book{name='java从入门到放弃~', price=300.0}, Book{name='青年文摘~', price=10.0}, Book{name='西游记~', price=120.0}, Book{name='红楼梦', price=100.0}]
六、System类
System类常见方法和案例
1)exit
:退出当前程序
2)arraycopy
:复制数组元素,比较适合底层调用,一般使用 Arrays.copyOf 完成复制数组。
int[] src = {1, 2, 3};
int[] dest = new int[3];
System.arraycopy(src, 0, dest, 0, 3);
3)currentTimeMillis
:返回当前时间距离 1970-1-1 的毫秒数
4)gc
:运行垃圾回收机制 System.gc();
public class System_ {
public static void main(String[] args) {
//exit:退出当前程序
System.out.println("ok1");
//解读:
//1. exit(0) 表示程序退出
//2. 0 表示一个状态,正常的状态
//System.exit(0);
System.out.println("ok2");
//arraycopy:复制数组元素,比较适合底层调用,
// 一般使用 Arrays.copyOf 完成复制数组。
int[] src = {1, 2, 3};
int[] dest = new int[3];// dest 当前是 {0,0,0}
//解读:
//1. 主要是搞清楚这5个参数的含义
//2.
// src: 源数组
// * @param src the source array.
// srcPos: 从源数组的哪个索引位置开始拷贝
// * @param srcPos starting position in the source array.
// dest: 目标数组,即把源数组的数据拷贝到哪个数组
// * @param dest the destination array.
// destPos: 把源数组的数据拷贝到 目标数组的哪个索引
// * @param destPos starting position in the destination data.
// length: 从源数组拷贝多少个数据到目标数组
// * @param length the number of array elements to be copied.
System.arraycopy(src, 0, dest, 0, src.length);
//int[] src = {1, 2, 3};
System.out.println("dest=" + Arrays.toString(dest));//[1, 2, 3]
//currentTimeMillis:返回当前时间距离 1970-1-1 的毫秒数
System.out.println(System.currentTimeMillis());
//gc:运行垃圾回收机制 System.gc();
System.gc();
}
}
七、BigInteger类和BigDecimal类
BigInteger和BigDecimal介绍
应用场景:
1)BigInteger适合保存比较大的整型
2)BigDecimal适合保存精度更高的浮点型(小数)
BigInteger和BigDecimal常见方法
1)add
加
2)subtract
减
3)multiply
乘
4)divide
除
BigInteger演示:
public class BigInteger_ {
public static void main(String[] args) {
//一般使用long类型
//long l = 23432432423428989999939L;//报错 超出long范围
//System.out.println("l=" + l);
//当我们编程中,需要处理很大的整数,long 不够用
//可以使用 BigInteger的类来处理
BigInteger bigInteger = new BigInteger("23432432423428989999939");
BigInteger bigInteger2 = new BigInteger("100");
System.out.println("bigInteger=" + bigInteger);
//解读:
//1. 在对 BigInteger 进行加减乘除的时候,需要使用对应的方法,不能直接进行 +-*/
//2. 可以创建一个 要操作的 BigInteger 然后进行相应操作
BigInteger add = bigInteger.add(bigInteger2);
System.out.println("add=" + add);//加
BigInteger subtract = bigInteger.subtract(bigInteger2);//减
System.out.println("subtract=" + subtract);
BigInteger multiply = bigInteger.multiply(bigInteger2);//乘
System.out.println("multiply=" + multiply);
BigInteger divide = bigInteger.divide(bigInteger2);//除
System.out.println("divide=" + divide);
}
}
BigDecimal 演示:
public class BigDecimal_ {
public static void main(String[] args) {
//当我们需要保存一个 精度很高的数时,double 不够用
//可以使用 BigDecimal
// double d = 199.1111111114444444111333333333333d;
// System.out.println(d);
BigDecimal bigDecimal = new BigDecimal("199.1111111114444444111333333333333");
System.out.println(bigDecimal);
//解读:
//1. 如果对 BigDecimal进行运算,比如加减乘除,需要对应的方法
//2. 需要创建一个需要操作的 BigDecimal 然后调用相应的方法即可
BigDecimal bigDecimal2 = new BigDecimal("1.1");
System.out.println(bigDecimal.add(bigDecimal2));//加
System.out.println(bigDecimal.subtract(bigDecimal2));//减
System.out.println(bigDecimal.multiply(bigDecimal2));//乘
//可能抛出异常(除不尽): java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.
//System.out.println(bigDecimal.divide(bigDecimal2));//除
//在调用divide 方法时,指定精度即可.
//BigDecimal.ROUND_CEILING:如果有无限循环小数,就会保留 分子 的精度
System.out.println(bigDecimal.divide(bigDecimal2, BigDecimal.ROUND_CEILING));
}
}
八、Date日期类、Calendar日历以及新的日期
第一代日期类
1)Date
:精确到毫秒,代表特定的瞬间
2)SimpleDateFormat
:格式和解析日期的类。
SimpleDateFormat 格式和解析日期的具体类,它允许进行格式化(日期 -> 文本)、解析(文本 -> 日期)和规范化。
字母 | 日期或时间元素 | 表示 | 示例 |
---|---|---|---|
G | Era 标志符 | Text | AD |
y | 年 | Year | 1996;96 |
M | 年中的月份 | Month | July; Jul; 07 |
w | 年中周数 | Number | 27 |
W | 月份中的周数 | Number | 2 |
D | 年中的天数 | Number | 189 |
d | 月份中天数 | Number | 10 |
F | 月份中星期 | Number | 2 |
E | 星期中的天数 | Text | Tuesday, Tue |
a | Am/pm 标记 | Text | PM |
H | 一天中小时数(0-23) | Number | 0 |
k | 一天中小时数(1-24) | Number | 24 |
K | am/pm 中的小时数(0-11) | Number | 0 |
h | am/pm 中的小时数(1-12) | Number | 12 |
m | 小时中的分钟 | Number | 30 |
s | 分钟中的秒数 | Number | 55 |
S | 毫秒数 | Number | 978 |
z | 时区 | General time zone | Pacific Standard Time; PST; GMT-08:00 |
Z | 时区 | RFC 822 time zone | -0800 |
X | 时区 | ISO 8601 time zone | -08; -0800; -08:00 |
3)应用实例
public class Date01 {
public static void main(String[] args) throws ParseException {
//解读:
//1. 获取当前系统时间
//2. 这里的Date 类在java.util包
//3. 默认输出的日期格是国外的方式,因此通常需要对格式进行转换
Date d1 = new Date();//获取当前系统时间
System.out.println("当前日期=" + d1);
Date d2 = new Date(9234567);//通过指定毫秒数得到时间
System.out.println("d2=" + d2);//获取某个时间对应的毫秒数 d2.getTime()
//解读:
//1. 创建 SimpleDateFormat对象,可以指定相应的格式
//2. 这里的格式使用的字母是规定好的,不能乱写
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss E");
String format = sdf.format(d1);//format:将日期转换成指定的字符串
System.out.println("当前日期=" + format);
//解读:
//1.可以把一个格式化的字符串 转成对应的 Date
//2.得到Date 仍然在输出时,还是按照国外的形式,如果希望指定格式输出,需要转换
//3.在把String -> Date ,使用的 sdf 格式需要和给的String的格式一样,否则会抛出异常ParseException
String s = "1996年01月01日 10:20:30 星期一";
Date parse = sdf.parse(s);
System.out.println("parse=" + parse);
System.out.println("parse=" + sdf.format(parse));
}
}
第二代日期类
1)第二代日期类,主要就是 Calendar类(日历)
package java.util;
public abstract class Calendar implements Serializable,
Cloneable, Comparable<Calendar> {
2)Calendar 类是一个抽象类,它为特定瞬间与一组诸如 YEAR、MONTH、DAY_OF_MONTH、HOUR 等 日历字段 之间转换提供了一些方法,并为操作日历字段(例如获得下星期的日期)提供了一些方法
3)应用实例
public class Calendar_ {
public static void main(String[] args) {
//解读:
//1. Calendar是一个抽象类,并且是构造器是private
//2. 可以通过 getInstance() 来换取实例
//3. 通过大量的方法和字段通过给程序员使用
//4. Calendar没有提供对应的格式化的类,因此需要程序员自己组合来输出
//5. 如果我们需要按照 24小时进制 Calendar.HOUR ==> Calendar.HOUR_OF_DAY
Calendar c = Calendar.getInstance();//创建日历类对象
System.out.println("c=" + c);
//2.获取日历对象的某个日历字段
System.out.println("年:" + c.get(Calendar.YEAR));
//这里为什么要 + 1,因为Calendar 返回月的时候,是按照 0 开始编号
System.out.println("月:" + (c.get(Calendar.MONTH) + 1));
System.out.println("日:" + c.get(Calendar.DAY_OF_MONTH));
System.out.println("小时:" + c.get(Calendar.HOUR_OF_DAY));
System.out.println("分钟:" + c.get(Calendar.MINUTE));
System.out.println("秒:" + c.get(Calendar.SECOND));
//Calendar 没有专门的格式化方法,所以需要程序员自己来组合显示
System.out.println(c.get(Calendar.YEAR) + "年" + (c.get(Calendar.MONTH) + 1) + "月"
+ c.get(Calendar.DAY_OF_MONTH) + "日" + " " + c.get(Calendar.DAY_OF_MONTH) + ":"
+ c.get(Calendar.MINUTE) + ":" + c.get(Calendar.SECOND));
}
}
第三代日期类
前面两代日期类的不足分析:
JDK 1.0中包含一个java.util.Date类,但是它的大多数方法已经在JDK 1.1引入Calendar类之后被弃用了。而Calendar也存在问题是:
- 可变性:像日期和时间这样的类应该是不可变的。
- 偏移性:Date中的年份是从1900开始的,而月份都从0开始
- 格式化:格式化只对Date有用,Calendar则不行
- 此外,它们也不是线程安全的;不能处理闰秒等(每隔2天,多出1s)。
第三代日期类常见方法
1)LocalDate(日期/年月日)
、LocalTime(时间/时分秒)
、LocalDateTime(日期时间/年月日时分秒) JDK8加入
LocalDate
只包含日期,可以获取日期字段LocalTime
只包含时间,可以获取时候字段LocalDateTime
包含日期 + 时间,可以获取日期和时间字段
案例演示:
public class LocalDate_ {
public static void main(String[] args) {
//第三代日期
//解读:
//1. 使用new() 返回表示当前日期时间的 对象
LocalDateTime ldt = LocalDateTime.now();//LocalDate.new();//LocalTime.new();
System.out.println(ldt);
System.out.println("年=" + ldt.getYear());
System.out.println("月=" + ldt.getMonthValue());
System.out.println("月(英文)=" + ldt.getMonth());
System.out.println("日=" + ldt.getDayOfMonth());
System.out.println("小时=" + ldt.getHour());
System.out.println("分钟=" + ldt.getMinute());
System.out.println("秒=" + ldt.getSecond());
LocalDate localDate = LocalDate.now();
System.out.println("localDate=" + localDate);//年月日 yyyy-MM-dd
LocalTime localTime = LocalTime.now();
System.out.println("localTime=" + localTime);//时分秒.毫秒
}
}
2)DateTimeFormatter
格式日期类
类似于 SimpleDateFormat
DateTimeFormat tfd = DateTimeFormatter.ofPattern(格式);
String str = dtf.format(日期对象);
案例演示:
public class DateTimeFormatter_ {
public static void main(String[] args) {
LocalDateTime ldt = LocalDateTime.now();
//使用 DateTimeFormatter 对象来进行格式化
//创建 DateTimeFormatter对象
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH小时mm分钟ss秒");
String format = dtf.format(ldt);
System.out.println("格式化的日期=" + format);
}
}
3)Instant 时间戳
类似于Date
提供了一系列和Date类转换的方法
Instant ------> Date;
Date date = Date.from(instant);
Date ------>Instant ;
Instant instant = date.toInstant();
案例演示:
public class Instant_ {
public static void main(String[] args) {
//1. 通过 静态方法 now() 获取表示当前时间戳的对象
Instant now = Instant.now();
System.out.println(now);
//2. 通过 from 方法把 Instant转成 Date
Date date = Date.from(now);
//3. 通过 date的的toInstant() 可以把 date 转成Instant对象
Instant instant = date.toInstant();
System.out.println(instant);
}
}
4)第三代日期类更多方法
- LocalDateTime类
- MonthDay类:检查重复事件
- 是否是闰年
- 增加日期的某个部分
- 使用plus方法测试增加时间的某个部分
- 使用minus方法测试查看一年前和一年后的日期
LocalDateTime ldt = LocalDateTime.now();
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
//通过了 plus 和 minus方法对当前时间进行加或者减
//看看890天后,是什么时候 把 年月日-时分秒 打印出来
LocalDateTime localDateTime = ldt.plusDays(890);
System.out.println("890天后=" + dtf.format(localDateTime));
//看看在 3456分钟前是什么时候 把 年月日-时分秒 打印出来
LocalDateTime localDateTime1 = ldt.minusMinutes(3456);
System.out.println("3456分钟前日期=" + dtf.format(localDateTime1));
作业
1、编程题
(1) 将字符串中指定部分进行反转。比如将 “abcdef” 反转为 “aedcbf”
(2) 编写方法 public static String reverse(String str, int start, int end);
public class Homework01 {
public static void main(String[] args) {
//测试
String str = "abcdef";
System.out.println("---交换前---");
System.out.println(str);
try {
str = reverse(str, 1, 4);
}catch (Exception e){
System.out.println(e.getMessage());
System.exit(0);
}
System.out.println("---交换后---");
System.out.println(str);
}
/*
(1) 将字符串中指定部分进行反转。比如将 “abcdef” 反转为 “aedcbf”
(2) 编写方法 public static String reverse(String str, int start, int end);
思路分析:
1. 先把方法确定 public static String reverse(String str, int start, int end);
2. 把 String 转成 char[],因为char[] 的元素是可以交换的
3. 代码实现
*/
public static String reverse(String str, int start, int end){
//对输入的参数做一个验证
//重要的编程技巧
//(1) 写出正确的情况
//(2) 然后取反即可
if (!(str != null && start >=0 && end > start && end < str.length())){
throw new RuntimeException("参数不正确");
}
char[] chars = str.toCharArray();
char temp = ' ';//交换辅助变量
for(int i = start, j= end; i < j; i++,j--){
temp = chars[i];
chars[i] = chars[j];
chars[j] = temp;
}
//使用chars 重新构建一个String 返回
return new String(chars);
}
}
2、编程题
输入用户名、密码、邮箱,如果信息录入正确,则提示注册成功,否则生成异常对象
要求:
(1)用户名长度为2或3或4
(2)密码的长度为6,要求全是数字
(3)邮箱中包含@和. 并且@在. 的前面
public class Homework02 {
public static void main(String[] args) {
String name = "jack";
String pwd = "123456";
String email = "jack@sohu.com";
try {
userRegister(name,pwd,email);
System.out.println("注册成功");
}catch (Exception e){
System.out.println(e.getMessage());
}
}
/**
* 输入用户名、密码、邮箱,如果信息录入正确,则提示注册成功,否则生成异常对象
* 要求:
* (1)用户名长度为2或3或4
* (2)密码的长度为6,要求全是数字
* (3)邮箱中包含@和. 并且@在. 的前面
*
* 思路分析:
* 1. 先编写方法名 userRegister(String name, String pwd, String email){}
* 2. 针对 输入的内容进行校验,如果发现有问题,就抛出异常,给出提示
* 3. 单独的写一个方法,判断 密码是否全部是数字字符 boolean
*/
public static void userRegister(String name, String pwd, String email){
//再加入一些效验
if(!(name != null && pwd != null && email != null)){
throw new RuntimeException("参数不能为空");
}
int userLength = name.length();
if(!(userLength >= 2 && userLength <= 4)){
throw new RuntimeException("用户名长度为2或3或4");
}
if(!(pwd.length() == 6 && isDigital(pwd))){
throw new RuntimeException("密码的长度为6,要求全是数字");
}
int i = email.indexOf('@');
int j = email.indexOf('.');
if(!(i > 0 && i < j)){
throw new RuntimeException("邮箱中包含@和. 并且@在. 的前面");
}
}
//单独的写一个方法,判断 密码是否全部是数字字符 boolean
public static boolean isDigital(String str){
char[] chars = str.toCharArray();
for (int i = 0; i < chars.length; i++) {
if(chars[i] < '0' || chars[i] > '9'){
return false;
}
}
return true;
}
}
3、编程题
(1)编写出java程序,输入形式为:Han shun Ping 的人名,以Ping,Han .S的形式打印出来。其中,.S是中间单纯的首字母
(2)例如输入 “Willian Jefferson Clinton”,输出形式为:Clinton,Willian .J
public class Homework03 {
public static void main(String[] args) {
String name = "Willian Jefferson Clinton";
printName(name);
}
/**
* (1)编写出java程序,输入形式为:Han shun Ping 的人名,以Ping,Han .S的形式打印出来。
* 其中,.S是中间单纯的首字母
* (2)例如输入 “Willian Jefferson Clinton”,输出形式为:Clinton,Willian .J
*
* 编写方法:完成输出格式要求的字符串
* 1. 对输入的字符串进行 分割split(" ")
* 2. 对得到的String[] 进行格式化String.format()
* 3. 对输入的字符串进行效验
*/
public static void printName(String str){
if(str == null){
System.out.println("str 不能为空");
return;
}
String[] names = str.split(" ");
if(names.length != 3){
System.out.println("输入的字符串格式不正确");
return;
}
String format = String.format("%s,%s .%c", names[2], names[0], names[1].toUpperCase(Locale.ROOT).charAt(0));
System.out.println(format);
}
}
4、编程题
输入字符串,判断里面有多少个大写字母,多少个小写字母,多少数字
public class Homework04 {
public static void main(String[] args) {
countStr("asdh1238AB$");
}
/**
* 输入字符串,判断里面有多少个大写字母,多少个小写字母,多少数字
*
* 思路分析:
* 1. 遍历字符串,如果 char 在 '0' - '9' 就是一个数字
* 2. 如果 char 在 'a' - 'z' 就是一个小写字母
* 3. 如果 char 在 'A' - 'Z' 就是一个大写字母
* 4. 使用三个变量记录 统计结果
*/
public static void countStr(String str){
if(str == null){
System.out.println("输入不能为null");
return;
}
int length = str.length();
int numCount = 0;
int lowerCount = 0;
int upperCount = 0;
int otherCount = 0;
for (int i = 0; i < length; i++) {
if(str.charAt(i) >= '0' && str.charAt(i) <= '9'){
numCount++;
}else if(str.charAt(i) >= 'a' && str.charAt(i) <= 'z'){
lowerCount++;
}else if(str.charAt(i) >= 'A' && str.charAt(i) <= 'Z'){
upperCount++;
}else {
otherCount++;
}
}
System.out.println("数字有 " + numCount);
System.out.println("小写字母有 " + lowerCount);
System.out.println("大写字母有 " + upperCount);
System.out.println("其他字符有 " + otherCount);
}
}
5、试写出以下运行结果
已知Animal类有属性name,可以通过有参构造为属性赋值
class Animal{
String name;
public Animal(String name){
this.name = name;
}
}
String s1 = "zzpude";
Animal a = new Animal(s1);
Animal b = new Animal(s1);
System.out.println(a == b);//false
System.out.println(a.equals(b));//false
System.out.println(a.name == b.name);//true
String s4 = new String("zzpedu");
String s5 = "zzpedu";
System.out.println(s1 == s4);//false
System.out.println(s4 == s5);//false
String t1 = "hello" + s1;
String t2 = "hellozzpedu";
System.out.println(t1.intern() == t2);//true
public class Homework05 {
public static void main(String[] args) {
String s1 = "zzpedu";
Animal a = new Animal(s1);
Animal b = new Animal(s1);
System.out.println(a == b);//false
System.out.println(a.equals(b));//false
System.out.println(a.name == b.name);//true
String s4 = new String("zzpedu");
String s5 = "zzpedu";
System.out.println(s1 == s4);//false
System.out.println(s4 == s5);//false
String t1 = "hello" + s1;
String t2 = "hellozzpedu";
System.out.println(t1.intern() == t2);//true
}
}
class Animal{
String name;
public Animal(String name){
this.name = name;
}
}
============控制台输出===============
false
false
true
false
false
true