文章目录
1、Object
Object类是所有类的父类,也就是说任何一个类在定义时如果没有明确地继承一个父类,那它就是Object类的子类,也就是说以下两种类定义的最终效果是完全相同的。
class Book{ class Book extends Object{
} }
Object类提供无参构造方法 ,之所以提供这样的无参构造,是因为在子类对象实例化时都会默认调用父类中的无参构造方法,这样在定义类时即使没有明确定义父类为Object,读者也不会感觉代码的强制性要求。
方法 | 说明 |
---|---|
Object clone() | 创建与该对象的类相同的新对象 |
boolean equals(Object) | 比较两个对象是否相等。默认比较的是地址值。 |
void finalize() | 当垃圾回收器确定不存在对该对象的更多引用时,对象的圾回收器调用该方法 |
Class getClass() | 返回一个对象运行时的实例类(.class文件) |
int hashCode() | 返回该对象的散列码值 |
void notify() | 激活等待在该对象的监视器上的一个线程 |
void notifyAll() | 激活等待在该对象的监视器上的全部线程 |
String toString() | 返回该对象的字符串表示,默认返回运行时类名+@+对象的hashCode的16进制数 |
void wait() | 在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待 |
注意:
- 如果两个对象的哈希码值不同,那这两个对象一定不等;
- 如果两个对象的哈希码值相同,不能确保这两个对象一定相等。
- 克隆对象对应的类需要实现Cloneable接口,否则会报错:java.lang.CloneNotSupportedException
如何获取类的字节码文件对象?
- 类名.class 说明: JVM将使用类装载器, 将类装入内存(前提是:类还没有装入内存),不做类的初始化工作.返回Class的对象
- Class.forName(“类名字符串”) (注:类名字符串是包名+类名) 说明:装入类,并做类的静态初始化,返回Class的对象
- 实例对象.getClass() 说明:对类进行静态初始化、非静态初始化; 返回引用o运行时真正所指的对象(因为:子对象的引用可能会赋给父对象的引用变量中) 所属的类的Class的对象
常覆写Object类的3个方法:toString(),equals(Object obj),hashCode()
为什么notify(), wait()等函数定义在Object中,而不是Thread中?
Object中的wait(), notify()等函数,和synchronized一样,会对“对象的同步锁”进行操作。
wait() 会使“当前线程”等待,因为线程进入等待状态,所以线程应该释放它锁持有的“同步锁”,否则其它线程获取不到该“同步锁”而无法运行!
OK,线程调用wait()之后,会释放它锁持有的“同步锁”;而且,根据前面的介绍,我们知道:等待线程可以被notify()或notifyAll()唤醒。现在,请思考一个问题:notify()是依据什么唤醒等待线程的?或者说,wait()等待线程和notify()之间是通过什么关联起来的?答案是:依据“对象的同步锁”。
负责唤醒等待线程的那个线程(我们称为“唤醒线程”),它只有在获取“该对象的同步锁”(这里的同步锁必须和等待线程的同步锁是同一个),并且调用notify()或notifyAll()方法之后,才能唤醒等待线程。虽然,等待线程被唤醒;但是,它不能立刻执行,因为唤醒线程还持有“该对象的同步锁”。必须等到唤醒线程释放了“对象的同步锁”之后,等待线程才能获取到“对象的同步锁”进而继续运行。
总之,notify(), wait()依赖于“同步锁”,而“同步锁”是对象锁持有,并且每个对象有且仅有一个!这就是为什么notify(), wait()等函数定义在Object类,而不是Thread类中的原因。
2、String
表示的是字符串,字符串是常量(值定义了之后,不可修改)
字符串可以看成是多个字符的连接
String 类是
不可变类
,也就是String对象声明后,将不可修改
1)构造方法
String(): 创建一个空的字符串
String(byte[] bys):通过字节数组创建字符串
String(char[] chs):通过字符数组创建字符串
String(byte[] bys,int offset,int length):通过字节数组一部分创建字符串
String(char[] chs,int offset,int length):通过字符数组一部分创建字符串
String(String original):通过字符串常量值创建字符串
/*
关于字符串常用构造方法
*/
public class StringTest02 {
public static void main(String[] args) {
String s1 = "abc";
String s2 = new String("abc");
byte[] bytes = {97,98,99,100};
String s3 = new String(bytes);
System.out.println(s3); // abcd String已经重写了Object中的toString
String s4 = new String(bytes,1,2);
System.out.println(s4);
char[] c1 = {'我','是','中','国','人'};
String s5 = new String(c1);
System.out.println(s5); // 我是中国人
String s6 = new String(c1,2,2);
System.out.println(s6); // 中国
}
}
2)成员方法
1》判断功能
equals(Object obj): 比较两个字符串是否相等
equalsIngnoreCase(Object obj):忽略大小写比较两个字符串是否相等
contains(String str): 是否包含指定字符串
startsWith(String str): 是否以指定的字符串开头
endWith(String str): 是否以指定的字符串结尾
isEmpty(): 是否为空,当且仅当length()为0时返回true
matches(String regex): 判断字符串是否匹配给定的正则表达式。
/*
1、字符串一旦创建不可再改变。"hello"字符串对象一旦创建,不可再改变成"hello1"
2、提升字符串的访问效率,在程序中使用了”缓存“技术。所以在java中所有使用”双引号“括起来的字符串都会在”字符串常量池“中创建一份。
字符串常量池在方法区中被存储
3、在程序执行过程中,如果程序用到某个字符串,例如"hello",那么程序会在字符串常量池中去搜索该字符串,如果没有找到则
在字符串常量池中新建一个"hello"字符串,如果找到就直接拿过来用(字符串常量池是一个缓存区,为了提高访问字符串的效率)
* 字符串做连接操作
* 如果是两个变量进行连接,先开辟空间,再连接
* 如果是两个常量进行连接,先连接,获取连接结构值。然后在常量池里面查找有没有这个结果值,如果有,直接给地址值;没有,开辟空间
*/
public class StringTest01 {
public static void main(String[] args) {
// 创建一个"hello"字符串对象,该对象的内存地址,让s1变量保存
// s1 是一个引用,s1指向"hello"对象
String s1 = "hello"; // 在字符串常量池中新建一个"hello"字符串对象,该对象不可变
String s2 = "hello"; // 从字符串常量池中直接拿来用
String s3 = "world";
String s4 = "helloworld";
// 该程序创建了3个对象,堆中两个,方法区常量池中各一个
String s5 = new String("hello");
System.out.println(s4 == s2 + s3); // false
// 比较两个字符串相等,必须使用String类提供的equals方法
System.out.println(s1 == s2); // true
System.out.println(s1 == s5); // false
System.out.println(s2.equals(s1)); // true
System.out.println(s2.equals(s5)); // true
System.out.println(s4 == "hello"+"world"); // true
System.out.println(s4.equals("hello"+"world")); // true
System.out.println("====================");
// 忽略大小写比较两个字符串是否相等
System.out.println("abc".equalsIgnoreCase("ABC")); // true
System.out.println("===================");
// 是否以指定的字符串结尾
System.out.println("HelloWorld.java".endsWith("java")); // true
System.out.println("HelloWorld.java".endsWith(".java")); // true
System.out.println("HelloWorld.java".endsWith("HelloWorld.java")); // true
System.out.println("HelloWorld.java".endsWith("java ")); // false
}
}
2》获取功能
length(): 获取长度
charAt(int index): 获取指定索引位置处的字符
indexOf(int ch): 获取指定字符第一次出现的索引值(从0开始)
indexOf(int ch,int fromIndex): 获取从指定索引位置开始,获取指定字符第一次出现的索引值
indexOf(String s): 获取指定字符串第一次出现的索引值
indexOf(String s,int fromIndex): 获取从指定索引位置开始,获取指定字符串第一次出现的索引值
lastIndexOf(int ch): 获取指定字符最后一次出现的索引值
substring(int start): 从指定位置开始一直截取到末尾
substring(int start,int end): 截取[start,end-1]范围
public class StringTest03 {
public static void main(String[] args) {
// 1.char charAt(int index);
String s1 = "我是王勇!";
char c1 = s1.charAt(2);
System.out.println(c1); // 王
// 2.int indexOf(String str);
System.out.println("ahsjahdi".indexOf("ah")); // 0
// 3.int indexOf(String str,int fromIndex);
System.out.println("javaeejavasejavaweb".indexOf("java",1)); // 6
// 4.int lastIndexOf(String str);
System.out.println("javaeejavasejavaweb".lastIndexOf("java")); // 12
// 5.int length();
System.out.println("abc".length()); // 3
// 6.String subString(int beginIndex);
System.out.println("abcd".substring(1)); //bcd
// 7.String subString(int beginIndex,int endIndex);
System.out.println("abcd".substring(1,3)); //bc [1,3)
}
}
3》转换功能
byte[] getBytes(): 将字符串转成字节数组
// byte[] getBytes();
byte[] bytes = "abc".getBytes();
for (int i = 0; i <bytes.length ; i++) {
System.out.println(bytes[i]+" "); // 换行的97 98 99
}
char[] toCharArray(): 将字符串转成字符数组
// char[] toCharArray();
char[] c2 = "我是琉璃酱".toCharArray();
for (int i = 0; i <c2.length ; i++) {
System.out.println(c2[i]); // 换行的 我 是 琉 璃 酱
}
static valueOf(char[] chs): 将char[]转成字符串
static valueOf(int num): 将int类型转成字符串
static valueOf(Object obj):将任意类型转成字符串
// String valueOf(Object obj);
Object o = null;
System.out.println(o); // 不会,因为并不是直接调用toString方法,其实是调用了String.valueOf(o),这个方法对空值处理了
System.out.println(String.valueOf(o)); // null
// System.out.println(o.toString()); // 会出现空指针
toLowerCase(): 转成小写
// 转换成小写
System.out.println("ABCDEF".toLowerCase()); // abcdef
toUpcase(): 转成大写
// 转换成大写
System.out.println("Abdcfg".toUpperCase()); // ABDCFG
concat(String str): 字符连接
4》其他功能
replace(char old,char new):将old字符替换成new字符
replace(String old,String new):将old字符串替换成new字符串
trim():去除两边空格
// String trim();
System.out.print(" a bc d ".trim()); // a bc d
int compareTo(String s):字典比较,如果前面值小于后面值返回负数,否则
返回正数,先比较第一个元素,如果相等再比较第二个元素…返回元素之间的
差值;如果比较字符串有包含关系,返回的值是它们长度的差值int
compareToIgnoreCase(String s): 忽略大小写字典比较
StringreplaceAll(String regex, String replacement):使用给定的
replacement 替换此字符串所有匹配给定的正则表达式的子字符串。
// String replaceAll(Strin s1,String s2);
System.out.println("javaeejavasejavaweb".replaceAll("java","mysql")); // mysqleemysqlsemysqlweb
String replaceFirst(String regex, Stringreplacement):使用给定的
replacement 替换此字符串匹配给定的正则表达式的第一个子字符串。
String[] split(String regex): 根据给定正则表达式的匹配拆分此字符串。
// String[] split(String regex);
String myTime = "2020,08,13";
String[] ymd = myTime.split(",");
for (int i = 0; i <ymd.length ; i++) {
System.out.println(ymd[i]); // 换行的2020 08 13
}
String[] split(String regex, int limit): 根据匹配给定的正则表达式来拆分此字符串。
3)编码表
编码表:由现实世界的字符和对应的数值组成的一张表
常见的有:
1)ASCII码:最高为是符号为,其他是数值位
2)ISO-8859-1:拉丁码表
3)BG2312:中文编码表
4)GBK:GB2312的升级版,1个汉字对应2个字节
5)GB18030:GBK的升级版
6)BIG-5:中文繁体编码表,俗称"大5码"
7)Unicode:国际标注码。所有字符都有两个字节表示
Java默认使用该编码表
8)UTF-8:万国码,一个汉字对应3个字节
tips:所有编码表都兼容ASCII码表
String中与字符集相关的方法
String(byte[] by,String charset):通过指定的字符集,将指定的字节数组转成字符串(解码)
byte[] getBytes(String charset):通过指定的字符集,将字符串转成字节数组(编码)
4)正则表达式
负责字符串的匹配处理(一般用于校验字符串格式,也可用于在一段文本中查找满足要求的内容)
^a{2}$ 表示两个a字符,等同于aa
规则
1)字符
x: x字符,a表a字符
\: 反斜线字符
\n: 换行符
\r: 回车符
2)字符类
3)预定义字符类
. : 表示任意字符
. : 表示’.'字符(前面加了一个转义字符)
\d: 表示数字字符,0-9
\w: 表示单词字符,[a-zA-Z_0-9]
4)边界匹配器
^: 表示行的开头
$: 表示行的结尾
\b: 表示单词的边界
例:^a{2}$ 表示两个a字符,等同于aa
5)数量词
? : 表示0次或者1次
*: 表示0次或者多次
+: 表示1次或者多次
{n}: 表示n次
{n,}: 表示至少n次
{n,m}:n~m次
3、StringBuilder类
线程不安全的可变字符序列
1)构造方法
StringBuilder():以默认容量创建空的StringBuilder对象
StringBuilder(int capacity):以指定容量创建空的StringBuilder对象
StringBuilder(String str):以指定的字符串创建StringBuilder对象
2)成员方法
获取功能
int capacity(): 获取容量
int length(): 获取长度
添加功能
append(int value): 追加。可以追加多种类型
insert(int offset,String s): 在指定的位置插入指定数据
删除功能
deleteCharAt(int index): 删除指定索引处的元素
delete(int start,int end): 删除[start,start-1]范围内的元素
替换功能
replace(int start,int end,String s):将[start,end-1]范围内的元素替换成指定字
符串
反转功能
reverse():元素反转
截取功能
String subString(int start): 截取指定位置一直到末尾
String subString(int start,int end): 截取[start,end-1]范围
3)String、StringBuilder和StringBuffer的区别?
String内容不可改变
StringBuilder和StringBuffer内容可变
StringBuilder是线程不安全的,不同步,效率高
StringBuffer是线程安全的,同步,效率低
示例1:StringBuffer
/*
如果以后需要大量字符串的拼接操作,建议使用JDK中自带的:
java.lang.StringBuffer
java.lang.StringBuilder
如何优化StringBuffer的性能?
在创建StringBuffer的时候尽可能给定一个初始化容量
最好减少底层数组扩容次数。预估计一下,给一个大一些的初始化容量
关键点:给一个合适的初始化容量。可以提高程序的执行效率
*/
public class StringBufferTest {
public static void main(String[] args) {
// 创建一个初始化容量为16个byte[] 数组。(字符串缓冲区对象)
StringBuffer stringBuffer = new StringBuffer();
// 拼接字符串,以后拼接字符串统一调用 append() 方法。
// append 是追加的意思。
stringBuffer.append("a");
stringBuffer.append("b");
stringBuffer.append(3.14);
stringBuffer.append(true);
// append方法底层在进行追加的时候,如果byte数组满了,会自动扩容
stringBuffer.append(100L);
System.out.println(stringBuffer.toString()); // ab3.14true100
// 指定初始化容量的StringBuffer对象(字符串缓冲区对象)
StringBuffer sb = new StringBuffer(100);
sb.append("hello");
sb.append("world");
sb.append("hello");
sb.append("kitty");
System.out.println(sb); // helloworldhellokitty
}
}
示例2:StringBuilder
/*
java.lang.StringBuilder
StringBuffer和StringBuilder的区别?
StringBuffer中的方法都有synchronized关键字修饰,表示StringBuffer在多线程环境下运行是安全的
StringBuilder中的方法都没有synchronized关键字修饰,表示StringBuilder在多线程环境下运行是不安全的
StringBuffer 是线程安全的
StringBuilder 是非线程安全的
*/
public class StringBuilderTest {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder();
sb.append(100);
sb.append(true);
sb.append("hello");
sb.append("kitty");
System.out.println(sb); // 100truehellokitty
}
}
4、Scanner
1)构造方法
Scanner(InputStream is)
构造一个文本扫描器,它生成的值是从指定的值输入流扫描的
System.in 是一个标准的输入流,属于InputStream
2)成员方法
boolean hasNext(): 是否有下一个数,有true,没有false
String next(): 获取下个数
int nextInt(): 获取下个int数据
String nextLine(): 获取一行数据
5、Math类
成员方法
abs(int a): 绝对值
ceil(double d): 向上取整
floor(double d): 向下取整
max(int a,int b): 最大值
pow(double a,double b): a的b次幂
random(): 随机数[0.0,1.0]
round(float f): 四舍五入
sqrt(double d): 算术平方根
6、Random类
1)构造方法
Random(): 以当前时间毫秒值作为种子,创建Random对象
Random(long seed): 以指定种子创建Random对象
2)成员方法
nextInt(): 生成1个int类型范围的随机数
nextInt(int n): 产生1个[0,n-1]范围内的随机数
生成0~n之间的数
①(int)Math.random()*(n+1)
②Random r = new Random();
r.nextInt(m)表示生成[0,m-1]之间的随机数,也就是说random.nextInt(m+1),将生成[0,m]之间的随机整数。
r.nextInt(n+1)
生成n~m之间的随机数
①n+(int)(Math.random()(m+1-n));
②Random r = new Random();
r.nextInt(m+1-n)+n;
public class RandomTest01 {
public static void main(String[] args) {
// 创建随机对象
Random random = new Random();
// 随机产生一个int类型取值范围内的数字。
int num1 = random.nextInt();
System.out.println(num1);
// 产生[0,100]之间的随机数,不能产生101.
// nextInt 翻译为:下一个int类型的数据是101,表示只能取到100
int num2 = random.nextInt(101); // 不包括101
System.out.println(num2);
}
}
题目:编写程序,生成5个[0,100]不重复的随机数,重复的话重新生成
最终生成的5个随机数放到数组中,要求数组中这5个随机数不重复
/*
编写程序,生成5个[0,100]不重复的随机数,重复的话重新生成
最终生成的5个随机数放到数组中,要求数组中这5个随机数不重复
*/
public class RandomTest02 {
private static int[] a;
private static int key;
public static void main(String[] args) {
// 创建random对象
Random random = new Random();
// 准备一个长度为5的一维数组。
int[] a = new int[5]; // 默认都是0
for (int i = 0; i < a.length ; i++) {
a[i] = -1;
}
// 循环,生成随机数
int index = 0;
while(index < a.length){
// 生成随机数
int num = random.nextInt(101);
// 判断a数组中有没有这个num
// 如果没有这个num,就放进去。
if(!contains(a,num)){
a[index++] = num;
}
}
// 遍历以上的数组
for (int i = 0; i < a.length ; i++) {
System.out.println(a[i]);
}
}
/**
* 单独编写一个方法,这个方法专门用来判断数组中是否包含某个元素
* @param a 数组
* @param key 元素
* @return true表示包含,false表示不包含
*/
public static boolean contains(int[] a,int key){
RandomTest02.a = a;
RandomTest02.key = key;
/*
这个方案bug(排序出问题了)
对数组进行升序
Arrays.sort(arr);
进行二分法查找
二分法查找的结果 >= 0说明,这个元素找到了,找到了表示存在!
return Arrays.binarySearch(arr,kry) >=0
*/
for (int i = 0; i < a.length; i++){
if(a[i] == key){
// 条件成立了表示包含,返回true
return true;
}
}
//这个就表示不包含
return false;
}
}
7、Date类
表示特定的瞬间,精确到毫秒值
1)构造方法
Date(): 以当前时间毫秒值创建Date对象
Date(long time): 以指定的毫秒值创建Date对象
public static void main(String[] args) throws Exception{
// 获取系统当前时间(精确到毫秒的系统当前时间)
// 直接调用无参数构造方法就行
Date nowTime = new Date();
// java.lang.Date类的toString()方法已经被重写了
// 输出的应该不是一个对象的内存地址,应该是一个日期字符串
System.out.println(nowTime); // Sun Aug 16 15:48:47 CST 2020
}
2)成员方法
getTime(): 获取Date对象的毫秒值
setTime(long time): 设置Data对象的毫秒值
/*
获取自1970年1月1日 00:00:00 000到当前系统时间的总毫秒数
*/
public class DateTest02 {
public static void main(String[] args) {
// 获取自1970年1月1日 00:00:00 000到当前系统时间的总毫秒数
long nowTimeMillis = System.currentTimeMillis();
System.out.println(nowTimeMillis); // 1597566877825
}
}
8、DateFormat
它是一个抽象类,用来格式化或者解析日期
格式化:Date————》String
解析:String————》Date
getDateInstance(int style,Locale loc): 获取日期格式器,该格式器具有给定的语言环境和给定的格式化风格
String format(Date date): 格式化
Date parse(String time): 解析
跟SimpleDateFormat的使用差不多
9、SimpleDateFormat
它是DateFormat的子类
1)构造方法
SimpleDateFormat(): 以默认模式创建对象
SimpleDateFormat(String pattern): 以指定模式创建对象
常用模式
yyyy: 年 MM:月 dd:日
HH: 时 mm:分 ss:秒
2)常成员方法
String format(Date date): 格式化
Date parse(String time): 解析
public class DateTest01 {
public static void main(String[] args) throws Exception{
// 日期可以格式化吗?
// 将日期类型Date,按照指定的格式进行转换:Date -- 转换成具有一定的日期字符串-->String
// SimpleDateFormat是java.text包下的。专门负责日期格式化的。
/*
yyyy 年(年是四位)
MM 月(月是2位)
dd 日
HH 时
mm 分
ss 秒
SSS 毫秒(毫秒三位,最高999.1000毫秒代表1秒)
*/
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
String nowTimeStr = sdf.format(nowTime);
System.out.println(nowTimeStr); // 2020-08-16 15:48:47
// String --> Date
String time = "2020-08-16 16:03:20 888";
// 括号里面的格式不能随便写,要和日期字符串格式相同
// 注意:字符串的日期格式和SimpleDateFormat 对象指定的日期格式要一致。不然会出现异常
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
Date dateTime = sdf2.parse(time);
System.out.println(dateTime);
}
}
10、Calendar类
日历类,用于获取或者操作日历字段(年月日)
该类是一个抽象类,不可以实例化
成员方法
static Calender getInstance():以默认时区和语言创建日历
int get(int field): 获取指定字段的日历值
set(int field,int value): 给指定的日历字段设置指定的值
set(int year,int month,int date):设置年月日
Date getTime(): 获取日历对象的日期
setTime(Date d): 设置日历对象的日期
add(int field,int amount):对指定的日历字段添加指定的值
11、System类
没有构造方法
成员方法
gc():运行垃圾回收处理机制(系统会在某个不确定的时间调用该方法)
会调用finalize(),进行垃圾回收
exit(int status):退出JVM,0表示非异常退出
currentTimeMills():获取当前时间毫秒值
arrayCopy(Object[] srcArr,int srcPos,Object[] desArr,int destPos,int len):数组复制
简单总结一下System类的相关属性和方法
System.out [out是System类的静态变量]
System.out.println() [println()方法不是System类的,是PrintStream类的方法]
12、BigInteger类
1)构造方法创建BigInteger对象
BigInteger(int num, Random rnd):获取随机大整数,范围: [0 ~ 2的num次方-1]
BigInteger(String val, int radix):获取指定进制的大整数
(字符串中的数字必须是整数、字符串中的数字必须要跟进制吻合,比如二进制中,那么只能写0和1,写其他的就报错。
BigInteger bd4 = new BigInteger(“123”,2);
System.out .println(bd4); // 报错)
BigInteger(String val):获取指定的大整数,通过字符串创建BigInteger对象
(字符串中必须是整数,否则会报错,像"1.1"或者"abc"这种都是会报错的)
2)静态方法创建BigInteger对象
public static BigInteger valueOf(long val) :能表示范围比较小,只能在1ong的取值 范围之内,如果超出1ong的范围就不行了(long的最大值为9223372036854775807
)。在内部对常用的数字:-16 ~ 16进行了优化。提前把-16 ~ 16先创建好BigInteger的对象,如果多次获取不会重新创建新的。(BigInteger bd5 = BigInteger.value0f(16);
BigInteger bd6 = BigInteger . value0f(16);
System.out.println( bd5 == bd6); // true,如果括号里换成17,输出结果就是false了
)
3)细节
- 如果BigInteger表示的数字没有超出long的范围,可以用静态方法获取。
- 如果BigInteger表示的超出long的范围,可以用构造方法获取。
- 对象一旦创建,BigInteger内部记录的值不能发生改变。
- 只要进行计算都会产生一个新的BigInteger对象。
4)成员方法
BigInteger add(BigInteger bi):加
BigInteger subtract(BigInteger bi):减
BigInteger multiply(BigInteger bi):乘
BigInteger divide(BigInteger bi):除(整数相除只保留整数部分)
BigInteger[] divideAndRemainder(BigInteger val):除,获取商和余数,数组的0索引表示商,1表示余数
boolean equals(Object x):比较是否相同(内部重写了equals方法,所以比较的是内容)
BigInteger pow( int exponent):次幂
BigInteger max/min(BigInteger val):返回较大值/较小值
int intValue(BigInteger val):转为int类型整数,超出范围数据有误
13、BigDecimal类
用于解决浮点型运算精度损失的问题。
BigDecimal 属于大数据,精度极高。不属于基本数据类型,属于java对象(引用数据类型)。这
是SUN提供的一个类,专门用在财务软件当中。
1)构造方法创建BigDecimal对象
public BigDecimal(double val):这种方式有可能是不精确的,所以不建议使用
public BigDecimal(String val):通过字符创建BigDecimal对象,建议使用
2)静态方法创建BigDecimal对象
public static BigDecimal value0f(double val):如果我们传递的是0~10之间的整数,包含0,包含10,那么方法会返回已经创建好的对象,不会重新new
3)细节
- 如果要表示的数字不大,没有超出double的取值范围,建议使用静态方法
- 如果要表示的数字比较大,超出了double的取值范围, 建议使用构造方法
4)成员方法
BigDecimal add(BigDecimal bi):加
BigDecimal subtract(BigDecimal bi):减
BigDecimal multiply(BigDecimal bi):乘
BigDecimal divide(BigDecimal bi):除(整数相除只保留整数部分)
BigDecimal divide(BigDecimal val,精确几位,舍入模式):除,例如divide(BigDecimal val,2,RoundingMode.HALF_UP),表示保留两位小数并四舍五入
public class BigDecimalTest {
public static void main(String[] args) {
// 这个100不是普通的100,是精度极高的100
BigDecimal b1 = new BigDecimal(100);
// 精度极高的200
BigDecimal b2 = new BigDecimal(200);
// 求和 不能直接b1+b2,必须调用方法
BigDecimal b3 = b1.add(b2);
System.out.println(b3);
// 相除 调用方法
BigDecimal b4 = b2.divide(b1);
System.out.println(b4);
// 通过静态方法获取对象
BigDecimal bd6 = BigDecimal.value0f(10);
BigDecimal bd7 = BigDecimal.value0f(10);
System.out.println(bd6 == bd7); // true,如果bd6和bd7括号里面是10.0,则输出结果为false
}
}
14、包装类
即8种数据类型对应的包装类型,重点以java.lang.Integer为代表进行学习,其它的类型照葫芦画瓢就行。
基本数据类型 | 包装类型 |
---|---|
byte | java.lang.Byte(父类Number) |
short | java.lang.Short(父类Number) |
int | java.lang.Integer(父类Number) |
long | java.lang.Long(父类Number) |
float | java.lang.Float(父类Number) |
double | java.lang.Double(父类Number) |
boolean | java.lang.Boolean(父类Object) |
char | java.lang.Character(父类Object) |
示例1:
public class IntegerTest01 {
public static void main(String[] args) {
// 123这个基本数据类型,进行构造方法的包装达到了:基本数据类型向引用类型的转换
// 基本数据类型-(转换为)->引用数据类型(装箱)
Integer i = new Integer(123); // 123
// 将引用数据类型--(转换为)->基本数据类型
float f = i.floatValue();
System.out.println(f); // 123.0
// 将引用数据类型--(转换为)->基本数据类型(拆箱)
int intValue = i.intValue();
System.out.println(intValue); // 123
}
}
八种包装类中其中6个都是数宇对应的包装类,他们的父类都是Number,可以先
研究一TNumber 中公共的方法:
Number是一个抽象类,无法实例化对象。
Number类中有这样的方法:
byte byteValue() 以byte形式返回指定的数值。
abstract double doubleValue() 以 double形式返回指定的数值。
abstract float floatValue() 以 float 形式返回指定的数值。
abstract int intValue() 以 int形式返回指定的数值。
abstract long longValue() 以 long形式返回指定的数值。
short shortValue() 以 short形式返回指定的数值。
这些方法其实所有的数字包装类的子类都有,这些方法是负责拆箱的。
Integer类的构造方法(已过时)
Integer(int)
Integer(String)
示例:
public class IntegerTest02 {
public static void main(String[] args) {
// Java9之后不建议使用这个构造方法了。出现横线表示已过时
// 将数字100转换成Integer包装类型(int --> Integer)
Integer x = new Integer(100); // 100
System.out.println(x);
// 将String类型的数字,转换成Integer包装类型。(String --> Integer)
Integer y = new Integer("123"); // 123
System.out.println(y);
// double --> Double
Double d = new Double(1.23);
System.out.println(d);
// String --> Double
Double e = new Double("3.14");
System.out.println(e);
}
}
通过访问包装类的常量,来获取最大值和最小值
public class IntegerTest03 {
public static void main(String[] args) {
// 通过访问包装类的常量,来获取最大值和最小值
System.out.println("int的最大值" + Integer.MAX_VALUE);
System.out.println("int的最小值" + Integer.MIN_VALUE);
System.out.println("byte的最大值" + Byte.MAX_VALUE);
System.out.println("byte的最小值" + Byte.MIN_VALUE);
}
}
经典题目:
-
面试题:String为什么是不可变的?
我看过源代码, String类中有一个byte[]数组 ,这个byte[]数组采用了final修
饰,因为数组一旦创建长度不可变。并且被final修饰的引用且指向某个对象之后,不可再指向其它对象,所以lstring是不可变的!
"abc"无法变成"abcd”
-
StringBuilder/StringBuffer为什么是可变的呢?
我看过源代码, StringBuffer/StringBuilder内部实际上是一个byte[]数組 ,
这个byte[]数组没有被final修饰, StringBuffer/StringBuilder的初始化
容量我记得应该是16 ,当存满之后会进行扩容,底层调用了数組拷贝的方法
Sys tem. arrgycopy()…是这样扩容的。所以StringBuilder/StringBuffer
适合于使用宇符串的频繁拼接操作。
自动装箱和自动拆箱
- 自动装箱:基本数据类型自动转换成包装类。
- 自动拆箱:包装类自动转换成基本数据类型。
public class InterTest04 {
public static void main(String[] args) {
Integer a = 128;
Integer b = 128;
System.out.println(a == b); // false
/*
java中为]掘高程序的执行效學,糊[-128到127]之间所有的包装对象捏前创建好
放到了一个方法区的“整数型常量池”当中了, 目的是只要用这个区间的数据不需要
再new了,直接从整数型常量池当中取出来。
原理:x变量中保存的对象的内存地址称y变量中保存的时象的内存地址是一样的。
*/
Integer x = 127;
Integer y = 127;
// == 永远判断的都是两个对象的内存地址是否相同
System.out.println(x == y); // true
}
}
15、enum枚举类型
-
枚举是一种引用数据类型
-
枚举类型的定义格式:
enum 枚举类型名{ 枚举值1,枚举值2,... }
-
结果只有两种情况的,建议使用布尔类型
结果超过两种并且还是可以一枚一枚列举出来的,建议使用枚举类型。
例如:颜色、四季、星期等都可以使用枚举类型。
示例:计算两个int类型数据的商
import java.util.Random;
public class enumTest01 {
public static void main(String[] args) {
// 创建Random对象
Random random = new Random();
// 准备一个长度为5的一维数组
int[] a = new int[5]; // 默认值都是0
for (int i = 0; i < a.length ; i++) {
a[i] = -1;
}
// 循环,生成随机数
int index = 0;
while(index < a.length){
// 生成随机数
int num = random.nextInt(101);
// 判断a数组中有没有这个num
// 如果没有这个num,就放进去。
if(!contains(a,num)){
a[index++] = num;
}
}
// 遍历以上的数组
for (int i = 0; i < a.length; i++) {
System.out.println(a[i]);
}
}
/**
* 单独编写一个方法,这个方法专门用来判断数组中是否包含某个元素
* @param a
* @param key
* @return true表示包含,false表示不包含
*/
public static boolean contains(int[] a,int key){
/*
// 这个方案bug。(排序出问题了)
// 对数组进行升序
Arrays.sort(a);
// 进行二分法查找
// 二分法查找的结果 >= 0 说明,这个元素找到了,找到了表示存在!
return Arrays.binarySearch(a,key) >= 0;
*/
for (int i = 0; i < a.length; i++) {
if(a[i] == key){
// 条件成立了表示包含,返回true
return true;
}
}
// 这个就表示不包含!
return false;
}
}
思考:以上的这个方法设计没毛病,挺好,返回true和false表示两种情况,但是在以后的开发中,有可能遇到一个方法·的执行结果可能包括三种情况,四种情况,五种情况不等,但是每一个都是可以数清楚的,一枚一枚都是可以列举出来的。这个布尔类型就无法满足需求了。此时需要使用Java语言中的枚举类型。
// 采用枚举的方式改造程序
public class enumTest02 {
public static void main(String[] args) {
Result r = divide(10,0);
System.out.println(r == Result.SUCCESS ?"计算成功":"计算失败");
}
/**
* 计算两个int类型数据的商
* @param a int数据
* @param b int数据
* @return Result.SUCCESS表示成功,Result.FAIL表示失败!
*/
public static Result divide(int a, int b){
try {
int c = a / b;
return Result.SUCCESS;
} catch (Exception e) {
return Result.FAIL;
}
}
// 枚举:一枚一枚可以列举出来的,才建议使用枚举类型
// 枚举编译之后也是生成class文件
// 枚举也是一种引用数据类型
// 枚举中的每一个值可以看做是常量
enum Result{
// SUCCESS 是枚举Result类型中的一个值
// FAIL 是枚举Result类型中的一个值
// 枚举中的每一个值可以看做是常量
SUCCESS,FAIL
}
}