类
1.抽象类及抽象方法
1.1 抽象方法
1.1.1 含义
没有代码块并且使用abstract修饰的方法。
1.1.2 注意
抽象方法必须在抽象类中。
1.1.3 应用场景
该类里的某个方法不太好实现并且该方法又应该在该类里,就不写代码块,将该方法变为抽象方法,抽象方法交给非抽象的子类去实现。
1.1.4 代码格式如下:
abstract修饰符.
public abstract class Person {
//抽象方法:交给非抽象的子类去实现
public abstract void eat();
}
//在非抽象的子类方法中去实现方法
public class Japanese extends Person {
@Override
public void eat() {
System.out.println(super.getName() + "吃米饭");
}
}
1.2 抽象类
使用abstract修饰的类.
1.3 深入抽象类和抽象方法(面试题)
1.可以使用new关键字来创建抽象类对象吗?
答:不可以。
补充:匿名内部类的步骤:
(1).顶层建立一个匿名类(没有名字的类);
(2).继承A类,实现A类的抽象方法;
(3).创建匿名对象。
很多人容易把匿名内部类当成使用new关键字创建抽象类的对象,这里一定要注意。
2.抽象类中只有抽象方法吗?
答:抽象类中就可以有静态方法和成员方法。
3.抽象类中可不可以没有抽象方法?
答:可以,但毫无意义。
4.如果父类是抽象类,则子类必须实现父类的抽象方法吗?
答:不是,子类如果是抽象类,可以不去实现父类的抽象方法。
5.抽象类能不能有构造方法?作用是什么?
答:可以。作用是让子类调用,给父类的属性赋值。
2.接口
2.1 含义
接口是特殊的抽象类。
2.2 接口关键字
implements是实现接口的关键字;
interface是定义接口的关键字。
2.3 注意
在JDK1.8之前,接口里只有静态常量和抽象方法;JDK1.8开始,接口里就有了默认方法和静态方法。
2.4 应用场景
抽象类中只有静态常量或者静态方法就用接口替代。
2.5 设计思想
接口更像一个规范/标准
2.6 经典面试题(重点)
1.一个类可以实现多个接口吗?
答:可以。
2.一个接口可以实现多个接口吗?
答:不可以。
3.接口里边的方法一定都是抽象的吗?
答:不一定。JDK1.8之后就允许使用静态方法和默认方法。
4.接口解决了单线程的问题。
5.一个类是否可以继承一个类,并同时实现多个接口?
答:可以。
6.接口可以new对象吗?
答:不可以。new出来的是匿名内部的对象
7.多个接口中有相同的抽象方法,在实现类中实现几个方法?
答:只有一个。
//I1和I2的默认方法名冲突了,在A类中就必须重写
@Override
public void method02() {
//可以在实现类中调用指定接口的默认方法
I1.super.method02();
System.out.println("xxxx");
}
3.多态
3.1 类的多态
子类对象指向父类引用(父类引用里存的是子类对象在堆里开辟的地址)。
Vehicle v = new Bike();
//Vehicle是父类,Bike是子类
3.2 接口的多态
实现类的对象指向接口的引用(接口的引用中存的是实现类对象在堆内存里开辟的地址)。
IUSB usb = new Disk();
//IUSB是接口,Disk是实现类
3.3 OPC原则 - 开闭原则
O - open - 在需求更改时,对创建类是欢迎的
C - close - 在需求更改时,改变原有类是拒绝的
P - principle(原则)
4 对象转型
4.1 前提
父子类关系
4.2 向上转型
向上转型:子类类型 转 父类类型
4.2.1 注意:
(1)向上转型就是多态;
(2)可以调用父类非私有化属性;
(3)可以调用父类非私有化方法;
(4)可以调用子类重写父类的方法;
(5)不可以调用子类属性;
(6)不可以调用子类方法。
4.2.2 向上转型(多态)的优缺点
优点:在需求更改时符合OCP原则
缺点:不可以调用子类/实现类自己独有的属性和方法
4.3 向下转型
向下转型:父类类型 转 子类类型 (强转)
4.3.1.注意:
向下转型不安全,容易出现ClassCastException(类型转换异常),所以不能直接将父类对象强转为子类类型。
解决方案:向下转型一定要向上转型后再向下转型;
向下转型一定要用instanceof判断。
Animal an = new Cat();//向上转型
//Animal an = new Dog();//向上转型
if(an instanceof Dog){//判断引用an所执行的对象是否是Dog类型的
Dog dog = (Dog) an;//向下转型
System.out.println(dog);
}else if(an instanceof Cat){//判断引用an所执行的对象是否是Cat类型的
Cat cat = (Cat) an;
System.out.println(cat);
}
5 内部类
5.1 含义
在一个类的内部定义的类称为内部类。内部类允许把一些逻辑相关的类组织在一起,并且控制内部类的可视性。
5.2 分类
1.成员内部类:
成员内部类里可以调用外部类的所有属性
2.静态内部类:
静态内部类只能调用外部类的静态属性
3.接口内部类:
接口内部类可以调用外部接口的静态常量
4.局部内部类:
局部内部类可以调用外部类当前方法的局部变量 + 所有属性
注意:(1)不能用访问修饰符修饰局部变量
(2)在局部内部类中调用方法中的局部变量,在JDK1.8版本之前,该变量必须手动添加final;在JDK1.8版本之后,该变量会自动转换为常量。
(3)不能用访问修饰符修饰局部内部类
面试题:为什么局部内部类中调用方法中的局部变量,该变量会变成常量?
答:变成常量后,该量存放在常量池中,比局部变量的生命周期更长,保证内部类对象可以随时调用该常量。
5.匿名内部类
应用场景1:如果抽象类的子类只使用一次,就直接用匿名内部类代替,减少了子类的创建
应用场景2:如果接口的实现类只使用一次,就直接用匿名内部类代替,减少了实现类的创建
/** 1.创建匿名类
* 2.匿名类继承A类,重写A类的抽象方法
* 3.创建匿名类的对象
* 4.该对象指向父类的引用(多态)
*/
A a = new A() {
@Override
public void method() {
System.out.println("xxx");
}
};
a.method();
/**
* 1.创建匿名类
* 2.匿名类实现I1接口,重写I1的抽象方法
* 3.创建匿名类的对象
* 4.该对象指向接口的引用(多态)
*/
I1 i1 = new I1() {
@Override
public void method() {
System.out.println("xxxxxxxxxxx");
}
};
i1.method();
6 包装类
6.1 含义
8种基本数据类型对应的8个类
6.2 出现原因
Java为纯面对对象语言(万物皆对象),8种基本数据类型不能创建对象,破坏了Java为纯面对对象语言的特征,Java就给8种基本数据类型分别分配了对应的类,这种类就叫做包装类(封装类)。
6.3 分类
基本数据类型 | 包装类 | 继承关系 |
---|---|---|
byte | Byte | extends Number extends Object |
short | Short | extends Number extends Object |
int | Integer | extends Number extends Object |
long | Long | extends Number extends Object |
float | Float | extends Number extends Object |
double | Double | extends Number extends Object |
char | Character | extends Object |
boolean | Boolean | extends Object |
注释:int的包装类是Integer,char的包装类是Character,其余基本数据类型的包装类都是首字母大写。
6.4 应用场景
集合。集合是存放数据的容器,和数组类似,但集合只能存引用数据类型的数据,要想集合存储基本数据类型,就可以将基本数据类型装箱成对应的引用数据类型。
6.5 装箱、拆箱
1.手动装箱
基本数据类型 --> 包装类的对象
关键字:valueOf、Integer
int i = 10;
Integer integer = Integer.valueOf(i);
System.out.println(integer);
2.手动拆箱
包装类的对象 --> 基本数据类型
关键字:intValue/…Value
Integer integer = new Integer();
int i = integer.intValue();
System.out.println(i);
3.自动装箱
从JDK1.5开始,就可以自动装箱和自动拆箱了。
int i = 10;
Integer integer = i;//底层实现与手动装箱一样
System.out.println(integer);
4.自动拆箱
Integer integer = new Integer();
int i = integer;
System.out.println(i);
6.6 经典面试题
1.将String类型数组转换为int类型的数组。
//将String[] s = {"1","2","3","4","5","6"}转换为int类型的数组
String[] s = {"1","2","3","4","5","6"};
int[] x = new int[s.length];
for(int i = 0;i < x.length;i++){
Integer integer = Integer.valueOf(s[i]);
is[i] = integer;//自动拆箱
}
for(int e : x){
System.out.println(e);
}
2.判断下列代码为true还是false
Integer integer1 = Integer.valueOf(100);
Integer integer2 = Integer.valueOf(100);
System.out.println(integer1 == integer2);//true
Integer integer3 = Integer.valueOf(200);
Integer integer4 = Integer.valueOf(200);
System.out.println(integer3 == integer4);//false
Integer integer5 = Integer.valueOf(-127);
Integer integer6 = Integer.valueOf(-127);
System.out.println(integer5 == integer6);//true -128~127
Integer a = new Integer(10);
Integer a1 = new Integer(10);
System.out.println(a == a1);//false,比较的是两个不同对象的地址,所以肯定不同
Integer b = 10;
Integer b1 = 10;
System.out.println(b == b1);//true,
// 首先我们应该知道随着Integer的加载,Integer中有一个静态内部类IntegerCache也会随之加载,这个内部类的加载时会生成一个包含[-128,127]的Integer对象的数组(你可以叫它是缓存,因为在这个区间的数用得最多)
// 首先b、b1是自动装箱,自动装箱其实就是自动调用了valueOf(int i),在这个方法中会判断如果i在[-128,127]之间,则会从缓存中获取。
// 因为10(<=127),所以b和b1都是从缓存中获取的同一个对象。
6.7 底层分析* - Integer
public class MyInteger{
private int value;
public MyInteger(int value){
this.value = value;
}
public int intValue(){
return value;
}
public static MyInteger valueOf(int i){
if(i >= MyIntegerCache.low && i <= MyIntegerCache.high){
return MyIntegerCache.cache[i - MyIntegerCache.low];
}
return new MyInteger(i);
}
//MyInteger的缓存类
private static class MyIntegerCache{
private static final int low = -128;
private static final int high = 127;
private static final MyInteger[] cache;
static{
int j = low;
cache = new MyInteger[high - low + 1];
for(int i = 0;i < cache.length;i++){
cache[i] = new MyInterger(j++);
}
}
}
}
7 String类、StringBuffer、StringBuilder
7.1 String
1.String创建对象问题(面试题)
//只创建1个对象 - "abc",在常量池中,就会生成一个对象
String str1 = "abc";
String str2 = "abc";
System.out.println(str1);
System.out.println(str2);
//面试题2:如下代码创建几个String对象
//创建三个String对象(两个new String,一个"abc")
String str3 = new String("abc");
String str4 = new String("abc");
System.out.println(str3);
System.out.println(str4);
//面试题3:
String str1 = "abc";
String str2 = "abc";
System.out.println(str1 == str2);//true
//面试题4:
//常量直接在翻译是就拼接
String str3 = "ab" + "c";
System.out.println(str1 == str3);//true
//面试题5:
//常量直接在翻译是就拼接
final String s1 = "ab";
final String s2 = "c";
String str4 = s1 + s2;
System.out.println(str1 == str4);//true
//面试题6:
String s3 ="ab";
String s4 = "c";
String str5 = s3 + s4;//new StringBuilder(s3).append(s4).toString()
System.out.println(str1 == str5);//false
2.String常用方法
注:以下方法使用时都要返回新的字符串
String方法 | 作用 |
---|---|
concat() | 在字符串末尾追加字符 |
substring(a) | 截取从a下标处到字符串末尾 |
substring(a,b) | 截取从a下标(包含)到b下标(不包含) |
toLowerCase() | 转小写 |
toUpperCase() | 转大写 |
trim() | 去掉首尾空格 |
replace(‘a’,‘b’) | 替换字符 |
replaceAll(“c”,“d”) | 替换字符串 |
replaceFirst(“c”,“d”) | 替换第一个出现的字符串 |
equals(“a” ,“b”) | 判断两个字符串是否相同(区分大小写) |
equalsIgnoreCase(“a” ,“b”) | 判断两个字符串是否相同(不区分大小写)(应用于验证码) |
startsWith(“a”) | 判断是否以某个字符串开头 |
endWith(“a”) | 判断是否以某个字符串开头 |
indexOf(“a”) | 查询子字符串在此字符串中的下标 |
lastIndexOf(“a”) | 查询子字符串在此字符串中最后一次的下标 |
length() | 获取字符串长度 |
charAt() | 获取指定下标上的字符 |
valueOf() | 将int/double/char…转换为String类型 |
3.代码演示
public static void main(String[] args) {
/**
* String 的常用方法
*/
String str = "123abcDEF";
str = str.concat("123");//在此字符串末尾追加字符串,返回新字符串
System.out.println(str);
str = str.substring(3);//从开始下标处截取到字符串末尾,返回新字符串
System.out.println(str);
str = str.substring(3, 7);//从开始下标处(包含)截取到结束下标处(不包含),返回新字符串
System.out.println(str);
str = str.toLowerCase();//转小写,返回新的字符串
System.out.println(str);
str = str.toUpperCase();//转大写,返回新的字符串
System.out.println(str);
str = " 1 23 ab cD EF 123 ";
str = str.trim();//去掉首尾空格,返回新的字符串
System.out.println(str);
str = str.replace('2', '-');//替换字符,返回新的字符串
System.out.println(str);
str = str.replaceAll(" ", "");//替换字符串,返回新的字符串
System.out.println(str);
str = str.replaceFirst("3", "Kobe");//替换第一个出现的字符串,返回新的字符串
System.out.println(str);
System.out.println("判断两个字符串是否相同(区分大小写):" + str.equals("1-KobeabcDEF1-3"));//true
System.out.println("判断两个字符串是否相同(不区分大小写):" + str.equalsIgnoreCase("1-KobeABCDEF1-3"));//true
System.out.println("判断此字符是否以某个字符串开头" + str.startsWith("1-"));//true
System.out.println("判断此字符是否以某个字符串结尾" + str.endsWith("e"));//false
System.out.println("查询子字符串在此字符串中的下标:" + str.indexOf("K"));//2
System.out.println("查询子字符串在此字符串中最后一次的下标:" + str.lastIndexOf("3"));//14
System.out.println("获取字符串的长度" + str.length());//15
System.out.println("获取指定下标上的字符:" + str.charAt(5));//e
System.out.println("将int转换为String:" + String.valueOf(100));
System.out.println("将double转换为String:" + String.valueOf(123.123));
System.out.println("将char转换为String:" + String.valueOf('c'));
//还有一种最简单的方法:把任意对象、基本数据类型与一个空字符串相连就可以直接转换成字符串。
int i = 100;
String s = i + "";
System.out.println(s);
}
7.2 StringBuffer和StringBuilder
7.2.1 含义
StringBuffer和StringBuilder都被称为字符串缓冲区。都代表可变的字符序列。
与String对象的不同:StringBuffer和StringBuilder为可变对象。
7.2.2 工作原理
预先申请一块内存,存放字符序列,如果字符序列满了,会重新改变缓存区的大小,以容纳更多字符。
7.2.3 底层分析
继承关系:StringBuffer extends AbstractStringBuilder
字符串缓冲区 继承 抽象字符串生成器
默认缓冲区大小:16个字符。
7.2.4 StringBuffer和StringBuilder常用方法
StringBuffer/StringBuilder方法 | 作用 |
---|---|
append() | 在末尾追加字符串 |
insert() | 指定下标处插入数据 |
setCharAt() | 替换指定下标上的字符 |
replace() | 从开始下标处(包含)替换到结束下标处(不包括)的字符串 |
deleteChar() | 删除指定下标上的字符 |
delete() | 从开始下标处(包含)删除到结束下标处(不包括)的字符串 |
reverse() | 反转字符 |
length() | 获取字符串长度 |
7.2.5 代码演示
//默认的缓冲区大小:16个字符
StringBuilder a = new StringBuilder();
System.out.println(a);
//自定义缓冲区大小:30个字符
StringBuilder b = new StringBuilder(30);
System.out.println(b);
//缓冲区大小:stu.length + 16 "abcd1234"+16
StringBuilder sb = new StringBuilder("abcd1234");
System.out.println(sb);
sb.append("DEF123");//在末尾追加字符串
sb.insert(5, "Tom");//指定下标处插入数据
sb.setCharAt(4, 'B');//替换指定下标上的字符
sb.replace(3, 6, "xx");//从开始下标处(包含)替换到结束下标处(不包括)的字符串
sb.deleteCharAt(1);//删除指定下标上的字符
sb.delete(2, 6);//从开始下标处(包含)删除到结束下标处(不包括)的字符串
sb.reverse();//反转字符
System.out.println(sb);
System.out.println("获取字符串长度" + sb.length());//11
7.2.6 StringBuffer vs StringBuilder
注意:使用上没有任何区别
StringBuffer:线程不安全,效率更高,在单线程的情况下使用;
StringBuilder:线程安全,效率更低,在多线程的情况下使用。
7.2.7 为什么需要StringBuffer和StringBuilder类?
因为其可变性。一个String对象的长度是固定不变的,如果我们要频繁的附加新的字符串,使用String对象的话,系统会频繁创建String对象,造成性能下降。所以不建议使用+来进行频繁的字符串串联,应该使用java.lang.StringBuffer或StringBuilder。
//获取自1970.1.1 0:0:0到现在的毫秒数
long startTime = System.currentTimeMillis();
String str = "Kobe";
System.out.println(str);
for(int i = 0;i < 30000;i++){
str += "NB";
//底层实现:str = new StringBuilder(str).append("NB").toString();
}
//获取自1970.1.1 0:0:0到现在的毫秒数
long endTime = System.currentTimeMillis();
System.out.println("消耗时长:" + (endTime - startTime));//效率比单纯的字符串拼接高的多
8 正则表达式regex
8.1 含义
用来描述或者匹配一系列符合某个语句规则的字符串。
8.2 经典案例
案例1:把一个字符串中的电话号码的中间四位替换成xxxx
String str = "小明18758184171 小强18240834972";
String regex = "(1\\d{2})(\\d{4})(\\d{4})";
str = str.replaceAll(regex,"$1****$3");
//分析底层:
//Pattern pattern = Pattern.compile(regex);//获取到正则表达式的对象
//Matcher matcher = pattern.matcher(str);//正则表达式的匹配结果
//matcher.replaceAll(str);//根据匹配结果替换字符串
System.out.println(str);
案例2:检验QQ邮箱
String str = "1875818417@qq.com";
String regex = "\\d{6,12}@qq.com";
boolean bool = str.matches(regex);//判断该字符串是否匹配正则表达式
//底层实现:
//Pattern.matches(regex,str);
//Pattern pattern = Pattern.compile(regex);//获取到正则表达式的对象
//Matcher matcher = pattern.matcher(str);//正则表达式的匹配结果
//matcher.matches();//根据匹配结果替换字符串
System.out.println(bool);
案例3:分隔路径
String str = "C:\\资源\\日韩\\波多野结衣.avi";
String regex = ":?\\\\";//:\\ 或 \\
String[] split = str.split(regex);
//底层实现:
//Pattern pattern = Pattern.compile(regex);//获取到正则表达式的对象
//String[] split = pattern.split(str);//依据正字表达式分隔字符串
for (String s : split) {
System.out.println(s);
案例4:找到前端代码中的图片路径
String str = "<img src='hhy/aaa.jpg'/><div><div/> <input type='image' src='submit.gif' /><img src='bbb.jpg'/>";
String regex = "<img\\b[^>]*\\bsrc\\b\\s*=\\s*('|\")?([^'\"\n\r\f>]+(\\.jpg|\\.bmp|\\.eps|\\.gif|\\.mif|\\.miff|\\.png|\\.tif|\\.tiff|\\.svg|\\.wmf|\\.jpe|\\.jpeg|\\.dib|\\.ico|\\.tga|\\.cut|\\.pic)\\b)[^>]*>";
Pattern pattern = Pattern.compile(regex);//获取到正则表达式的对象
Matcher matcher = pattern.matcher(str);//获取匹配结果
//System.out.println("在字符串中是否整个匹配:" + matcher.matches());
//System.out.println("在字符串中是否开头就匹配:" + matcher.lookingAt());
//System.out.println("在字符串中是否有包含匹配:" + matcher.find());
//遍历匹配结果
while(matcher.find()){
String group = matcher.group();
System.out.println(group);
String group1 = matcher.group(2);//获取正则表达式的第二组数据
System.out.println(group1);
}
8.3 底层分析
Pattern:代表正则表达式的匹配模式
Matcher:提供了对正则表达式的分组支持,以及对正则表达式的多次匹配支持。
9 时间类(Date、SimpleDateFormat、Calendar)
9.1 Date类
日期类。表示特定的瞬间,精确到毫秒。
Date date = new Date();
System.out.println(date);
//Wed Apr 28 11:25:08 CST 2021
//星期 月份 日期 时:分:秒 时区 年份
//从1970.1.1 0:0:0 往后推1000毫秒
Date date2 = new Date(1000);
System.out.println(date2);
补充:@Deprecated —> 过时的注解
9.2 SimpleDateFormat类
格式化日期类。将显示的日期信息格式化。
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
//格式化日期时间
String string = sdf.format(new Date());
System.out.println(string);//2021年04月28日 11:45:16
//将字符串转换为Date对象
Date date = sdf.parse("2021年04月28日 11:61:02");
System.out.println(date);
9.3 Calendar类
日历类。是一个抽象类,主要用于完成日期字段之间相互操作的功能,即可以设置和获取日期数据的特定部分。
//获取日历数的对象
Calendar c = Calendar.getInstance();
int year = c.get(Calendar.YEAR);
int month = c.get(Calendar.MONTH)+1;
int day = c.get(Calendar.DAY_OF_MONTH);
int hour = c.get(Calendar.HOUR);
int minute = c.get(Calendar.MINUTE);
int second = c.get(Calendar.SECOND);
System.out.println(year);
System.out.println(month);
System.out.println(day);
System.out.println(hour);
System.out.println(minute);
System.out.println(second);
//JDK1.8开始,使用到的时间类
System.out.println(LocalDate.now());
System.out.println(LocalDateTime.now());
10 Math类
10.1 含义
Math类提供了一序列基本数学运算和几何函数的方法。
Math类是final类,并且它的所有成员变量和成员方法都是静态的。
10.2 常用方法
Math方法 | 作用 |
---|---|
Math.pow(a,b) | a的b次方 |
Math.sqrt(a) | 平方根 |
Math.abs(a) | 绝对值 |
Math.ceil(a) | 向上取整 |
Math.floor(a) | 向下取整 |
Math.round(a) | 四舍五入 |
Math.max(a) | 最大值 |
Math.min(a) | 最小值 |
Math.random() | 获取随机值0(包含)~1(不包含) |
10.3 经典面试题
面试题1:随机输出1~100的数字
System.out.println("获取1~100的随机值" + ((int)(Math.random()*100)+1));
面试题2:abs()有可能出现负数吗?
答:会
System.out.println("绝对值:" + Math.abs(Integer.MIN_VALUE));
abs()底层实现:
public static int abs(int a) {
return (a < 0) ? -a : a;
}
//-2147483648 ~2147483647
11. 静态导入
当使用一个类里面的静态方法或者静态变量时,每次都要写类名。如果不想写,想直接写方法名或者变量名,就可以考虑静态导入。
语法:import static 包名.类名.*
如:import static java.lang.Math.*;
导入该类下的所有静态方法和常量
不需用写类名,直接用方法名调用
缺点:可读性不高
12.Random类
12.1 含义
此类用于生成随即数。
12.2 理解什么是随机
系统里的随机数都是伪随机,通过算法得出的一个较为随机的数字。
种子数:种子固定,随机出来的数据也是固定的。
12.3 应用需求
1.点名器
String[] names = {"小明","小陆","小郑","小罗","小刘","小白","小张","小李","小强","小美",};
Random ran = new Random();
int index = ran.nextInt(names.length);
System.out.println(names[index]);
2.随机数
.nextInt()、.nextDouble()、.nextBoolean()
//创建随机类的对象
Random ran = new Random();
System.out.println("随机出int值:" + ran.nextInt());
System.out.println("随机出int值(0~9):" + ran.nextInt(10));
System.out.println("随机出double值:" + ran.nextDouble());
System.out.println("随机出boolean值:" + ran.nextBoolean());
12.4 底层分析
public class MyRandom{
//种子数
private long seed;
public MyRandom(){
//计算出较为随机的种子数
this(seedUniquifier() ^ System.nanoTime());
}
//提供随机数字的方法
public long seedUniquifier(){
long current = System.currentTimeMillis();
for(;;){
current = current * 181783497276652981L;
if(c%5==0){
return current;
}
}
}
public MyRandom(long seed){
this.seed = seed;
}
public int nextInt(){
return (int)seed;
}
public int nextInt(int num){
return Math.abs((int)seed)%num;
}
public boolean nextBoolean(){
return ((int)seed)>0?true:false;
}
}
13.System类
13.1 含义
系统类。System类提供了一些静态属性和方法,允许通过类名直接调用。
13.2 分类
(1) 系统标准的输入流(控制台 -> 程序)
InputStream in = System.in;
(2) 系统标准的输出流(程序 -> 控制台)
PrintStream out = System.out;
(3) 系统标准的错误输出流(程序 -> 控制台)
PrintStream err = System.err;
(4) 研究系统的输出流和错误流:
结论:out是一个线程,err是一个线程,两个线程抢到CPU资源后才能运行,抢资源的过程是随机的。
13.3 System的静态方法
(1) 退出当前虚拟机,输入0表示正常退出
System.exit(0);
(2) 获取1970.1.1 0:0:0到现在的毫秒数
System.out.println("获取毫秒值:" + System.currentTimeMillis());
(3) 获取到当前系统参数(以键值对的形式存储参数) Key - Value
Properties properties = System.getProperties();
System.out.println(properties);
String value = System.getProperty("os.name");
System.out.println(value);
14.Runtime类
14.1 含义
表示运行环境的对象。
14.2 常见方法
获取闲置内存数:freeMemory();
获取最大内存数:maxMemory();
获取处理数:availableProcessors();
获取系统的时间:currentTimeMillis();
//获取运行环境的对象
Runtime run = Runtime.getRuntime();
System.out.println("获取闲置内存数" + run.freeMemory());
System.out.println("获取最大内存数" + run.maxMemory());
System.out.println("获取处理数" + run.availableProcessors());
/**
* 测试程序:消耗时长、消耗内存
*/
//获取运行环境的对象
Runtime run = Runtime.getRuntime();
long startTime = System.currentTimeMillis();
long startMemory = run.freeMemory();
StringBuilder sb = new StringBuilder("燕燕小可爱");
for (int i = 0; i < 30000; i++) {
sb.append("皇冠给你带");
}
long endTime = System.currentTimeMillis();
long endMemory = run.freeMemory();
System.out.println("消耗时长:" + (endTime - startTime));
System.out.println("消耗内存:" + (startMemory - endMemory));
14.3 面试题
问题:消耗内存会出现负数吗?
答案:有可能,在执行代码块的时候,垃圾回收器回收了一部分闲置内存,导致运行后的内存反而更大了。
15.大数值运算类
15.1 BigInteger
整数类型的大数值运算
加法:add();
减法:subtract();
乘法:multiply();
除法:divide();
/**
* 大数值的运算类
*
* BigInteger - 整数类型的大数值运算
*/
BigInteger big1 = new BigInteger("123467890");
BigInteger big2 = new BigInteger("123467890");
BigInteger add = big1.add(big2);//加法
System.out.println(add);
BigInteger subtract = big1.subtract(big2);//减法
System.out.println(subtract);
BigInteger multiply = big1.multiply(big2);//乘法
System.out.println(multiply);
BigInteger divide = big1.divide(big2);//除法
System.out.println(divide);
15.2 BigDecimal
小数类型的大数值运算类
注意:不要将小数直接做运算,会失去精度。如:0.5-0.3
加法:add();
减法:subtract();
乘法:multiply();
除法:divide();
divide(除数,保留小数位,保留模式);
保留模式:
保留模式 | 说明 |
---|---|
BigDecimal.ROUND_DOWN | 直接省略多余的小数,比如1.28如果保留1位小数,得到的就是1.2 |
BigDecimal.ROUND_UP | 直接进位,比如1.21如果保留1位小数,得到的就是1.3 |
BigDecimal.ROUND_HALF_UP | 四舍五入,2.35保留1位,变成2.4 |
BigDecimal.ROUND_HALF_DOWN | 四舍五入,2.35保留1位,变成2.3 |
代码:
BigDecimal big1 = new BigDecimal("0.5");
BigDecimal big2 = new BigDecimal("0.2");
BigDecimal add = big1.add(big2);//加法
System.out.println(add);
BigDecimal subtract = big1.subtract(big2);//减法
System.out.println(subtract);
BigDecimal multiply = big1.multiply(big2);//乘法
System.out.println(multiply);
BigDecimal divide = big1.divide(big2);//除法
System.out.println(divide);
BigDecimal big1 = new BigDecimal("10");
BigDecimal big2 = new BigDecimal("3");
BigDecimal divide = big1.divide(big2);//除法
System.out.println(divide);//报错,无限循环
//divide(big2, 保留小数位, 保留模式)
BigDecimal divide = big1.divide(big2, 3, BigDecimal.ROUND_HALF_UP);
System.out.println(divide);