目录
泛型
定义:在调用方法时,我们通常需要传入某种类型的参数,而这种类型,我们可以将其定义成参数(类型形参),这种方法称为泛型。因为我们在传递参数时,有时候我们不确定需要传递哪种类型的参数,或者需要传入多种类型的参数,此时我们就可以用泛型作为类型形参。然后在使用时传入具体的类型。
泛型的使用
泛型类
定义一个泛型类: public class ClassName<T>{ private T data; public T getData() { return data; } public void setData(T data) { this.data = data; } }
泛型接口
public interface IntercaceName<T>{ T getData(); } 实现接口时,可以选择指定泛型类型,也可以选择不指定, 如下: 指定类型: public class Interface1 implements IntercaceName<String> { private String text; @Override public String getData() { return text; } } 不指定类型: public class Interface1<T> implements IntercaceName<T> { private T data; @Override public T getData() { return data; } }
泛型方法
常用写法:public static <T> void print(T a) private static <T> T 方法名(T a, T b) {}
注意
-
在编译之后程序会采取去泛型化的措施。
-
也就是说Java中的泛型,只在编译阶段有效。
-
在编译过程中,正确检验泛型结果后,会将泛型的相关信息擦出,并且在对象进入和离开方法的边界处添加
-
类型检查和类型转换的方法。也就是说,泛型信息不会进入到运行时阶段。
-
在类,方法或接口可以使用多个泛型。如下图
泛型限制类型
-
在使用泛型时, 可以指定泛型的限定区域 ,
- 例如: 必须是某某类的子类或 某某接口的实现类,格式:<T extends 类或接口1 & 接口2>
泛型中的通配符 ?
类型通配符是使用?代替方法具体的类型实参。
1 <? extends Parent> 指定了泛型类型的上届
2 <? super Child> 指定了泛型类型的下届
3 <?> 指定了没有限制的泛型类型
作用
1、 提高代码复用率
2、 泛型中的类型在使用时指定,不需要强制类型转换(类型安全,编译器会检查类型)
常用库类整理
Object类功能分析
我们可以看到Objects类是Final的,即不可以被其他类继承,并且它里面的方法都是static的。说明这是一个工具类
接下来我们分析一下他们的功能,废话不说,直接上代码。
-
equals ,deepEquals 比较两个对象是否相等
可以看到equals方法的功能是判断两个对象 是否是同一个对象,或者两个对象是否相等。
deepEquals就比较严格一点,它的功能是首先比较两个对象是否是同一个对象,然后再调用对象的equals方法。
1)首先它比较两个对象是否是同一个对象; 2) 如果不是,再判断它们是否是矩阵,对于矩阵的每个元素,它们是否是同一个对象 3)最后调用对象的equals方法
2 . 计算对象的hashcode
hashCode(Object),hashCode(Object...)
说明: hashCode(Object)是计算单个对象的hashCode , hashCode(Object...)是计算矩阵的hashCode
没什么说的,对象要是为null , hashCode的值为 0
String hashcode
对于矩阵的hashCode : 计算公式 s[0] * 31 ^ (n -1) + s[1 ] * 31 ^ (n-2) + .... + s[n-1] + 31 ^ n
String的hashCode:计算公式 : s[0] * 31^(n-1) + s[1] * 31 ^ (n-2) + ........ + s[n-1]
可以看出 矩阵的hashCode的计算公式比String的hashCode的计算公式多了一个后缀 31^ n
-
toString
加强版的toString多了一个nullDefault ,当对象为null的时候,默认的toString值 ,我觉得是防御性编程的一种体现
4 .compare 比较
可以看到,方法传入了一个Comparator接口,它是一个函数式接口,这也是函数式编程思想的一种体现。
-
判断非null requireNonNull(Object) ,requireNonNull(Object,String messgae)
如果对象为Null ,则抛出异常,否则返回这个对象本身
6.判断对象是否为Null
判断对象是否为Null ,返回true,false
总结: Objects的功能 1) 判断是否相等
2)计算hashCode
3)toString
4)compare比较
5 ) 判断对象是否非Null,并返回这个对象
6 )判断对象是否非Null , 返回true,false
Math类的方法函数
Arrays类
1、填充数组:fill
eg1.
int []arr = new int[5]; Arrays.fill(arr, 2); output(arr);123
结果是:2 2 2 2 2 分析:给所有值赋值2 eg2.
int []arr = new int[5]; Arrays.fill(arr, 1,3,8); output(arr);123
结果是:0 8 8 0 0 分析:给第1位(0开始)到第3位(不包括)赋值8
2、数组元素排序:sort
eg1.
int []arr = {3,2,1,5,4}; Arrays.sort(arr); output(arr);123
结果是:1 2 3 4 5 分析:给所有数按升序排序 eg2.
int []arr = {3,2,1,5,4}; Arrays.sort(arr,1,3); output(arr);123
结果是:3 1 2 5 4 分析:给第1位(0开始)到第3位(不包括)排序
3、比较数组元素是否相等:equals
int []arr1 = {1,2,3}; int []arr2 = {1,2,3}; System.out.println(Arrays.equals(arr1,arr2));123
结果是:true 分析:如果是arr1.equals(arr2),则返回false,因为equals比较的是两个对象的地址,不是里面的数,而Arrays.equals重写了equals,所以,这里能比较元素是否相等。 这里补充一下,如果还是不用Arrays.equals,那么我们应该如何重写equals来比较两个数组的元素是否相等呢?这里提供一段代码
//Compare the contents of two int arrays public static boolean isEquals(int[] a, int[] b) { if( a == null || b == null ) { return false; } if(a.length != b.length) { return false; } for(int i = 0; i < a.length; ++i ) { if(a[i] != b[i]) { return false; } } return true; }1234567891011121314151617181920
4、二分查找法找指定元素的索引值(下标):binarySearch
数组一定是排好序的,否则会出错。找到元素,只会返回最后一个位置 eg1:
int []arr = {10,20,30,40,50}; System.out.println(Arrays.binarySearch(arr, 20));12
结果是:1 分析:能找到该元素,返回下标为1(0开始) eg2:
int []arr = {10,20,30,40,50}; System.out.println(Arrays.binarySearch(arr, 35));12
结果是:-4 分析:找不到元素,返回-x,从-1开始数,如题,返回-4 eg3:
int []arr = {10,20,30,40,50}; System.out.println(Arrays.binarySearch(arr, 0,3,30));12
结果是:2 分析:从0到3位(不包括)找30,找到了,在第2位,返回2 eg4:
int []arr = {10,20,30,40,50}; System.out.println(Arrays.binarySearch(arr, 0,3,40));12
结果是:-4 分析:从0到3位(不包括)找40,找不到,从-1开始数,返回-4
5、截取数组:copeOf和copeOfRange
eg1: copy
int []arr = {10,20,30,40,50}; int []arr1 = Arrays.copyOf(arr, 3); output(arr1);123
结果:10 20 30 分析:截取arr数组的3个元素赋值给姓数组arr1 eg2: copyOfRange
int []arr = {10,20,30,40,50}; int []arr1 = Arrays.copyOfRange(arr,1,3); output(arr1);123
结果:20 30 分析:从第1位(0开始)截取到第3位(不包括)
6、其他
还有hashCode,toString,clone等这里就不介绍了,暂时用的少
BigDecimal类
-
add(BigDecimal)
BigDecimal对象中的值相加,返回BigDecimal对象
-
subtract(BigDecimal)
BigDecimal对象中的值相减,返回BigDecimal对象
-
multiply(BigDecimal)
BigDecimal对象中的值相乘,返回BigDecimal对象
-
divide(BigDecimal)
BigDecimal对象中的值相除,返回BigDecimal对象
-
toString()
将BigDecimal对象中的值转换成字符串
-
doubleValue()
将BigDecimal对象中的值转换成双精度数
-
floatValue()
将BigDecimal对象中的值转换成单精度数
-
longValue()
将BigDecimal对象中的值转换成长整数
-
intValue()
将BigDecimal对象中的值转换成整数
10.bigdemical.compareTo(bigdemical2)
将BigDecimal的两个对象进行大小比较
Date类
-
Date
类表示特定的时刻,精度为毫秒。 -
在JDK 1.1之前,
Date
类还有两个附加功能。 它允许将日期解释为年,月,日,小时,分钟和秒值。 它还允许格式化和解析日期字符串。 不幸的是,这些功能的API不适合国际化。 -
从JDK 1.1开始,
Calendar
类应该用于在日期和时间字段之间进行转换, -
而
DateFormat
类应该用于格式化和解析日期字符串。 不推荐使用Date
中的相应方法。
常用的方法
1.构造方法
Date()//返回当前时间 Date(long date) //返回参数date到1970年1月1日8时的毫秒数
2.常用方法
getTime()//返回调用方法时到1970年1月1日8时的毫秒数 after(Date when) //测试此日期是否在指定日期之后。 before(Date when) //测试此日期是否在指定日期之前。 toString() //将此 Date对象转换为以下形式的 String :
Calendar类
-
Calendar是一个抽象类,不能通过new来创建对象,而是要通过Calendar.getInstance()来创建。
-
年月日在Calendar类中是以数组的形式进行储存。
-
月的数字是从0-11,周是从周日开始算新的一周
-
只要更改过日历,再用get方法获取到的是更改后的日历信息
/** * set * get * add * getTime:获取日历时间 表示的Date对象 * getActualMaxmum :获取某字段的最大值 * @param args */ public static void main(String[] args) { Calendar cl = Calendar.getInstance(); cl.set(Calendar.YEAR,2021);//设置时间 //获取当前的年月日 int year = cl.get(Calendar.YEAR); int day = cl.get(Calendar.DAY_OF_YEAR); cl.add(Calendar.YEAR,10);//时间运算 int add_year = cl.get(Calendar.YEAR); Date d = cl.getTime(); int Month_Max = cl.getActualMaximum(Calendar.MONTH);//获取月份的最大值 /** * 获取某月最大天数 */ cl.set(Calendar.MONTH,1); int Day_Max = cl.getActualMaximum(Calendar.DAY_OF_MONTH);
String类(绝对重点)
-
String
类表示字符串。Java程序中的所有字符串文字(例如"abc"
)都实现为此类的实例。字符串是不变的; (因为在String类中,字符是以数组的形式来储存的,而数组长度一旦确定,就无法改变。所以字符串是不变的)它们的值在创建后无法更改。因为String对象是不可变的,所以可以共享他们。(说人话就是如果两个字符串内容是完全相同的,那么他们两个则采用同一块内存地址,如下图)
字符串常量池
方法区
堆
方法区的实现的演变
通过加法进行字符串拼接原理
通过加法进行n次字符串拼接,会产生n-1个内存垃圾
StringBuffer和StringBuilder
相同:都是用于字符串拼接。StringBuffer.append()方法进行拼接,StringBuffer()的初始容量是16个字符,当容量满了之后会进行动态扩容。
异:StringBuffer是多个字符串顺序拼接,StringBuilder是多个字符串同时拼接。StringBuffer是线程不安全的实现,StringBuilder是线程安全的实现。
休息日练习
1.逻辑与关键点
* 1.用户输入年月,并储存。 * 2.循环计算该月每天离第一个休息日的天数差(用date对象进行计算),编写函数,传入初始时间和结束时间。 * 3.计算休息日。因为第一个休息日为2号,每三天休息一次,采用绝对时间的计算方式,将天数差%4==2的日期就是休息日 * 4.算出休息日后,需要用字符串拼接来打印【日期】,判断是否为周末,要进行计数。否则。非休息日至今打印(在循环中打印月的当前最大天数) * 5.打印: * 表头 * 周六就换行
-
1.用户输入年月,并储存。
-
2.循环计算该月每天离第一个休息日的天数差(用date对象进行计算),编写函数,传入初始时间和结束时间。
-
3.计算休息日。每三天休息一次,将天数差%4==1的日期就是休息日
-
4.算出休息日后,需要用字符串拼接来打印【日期】,判断是否为周末,要进行计数。否则。非休息日至今打印(在循环中打印月的当前最大天数)
-
5.打印:
-
表头
-
周六就换行
-
视图层
package homewwork_commonLibraries; import java.util.Calendar; import java.util.Scanner; public class Views { public Calendar input() { Calendar c = Calendar.getInstance(); input_year(c); input_month(c); c.set(Calendar.DAY_OF_MONTH, 1); //初始化每月的日期为1日 return c; } //输入年 public void input_year(Calendar c) { try { while (true) { System.out.println("请输入年:"); Scanner input = new Scanner(System.in); int year = Integer.parseInt(input.nextLine()); if (year < 1970 || year > 9999) { System.out.println("请输入1970年后有效的年份!"); } else { c.set(Calendar.YEAR, year); break; } } } catch (NumberFormatException e) { System.out.println("请输入数字"); input_year(c); } } //输入月 public void input_month(Calendar c) { try { while (true) { System.out.println("请输入月:"); Scanner input = new Scanner(System.in); int month = Integer.parseInt(input.nextLine()); if (month < 1 || month > 12) { System.out.println("你输入的月份有误,请重新输入"); } else { int true_month = month - 1; c.set(Calendar.MONTH, true_month); break; } } } catch (NumberFormatException e) { System.out.println("请输入数字"); input_month(c); } } //打印表头 public void print_Header(Calendar c){ //获取周六是第几天 int weekstart = c.get(Calendar.DAY_OF_WEEK); System.out.println("星期日\t星期一\t星期二\t星期三\t星期四\t星期五\t星期六"); for(int i=1;i<weekstart;i++){ System.out.printf("%-8s",""); } } //打印休息日 //打印不了,不要用 public void print_RelaxDay(Calendar c){ StringBuffer sb = new StringBuffer(); //%-8s表示字符串最小显示长度为8字符 StringBuffer s = sb.append("%-8s").append("[").append(c.get(Calendar.DAY_OF_MONTH)).append("]"); System.out.print(sb); } //打印工作日 public void print_Workday(Calendar c){ StringBuffer sb = new StringBuffer(); sb.append("%-8s"); sb.append(c.get(Calendar.DAY_OF_MONTH)); System.out.print(sb); } }
dao层
package homewwork_commonLibraries; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; public class Dao { Views v = new Views(); /** * 初始化将第一次休息日的日期转换为时间戳。 */ public Date initialize() throws ParseException { //格式化开始时间 DateFormat df = new SimpleDateFormat("yyyy-MM-dd"); //设置开始时间 Date startDate = df.parse("2020-02-01"); return startDate; } /** * 计算输入日期与第一次休息日相隔天数 * @param start:第一个休息天 * @param end :当前日期 * @return 间隔天数 */ public int Day_interval(Date start,Date end){ //获取开始时间戳 long fromTime = start.getTime(); //获取开始时间戳 long toTime = end.getTime(); //计算时间戳差距并转换成天数 int days = (int) ((toTime - fromTime) / (1000 * 60 * 60 * 24)); return days; } public void CalculateRelaxDays_print(Calendar c) throws ParseException { int relax_count = 0; //本月休息日统计 int weekend_count = 0;//本月休息日为周末的统计 int maxDate = c.getActualMaximum(Calendar.DATE);//获取本月最大天数 for(int i=1;i<=maxDate;i++){ c.set(Calendar.DAY_OF_MONTH, i); Date start = initialize(); Date end= c.getTime(); int gap = Day_interval(start,end); if (gap%4==1){ //打印休息日 System.out.printf("%-8s","["+c.get(Calendar.DAY_OF_MONTH)+"]"); relax_count++; if (c.get(Calendar.DAY_OF_WEEK)==Calendar.SATURDAY||c.get(Calendar.DAY_OF_WEEK)==Calendar.SUNDAY){ //如果这四天包含周末休息天++ weekend_count++; } } else{ //打印工作日 System.out.printf("%-8s", c.get(Calendar.DAY_OF_MONTH)); } //周六就换行 if (c.get(Calendar.DAY_OF_WEEK)==Calendar.DAY_OF_WEEK){ System.out.println(); } } System.out.println(); System.out.println("本月休息的天数有:"+relax_count); System.out.println("本月轮到周末休息的天数有:"+weekend_count); } }
主函数
package homewwork_commonLibraries; import java.text.ParseException; import java.util.Calendar; public class Offday { public static void main(String[] args) throws ParseException { Views v = new Views(); Dao dao = new Dao(); Calendar c = v.input(); v.print_Header(c);//打印表头 dao.CalculateRelaxDays_print(c); } }