java基础(6)常用API
1 Object类
`java.lang.Object`类是Java语言中的根类,即所有类的父类。它中描述的所有方法子类都可以使用。在对象实例化的时候,最终找的父类就是Object。
如果一个类没有特别指定父类, 那么默认则继承自Object类。例如:
public class MyClass /*extends Object*/ { // ... }
根据JDK源代码及Object类的API文档,Object类当中包含的方法有11个。这里以其中的2个为例:
* `public String toString()`:返回该对象的字符串表示。
* `public boolean equals(Object obj)`:指示其他某个对象是否与此对象“相等”。
1.1 toString方法
toSttring方法:`public String toString()`:返回该对象的字符串表示。
toString方法返回该对象的字符串表示,其实该字符串内容就是对象的类型+@+内存地址值。
由于toString方法返回的结果是内存地址,没有什么意义。
而在开发中,经常需要按照对象的属性得到相应的字符串表现形式,因此也需要重写它。
//自定义一个名为toString的类 public class toString { String name; int id;
//重写toString方法 @Override public String toString(){ return "toString{name="+name+",id="+id+"}";//返回值是一个字符串,按照自己的需要拼接成自定义的该类的字符串信息 } } //测试 public class testToSring { public static void main(String[] args) { System.out.println(new toString()); } }
//Output
toString{name=null,id=0}
//这个是编译器自动重载所写的toString,可以看到就是字符串拼接,拼接类的名字和成员变量信息 @Override public String toString() { return "toString{" + "name='" + name + '\'' + ", id=" + id + '}'; }
1.2 equals方法
public boolean equals(Object obj)
1.2.1 默认地址比较:
如果自定义类中没有覆盖重写equals方法,那么Object类中默认进行`==`运算符的对象地址比较,只要不是同一个对象,结果必然为false。
public class myEquals { String name; int age; } public class myEquealsTest { public static void main(String[] args) { myEquals m1 = new myEquals(); myEquals m2 = new myEquals(); System.out.println(m1.equals(m2)); System.out.println("========="); m2 = m1;//将m1赋予m2 System.out.println(m1.equals(m2)); } } //Output false ========= true
1.2.2 重写equals方法-对象内容比较
比如String类就重写了该方法:
//Java 源码,对字符串的内容进行比较 public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String anotherString = (String)anObject; int n = value.length; if (n == anotherString.value.length) { char v1[] = value; char v2[] = anotherString.value; int i = 0; while (n-- != 0) { if (v1[i] != v2[i]) return false; i++; } return true; } } return false; }
如果我自定义了一个Person类,需要进行内容比较,也需要重写equals方法
public class Person { private String name; private int age; @Override//IDEA中按住alt+Insert选择重写equals方法 public boolean equals(Object o) { // 如果对象地址一样,则认为相同 if (this == o) return true; // 如果参数为空,或者类型信息不一样,则认为不同。使用反射技术,判断o是否为Person类型 if (o == null || getClass() != o.getClass()) return false; // 转换为当前类型 Person person = (Person) o; // 要求基本类型相等,并且将引用类型交给java.util.Objects类的equals静态方法取用结果 return age == person.age && Objects.equals(name, person.name); } }
上述代码充分考虑了对象是否为本身、为空、类型不一致等问题。
注意:
代码中有这句话:
Objects.equals(name, person.name)
Objects工具类,它提供了一些方法来操作对象,它由一些静态的实用方法组成,这些方法是null-save(空指针安全的)或null-tolerant(容忍空指针的),用于计算对象的hashcode、返回对象的字符串表示形式、比较两个对象。
在比较两个对象的时候,Object的equals方法容易抛出空指针异常,而Objects类中的equals方法就优化了这个问题。
Objects类的作用:String类的两个对象比较的时候,防止抛出空指针异常。
~~~java源码 public static boolean equals(Object a, Object b) { return (a == b) || (a != null && a.equals(b)); } ~~~
源码解读:
为什么上述源码只判断了Object a是否为空呢?
首先: null是不能调用方法的(null表示没有创建对象,没有在队内存中分配空间),会抛出空指针异常。
所以源码中先判断a不为空,再用a来调用equals方法,所以不需要判断b是否为空。
下面是一个例子:
import java.util.Objects; public class Demo03Objects { public static void main(String[] args) { String s1 = "abc"; //String s1 = null; String s2 = "abc"; //boolean b = s1.equals(s2); // 抛出NullPointerException异常,因为 null是不能调用方法的,会抛出空指针异常 //System.out.println(b); /* Objects类的equals方法:对两个对象进行比较,防止空指针异常 public static boolean equals(Object a, Object b) { return (a == b) || (a != null && a.equals(b)); } */ boolean b2 = Objects.equals(s1, s2); System.out.println(b2); } }
2 Date类
2.1 Date类概述
/* java.util.Date:表示日期和时间的类 类 Date 表示特定的瞬间,精确到毫秒。 毫秒:千分之一秒 1000毫秒=1秒 特定的瞬间:一个时间点,一刹那时间 2088-08-08 09:55:33:333 瞬间 2088-08-08 09:55:33:334 瞬间 2088-08-08 09:55:33:334 瞬间 ... 毫秒值的作用:可以对时间和日期进行计算 2099-01-03 到 2088-01-01 中间一共有多少天 可以日期转换为毫秒进行计算,计算完毕,在把毫秒转换为日期 把日期转换为毫秒: 当前的日期: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毫秒 */ public class Demo01Date { public static void main(String[] args) { System.out.println(System.currentTimeMillis());//获取当前系统时间到1970 年 1 月 1 日 00:00:00经历了多少毫秒 } }
2.2 Date类的构造方法
2.2.1 空参数构造
public class MyDateTest { public static void main(String[] args) { System.out.println(System.currentTimeMillis()); demo01(); } /* Date类的空参数构造方法 Date() 获取当前系统的日期和时间 */ private static void demo01() { Date date = new Date(); System.out.println(date);//Sun Jan 20 16:57:40 CST 2019,直接打印date,不是一个地址,说明Date类重写了toString方法 } }
2.2.2 带参数构造
public class MyDateTest { public static void main(String[] args) { System.out.println(System.currentTimeMillis()); demo02(); } /* Date类的带参数构造方法 Date(long date) :传递毫秒值,把毫秒值转换为Date日期 */ private static void demo02() { Date date = new Date(1547974660147L); System.out.println(date);// Sun Jan 20 17:00:23 CST 2019 } }
2.2.3 getTime方法
////
Date类中的多数方法已经过时,常用的方法有: * `public long getTime()` 把日期对象转换成对应的时间毫秒值。
public class MyDateTest { public static void main(String[] args) { System.out.println(System.currentTimeMillis()); demo03(); } /* long getTime() 把日期转换为毫秒值(相当于System.currentTimeMillis()方法) 返回自 1970 年 1 月 1 日 00:00:00 GMT 以来此 Date 对象表示的毫秒数。 */ private static void demo03() { Date date = new Date(); long time = date.getTime(); System.out.println(time); } }
2.3 DateFormate类和SimpleDateFormate类
DateFormat 是日期/时间格式化子类的抽象类,它以与语言无关的方式格式化并解析日期或时间。
日期/时间格式化子类(如 SimpleDateFormat)允许进行格式化(也就是日期 -> 文本)、解析(文本-> 日期)和标准化。
将日期表示为 Date
对象,或者表示为从 GMT(格林尼治标准时间)1970 年 1 月 1 日 00:00:00 这一刻开始的毫秒数。
DateFormat类:是一个抽象类
要格式化一个当前语言环境下的日期,可使用某个静态工厂方法:
myString = DateFormat.getDateInstance().format(myDate);
//使用示例 Date date = new Date();//可以不填参数,默认为系统当前时间 String myString = DateFormat.getDateInstance().format(date); System.out.println(myString);//2019-1-20 Date date2 = new Date(10120133110L);//也可以传入毫秒值 String myString2 = DateFormat.getDateInstance().format(date2); System.out.println(myString2);//1970-4-28
由于DateFormat为抽象类,不能直接使用,所以需要常用的子类`java.text.SimpleDateFormat`。
这个类需要一个模式(格式)来指定格式化或解析的标准。构造方法为:
* `public SimpleDateFormat(String pattern)`:用给定的模式和默认语言环境的日期格式符号构造SimpleDateFormat。
//SimpleDateFormat的格式化方法使用示例 public class MyDateFormateTest1 { public static void main(String[] args) { // 第1步.创建SimpleDateFormat对象,构造方法中传递指定的模式 SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd/ HH/mm/ss/");//第一种格式 SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒");//第二种格式 //第2步.创建Date对象,将其传入SimpleDateFormat的format方法,按照构造方法中指定的模式,将Date对象转换成符合模式的字符串(文本) Date date = new Date(); Date date2 = new Date(123456789L); String myString1 = sdf.format(date); String myString2 = sdf2.format(date2); System.out.println(myString1);// 2019/01/20/ 19/56/07/ System.out.println(myString2);// 1970年01月02日 18时17分36秒 } }
//SimpleDateFormat的解析方法parse使用示例 //Java中该parse方法的源码,按照该源码写代码 public Date parse(String source) throws ParseException { ParsePosition pos = new ParsePosition(0); Date result = parse(source, pos); if (pos.index == 0) throw new ParseException("Unparseable date: \"" + source + "\"" , pos.errorIndex); return result; }
//使用parse方法的步骤: //第一步:创建SimpleDateFormat对象,构造方法中传递指定的模式 SimpleDateFormat sdf3 = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss"); //第二步:String format(Date date) 按照指定的模式,把Date日期,格式化为符合模式的字符串 String source = new String("1990-10-10 10-20-20");//如果这里输入的字符串的模式不符合上面的模式,就会抛出异常 Date returnDate = new Date(); try { returnDate = sdf3.parse(source); } catch (ParseException e) { e.printStackTrace(); } System.out.println(returnDate);
2.4 Calendar类
2.4.1 Calendar抽象类获取对象的方法
Calendar
类是一个抽象类,无法创建对象使用。里面有一个静态方法getInstance(),该方法返回了一个Calendar子类对象:
public class myCalendar { public static void main(String[] args) { Calendar calendar = Calendar.getInstance();//Calendar.getInstance()直接返回一个Calendar的子类对象。 // 父类,接收子类对象,存在多态 System.out.println(calendar); //java.util.GregorianCalendar[time=1547987922275,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Asia/Shanghai",offset=28800000,dstSavings=0,useDaylight=false,transitions=19,lastRule=null],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2019,MONTH=0,WEEK_OF_YEAR=4,WEEK_OF_MONTH=4,DAY_OF_MONTH=20,DAY_OF_YEAR=20,DAY_OF_WEEK=1,DAY_OF_WEEK_IN_MONTH=3,AM_PM=1,HOUR=8,HOUR_OF_DAY=20,MINUTE=38,SECOND=42,MILLISECOND=275,ZONE_OFFSET=28800000,DST_OFFSET=0] } }
//返回了一组诸如YEAR,
MONTH,
DAY_OF_MONTH,
HOUR
等的日历字段
2.4.2 Calendar类的常用成员方法
根据Calendar类的API文档,常用方法有: - `public int get(int field)`:返回给定日历字段的值。 - `public void set(int field, int value)`:将给定的日历字段设置为给定值。 - `public abstract void add(int field, int amount)`:根据日历的规则,为给定的日历字段添加或减去指定的时间量。 - `public Date getTime()`:返回一个表示此Calendar时间值(从历元到现在的毫秒偏移量)的Date对象。
//field: Calendar类中提供很多成员常量,代表给定的日历字段: | 字段值 | 含义 | | ------------ | -------------------- | | YEAR | 年 | | MONTH | 月(从0开始,可以+1使用) | | DAY_OF_MONTH | 月中的天(几号) | | HOUR | 时(12小时制) | | HOUR_OF_DAY | 时(24小时制) | | MINUTE | 分 | | SECOND | 秒 | | DAY_OF_WEEK | 周中的天(周几,周日为1,可以-1使用) |
//使用示例 public class MyCalendar2 { public static void main(String[] args) { //获取日历对象对应的的日期 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); System.out.println(year +"月" +month+"月" +day+"日");//2019月1月20日 //设置日历中某个字段的值 c.set(1234,2,5); year = c.get(Calendar.YEAR); month = c.get(Calendar.MONTH)+1; day = c.get(Calendar.DAY_OF_MONTH); System.out.println(year +"月" +month+"月" +day+"日");//1234月3月5日 //在日历对象上增加年月日 c.add(Calendar.YEAR,23); c.add(2,1); year = c.get(Calendar.YEAR); month = c.get(Calendar.MONTH)+1; day = c.get(Calendar.DAY_OF_MONTH); System.out.println(year +"月" +month+"月" +day+"日");//1257月4月5日 //获取日历对象对应的日期 Date date = c.getTime(); System.out.println(date);//Thu Apr 05 21:02:53 CST 1257 } }
3 System类
import java.util.Arrays; public class MySystem { public static void main(String[] args) { demo01(); demo02(); } //System.currentTimeMillis()方法 private static void demo01() { long t0 = System.currentTimeMillis(); for (int i = 0; i < 1000; i++) { System.out.println(i); } long t1 = System.currentTimeMillis(); System.out.println(t1-t0); } //System.arraycopy()方法 private static void demo02() { int[] src = new int[]{1,2,3,4,5}; int[] dest = new int[]{6,7,8,9,10}; System.out.println("复制后"+Arrays.toString(dest)); System.arraycopy( src, 1, dest, 0, 3); for (int i = 0; i < dest.length; i++) { System.out.println(dest[i]); }//2 3 4 9 10 //还可以使用Arrays类中的toString方法打印 System.out.println("复制后"+Arrays.toString(dest));//复制后[2, 3, 4, 9, 10] } }
4 StringBuilder类
4.1 字符串拼接问题
由于String类的对象内容不可改变,所以每当进行字符串拼接时,总是会在内存中创建一个新的对象。例如:
~~~java public class StringDemo { public static void main(String[] args) { String s = "Hello"; s += "World"; System.out.println(s); } } ~~~
其实总共产生了三个字符串,即`"Hello"`、`"World"`和`"HelloWorld"`。引用变量s首先指向`Hello`对象,最终指向拼接出来的新字符串对象,即`HelloWord` 。
在API中对String类有这样的描述:字符串是常量,它们的值在创建后不能被更改。底层是一个被final修饰的量。
如果对字符串进行拼接操作,每次拼接,都会构建一个新的String对象,既耗时,又浪费空间。为了解决这一问题,可以使用`java.lang.StringBuilder`类。
4.2 StringBuilder概述
StringBuilder是个字符串的缓冲区,即它是一个容器,容器中可以装很多字符串。并且能够对其中的字符串进行各种操作。
底层也是一个数组,但是没有被final修饰,可以改变长度。
4.3 构造方法
根据StringBuilder的API文档,常用构造方法有2个:
- `public StringBuilder()`:构造一个空的StringBuilder容器。 - `public StringBuilder(String str)`:构造一个StringBuilder容器,并将字符串添加进去。
public class MyStringBuilder { public static void main(String[] args) { StringBuilder sb1 = new StringBuilder(); System.out.println("不带参数构造字符串:"+sb1); StringBuilder sb2 = new StringBuilder("abssssweweweweeeeeeee"); System.out.println("带参数构造字符串:"+sb2); } }
//Output
不带参数构造字符串:
带参数构造字符串:abssssweweweweeeeeeee
4.4 Append方法和toString方法
public static void main(String[] args) { //创建对象 StringBuilder builder = new StringBuilder(); //public StringBuilder append(任意类型) StringBuilder builder2 = builder.append("hello"); //对比一下 System.out.println("builder:"+builder); System.out.println("builder2:"+builder2); System.out.println(builder == builder2); //true // 可以添加 任何类型 builder.append("hello"); builder.append("world"); builder.append(true); builder.append(100); // 在我们开发中,会遇到调用一个方法后,返回一个对象的情况。然后使用返回的对象继续调用方法。 // 这种时候,我们就可以把代码现在一起,如append方法一样,代码如下 //链式编程 builder.append("hello").append("world").append(true).append(100); System.out.println("builder:"+builder); }
public class Demo16StringBuilder { public static void main(String[] args) { // 链式创建 StringBuilder sb = new StringBuilder("Hello").append("World").append("Java"); // 调用方法 String str = sb.toString(); System.out.println(str); // HelloWorldJava } }
5 包装类
5.1 包装类概述
Java提供了两个类型系统,基本类型与引用类型,使用基本类型在于效率,然而很多情况,会创建对象使用,因为对象可以做更多的功能,
如果想要我们的基本类型像对象一样操作,就可以使用基本类型对应的包装类。
| 基本类型 | 对应的包装类(是某一种类,位于java.lang包中,无需导包) | | ------- | --------------------- | | byte | Byte | | short | Short | | int | **Integer** | | long | Long | | float | Float | | double | Double | | char | **Character** | | boolean | Boolean |
5.2 装箱和拆箱
* **装箱**:从基本类型转换为对应的包装类对象。
* **拆箱**:从包装类对象转换为对应的基本类型。
/* 装箱:把基本类型的数据,包装到包装类中(基本类型的数据->包装类) 构造方法两种: Integer(int value) 构造一个新分配的 Integer 对象,它表示指定的 int 值。 Integer(String s) 构造一个新分配的 Integer 对象,它表示 String 参数所指示的 int 值。 传递的字符串,必须是基本类型(int double等是基本类型,String不是基本类型)的字符串,否则会抛出异常 "100" 正确 "a" 抛异常 静态方法: static Integer valueOf(int i) 返回一个表示指定的 int 值的 Integer 实例。 static Integer valueOf(String s) 返回保存指定的 String 的值的 Integer 对象。 拆箱:在包装类中取出基本类型的数据(包装类->基本类型的数据) 调用Integer类的成员方法: int intValue() 以 int 类型返回该 Integer 的值。 */ public class Demo01Integer { public static void main(String[] args) { //装箱:把基本类型的数据,包装到包装类中(基本类型的数据->包装类) //构造方法 Integer in1 = new Integer(1);//方法上有横线,说明方法过时了 System.out.println(in1);//1 重写了toString方法 Integer in2 = new Integer("1"); System.out.println(in2);//1 //静态方法 Integer in3 = Integer.valueOf(1); System.out.println(in3); //Integer in4 = Integer.valueOf("a");//NumberFormatException数字格式化异常 Integer in4 = Integer.valueOf("1"); System.out.println(in4); //拆箱:在包装类中取出基本类型的数据(包装类->基本类型的数据) int i = in1.intValue(); System.out.println(i); } }
5.3 自动装箱和自动拆箱
import java.util.ArrayList; /* 自动装箱与自动拆箱:基本类型的数据和包装类之间可以自动的相互转换 JDK1.5之后出现的新特性 */ public class Demo02Ineger { public static void main(String[] args) { /* 自动装箱:直接把int类型的整数赋值包装类 Integer in = 1; 就相当于 Integer in = new Integer(1); */ Integer in = 1; /* 自动拆箱:in是包装类,无法直接参与运算,可以自动转换为基本数据类型,再进行计算 in+2;就相当于 in.intVale() + 2 = 3 in = in.intVale() + 2 = 3 又是一个自动装箱 */ in = in+2; ArrayList<Integer> list = new ArrayList<>(); /* ArrayList集合无法直接存储整数,可以存储Integer包装类 */ list.add(1); //-->自动装箱 list.add(new Integer(1)); int a = list.get(0); //-->自动拆箱 list.get(0).intValue(); } }
5.4 基本类型与字符串之间的转换
/* 基本类型与字符串类型之间的相互转换 一、基本类型->字符串(String)(三种方法) 1.基本类型的值+"" 最简单的方法(常用) 2.包装类的静态方法toString(参数),不是Object类的toString() 重载 static String toString(int i) 返回一个表示指定整数的 String 对象。 3.String类的静态方法valueOf(参数) static String valueOf(int i) 返回 int 参数的字符串表示形式。 二、字符串(String)->基本类型
包装类都具有parseXxx静态方法可以将字符串参数转换为对应的基本类型: 使用包装类的静态方法parseXXX("字符串"); Integer类: static int parseInt(String s) Double类: static double parseDouble(String s) */ public class Demo03Integer { public static void main(String[] args) { //基本类型->字符串(String) int i1 = 100; String s1 = i1+""; System.out.println(s1+200);//字符串和数字直接相加,是把数字当成了字符串,这是JAVA的装箱机制,最终相当于字符串的连接,100200 String s2 = Integer.toString(100); System.out.println(s2+200);//100200 String s3 = String.valueOf(100); System.out.println(s3+200);//100200 //字符串(String)->基本类型 int i = Integer.parseInt(s1); //s1应该是一个基本数据类型,而不能是字符串 System.out.println(i-10);//90 int a = Integer.parseInt("a");//NumberFormatException, 传入的应该是一个基本数据类型,而不能是字符串
System.out.println(a); }
注意:如果字符串参数的内容无法正确转换为对应的基本类型,则会抛出`java.lang.NumberFormatException`异常。