黑马毕向东Java课程笔记(day18-1——18-14):System、Runtime、Date、Calendar、Math-Random、Object、Scanner

1、System
1.1、System类的特点
  System 类包含一些有用的类字段和方法。它不能被实例化。(不能被实例化说明其美元构造函数,因此System里面的成员全部为静态)
  在 System 类提供的设施中,有标准输入、标准输出和错误输出流;对外部定义的属性和环境变量的访问;加载文件和库的方法;还有快速复制数组的一部分的实用方法。

1.2、System的常用方法
  System的系统信息获取

/*
System:类中的方法和属性都是静态的。
out:标准输出,默认是控制台。
in:标准输入,默认是键盘。
*/
package pack;

import java.util.*;

class SystemDemo 
{
	public static void main(String[] args) 
	{
//System是系统类,它可以描述系统环境,系统环境在虚拟机启动的时候会加载一些默认的系统启动信息,可以通过getProperties()查阅当前系统属性。
		//获取系统属性信息:public static Properties getProperties(),它返回Properties类对象
		Properties prop = System.getProperties();
		/*
		 * 因为Properties是Hashtable的子类,也就是Map集合的一个子类对象。那么可以通过map的方法取出该集合中的元素。(将其看做一个map集合即可)
		 * 该集合prop中存储都是字符串,没有定义泛型。(也就是Properties类没有定义泛型,因此在获取prop的Set集合时(既获取prop的键),也不能定义泛型)
		 */
		//利用foreach获取所有属性信息
		Set keySet = prop.keySet();//获取prop(Map)集合的键的集合(此处没有定义泛型)
		for(Object obj : keySet)//我们在此处没有添加泛型,因此必须用Object表示,以兼容所有类型
		{//获取Object类型的值,并向下强转为String(prop虽然不能定义泛型,但是他的全部值都是String类型)
			String value = (String)prop.get(obj);//获取prop集合的值并装换为String类型
			System.out.println(obj+"---"+value);
		}
	}	
}
/*
结果:(信息分析见18-1,10分钟开始处)
如果在其他电脑上运行这段程序,会出现不一样的结果!
*/

  System关于系统信息的其他功能

package pack;

import java.util.*;

class SystemDemo 
{
	public static void main(String[] args) 
	{
		//如何在系统中自定义一些特有信息呢?
		System.setProperty("myKey", "myValues");//结果系统信息中出现了:myKey---myValues
		Properties prop = System.getProperties();	
		Set keySet = prop.keySet();
		for(Object obj : keySet)
		{
			String value = (String)prop.get(obj);
			System.out.println(obj+"---"+value);
		}
		
		//获取单个属性
		String value = prop.getProperty("os.name");
		System.out.println("value="+value);//value=Windows 10
		
		//可不可以在jvm启动时,动态加载一些属性信息呢?(18-01,21)
		//我们可以在编译的时候通过命令行的命令来动态设置。
		String v = System.getProperty("haha");
		System.out.println("v="+v);
	}	
}

在这里插入图片描述
  对于上面所述的最后一个动态添加属性信息的示例,我们在pack包下面,使用命令行,可以编译,但是没办法运行,因为代码中指定了包,我们在编译的时候必须指定包要存放的位置!
在这里插入图片描述
  我们在编译的时候指定包存放在当前目录下,在运行的时候注意加上包名,这样便正常运行。同时,在当前目录下,有一个存放SystemDemo.java的包pack存在。
在这里插入图片描述
在这里插入图片描述
  同时,我们发现,如果我们退pack文件夹,再在pack文件夹外面使用java pack.SystemDemo命令,就可以正常运行。
在这里插入图片描述
  我们再创建一个SystemDemo类,但是我们不使用包来封装这个类,我们直接编译,发现正常运行。
在这里插入图片描述
在这里插入图片描述
  如果我们在上面的SystemDemo.java中加入package pack包,如下:
在这里插入图片描述
  综上所述,如果我们的代码里面指定了包来封装当前的类,那么我们,在命令行编译的时候必须指定包含“.class”的包所存放的位置,然后在运行的时候用“java 包名.类名”来运行,不可以进入包中用“java 类名”进行直接运行,这样会出错,因为包和“.class”文件是一个整体。
  另外,像向第一个例子,我们的SystemDemo.java文件已经存放在pack包下,编译生成的SystemDemo.class也在pack下,但是由于代码指定了包名,因此在运行的时候需要退出pack,在pack外面用“java pack.SystemDemo”来运行。
  总而言之,带有包名的类在编译时指定包存放位置,在运行的时候在包外用“java 包名.类名”来运行就不会出错。

  System的arraycopy()方法

