常用类
包装类(Wrapper)
- 下列包装类的父类都是:Number
基本数据类型 | 包装类 |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
- 独立的两个包装类
Character类关系图
Boolean类关系图
基本数据类型 | 包装类 |
---|---|
boolean | Boolean |
char | Character |
包装类和基本数据的转换
- jdk5前是手动装箱和拆箱方式,装箱:基本类型->包装类型,反之,拆箱
- jdk5以后(含)是自动装箱和拆箱方式
- 自动装箱底层调用的是 valueOf 方法,比如 Integer.valueOf()
装箱与拆箱的演示:
package com.hspedu.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) 可通过调试中的Force Step Into查看
//自动拆箱 Integer-->int
int n3=integer2; //底层使用的是 Integer.intValue(n3)
}
}
包装类的练习
package com.hspedu.wrapper;
public class WrapperExercise01 {
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 if-else语句是独立的,不会提升精度
}
}
包装类型和String类型的相互转换
以Integer与String的转换为例:
package com.hspedu.wrapper;
public class WrapperVSString {
public static void main(String[] args) {
//Integer-->String
Integer i = 100;
//方式1:
String str1 = i + "";
//方式2:使用包装类的toString方法
String str2 = i.toString();
//方式3:
String str3 = String.valueOf(i);
//String-->Integer
String str4 = "12345";
//方法1:
Integer i2 = Integer.parseInt(str4);
//方法2:
Integer i3 = new Integer(str4);
//方法3:
Integer i4 = Integer.valueOf(str4);
}
}
Integer类和Character类的常用方法
方法太多不能一一列举,用的时候查API
package com.hspedu.wrapper;
public class WrapperMethod {
public static void main(String[] args) {
System.out.println(Integer.MIN_VALUE);//返回int类型的最小值 -2147483648
System.out.println(Integer.MAX_VALUE);//返回最大值 2147483647
System.out.println(Character.isDigit('a'));//判断是不是数字
System.out.println(Character.isLetter('a'));//判断是不是字母
System.out.println(Character.isUpperCase('a'));//判断是不是大写
System.out.println(Character.isLowerCase('a'));//判断是不是小写
System.out.println(Character.isWhitespace('a'));//判断是不是空格
System.out.println(Character.toUpperCase('a'));//转成大写
System.out.println(Character.toLowerCase('a'));//转成小写
}
}
Integer创建机制
Integer面试题总结
package com.hspedu.wrapper;
public class WrapperExercise02 {
public static void main(String[] args) {
Integer i = new Integer(1);
Integer j = new Integer(1);
System.out.println(i==j); //false,显然易见,i和j分别new出来的不是同一个对象
Integer m = 1;//自动装箱 底层:Integer.valueOf(1)-->查看源码
Integer n = 1;//查看源码在 -128~127 范围内直接返回一个Integer[]内的值,否则会返回 new Integer(i)
System.out.println(m==n); //true
Integer x = 128;//底层:Integer.valueOf(128)
Integer y = 128;//超出范围,是返回了 new Integer(128)
System.out.println(x==y); //false
Integer i1 = 127; //只要有基本数据类型
int i2 = 127; //判断的就是值是否相同
System.out.println(i1 == i2);//true
Integer i3 = 128; //这里i3会自动装箱 valueOf
int i4 = 128;
System.out.println(i3 == i4);//true
// 这里i3在比较的时候 ,会自动拆箱 intValue 所以实际上是两个int类型的值在比较,所以说“有基本数据类型时,判断的是值是否相同”
}
}
源码:
//变量
private final int value;
//构造
public Integer(int value) {
this.value = value;
}
//装箱
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
//拆箱
public int intValue() {
return value;
}
String
String类的理解和创建对象
-
String 对象用于保存字符串,也就是一组字符序列
-
字符串常量对象是用双引号括起来的字符序列,例如 “123”,“nihao”
-
字符串的字符使用Unicode字符编码,一个字符(不区分字母还是汉字)占两个字节
-
String构造器有很多
-
String 可以串行化:可以在网络传输
-
String 是个final类,不能被其他类继承
-
String 底层保存在char数组中,如下:
-
private final char value[]
-
一定要注意: value 是一个 final类型,不可以被修改 (这指的是: value 不能指向新的地址,但是单个字符的内容是可以变化的)
两种创建String对象的区别
方法一: 直接赋值 String s = “zmc”
方法二: 调用构造器 String s2 = new String(“zmc”)
- 方式一:先从常量池查看是否有"zmc"数据空间,如果有,直接指向;如果没有,则重新创建,然后指向. s 最终指向的是常量池的空间地址
- 方式二:先在堆中创建空间,里面维护了value属性,指向常量池的"zmc"空间.如果常量池没有"zmc",重新创建,如果有,直接通过value指向.最终指向的是堆中的空间地址.
练习一
package com.hspedu.string_;
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 同一个常量池中的地址
}
}
练习二
package com.hspedu.string_;
public class StringExercise02 {
public static void main(String[] args) {
String a = new String("abc");
String b = new String("abc");
System.out.println(a.equals(b));//true
System.out.println(a==b);//false 堆中的地址不同
}
}
练习三
- 当调用intern()方法时,如果池已经包含一个等于此String对象的字符串(用equals(Object)方法确定),则返回池中的字符串.否则,将此String对象添加到池中,并返回此String对象的引用, 即intern()方法最终返回的是常量池的地址
package com.hspedu.string_;
public class StringExercise03 {
public static void main(String[] args) {
String a = "zmc";// a指向常量池的”zmc“
String b = new String("zmc");// 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
}
}
练习四
package com.hspedu.string_;
public class StringExercise04 {
public static void main(String[] args) {
String s1 = "zmc";
String s2 = "java";
String s4 = "java";
String s3 = new String("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
}
}
练习五
package com.hspedu.string_;
public class StringExercise05 {
public static void main(String[] args) {
Person p1 = new Person();//堆
p1.name = "hspedu";//常量池
Person p2 = new Person();//堆
p2.name = "hspedu";//常量池
System.out.println(p1.name.equals(p2.name));//true
System.out.println(p1.name == p2.name);//true,
System.out.println(p1.name == "hspedu");//true, "hspedu"返回的就是池中的地址
String s1 = new String("bcde");
String s2 = new String("bcde");
System.out.println(s1 == s2);//false
}
}
class Person{
public String name;
}
String对象特性
练习六
package com.hspedu.string_;
public class StringExercise06 {
public static void main(String[] args) {
//以下语句创建了几个对象?
String s1 = "hello";
s1 = "haha";
//两个!首先在常量池中创建"hello",然后创建了"haha",s1取消对"hello"的指向,指向的而是"haha"
}
}
练习七
package com.hspedu.string_;
public class StringExercise07 {
//这里又创建了几个对象?
String a = "hello"+"abc";
//一个!
//编译器会进行优化,《==》优化等价为 String a = "helloabc"
//编译器会判断创建常量池的对象,是否有引用指向
}
练习八
package com.hspedu.string_;
public class StringExercise08 {
public static void main(String[] args) {
//创建了几个对象?
String a = "hello";
String b = "abc";
String c = a + b;
// c = a + b 与 c = "hello" + "abc" 是不同的 常量
// 1.先执行一个 StringBuilder sb = StringBuilder()
// 2.执行 sb.append("hello")
// 3.sb.append("abc")
// 4.String c = sb.toString()
//最后其实是 c 指向堆中的对象(String) value[] -> 池中 "helloabc"
// 3个对象!
}
}
- 常量相加 String c1 = “ab” + “cd” ,看的是 池 ;变量相加 String c1 = a +b,看的是 堆 .
练习九
package com.hspedu.string_;
public class StringExercise09 {
public static void main(String[] args) {
String s1 = "hspedu";// 指向池中的"hspedu"
String s2 = "java"; // 指向池中的"java"
String s5 = "hspedujava";// 指向池中的"hspedujava"
String s6 = (s1+s2).intern();// s1+s2先指向的是堆,再调用intern(),指向的是池中的对象
System.out.println(s5 == s6);//true
System.out.println(s5.equals(s6));//true
}
}
练习十
package com.hspedu.string_;
public class Test1 {
String str = new String("hsp");
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.println(ex.str+"and");
System.out.println(ex.ch);
}
}
这里看晕了,需要多看两遍 0470 String对象特征2
String类常用方法
- String类是保存字符串常量的.每次更新都需要重新开辟空间,效率较低,因此Java设计者还设计了 StringBuilder 和 StringBuffer 来增强String的功能,并提高效率.
String常用方法实例1
- equalsIgnoreCase //忽略大小写的判断内容是否相等
- indexOf //获取字符在字符串中第1次出现的索引,索引从0开始,如果找不到,返回-1
- lastIndexOf //同上,不过是最后最后一次出现的索引,找不到也返回-1
- substring //获得字串
- trim //去除前后空格
- charAt //获取某索引处的字符,注意不能使用str[index]这种方法
String常用方法实例2
- toUpperCase //转换大写
- toLowerCase //转换小写
- concat //拼接字符串
- replace //替换字符串中的字符
- split //分割字符串,对于某些分割的字符,我们需要转义
- compareTo //比较两个字符串的大小
- toCharArray //转换成字符数组
- format //格式化字符串,%s 字符串 %c 字符 %d 整形 %.2f 浮点型
StringBuffer
StringBuffer结构剖析
- StringBuffer代表可变的字符序列,可以对字符串内容进行增删
- StringBuffer的很多方法与String相同,但是StringBuffer是可变长度的
- StringBuffer是一个容器
- StringBuffer实现了Serializable ,即StringBuffer的对象可以串行化
- 在父类中 AbstractStringBuilder 有属性 char[ ] value,不是final,该value数组存放字符串内容,存放在堆中,而不是常量池了
- StringBuffer是一个final类,不能被继承
String VS StringBuffer
- String保存的是字符串常量,里面的值不能更改,每次String类的更新实际上就是更改地址,效率较低 // private final char value[];
- StringBuffer保存的是字符串变量,里卖的值可以更改,每次StringBuffer的更新实际上可以更新内容,不用每次更新地址(当数组容量不够时,会拷贝到一个容量更大的数组中,此时才会更新地址),效率较高 //char[ ] value 这个放在堆
StringBuffer构造类
package com.hspedu.stringbuffer_;
public class StringBuffer01 {
public static void main(String[] args) {
//1.创建一个大小为16的char[],用于存放字符内容(源码中)
StringBuffer stringBuffer = new StringBuffer();
//2.通过构造器指定 char[] 大小
StringBuffer stringBuffer1 = new StringBuffer(100);
//3.通过 给一个String 创建StringBuffer,char大小就是 str.length()+16
StringBuffer hello = new StringBuffer("hello");
}
}
StringBuffer的转换
StringBuffer与String相互转化
package com.hspedu.stringbuffer_;
public class StringAndStringBuffer {
public static void main(String[] args) {
//String-->StringBuffer
String str = "hello tom";
//方式1:使用构造器,返回的才是StringBuffer对象,对str本身没有影响
StringBuffer stringBuffer = new StringBuffer(str);
//方式2:使用append方法
StringBuffer stringBuffer1 = new StringBuffer();
stringBuffer1.append(str);
//StringBuffer-->String
StringBuffer stringBuffer2 = new StringBuffer("zmc");
//方式1 使用StringBuffer提供的 toString方法
String s = stringBuffer2.toString();
//方式2 使用String的构造器
String s1 = new String(stringBuffer2);
}
}
StringBuffer常用方法
package com.hspedu.stringbuffer_;
public class StringBufferMethod {
public static void main(String[] args) {
StringBuffer s = new StringBuffer("hello");
//1.增加 append
s.append(',');
s.append("张三丰");
s.append("赵敏").append(100).append(true).append(10.5);
System.out.println(s);// hello,张三丰赵敏100true10.5
//2.删除 delete 删除索引 >=start && <end 处的字符 左闭右开
s.delete(11,14);
System.out.println(s);
//3.修改 同样是左闭右开
s.replace(9,11,"周芷若");
System.out.println(s);
//4.查找指定字串在字符串中第一次出现的位置,找不到则返回-1
int indexOf = s.indexOf("张三丰");
System.out.println(indexOf);
//5.插入 在索引为9的位置插入“赵敏”,原来索引为9的内容自动后移
s.insert(9,"赵敏");
System.out.println(s);
//6.长度 length
System.out.println(s.length());
}
}
练习
练习一
package com.hspedu.stringbuffer_;
public class StringBufferExercise01 {
public static void main(String[] args) {
String str = null;
StringBuffer sb = new StringBuffer();
sb.append(str);//str为null市,底层调用的是 abstractStringBuilder 的 appendNull
System.out.println(sb.length());// 4
System.out.println(sb);// null
//下面的构造器,会抛出空指针异常
StringBuffer sb1 = new StringBuffer(str);//看源码:super(str.length() + 16); 即 null.length()
System.out.println(sb1);
}
}
练习二
package com.hspedu.stringbuffer_;
public class StringBufferExercise02 {
public static void main(String[] args) {
/*
1.定义一个Scanner对象,接收用户输入的 价格(String)
2.希望使用StringBuffer的insert,需要将String转成StringBuilder
*/
String price = "234123564.59";
StringBuffer sb = new StringBuffer(price);
//找到小数点的索引,然后在该位置的前3位,插入逗号即可
for (int i = sb.lastIndexOf(".")-3; i > 0; i-=3) {
sb.insert(i,",");
}
System.out.println(sb);
}
}
StringBuilder
StringBuilder结构剖析
- 一个可变的字符序列。此类提供一个与StringBuffer兼容的API,但不保证同步(StringBuilder不是线程安全)。该类被设计用作StringBuffer的一个简易替换,用在字符串缓冲区被单个线程使用的时候。如果可能,建议优先采用该类,因为在大多数实现中,它比StringBuffer要快
- 在StringBuilder上主要操作是 append 和 insert 方法,可以重载这些方法,以接受任意类型的数据
- StringBuilder实现了Serializable ,即StringBuffer的对象可以串行化
- StringBuilder继承 AbstractStringBuilder 类
- StringBuilder是final类,不能被继承
- StringBuilder 对象字符序列仍然是存放在父类中 AbstractStringBuilder 的属性 char[ ] value,因此字符序列是存在堆里的
- StringBuilder的方法,都没有做互斥处理,即和StringBuffer比较,StringBuilder的方法都没有synchronized关键字,因此在单线程的情况下建议使用StringBuilder
String、StringBuffer和StringBuilder的比较
- StringBuilder和StringBuffer非常类似,均可代表可变字符序列,而且方法也一样
- String:不可变字符序列,效率低,但是复用率高(常量池中一个字符可被多个引用)
- StringBuffer:可变字符序列,效率较高(增删)、线程安全
- StringBuilder:可变字符序列,效率最高、线程不安全
- 如果我们对字符串要做大量修改,不要使用String,因为会导致大量副本字符串对象存留在对象中,降低效率,可以选用其他两种
Math
- ceil 向上取整
- floor 向下取整
- round 四舍五入
- random 0<=x<1的小数
package com.hspedu;
public class math_ {
public static void main(String[] args) {
//ceiling(天花板)向上取整
double ceil = Math.ceil(-3.000001);
System.out.println(ceil);//-3.0
//floor(地板)向下取整
double floor = Math.floor(4.001);
System.out.println(floor);//4.0
//round 四舍五入 Math.floor(参数+0.5)
long round = Math.round(5.49);
System.out.println(round);
//random 随机数 返回 0<= x < 1之间的一个随机小数
//a到b 之间的一个随机整数,a,b均为整数 ,例 2~7
// int(a) <= x <= (int)(a + Math.random()*(b-a+1))
// 2+Math.random()*6返回的就是 2 <= x < 8 的小数,再int转换一下 就是 2~7
for (int i = 0; i < 100; i++) {
System.out.println((int)(2+Math.random()*6));
}
}
}
Date、Calendar、LocalDate
第一代日期类 Date
- Date:精确到毫秒,代表特定的瞬间
- SimpleDateFormat:格式和解析日期的类。SimpleDateFormat格式化和解析日期的具体类。它允许进行格式化(日期->文本)、解析(文本->日期)和规范化.
package com.hspedu.date_;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
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);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss E");//格式字母是规定好的,不能乱写
String format = sdf.format(d1);// format:将日期转换成指定格式的字符串
System.out.println("当前日期="+format);
String s = "1990年01月01日 10:20:30 星期一";
Date parse = sdf.parse(s);
System.out.println("parse="+parse);//Parse(解析的意思)
}
}
第二代日期类 Calendar
-
第二代日期类主要就是Calendar类(日历)。public abstract class Calendar extends Object implements Serializable,Cloneable, Comparable < Calendar >
-
Calendar类是一个抽象类,它为特定瞬间与一组诸如YEAR、MONTH、DAY_OF_MONTH、HOUR等日历字段之间的转换提供了一些方法,并为操作日历字段(例如获得下星期的日期)提供了一些方法。
package com.hspedu.date_;
import java.util.Calendar;
public class Calendar_ {
public static void main(String[] args) {
//Calendar是一个抽象类,并且构造器是private私有的,我们可以通过 getInstance() 来获取实例
Calendar c = Calendar.getInstance(); //创建日历类对象//比较简单,自由
System.out.println(c);
//2.获取日历对象的某个日历字段
System.out.println("年:"+ c.get(Calendar.YEAR));
System.out. println("月:"+ (c.get(Calendar.MONTH) + 1));//月份默认从0开始,所以要+1
System.out.println("日:" + c.get(Calendar.DAY_OF_MONTH));
System.out.println("小时:"+ c.get(Calendar.HOUR));
System.out.println("分钟: " + c.get(Calendar.MINUTE));
System.out.println("秒:"+ c.get(Calendar.SECOND)) ;
//CaLender没有专门的格式化方法,所以需要程序员自己来组合显示,如下:
System.out.println(c.get(Calendar.YEAR)+"-"+(c.get(Calendar.MONTH) + 1)+"-"+c.get(Calendar.DAY_OF_MONTH)+" "+c.get (Calendar.HOUR)+"-"+c.get (Calendar.MINUTE)+"-"+c.get (Calendar.SECOND));
//如果我们需要按照24小时进制来获取时间,Calendar.HOUR 改成=> Calendar.HOUR_OF_DAY
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));
}
}
第三代日期类
➢前面两代日期类的不足分析
JDK 1.0中包含了一个java.util.Date类, 但是它的大多数方法已经在JDK 1.1引入Calendar类之后被弃用了。而Calendar也存在问题是:
- 可变性:像日期和时间这样的类应该是不可变的。
- 偏移性: Date中的年份是从1900开始的,而月份都从0开始。
- 格式化:格式化只对Date有用,Calendar则不行。
- 此外,它们也不是线程安全的;不能处理闰秒等(每隔2天,多出1s)。
➢第三代日期类的常见方法
- LocalDate(包含年月日)
- LocalTime(包含时分秒)
- LocalDateTime(上面两者都有)
package com.hspedu.date_;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class LocalDate_ {
public static void main(String[] args) {
//使用now() 返回表示当前日期时间的对象
LocalDateTime now = LocalDateTime.now();//LocalDate.now() //LocalTime.now()
System.out.println(now);
System.out.println("年="+now.getYear());
System.out.println("月="+now.getMonth());
System.out.println("月="+now.getMonthValue());
//使用DateTimeFormatter对象来进行格式化
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH小时mm分钟ss秒");
String format = dateTimeFormatter.format(now);
System.out.println("格式化的日期="+format);
}
}
- Instant 时间戳: 类似于Date ,提供了一系列和Date类转换的方式
package com.hspedu.date_;
import java.time.Instant;
import java.util.Date;
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();
}
}
第三代日期类更多方法
//提供 plus 和 minus 方法可以对当前时间进行加或者减
//看看890天后,是什么时候
LocalDateTime localDateTime = now.plusDays(890);
System.out.println("890天后是什么时候:"+dateTimeFormatter.format(localDateTime));
//看看3456分钟前是什么时候
LocalDateTime localDateTime1 = now.minusMinutes(3456);
System.out.println("3456分钟前是什么时候:"+dateTimeFormatter.format(localDateTime1));
System
System类常见方法和案例
-
exit 退出当前程序
-
arraycopy 复制数组元素,比较适合底层调用,一般使用Arrays.copyOf完成复制数组
-
currentTimeMillens 返回当前时间距离1970-1-1 的毫秒数
-
gc 运行垃圾回收机制 System.gc()
package com.hspedu.system_;
public class SystemMethod {
public static void main(String[] args) {
int[] src={1,2,3};
int[] dest = new int[3];//dest 当前是{0,0,0}
//src:原数组
//srcPos:从原数组的哪个索引位置开始拷贝
//dest:目标数组
//destPos:把原数组的数据拷贝到目标数组的哪个索引
//length:从原数组拷贝多少个数据到目标数组
System.arraycopy(src,0,dest,0,3);
}
Arrays
- Arrays里面包含了一系列的静态方法,用于管理或操作数组(比如排序和搜索)
Arrays的常用方法
- toString返回数组的字符串形式 Arrays.toString(arr)
- sort 排序
package com.hspedu.arrays_;
import java.util.Arrays;
import java.util.Comparator;
public class ArraysMethod01 {
public static void main(String[] args) {
Integer[] integers = {1, 20, 90};
//1.toString
System.out.println(Arrays.toString(integers)); //[1, 20, 90]
//2.sort
Integer[] arr = {1, -1, 20, 0, 90};
//默认排序
Arrays.sort(arr);
System.out.println(Arrays.toString(arr));//[-1, 0, 1, 20, 90]
//定制排序
//sort是有重载的,也可以通过传入一个一个接口 Comparator 实现定制排序
//调用定制排序时。传入两个参数(1)排序的数组arr (2)实现了Comparator接口的匿名内部类,要求实现compare方法
//调用顺序:
//(1)Arrays.sort(arr, new Comparator()
//(2)执行到TimSort类的 private static <T> void binarySort(T[] a, int lo, int hi, int start,Comparator<? super T> c)
//(3)执行到binarySort中的
// while (left < right) {
// int mid = (left + right) >>> 1;
// if (c.compare(pivot, a[mid]) < 0)
// right = mid;
// else
// left = mid + 1;
//}
//(4)new Comparator(){
// @Override
// public int compare(Object o1, Object o2) {
// Integer i1 = (Integer) o1;
// Integer i2 = (Integer) o2;
// return i1-i2;
// }
// }
//(5)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 i1-i2;
}
});
}
}
模拟排序 (对上面例子的近一步解释)
package com.hspedu.arrays_;
import java.util.Arrays;
import java.util.Comparator;
public class ArraysSortCustom {
public static void main(String[] args) {
int[] arr = {1,-1,8,0,20};
//bubble01(arr);
bubble02(arr, new Comparator() {
@Override
public int compare(Object o1, Object o2) {
int i1 = (Integer) o1;
int i2 = (Integer) o2;
return i1-i2; //实际上时设定是 i1-i2 还是 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-1-i; j++) {
//从小到大排序
if(arr[j]>arr[j+1]){
temp=arr[j];
arr[j] = arr[j+1];
arr[j+1] = 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-1-i; j++) {
//数组排序由 c.compare(arr[j],arr[j+1])的返回值决定
if(c.compare(arr[j],arr[j+1])>0){
temp=arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
}
}
- binarySearch 通过二分搜索法进行查找,要求必须排好序:升序
- 其他常用方法:
package com.hspedu.arrays_;
import java.util.Arrays;
import java.util.List;
public class ArraysMethod02 {
public static void main(String[] args) {
Integer[] arr = {1,2,3,123,567};
//binarySearch 该数组必须是有序(升序)的,否则不能使用
// 如果数组中不存在元素,看源码,就返回 return -(low+1) low 是这个数字应该在的位置 ,比如 4,应该在3后面,low=3 返回 -(3+1)
int index = Arrays.binarySearch(arr, 4);
System.out.println(index);
//copyOf 数组元素的复制
//1.从arr中,拷贝arr.length个元素到 newArr数组中
//2.如果拷贝的长度大于arr.length,就在新数组的后面 增加null
Integer[] newArr = Arrays.copyOf(arr, arr.length);
System.out.println(Arrays.toString(newArr));
//fill数组元素的填充
//1.使用传入的参数,替换所有的元素
Integer[] num = {9, 3, 2};
Arrays.fill(num,99);
System.out.println("==num数组填充后==");
System.out.println(Arrays.toString(num));
//equals 比较两个数组元素内容是否完全一致
//1.如果两个数组的元素一样,则返回true,否则false
Integer[] arr2 = {1,2,90,123,567};
boolean equals = Arrays.equals(arr, arr2);
//asList 将一组值,转换成list
//1.asList方法会将(2, 3, 4, 5, 6, 1)数据转成一个List集合
//2.返回的 asList 编译类型 List(接口)
List<Integer> asList = Arrays.asList(2, 3, 4, 5, 6, 1);
System.out.println("asList="+asList);
System.out.println("asList的运行类型"+asList.getClass());
}
}
练习(定制排序)
package com.hspedu.arrays_;
import java.util.Arrays;
import java.util.Comparator;
public class ArrayExercise {
public static void main(String[] args) {
Book[] books = new Book[4];
books[0] = new Book("红楼梦", 100);
books[1] = new Book("西游记新", 90);
books[2] = new Book("青年文摘20年", 5);
books[3] = new Book("java从入门到放弃~", 300);
//(1)price 从大到小
// Arrays.sort(books, new Comparator() {
// @Override
// public int compare(Object o1, Object o2) {
// Book book1 = (Book) o1;
// Book book2 = (Book) o2;
// double price = book2.getPrice()-book1.getPrice();
// //数据转换
// if(price > 0){
// return 1;
// }else if(price < 0){
// return -1;
// }else{
// return 0;
// }
// }
// });
//(2)按书名的长度排序
Arrays.sort(books, new Comparator() {
@Override
public int compare(Object o1, Object o2) {
Book book1 = (Book) o1;
Book book2 = (Book) o2;
int price = book2.getName().length()-book1.getName().length();
return price;
}
});
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 +
'}';
}
}
BigInteger BigDecimal
应用场景与介绍
- BigInteger 适合保存比较大的整型
- BigDecimal适合保存精度更高的浮点型(小数)
BigInteger 常用方法
package com.hspedu.bignum;
import java.math.BigInteger;
public class BigInteger_ {
public static void main(String[] args) {
//当我们的编程中,需要处理很大的整数,long不够用,可以使用BigInteger的类来搞定
BigInteger bigInteger = new BigInteger("999999999999999999999");
System.out.println(bigInteger);
//在对BigInteger 进行加减乘除的时候,需要使用对应的方法,不能用 + - * /
//bigInteger.add() 加
//bigInteger.subtract() 减
//bigInteger.multiply() 乘
//bigInteger.divide() 除
}
}
BigDecimal常用方法
package com.hspedu.bignum;
import java.math.BigDecimal;
public class BigDecimal_ {
public static void main(String[] args) {
//使用BigDecimal
BigDecimal bigDecimal = new BigDecimal(25.99999999999999d);
BigDecimal bigDecimal2 = new BigDecimal("5");
//1.对BigDecimal进行四则运算,需要使用对应的方法
//四种方法同上
//但是 divide方法可能抛出异常ArithmeticException
//可以指定精度,BigDecimal.ROUND_CEILING
//如果是无限循环小数,会保留与被除数同样的精度
System.out.println(bigDecimal.divide(bigDecimal2,BigDecimal.ROUND_CEILING));
}
}