zoukankan      html  css  js  c++  java
  • Java 面向对象(七)

    枚举

    枚举的引入(模拟枚举)

    class Student {
    	private int restDay;
    
    	public int getRestDay() {
    		return restDay;
    	}
    
    	public void setRestDay(int restDay) {
    		this.restDay = restDay;
    	}
    }
    
    public class Test {
    	public static void main(String[] args) {
    		Student stu = new Student();
    		stu.setRestDay(1);
    		int res = stu.getRestDay();
    		if (res == 6 || res == 7) {
    			System.out.println("放假");
    		} else {
    			System.out.println("上课");
    		}
    	}
    }
    

    上面的代码,存在一些问题:

    (1)数据不安全,输入8

    stu.setRestDay(8);	// 输出:上课(没有星期八)
    

    (2)业务逻辑不合理:中外一周的第一天不一样,中国第一天是周一,外国第一天是周天。

    改进后:

    class WeekDay {
    	public static final int MONDAY = 1;
    	public static final int TUESDAY = 2;
    	public static final int WEDNESDAY = 3;
    	public static final int THURSDAY = 4;
    	public static final int FRIDAY = 5;
    	public static final int SATURDAY = 6;
    	public static final int SUNDAY = 7;
    }
    
    class Student {
    	private int restDay;
    
    	public int getRestDay() {
    		return restDay;
    	}
    
    	public void setRestDay(int restDay) {
    		this.restDay = restDay;
    	}
    }
    
    public class Test {
    	public static void main(String[] args) {
    		Student stu = new Student();
    		stu.setRestDay(WeekDay.MONDAY);
    		int res = stu.getRestDay();
    		if (res == 6 || res == 7) {
    			System.out.println("放假");
    		} else {
    			System.out.println("上课");
    		}
    	}
    }
    

    改进后的代码,还存在问题:

    (1)数据不安全,输入8

    stu.setRestDay(8);	// 输出:上课(没有星期八)
    

    再次改进:

    class WeekDay {
    	private WeekDay() {}
    	public static final WeekDay MONDAY = new WeekDay();
    	public static final WeekDay TUESDAY = new WeekDay();
    	public static final WeekDay WEDNESDAY = new WeekDay();
    	public static final WeekDay THURSDAY = new WeekDay();
    	public static final WeekDay FRIDAY = new WeekDay();
    	public static final WeekDay SATURDAY = new WeekDay();
    	public static final WeekDay SUNDAY = new WeekDay();
    }
    
    class Student {
    	private WeekDay restDay;
    
    	public WeekDay getRestDay() {
    		return restDay;
    	}
    
    	public void setRestDay(WeekDay restDay) {
    		this.restDay = restDay;
    	}
    }
    
    public class Test {
    	public static void main(String[] args) {
    		Student stu = new Student();
    		stu.setRestDay(WeekDay.MONDAY);
    		WeekDay res = stu.getRestDay();
    		if (res == WeekDay.SATURDAY || res == WeekDay.SUNDAY) {
    			System.out.println("放假");
    		} else {
    			System.out.println("上课");
    		}
    	}
    }
    

    上面的代码,问题解决了,但是代码不好看,太冗余。

    什么是枚举

    枚举:表示一个事物固定状态。

    比如:季节(春,夏,秋,冬)、星期(周一到周日)、性别(男,女)

    枚举的定义

    格式:

    [修饰符] enum 枚举的名称  {
    	常量1,常量2,常量3……
    }
    

    比如:

    enum Sex {
    	MAN, FEMALE
    }
    

    枚举的本质

    java 枚举是一个语法糖。是一个特殊的类,是多个常量对象的集合。

    当我们定义一个枚举后,它的本质还是一个类,一个继承了Enum的类。

    enum Sex {
    	MAN, FEMALE
    }
    

    反编译后:

    final class Sex extends Enum
    {
    
    	public static final Sex MAN;
    	public static final Sex FEMALE;
    	private static final Sex ENUM$VALUES[];
    
    	private Sex(String s, int i)
    	{
    		super(s, i);
    	}
    
    	public static Sex[] values()
    	{
    		Sex asex[];
    		int i;
    		Sex asex1[];
    		System.arraycopy(asex = ENUM$VALUES, 0, asex1 = new Sex[i = asex.length], 0, i);
    		return asex1;
    	}
    
    	public static Sex valueOf(String s)
    	{
    		return (Sex)Enum.valueOf(Test/Sex, s);
    	}
    
    	static 
    	{
    		MAN = new Sex("MAN", 0);
    		FEMALE = new Sex("FEMALE", 1);
    		ENUM$VALUES = (new Sex[] {
    			MAN, FEMALE
    		});
    	}
    }
    

    程序 main 方法

    public static void main(String[] args) {
    	
    }
    

    当点击运行时,JVM自动会调用main方法。

    public : 被JVM调用的方法,它的权限要足够的大。

    static : 被JVM调用的方法,不需要创建对象,直接使用类名调用

    void : 被JVM调用的方法,不需要有任何 的返回值。

    main : 方法 的名称 ,只能这样写,不然JVM识别不了

    String[] args : 以前是指键盘录入。

    常用类之Scanner

    Scanner类常用的场景为:

    (1)控制台输入(等待从键盘录入一个数);

    (2)字符串分割;

    (3)文本整行读取。

    控制台输入

    输入八大基本数据类型

    在输入之前最好先使用 hasNextXxx() 方法进行验证是否还有输入的数据,再使用 nextXxx() 来读取。

    public static void main(String[] args) {
    	Scanner in = new Scanner(System.in);
    	if (in.hasNextInt()) {
    		System.out.println("请输入一个数:");
    		int input = in.nextInt();
    		System.out.println("input ==> " + input);
    	}
    	in.close();
    }
    

    这时候,我们可能希望的是:先输出“请输入一个数:”,然后我们就可以在控制台输入一个字符串或数字。

    但是,事实却是:控制台要我们先输入,输入后才显示“请输入一个数:”。

    个人理解如下:

    首先,in.hasNextInt() 和 in.nextInt() 都可以用来输入。

    in.hasNextInt()输入:

    Scanner in = new Scanner(System.in);
    boolean b = in.hasNextInt();	// 输入1:12		输入2:12.5
    System.out.println(b);			// 输出1:true		输出2:false
    

    in.hasNext:读取数据存储区,有下一个则返回布尔true,否则一直等待输入(不会返回false)

    可设置终止符:hasNext(String patten),如果下一个标记与从指定字符串构造的模式匹配,则返回 true。

    Scanner in = new Scanner(System.in);
    boolean b = in.hasNext("0");	// 输入1:0		输入2:java
    System.out.println(b);			// 输出1:true	输出2:false
    

    in.nextInt()输入:

    Scanner in = new Scanner(System.in);
    int i = in.nextInt();			// 输入1:12		输入2:java
    System.out.println(i);			// 输出1:12		输出2:抛异常
    

    可以发现,hasNextXxx()返回的是boolean类型,而nextXxx()返回的是输入的那个值。

    in.hasNextXxx()可以理解为: 从一段用于用户输入的内存(可以理解为in)当中扫描,
    如果该内存中有值,判断是否符合类型。符合就返回true,不符合就返回false。
    如果该内存中没有值,会阻塞,先从键盘读取一个值存到该内存中,在进行判断是否符合类型。

    in.next()可以理解为:从一段用于用户输入的内存(可以理解为in)中取值,
    如果该内存中有值,会先判断是否符合类型,如果符合直接取值,取值后将标识符后移(可以理解为:取完值后这个值就不在了),如果不符合会报异常;
    如果该内存中没有值,会阻塞,先从键盘读取一个值存到该内存中,再取值(取值时也要判断是否符合类型)。

    输入字符串

    可以使用 next() 与 nextLine()。在输入之前也是最好先使用 hasNext() 方法进行验证是否还有输入的数据。

    next() 与 nextLine() 区别

    next():

    1、一定要读取到有效字符后才可以结束输入。
    2、对输入有效字符之前遇到的空白,next() 方法会自动将其去掉。
    3、只有输入有效字符后才将其后面输入的空白作为分隔符或者结束符。

    注意:next() 不能得到带有空格的字符串。

    nextLine():

    1、以Enter为结束符,也就是说 nextLine()方法返回的是输入回车之前的所有字符。
    2、可以获得空白。

    字符串分割

    public static void main(String[] args) {
    	String inputStr = "123 456,abc.def...张三|李四";
    	Scanner in = new Scanner(inputStr);
    	in.useDelimiter(" |,|\.|\|");
    	while(in.hasNext()){
    		String input = in.next();
    		System.out.println("input ==> " + input);
    	}
    	in.close();
    }
    

    文本整行读取

    public static void main(String[] args) {
    	InputStream is = null;
    	try {
    		is = new FileInputStream(new File("D:\Desktop\Hello.txt"));
    		Scanner in = new Scanner(is);
    		while (in.hasNextLine()) {
    			String input = in.nextLine();
    			System.out.println("input ==> " + input);
    		}
    		in.close();
    	} catch (FileNotFoundException e) {
    		e.printStackTrace();
    	} finally {
    		try {
    			is.close();
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    	}
    }
    

    常用类之System(java.lang.System)

    常用类主要说的是常用类当中常用的方法 (系统已经给我们提供了很多可以直接使用的方法)

    常用类一般都不允许你创建对象。 一般都私有化了构造器。

    java.lang 是不需要导入包的。

    数组拷贝

    public static void main(String[] args) {
    	int[] src = { 1, 2, 3, 4, 5, 6 };
    	int[] dest = new int[8];
    	/*
    	 * 数组拷贝
    	 * public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length) 
    	 * src		:源数组
    	 * srcPos	:源数组中的起始位置
    	 * dest		:目标数组
    	 * destPos	:目标数据中的起始位置
    	 * length	:要复制的数组元素的数量
    	 */
    	System.arraycopy(src, 2, dest, 2, 4);
    	// 数组打印
    	System.out.println(Arrays.toString(src));	// [1, 2, 3, 4, 5, 6]
    	System.out.println(Arrays.toString(dest));	// [0, 0, 3, 4, 5, 6, 0, 0]
    }
    

    返回以毫秒为单位的当前时间(用于计算代码耗时)

    public static void main(String[] args) {
    	// 获取当前时间与 1970 年 1 月 1 日午夜之间的时间差(以毫秒为单位测量)。
    	long time1 = System.currentTimeMillis();
    	for (int i = 0; i < 100; i++) {
    		System.out.println(i);
    	}
    	long time2 = System.currentTimeMillis();
    	long time3 = time2 - time1;
    	System.out.println("总耗时:" + time3 + " ms");
    }
    

    终止当前正在运行的 Java 虚拟机

    public static void exit(int status)
    

    非 0 的状态码表示异常终止。

    正常终止:

    System.exit(0);
    

    运行垃圾回收器

    System.gc();
    

    例子:

    public class Test {
    	
    	/**
    	 * 当一个对象被垃圾回收时,自动调用的一个方法
    	 */
    	@Override
    	protected void finalize() throws Throwable {
    		super.finalize();
    		System.out.println("我被回收了");
    	}
    	
    	public static void main(String[] args) {
    		
    		new Test();
    		new Test();
    		/*
    		 * 一个对象并不是立即被回收
    		 * 执行gc,立即运行垃圾回收器
    		 */
    		System.gc();
    	}
    }
    

    常用类之Math(java.lang.Math)

    java.lang 是不需要导入包的。

    说明 方法
    求绝对值 abs
    求平方根 sqrt
    求立方根 cbrt
    求最大值 max
    求最小值 min
    求 n 次方 pow
    随机数 random
    三角函数 ……
    对数 ……
    指数 ……
    public static void main(String[] args) {
    
    	// abs : 求绝对值
    	int abs = Math.abs(-62);
    	System.out.println(abs);
    	
    	// sqrt : 求平方根
    	double sqrt = Math.sqrt(4.0);
    	System.out.println(sqrt);
    	
    	// cbrt : 求立方根
    	double cbrt = Math.cbrt(27);
    	System.out.println(cbrt);
    
    	// max : 求最大值
    	// min : 求最小值
    	int max = Math.max(6, 10);
    	double min = Math.min(6.0, 3.0);
    	System.out.println("max: " + max + ",  min: " + min);
    
    	// pow : 求一个数的 n 次方
    	double pow = Math.pow(2, 3);
    	System.out.println(pow);
    
    	// random : 返回一个 [0,1) 的随机数
    	double random = Math.random();
    	System.out.println(random);
    	// 返回 [0,100) 的随机数
    	double random2 = Math.random() * 100;
    	System.out.println(random2);
    	// 返回 [0,100) 的随机整数
    	int random3 = (int)(Math.random() * 100);
    	System.out.println(random3);
    }
    

    大精度小数

    先来看个例子:

    // float double 表示小数,但是不能表示精确的小数
    System.out.println("0.09 + 0.01 = " + (0.09 + 0.01));
    System.out.println("1.0 - 0.33 = " + (1.0 - 0.33));
    System.out.println("4.015 * 1000 = " + (4.015 * 1000));
    System.out.println("12.3 / 100 = " + (12.3 / 100));
    

    输出结果:

    0.09 + 0.01 = 0.09999999999999999
    1.0 - 0.33 = 0.6699999999999999
    4.015 * 1000 = 4014.9999999999995
    12.3 / 100 = 0.12300000000000001
    

    这里结果精度差了点,如果用来表示金钱,问题就大了。

    金钱对精度要求比较高,所以不用 float 和 double,用 BigDecimal

    BigDecimal b1 = new BigDecimal(0.09);
    BigDecimal b2 = new BigDecimal(0.01);
    BigDecimal add = b1.add(b2);
    System.out.println(add);
    // 输出结果: 0.09999999999999999687749774324174723005853593349456787109375
    

    发现结果精度更高了,但还不是我们想要的结果。这是构造器的原因:

    public BigDecimal(double val):

    (1)此构造方法的结果有一定的不可预知性。有人可能认为在 Java 中写入 new BigDecimal(0.1) 所创建的 BigDecimal 正好等于 0.1,但是它实际上等于 0.1000000000000000055511151231257827021181583404541015625。这是因为 0.1 无法准确地表示为 double(或者说对于该情况,不能表示为任何有限长度的二进制小数)。这样,传入到构造方法的值不会正好等于 0.1(虽然表面上等于该值)。

    (2)另一方面,String 构造方法是完全可预知的:写入 new BigDecimal("0.1") 将创建一个 BigDecimal,它正好等于预期的 0.1。因此,比较而言,通常建议优先使用 String 构造方法。

    BigDecimal b1 = new BigDecimal("0.09");
    BigDecimal b2 = new BigDecimal("0.01");
    BigDecimal add = b1.add(b2);
    System.out.println(add);
    // 输出结果: 0.10
    

    BigDecimal 加减乘除:

    public static void main(String[] args) {
    	double d1 = 0.09;
    	double d2 = 0.01;
    	BigDecimal b1 = new BigDecimal(Double.toString(d1));
    	BigDecimal b2 = new BigDecimal(Double.toString(d2));
    	// d1+d2
    	BigDecimal add = b1.add(b2);
    	System.out.println(add);
    	// d1-d2
    	BigDecimal sub = b1.subtract(b2);
    	System.out.println(sub);
    	// d1*d2
    	BigDecimal mul = b1.multiply(b2);
    	System.out.println(mul);
    	// d1/d2
    	BigDecimal div = b1.divide(b2);
    	System.out.println(div);
    	
    	// BigDecimal -> double
    	double d3 = div.doubleValue();
    	System.out.println(d3);	
    }
    
  • 相关阅读:
    设计模式-策略模式
    .NET操作RabbitMQ组件EasyNetQ使用中文简版文档。
    LayIM项目之基础数据获取代码优化,Dapper取代ADO.NET
    干货!手把手教你如何使用第三方通讯服务实现LayIM Socket组件开发。
    几句代码简单实现IoC容器
    .NET Core On Mac 第一步,配置环境
    Func<T,T>应用之Elasticsearch查询语句构造器的开发
    四个人17分钟过桥的问题
    ElasticSearch中的简单查询
    ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(十四)之漏掉的客服消息
  • 原文地址:https://www.cnblogs.com/xzh0717/p/11232811.html
Copyright © 2011-2022 走看看