/*
        public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length):将数组中指定的数据拷贝到另一个数组中。
        参数:
            src - 源数组。
            srcPos - 源数组中的起始位置(起始索引)。
            dest - 目标数组。
            destPos - 目标数据中的起始位置。
            length - 要复制的数组元素的数量。
        练习:
            将src数组中前3个元素,复制到dest数组的前3个位置上
                复制元素前:
                src数组元素[1,2,3,4,5],dest数组元素[6,7,8,9,10]
                复制元素后:
                src数组元素[1,2,3,4,5],dest数组元素[1,2,3,9,10]
     */
    private static void demo02() {
        //定义源数组
        int[] src = {1,2,3,4,5};
        //定义目标数组
        int[] dest = {6,7,8,9,10};
        System.out.println("复制前:"+ Arrays.toString(dest));
        //使用System类中的arraycopy把源数组的前3个元素复制到目标数组的前3个位置上
        System.arraycopy(src,0,dest,0,3);
        System.out.println("复制后:"+ Arrays.toString(dest));
        //注意复制的内容会将目标数组的相应位置的内容覆盖!
    }

2、Runtime
  每个 Java 应用程序都有一个 Runtime 类实例,使应用程序能够与其运行的环境相连接。(见18-02,0.20处解析)
  Runtime并没有提供构造函数,说明不可以new对象,那么会直接想到该类中的方法都是静态的,但是我们发现该类中还有非静态方法。这说明该类肯定会提供了方法获取本类对象,而且该方法是静态的,并返回值类型是本类类型。由这个特点可以看出该类使用了单例设计模式完成。该方式是static Runtime getRuntime();

  • public static Runtime getRuntime():返回与当前 Java 应用程序相关的运行时对象,该对象不需要我们创建,应用程序本身就创建完毕,我们只需要获取使用即可。Runtime 类的大多数方法是实例方法,并且必须根据当前的运行时对象对其进行调用。
      代码示例:
package pack;

import java.io.IOException;

class RuntimeDemo 
{
	//注意抛出IO异常的导入相应的包,抛出sleep的InterruptedException
	public static void main(String[] args) throws IOException , InterruptedException
	{
		Runtime r = Runtime.getRuntime();//创建一个与应用程序相关的运行对象
		//exec(String command):在单独的进程中执行指定的字符串命令。(18-02,7.00)
		//我们有可能传错数据,这样会抛出异常,且exec方法也会抛出IOException,那么我们这里在方法处手动抛出异常。
		r.exec("G:\\write.exe");//我们在该目录下放入写字板的执行文件,执行这段代码就会运行写字板
		//我们不指定执行文件的目录,仍然可以执行。(18-02,10.40)
		//如果在当前目录下找不到或者没有当前目录,就会到path设置的系统目录下面找,找不到就运行失败!
		r.exec("write.exe");
		
//示例:这里“\”是转义字符,如\Program会将P转义,就是“\p”,这样没有意义,那么我们再加一个“\”吗,表示为“\\”,这就是普通的“\”目录封装符
		r.exec("C:\\Program Files (x86)\\Tencent\\QQ\\Bin\\QQ.exe");//打开了qq
		
		/*
		 * process类(18-02,13.00): Runtime.exec 方法创建一个本机进程,并返回 Process子类的一个实例,该实例可用来控制进程并获得相关信息。
		 * process类是抽象的,它的方法也是抽象的,但是没有实现process的子类。因为应用程序一被执行,就已经产生进程,这个进程是调用底层资源创建的,
		 * 因此我们只定义抽象类Process而不定义实现Process的子类,因为底层在做Process的实现,不需要我们来实现。
		*/
		//destroy():杀掉子进程。
		Process p = r.exec("C:\\Program Files (x86)\\Tencent\\QQ\\Bin\\QQ.exe");
		Thread.sleep(4000);//使用Thread的sleep()方法让线程等一下,注意抛出InterruptedException
		p.destroy();//清除p所指定的子线程
		//我们只能操作p所指定的进程,其他进程无法操作
		
		//用记事本文件打开SystemDemo.java文件。只要是记事本可以打开的文件,就都可以用这个命令打开。
		//在eclipse中,这个文件必须放置Test项目文件夹下,系统才能找到。路径:F:\研究生学习资料\java\eclipse\eclipse\workspace\Test
		Process p1 = r.exec("notepad.exe SystemDemo.java");
	}	
}

