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的装箱机制,最终相当于字符串的连接, String s2 = Integer.toString(100);
System.out.println(s2+200);// 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`异常。