Day15
一、Random类
Random类主要是生成随机数。
Random类是专门用于生成一个伪随机数的类,其产生的随机数是根据种子和顺序决定的;ThreadLocalRandom类是Java 7新增的一个类,它是Random的增强版。在并发访问的环境下,保证系统具有更好的线程安全性。Random类有两个构造器:
1、Random():创建一个新的随机数生成器。
2、Random(long seed):使用单个long种子创建一个新的随机数生成器。
1.1基本用法:
1.随机生成int取值范围内的数
int num1 = ran.nextInt(); System.out.println(num1);
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zsRnFyK4-1652098417860)(C:\Users\Hp\AppData\Roaming\Typora\typora-user-images\image-20220509182048506.png)]
2.随机出int类型0~9的数字
int num2 = ran.nextInt(10);//底层原理:随机获取正整数的数字%10 System.out.println(num2);
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Y85WFu60-1652098417862)(C:\Users\Hp\AppData\Roaming\Typora\typora-user-images\image-20220509182235453.png)]
3.随机出double取值范围内的数据
double num3 = ran.nextDouble(); System.out.println(num3);
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Jb3QTiSO-1652098417863)(C:\Users\Hp\AppData\Roaming\Typora\typora-user-images\image-20220509182409357.png)]
4.随机出boolean类型的值
boolean bool = ran.nextBoolean(); System.out.println(bool);
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BL1j5Mmt-1652098417863)(C:\Users\Hp\AppData\Roaming\Typora\typora-user-images\image-20220509182500032.png)]
1.2应用 – 点名器
将所有的学生姓名放在一个数组内,数组是已知的长度,长度为学生的个数,通过生成随机数去匹配学生在数组的下标,即可找到随机的学生。
public static void main(String[] args) { String[] names = {"罗菌鱼","张三","李四","王二麻子","赵五","钱六"}; Random ran = new Random(); int index = ran.nextInt(names.length); System.out.println(names[index]); }
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-96C8IIp4-1652098417864)(C:\Users\Hp\AppData\Roaming\Typora\typora-user-images\image-20220509183035431.png)]
1.3种子数
种子数固定,随机出的数字就是固定的
public class Random { public Random() { //调用本类其他的构造方法 this(seedUniquifier() ^ System.nanoTime()); } private static long seedUniquifier() { for (;;) { //获取了一个值 long current = seedUniquifier.get(); //算法 long next = current * 181783497276652981L; //判断next达到某个条件后,返回数据 if (seedUniquifier.compareAndSet(current, next)) return next;//返回了一个较为随机的值 } } //有参构造 -- 传入的数据是种子数 public Random(long seed) { if (getClass() == Random.class) this.seed = new AtomicLong(initialScramble(seed)); else { // subclass might have overriden setSeed this.seed = new AtomicLong(); setSeed(seed); } } }
二、Runtime类
含义:代表着Java的运行环境(JRE、JVM)
常用方法:
- availableProcessors():获取处理数
- maxMemory():获取最大内存数,单位为字节单位
- freeMemory():获取闲置内存数(字节)
public static void main(String[] args) { //获取运行时类的对象 Runtime run = Runtime.getRuntime(); System.out.println("获取处理数:" + run.availableProcessors());//8 System.out.println("获取最大内存数(字节):" + run.maxMemory()); System.out.println("获取闲置内存数(字节):" + run.freeMemory()); }
2.1消耗时长和消耗内存 考虑一段代码的效率
public static void main(String[] args) { Runtime runtime = Runtime.getRuntime(); long startMemory = runtime.freeMemory(); long startTime = System.currentTimeMillis(); String str = "甜甜"; for (int i = 0; i < 10000; i++){ str += "的冰激凌"; //str = new StringBuilder(str).append("拍电影").toString(); } long endMemory = runtime.freeMemory(); long endTime = System.currentTimeMillis(); System.out.println("消耗时长:" + (endTime - startTime)); System.out.println("消耗内存:" + (startMemory - endMemory)); System.out.println("-------------------"); long startMemory1 = runtime.freeMemory(); long startTime1 = System.currentTimeMillis(); StringBuilder stringBuilder = new StringBuilder("苦苦"); for (int i = 0; i < 10000; i++){ stringBuilder.append("的巧克力"); } long endMemory1 = runtime.freeMemory(); long endTime1 = System.currentTimeMillis(); System.out.println("消耗时长:" + (endTime1 - startTime1)); System.out.println("消耗内存:" + (startMemory1 - endMemory1)); }
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aLmqxSrQ-1652098417866)(C:\Users\Hp\AppData\Roaming\Typora\typora-user-images\image-20220509185056570.png)]
2.2设计模式之单例模式
前言:new对象的过程叫做实例化
理解:该类的对象只有一个
单例模式:
- 私有化构造方法
- 创建静态常量:private static final A a = new A();
- 添加静态的get方法
public class A { /** * 为什么使用private修饰: * 私有化属性,并且添加get方法让外界获取a对象 * 为什么使用static修饰: * 使用到该类,该类的class文件加载到方法区时(类加载机制),就会在静态区中创建A类的对象 * getInstance方法是静态方法,静态方法只能调用静态属性 * 为什么使用final修饰: * 应该该对象创建后,不允许外界改变 */ private static final A a = new A(); private A() { } public static A getInstance(){ return a; } }
**问题1:**为什么使用private修饰:
- 私有化属性,并且添加get方法让外界获取a对象
**问题2:**为什么使用static修饰:
- 使用到该类,该类的class文件加载到方法区时(类加载机制),就会在静态区中创建A类的对象
- getInstance方法是静态方法,静态方法只能调用静态属性
问题3: 为什么使用final修饰:
- 应该该对象创建后,不允许外界改变
public static void main(String[] args) { //单例模式 Runtime run = Runtime.getRuntime(); Calendar calendar = Calendar.getInstance(); A a = A.getInstance(); }
三、System类
知识点:研究System类的属性
(注意流的方向是站在程序的角度去看待)
输入流:
//系统标准的输入流(方向:控制台->程序) InputStream in = System.in; Scanner scan = new Scanner(in); String str = scan.next(); scan.close();//关闭资源 //程序标准的错误输出流(方向:程序->控制台) PrintStream err = System.err;//err -- error错误 err.println(str);
输出流:
//程序标准的输出流(方向:程序->控制台) PrintStream out = System.out; out.println(str);
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hrgD6CSf-1652098417867)(C:\Users\Hp\AppData\Roaming\Typora\typora-user-images\image-20220509190726326.png)]
3.1研究System的out和err
System.out.println("小明"); System.err.println("小红"); System.out.println("小强");
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yLhKuZcb-1652098417868)(F:\java_learing\doc\Weeks04\Day15\system.png)]
**注意:**err是一个线程里的代码、out是另一个线程里的代码
3.2、System的常用方法
- getProperties():获取系统配置文件对象
- getProperty():通过键找到配置文件中对应的值
//获取系统配置文件对象 Properties properties = System.getProperties(); System.out.println(properties); //通过键找到配置文件中对应的值 String value = System.getProperty("os.name"); System.out.println(value);
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ek5uJhd9-1652098417869)(C:\Users\Hp\AppData\Roaming\Typora\typora-user-images\image-20220509191449831.png)]
- arraycopy():用于删除数组元素,原数组,开始下标,原数组,开始下标,拷贝次数
int[] is = {1,2,3,4,5,6,7,8,9}; System.out.println("原数组:" + Arrays.toString(is)); System.arraycopy(is, 3, is, 2, is.length - 3);//原数组,开始下标,原数组,开始下标,拷贝次数 is[is.length-1] = 0;//将0赋值给最后下标的位置 System.out.println("删除后:" + Arrays.toString(is));
- src表示源数组
- srcPos表示源数组中拷贝元素的起始位置。
- dest表示目标数组
- destPos表示拷贝到目标数组的起始位置
- length表示拷贝元素的个数
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QLj9z0C7-1652098417869)(C:\Users\Hp\AppData\Roaming\Typora\typora-user-images\image-20220509192600406.png)]
四、大数值运算
4.1整数大数值运算类
常用的方法:
- .add:加法
- .subtract:减法
- .multiply:乘法
- .divide:除法
BigInteger bigInteger1 = new BigInteger("1234567890147"); BigInteger bigInteger2 = new BigInteger("1234567890147"); BigInteger add = bigInteger1.add(bigInteger2); System.out.println("加法:" + add); BigInteger subtract = bigInteger1.subtract(bigInteger2); System.out.println("减法:" + subtract); BigInteger multiply = bigInteger1.multiply(bigInteger2); System.out.println("乘法:" + multiply); BigInteger divide = bigInteger1.divide(bigInteger2); System.out.println("除法:" + divide);
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ccmvNlsV-1652098417870)(C:\Users\Hp\AppData\Roaming\Typora\typora-user-images\image-20220509192848609.png)]
4.2注意:小数在底层使用二进制存储时会失去精度,千万不能直接做运算
在数据敏感的项目中不能直接进行运算,因为会损失精度,因此会使用到BigDecimal。
BigDecimal bigDecimal1 = new BigDecimal("0.5"); BigDecimal bigDecimal2 = new BigDecimal("0.4"); BigDecimal add = bigDecimal1.add(bigDecimal2); System.out.println(add); BigDecimal subtract = bigDecimal1.subtract(bigDecimal2); System.out.println(subtract); BigDecimal multiply = bigDecimal1.multiply(bigDecimal2); System.out.println(multiply); BigDecimal divide = bigDecimal1.divide(bigDecimal2); System.out.println(divide);
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-K9AlvluS-1652098417871)(C:\Users\Hp\AppData\Roaming\Typora\typora-user-images\image-20220509193222468.png)]
注意:小数在底层使用二进制存储时会失去精度,千万不能直接做运算
BigDecimal big1 = new BigDecimal("10"); BigDecimal big2 = new BigDecimal("3"); BigDecimal divide = big1.divide(big2, 3, BigDecimal.ROUND_HALF_UP);//(除数,保留小数位,进制模式) System.out.println("除法:" + divide);
五、枚举
5.1引入
需求:编写季节类(Season),该类只有四个对象(spring,summer,autumn,winter)
public static final Season spring = new Season("春天", "万物复苏"); public static final Season summer = new Season("夏天", "烈日炎炎"); public static final Season autumn = new Season("秋天", "硕果累累"); public static final Season winter = new Season("冬天", "寒风凛冽");
分析:上面并没有使用枚举,这样做一共new了4个对象,对于代码的可读性以及效率都不是很高,那怎样解决呢?下面开始引入枚举
枚举:枚举是在一定范围内取值,并且这个值必须是枚举类型中的任意一个,并且只能有一个
特点:
- 必须在规定范围内取值
- 这个值只能取一个
- 这个值可以是规定范围内的任意一个
枚举的本质就是一个Java类
SPRING("春天", "万物复苏"), SUMMER("夏天", "烈日炎炎"), AUTUMN("秋天", "硕果累累"), WINTER("冬天", "寒风凛冽"); private String name; private String info;
枚举类型默认使用public static final 类名 修饰
应用场景:一个类只能有固定的几个对象时,就考虑使用枚举
枚举中常用的方法:
- Enum.valueOf:通过字符串找到枚举类的某个对象,这里的valueOf是Enum的方法
- 类名.valueOf:这里的valueOf是父类的方法
//通过字符串找到枚举类的某个对象 Season season1 = Enum.valueOf(Season.class, "spring"); System.out.println(season1); //通过字符串找到枚举类的某个对象 Season season2 = Season.valueOf("spring"); System.out.println(season2); //获取该枚举类中所有的对象 Season[] seasons = Season.values(); for (Season season : seasons) { //获取枚举对象的名字 String name = season.name(); System.out.println(name); }
5.2状态机
枚举的应用之状态机
//信号灯 public enum Signal { RED,YELLOW,GREEN; }
public static void main(String[] args) { Scanner scan = new Scanner(System.in); System.out.println("请选择信号灯:RED,YELLOW,GREEN"); String str = scan.next(); scan.close(); //通过字符串找到枚举类的对象 Signal signal = Signal.valueOf(str); String trafficInstruct = getTrafficInstruct(signal); System.out.println(trafficInstruct); } public static String getTrafficInstruct(Signal signal){ String instruct = "信号灯故障"; switch (signal) { case RED: instruct = "红灯停"; break; case YELLOW: instruct = "黄灯请注意"; break; case GREEN: instruct = "绿灯行"; break; } return instruct; }
5.3枚举应用之组织枚举
可以将类型相近的枚举通过接口或类组织起来(但是一般用接口方式进行组织)
原因:
- Java接口在编译时会自动为enum类型加上public static修饰符;
- Java类在编译时会自动为 enum 类型加上static修饰符;
- 就是说,在类中组织 enum,如果你不给它修饰为 public,那么只能在本包中进行访问。
enum AddCode { ERROR_A(-1,"添加失败 -- 学生信息不合法"), ERROR_B(-2,"添加失败 -- 有重复学生"), OK(1,"添加成功"); private int code; private String info; } enum DeleteCode { ERROR_A(-1,"删除失败 -- 学生信息不合法"), ERROR_B(-2,"删除失败 -- 没有该学生"), OK(1,"删除成功"); private int code; private String info; }
5.4枚举应用之策略枚举
//工资的枚举 public enum Salary { Java(StaffType.teacher), Html(StaffType.teacher), Python(StaffType.teacher), Reception(StaffType.administrative), Principal(StaffType.administrative) ; private StaffType staffType; private Salary(StaffType staffType) { this.staffType = staffType; } public double getSalary(double baseSalary, int classHour, double teachingHourSubsidy, double achievements){ return staffType.calculationSalary(baseSalary, classHour, teachingHourSubsidy, achievements); } //员工类别 enum StaffType{ //匿名内部类的对象: class 匿名类 extends StaffType teacher{ @Override public double calculationSalary(double baseSalary, int classHour, double teachingHourSubsidy, double achievements) { //老师的工资:基本工资 + 课时*课时费 + 绩效 BigDecimal big1 = new BigDecimal(String.valueOf(baseSalary)); BigDecimal big2 = new BigDecimal(String.valueOf(classHour)); BigDecimal big3 = new BigDecimal(String.valueOf(teachingHourSubsidy)); BigDecimal big4 = new BigDecimal(String.valueOf(achievements)); BigDecimal salary = big2.multiply(big3).add(big1).add(big4); return salary.doubleValue(); } }, //匿名内部类的对象: class 匿名类 extends StaffType administrative{ @Override public double calculationSalary(double baseSalary, int classHour, double teachingHourSubsidy, double achievements) { BigDecimal big1 = new BigDecimal(String.valueOf(baseSalary)); BigDecimal big2 = new BigDecimal(String.valueOf(achievements)); BigDecimal salary = big1.add(big2); return salary.doubleValue(); } } ; /** * 计算工资的方法 * @param baseSalary 基本工资 * @param classHour 课时 * @param teachingHourSubsidy 课时费 * @param achievements 绩效 * @return 应得工资 */ public abstract double calculationSalary(double baseSalary,int classHour,double teachingHourSubsidy,double achievements); }
public static void main(String[] args) { /** * 枚举应用之策略枚举 * * 需求:模拟千锋计算工资的场景 */ double salary1 = Salary.Java.getSalary(1300, 84, 15, 1000); System.out.println(salary1); double salary2 = Salary.Reception.getSalary(500, 0, 0, 10000); System.out.println(salary2); }
teachingHourSubsidy 课时费
* @param achievements 绩效 * @return 应得工资 */ public abstract double calculationSalary(double baseSalary,int classHour,double teachingHourSubsidy,double achievements); }
```java public static void main(String[] args) { /** * 枚举应用之策略枚举 * * 需求:模拟千锋计算工资的场景 */ double salary1 = Salary.Java.getSalary(1300, 84, 15, 1000); System.out.println(salary1); double salary2 = Salary.Reception.getSalary(500, 0, 0, 10000); System.out.println(salary2); }