3、Date工具类
  Date工具类在java.util包中,使用前需先导入util包。类 Date 表示特定的瞬间,精确到毫秒。 从 JDK 1.1 开始,应该使用 Calendar 类实现日期和时间字段之间转换,使用 DateFormat 类来格式化和解析日期字符串。Date 中的相应方法已废弃。
  代码示例

package pack;

import java.util.*;
import java.text.*;

class DateDemo 
{
	public static void main(String[] args) throws ParseException
	{
	//先将时间转换为文本
		Date d = new Date();
		System.out.println(d);//Thu Sep 19 02:17:57 CST 2019:格式较为复杂
		//将我们想设置的简单的模式封装到SimpleDateformat对象中。
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 E hh:mm:ss");//这里y\M\d只要有一个出现就会显示
		String time = sdf.format(d);//使用SimpleDateFormat的format方法将给定的 Date对象格式化为指定的日期/时间字符串
		System.out.println("time:"+time);
		
		//Date的另一种初始化方法:Date(long date) 
		long l = System.currentTimeMillis();
		Date d1 = new Date(l);	
		System.out.println("d1:"+d1);

		//以上是将时间转换为文本,下面我们将文本转换为时间
		//1.创建SimpleDateFormat对象,构造方法中传递指定的模式
        SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒");
        //2.调用SimpleDateFormat对象中的方法parse,把符合构造方法中模式的字符串,解析为Date日期
        //Date parse(String source)  把符合模式的字符串,解析为Date日期
        Date date = sdf1.parse("2088年08月08日 15时51分54秒");
        System.out.println(date);
	}	
}

  日期与毫秒之间的转换

把日期转换为毫秒:
        当前的日期:2088-01-01
        时间原点(0毫秒):1970 年 1 月 1 日 00:00:00(英国格林威治)
        就是计算当前日期到时间原点之间一共经历了多少毫秒 (3742767540068L)
    注意:
        中国属于东八区,会把时间增加8个小时
        1970 年 1 月 1 日 08:00:00

    把毫秒转换为日期:
        1 天 = 24 × 60 × 60 = 86400 秒  = 86400 x 1000 = 86400000毫秒

4、Calendar工具类
  Calendar 类是一个抽象类,它为特定瞬间与一组诸如 YEAR、MONTH、DAY_OF_MONTH、HOUR 等 日历字段之间的转换提供了一些方法,并为操作日历字段(例如获得下星期的日期)提供了一些方法。
  Calendar示例1:注意Calendar获取的都是数字

package pack;
import java.util.*;
import java.text.*;

class DateDemo 
{
	public static void main(String[] args) 
	{
		/*
		//如果我们单单想获得年
		Date d = new Date();
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy");
		System.out.println("年:"+sdf.format(d));//年:2019
		//这里获得的年是字符串,我们可以用Integer的parseInt转换为int类型
		*/
		
		//static Calendar getInstance():Calendar是抽象类,不能直接实例化,
		//只能使用getInstance()方法获取Calendar子类GregorianCalendar的实例
		Calendar c = Calendar.getInstance();
		System.out.println(c);
//分析:(18-04,8.00):打印了一堆信息。发现返回GregorianCalendar对象,也就是getInstance()返回Calendar的子类GregorianCalendar的对象
		System.out.print(c.get(Calendar.YEAR)+"年");
		System.out.print((c.get(Calendar.MONTH)+1)+"月");//月份用0-11表示,使用的时候+1
		System.out.print(c.get(Calendar.DAY_OF_MONTH)+"日");
		System.out.println("  星期"+(c.get(Calendar.DAY_OF_WEEK)-1));//这里星期天对应数字1,表示出来是星期0
//2019年8月19日 星期4——系统月份从0开始——调整(月+1):2019年9月19日  星期4——很麻烦,而且不好看,且星期几不好表示
		
		//使用查表法
		String[] mons = {"一月","二月","三月","四月",
						"五月","六月","七月","八月",
						"九月","十月","十一月","十二月"};//注意月份从0-11,刚刚好对应数组下标。


	   String[] weeks = {
					"星期日","星期一","星期二","星期三","星期四","星期五","星期六",
						};//1-7对应周日到周六,且数组下标从0开始,将星期天放在数组开始,并且表示的时候应该-1
	   //我们先获取月日对应的数字,再拿去查表
	   int monthIndex = c.get(Calendar.MONTH);
	   int weekIndex = c.get(Calendar.DAY_OF_WEEK);
	   System.out.println(mons[monthIndex]);//九月:这样就好看很多。
	   System.out.println(weeks[weekIndex-1]);
	}	
}

  Calendar示例2

package pack;
import java.util.*;
import java.text.*;

class DateDemo 
{
	public static void main(String[] args) 
	{
		Calendar c = Calendar.getInstance();
		//如果想对c进行重新的时间设定,可以使用set()方法
//		c.set(2020,6,6);//这里set设置月份也是从0-11,6代表7月
//		printCalendar(c);//2020年七月6日:星期一
		
		//add(int field, int amount):根据日历的规则,为给定的日历字段添加或减去指定的时间量。
//		c.add(Calendar.YEAR, -8);//当前年减去8年
//		printCalendar(c);//2011年九月19日:星期一
		c.add(Calendar.MONTH, 3);
		printCalendar(c);
	}	
	
	//设置一个专门打印Calendar的方法
	public static void printCalendar(Calendar c)
	{
		String[] mons = {"一月","二月","三月","四月"
					,"五月","六月","七月","八月"
					,"九月","十月","十一月","十二月"};


		String[] weeks = {
						"","星期日","星期一","星期二","星期三","星期四","星期五","星期六",
							};
		int index = c.get(Calendar.MONTH);//获取月
		int index1 = c.get(Calendar.DAY_OF_WEEK);//获取周
		System.out.print(c.get(Calendar.YEAR)+"年");
		System.out.print(mons[index]);
		System.out.print(c.get(Calendar.DAY_OF_MONTH)+"日"+":");
		System.out.print(weeks[index1]);
	}
}

  Calendar练习

/*
三个练习:
1,获取任意年的二月有多少天。
	思路:根据指定年设置一个时间就是 :c.set(year,2,1)//某一年的3月1日。
		c.add(Calenar.DAY_OF_MONTH,-1);//3月1日,往前推一天,就是2月最后一天。

2,获取昨天的现在这个时刻:c.add(Calenar.DAY_OF_MONTH,-1);

3,求一段时间内的有效天数——如从6月6日到8月18日培训,周六日不上课,求期间上课的有效天数
*/
package pack;
import java.util.*;
import java.text.*;

class DateDemo 
{
	public static void main(String[] args) 
	{
		Calendar c = Calendar.getInstance();
		//获取某一年2月份天数
//		System.out.print("2019年2月份天数为:");
//		getFebDays(c,2019);
		
		//获取昨天这个时刻
		getYesTime(c);
		//昨天是18日 4时47分14秒
		
		//求一段时间内的有效天数——如从6月6日到7月18日培训,周六日不上课,求期间上课的有效天数
		getClassDays(c);
	}
	//求一段时间内的有效天数——如从6月6日到7月18日培训,周六日不上课,求期间上课的有效天数
	public static void getClassDays(Calendar c)
	{
		c.set(2019,6,18);
		int lastDay = c.get(Calendar.DAY_OF_MONTH);
		int lastMonth = c.get(Calendar.MONTH);//获取最后一天的日与月
		c.set(2019,5,6);//将日期设置为最开始的那天
		int dayNum = 0;
		//如果月份与日期对不上,就将日期加一
		for(;!(c.get(Calendar.MONTH)==lastMonth && c.get(Calendar.DAY_OF_MONTH)==lastDay) ; c.add(Calendar.DAY_OF_MONTH, 1) )
		{
			//如果日期在逐渐+1的过程中,不是星期六与星期天,就将计算天数+1
			if(!(c.get(Calendar.DAY_OF_WEEK)==1) && !(c.get(Calendar.DAY_OF_WEEK)==7))
				dayNum++;
		}
		System.out.println("上课的天数为:"+dayNum);//上课的天数为:30。正确
	}
	
	
	//获取昨天这个时刻的方法
	public static void getYesTime(Calendar c)
	{
		c.add(Calendar.DAY_OF_MONTH, -1);//直接将当前天数-1
		System.out.println("昨天是"+c.get(Calendar.DAY_OF_MONTH)+"日");
		System.out.println(c.get(Calendar.HOUR_OF_DAY)+"时"+c.get(Calendar.MINUTE)+"分"+c.get(Calendar.SECOND)+"秒");//获取昨天这个时刻
	}
	
	//获取某一年2月天数的方法
	public static void getFebDays(Calendar c, int year)
	{
		//先设置某一年的3月1日(注意月份从0-11)
		c.set(year,2,1);
		c.add(Calendar.DAY_OF_MONTH, -1);//3月1日,往前推一天,就是2月最后一天,也就是2月份的天数
		System.out.println(c.get(Calendar.DAY_OF_MONTH));//获取2月份最后一天,也就是这一年2月份天数
	}
	
	//设置一个专门打印Calendar的方法
	public static void printCalendar(Calendar c)
	{
		String[] mons = {"一月","二月","三月","四月"
					,"五月","六月","七月","八月"
					,"九月","十月","十一月","十二月"};


		String[] weeks = {
						"","星期日","星期一","星期二","星期三","星期四","星期五","星期六",
							};
		int index = c.get(Calendar.MONTH);//获取月
		int index1 = c.get(Calendar.DAY_OF_WEEK);//获取周
		System.out.print(c.get(Calendar.YEAR)+"年");
		System.out.print(mons[index]);
		System.out.print(c.get(Calendar.DAY_OF_MONTH)+"日"+":");
		System.out.print(weeks[index1]);
	}
}

6、Math类与Random类
  Math 类包含用于执行基本数学运算的方法,如初等指数、对数、平方根和三角函数。 Math中的成员都是静态的。示例如下:

package pack;
import java.util.*;

class DateDemo 
{
	public static void main(String[] args) 
	{
		showRandom();
	}
	public static void show()
	{
		//static double ceil(double a) 返回大于a值的最小的double类型的整数。
		double d = Math.ceil(12.567);
		System.out.println(d);//13.0
		double d1 = Math.ceil(-12.567);
		System.out.println(d1);//-12.0
		
		//static double floor(double a) 返回小于a值的最大double类型的整数
		double d2 = Math.floor(12.567);
		System.out.println(d2);//12.0
		double d3 = Math.floor(-12.567);
		System.out.println(d3);//-13.0 
		
		//static long/int round(double a) :四舍五入
		 int r = Math.round(12.56f);
		 System.out.println(r);//13
		 long r1 = Math.round(12.46);
		 System.out.println(r1);//12
		 
		 //static double pow(double a, double b) :幂运算
		 double db = Math.pow(2, 3);
		 System.out.println(db);//2^3=8.0		
	}
	
	public static void showrandom()
	{
		//static double random() 返回带正号的 double 值,该值大于等于 0.0 且小于 1.0。
		for(int x=0; x<10 ;x++)
		{
			double d = Math.random();
			System.out.println(d);//打印10个double类型的0.0-1.0的随机数
		}
		
		//打印1-10之间的随机数
		for(int x=0; x<10 ;x++)
		{
			int i = (int)(Math.random()*10+1);//1<=Math.random()*10+1<11,强转为int后为1-10
			System.out.println(i);//打印10个double类型的0.0-1.0的随机数
		}		
	}
	
	public static void showRandom()
	{
		Random r = new Random();
		for(int x=0; x<10 ;x++)
		{
//int nextInt(int n) 返回一个伪随机数,它是取自此随机数生成器序列的、在 0(包括)和指定值(不包括)之间均匀分布的 int 值。 
			int i = r.nextInt(10)+1;//返回1-11(不包含11)之间的随机整数
			System.out.println(i);
		}
	}
}

  Math练习

/*
练习:给定一个小数,保留该小数的后两位。
可以考虑,保留时进行四舍五入,或者不进行四舍五入直接保留。
*/
package pack;
import java.util.*;

class DateDemo 
{
	public static void main(String[] args) 
	{
		saveTwo(12.56678,2,true);//四舍五入:12.57
		saveTwo(12.56678,2,false);//不四舍五入:12.56
	}
	//double为要保留的数,scale为要保留的小数位数,isRound表示是否需要四舍五入
	public static void saveTwo(double num, int scale, boolean isRound)
	{
		double base = Math.pow(10, scale);
		//需要四舍五入就先乘以base,四舍五入后为整数再除以base;不需要四舍五入就直接乘以base,int强制取整,再除以base
		double number = isRound?Math.round(num*base)/base:((int)(num*base))/base; 
		System.out.println(number);
	}
}

7、Object类
  理论上Object类是所有类的父类,即所有类都直接或间接的继承java.lang.Object类。由于所有的类都继承在Object类,因此省略了extends Object关键字。Object中定义的方法是所有对象都具备的方法!
  该类中主要有以下方法: toString()、getClass()、equals()、clone()、finalize()、hashCode()、notify()、notifyAll()、wait()。 其中toString(),getClass(),equals()是其中最重要的方法。
  Object类中的getClass()、notify()、notifyAll()、wait()等方法被定义为final类型,因此不能重写。
  下面我们说一下Object类中的几个方法。参考如下文章
添加链接描述

7.1、equals()方法
  java认为所有的对象都具备比较性,都能比较2个对象是否相同。
  equals(Object obj) ,这里使用了多态的特性!!!

public boolean equals(Object obj)
{
	return this == obj;
}

  Object中的equals方法是直接判断this和obj本身的值是否相等,即用来判断调用equals的对象和形参obj所引用的对象是否是同一对象。所谓同一对象就是指内存中同一块存储单元,如果this和obj指向的同一块存储单元,则返回true,如果this和obj指向的不是同一块内存,则返回false。
  注意:即便是内容完全相等的两块不同的内存对象,也返回false。如果希望不同内存但相同内容的两个对象equals时返回true,则我们需要重写父类的equal方法,String类已经重写了object中的equals方法(这样就是比较内容是否相等了)

public class ObjectDemo {

	public static void main(String[] args) {
		Demo d1 = new Demo();
		Demo d2 = new Demo();
		Demo d3 = d1;
		//false,因为2个不同的对象会在堆内存中开辟2个不同区域
		System.out.println(d1.equals(d2));
		//true,因为d1与d3是同一个对象,同一个内存地址!!!
		System.out.println(d1.equals(d3));
	}
}
class Demo{}

  我们可能有比较内存不同但内容不知道是否相同的2个对象。如下:


public class ObjectDemo {

	public static void main(String[] args) {
		Demo d1 = new Demo(3);
		Demo d2 = new Demo(4);
		//用于比较对象的内容是否相同
		System.out.println(d1.compare(d2));
	}
}

class Demo
{
	private int num;
	public Demo(int num) 
	{
		this.num = num;
	}
	//用compare方法比较Demo2个对象的num值是否相同
	public boolean compare(Demo d)
	{
		return this.num == d.num;
	}
}

  如果自定义类中也有比较相同的功能,没有必要重新定义,只要沿袭父类中的功能,建立自己特有比较内容即可,这就是覆盖(重写)。比如如果希望比较不同内存但相同内容的两个对象equals时返回true,则我们需要重写父类的equal方法,如下:


public class ObjectDemo {

	public static void main(String[] args) {
		Demo d1 = new Demo(3);
		Demo d2 = new Demo(4);
		//用于比较对象的内容是否相同
		System.out.println(d1.equals(d2));
		//对于另一个类的对象,如果我们不在重写的equals方法中比较,会出错
		Person p = new Person(3); 
		System.out.println(d1.equals(p));
		//结果:2个对象不属于同类 false
	}
}

class Demo
{
	private int num;
	public Demo(int num) 
	{
		this.num = num;
	}
	//我们重写equals方法来比较内容
	public boolean equals(Object obj)//Object obj = d2
	{
		//此处使用多态,obj是Object类的引用,不可以直接使用Demo的私有变量num
//		return this.num == obj.num;

		/*
		//增加一个判断,传递的参数obj如果是this本身,直接返回true,提高程序的效率
        if(obj==this){
            return true;
        }

        //增加一个判断,传递的参数obj如果是null,直接返回false,提高程序的效率
        if(obj==null){
            return false;
        }
        */

		//编译器重写格式如下
		@Override
    public boolean equals(Object o) {
        if (this == o) return true;
        //getClass() != o.getClass() 使用反射技术,判断o是否是Person类型  等效于 obj instanceof Person
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return age == person.age &&
                Objects.equals(name, person.name);
    }
	
		
		//我们使用向下类型转换就可以调用子类特有的内容
		if(obj instanceof Demo)
		{
			Demo d = (Demo)obj;
			return this.num == d.num;
		}else {//如果我们传入的对象不是Demo类型,内容肯定不同(就算数字相同,但是对象不同内容必然不同)
			System.out.println("2个对象不属于同类");
			return false;
		}
	}
}

class Person
{
	private int num;
	public Person(int num) 
	{
		this.num = num;
	}
}

  这里使用到了java.util.Objects类,那么这个类是什么呢?

  在JDK7添加了一个Objects工具类,它提供了一些方法来操作对象,它由一些静态的实用方法组成,这些方法是null-save(空指针安全的)或null-tolerant(容忍空指针的),用于计算对象的hashcode、返回对象的字符串表示形式、比较两个对象。

在比较两个对象的时候,Object的equals方法容易抛出空指针异常,而Objects类中的equals方法就优化了这个问题。方法如下:

  • public static boolean equals(Object a, Object b):判断两个对象是否相等。

我们可以查看一下源码,学习一下:

public static boolean equals(Object a, Object b) {  
//这里如果a,b有一个为空,或者a,b地址值不相同,就会判断“a == b”,返回flase,那么后面一句比如也是false;如果a,b地址值相同,直接返回true;在a,b不为空且地址值不同的时候,再判断他们的内容是否相同。
    return (a == b) || (a != null && a.equals(b));  
}

7.2、toString()方法
  java认为所有对象都能转换为字符串被打印
  Object 类的 toString 方法返回一个字符串,该字符串由类名(对象是该类的一个实例)、at 标记符“@”和此对象哈希码的无符号十六进制表示组成。该方法用得比较多,一般子类都有覆盖。

public String tostring()
{ 
	return getClass(). getName()+"@"+Integer. toHexstring (hashCode());//其实getClass()与hashCode()方法前面都应该加一个this表示当前对象
}

  例子如下

public class ObjectDemo {
	public static void main(String[] args) {
		Demo d1 = new Demo();
		Demo d2 = new Demo();
		System.out.println(d1.toString());
	}
}
class Demo{}

7.3、hashCode()方法

public int hashCode()

  返回该对象的哈希码值

public class ObjectDemo {
	public static void main(String[] args) {
		Demo d1 = new Demo();
		System.out.println(d1.toString());
		System.out.println(Integer.toHexString(d1.hashCode()));
	}
}
class Demo{}
//结果
Demo@7852e922
7852e922

7.4、getClass()方法

public final Class getClass()//返回类名,返回值是Class类,比较特殊
//Class类用于描述class文件,就是***.class文件。

  返回次Object的运行时类类型。不可重写,要调用的话,一般和getName()联合使用,如getClass().getName()。(这一部分具体见8.9第6分钟开始的分析,目前比较难理解)
  这其中又涉及getName()方法,这个方法以 String 的形式返回此 Class 对象所表示的实体(类、接口、数组类、基本类型或 void)名称。

public class ObjectDemo {

	public static void main(String[] args) {
		Demo d1 = new Demo();
		//返回d1所对应的Demo类类型,将这个Demo类型赋予Class类的对象c;
		//因为Class类本来就是用来描述类文件“.class”文件的,此时c代表了“Demo.class”这个类,因此可以用Class类的getName()方法来获取Demo的类名
		Class c = d1.getClass();	
		System.out.println(c.getName());//结果是Demo
		System.out.println(d1.getName());//这样就会出错,因为Demo中没有getName()方法
	}
}
class Demo{}

  例子:

public class ObjectDemo {

	public static void main(String[] args) {
		Demo d1 = new Demo(4);
		System.out.println(d1.toString());
		//结果是:Demo:4
		//在实际开发过程中,java很多方法需要重写才能符合我们的使用需求
	}
}

class Demo
{
	private int num;
	Demo(int num)
	{
		this.num = num;
	}
	//我们发现toString类返回值没有什么意义,我们将其复写
	public String toString()
	{
		return "Demo:"+num;
	}
}

8、Scanner类
  键盘输入的几类方法见下面文章:java键盘输入
  相应的代码示例如下:

package lkj.demo1;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Scanner;

public class ScannerTest
{
    public static void main(String[] args)throws Exception
    {
        //键盘输入的几类方法

        //Scanner(InputStream source):构造一个新的 Scanner,它生成的值是从指定的输入流扫描的。
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入字符串:");
        String str1 = sc.next();//输入字符串的方法是next()
        System.out.println("输入的字符串是:"+str1);

        //使用InputStreamReader类与BufferedReader类
        BufferedReader bufr =
                new BufferedReader(new InputStreamReader(System.in));
        System.out.println("请输入字符串:");
        String str2 = bufr.readLine();//注意,readLine方法会抛出异常
        System.out.println("输入的字符串是:"+str2);
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值