常用类:Object

一、API概述(Application Programming Interface)

应用程序编程接口
编写一个机器人程序去控制机器人踢足球,程序就需要向机器人发出向前跑、向后跑、射门、
抢球等各种命令,没有编过程序的人很难想象这样的程序如何编写。但是对于有经验的开发人员来说,
知道机器人厂商一定会提供一些用于控制机器人的Java类,这些类中定义好了操作机器人各种
动作的方法。其实,这些Java类就是机器人厂商提供给应用程序编程的接口,
大家把这些类称为Xxx Robot API。
本章涉及的Java API指的就是JDK中提供的各种功能的Java类。

二、常用类

Object类/Scanner类
String类/StringBuffer类/StringBuilder类
数组高级和Arrays类
基本类型包装类(Integer,Character)
正则表达式(Pattern,Matcher)
Math类/Random类/System类
BigInteger类/BigDecimal类
Date类/DateFormat类/Calendar类

三、Object类概述及其类中的方法

1、Object类概述

Class Object是类Object结构的根;
每个班都有Object作为超类;
所有对象(包括数组)都实现了这个类的方法;
每个类都直接或者间接的继承Object类

例:随便写个类,都默认继承Object类
    public class Student extends Object{
    }

2、学习Object中的一个方法:哈希算法

java robot 类 javarobot类介绍_System

public int hashCode()返回对象的哈希码值
注意:这里的哈希码值是根据哈希算法计算出来的一个值,这个值和地址有关系,
	但是并不是实际的地址值。简单理解为地址值的另一种表现形式

案例:

//创建一个class文件,定义一个类
public class Student extends Object{
}

//同一个包下再创建一个class文件,定义一个类
public class StudentTest {
    public static void main(String[] args) {
        //因为在一个包内,所以能创建Student对象
        Student s = new Student();
        //调用Object中的hashCode方法
        System.out.println(s.hashCode());
        //再创建一个Student对象
        Student s1 = new Student();
        System.out.println(s1.hashCode());
    }
}
        执行结果如下:
        356573597
        1735600054

        Process finished with exit code 0
        
  //结论:调用hashCode方法时,输出的哈希码值不一定相同

3、学习Object中的一个方法:getClass

java robot 类 javarobot类介绍_构造方法_02

public final 类 getClass()
返回此Object的运行时类
返回的类对象是被表示类的static synchronized方法锁定的对象

案例:

public class StudentTest {
    public static void main(String[] args) {
        //创建一个Student对象
        Student s = new Student();
        System.out.println(s.getClass());
    }
}
        执行结果如下:
            class myself.day18.Student

            Process finished with exit code 0
            //输出的是当前项目下一个相对路径的class类型

4、学习Object类中的一个方法:toSring

java robot 类 javarobot类介绍_System_03

//创建一个Student2的类
public class Student2 {
    //定义成员变量
    private String name;
    private int age;
    //无参构造方法
    Student2(){
    }
    //带参构造方法
    Student2(String name,int age){
        this.name = name;
        this.age  = age;
    }
    //定义公共的setXxx()和getXxx()方法
    public void setName(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public int getAge() {
        return age;
    }
}

public class StudentTest2 {
    public static void main(String[] args) {
        //创建Student2对象
        Student2 s2 = new Student2();
        System.out.println(s2.toString());//myself.day18.Student2@1540e19d
       //System.out.println(s2.getClass().getName());//myself.day18.Student2
    }
}
            执行结果如下:
                    myself.day18.Student2@1540e19d

                    Process finished with exit code 0
 /*
 s2.toString()在s2.getClass().getName()基础上多了@1540e19d
 根据toString方法说明:
 			getClass().getName() + '@' + Integer.toHexString(hashCode())
 可知:
 Integer类中有一个toHexString方法将哈希值转换成地址值
 */

查找Integer类中的toHexString方法

java robot 类 javarobot类介绍_成员变量_04

Integer类中有一个toHexString方法将哈希值转换成地址值
public static String toHexString(int i)
返回整数参数的字符串表示形式,作为16位中的无符号整数

因此可知:
	System.out.println(s.toString());
等价于
    System.out.println(s.getClass().getName()+"@"+Integer.toHexString(s.hashCode()));
我们虽然掌握了toString()的方法使用,但是呢打印的结果是一个地址值,拿到地址值是没有意义的

我们正常打印一个对象,其实是想看该对象中的成员变量的值。
又因为toString()方法的返回值是String类型,并且属于Object类中的
而Object类是所有类的父类,那么我们自己定义类的时候,就可以重写该方法,重写里面的实现。
将来调用toString()方法的时候,严格遵循编译看左,运行看右,所以调用的是重写后的方法。

在Student2中重写toString方法

.......(方便观看,上方省略)
   public int getAge() {
        return age;
    }
//重写toString方法
    @Override
    public String toString() {
//        return super.toString();
        return "姓名:" + name + "年龄:" + age;
    }
}

重写以后再返回StudentTest2类中,再次运行一下

public class StudentTest2 {
    public static void main(String[] args) {
        //创建Student2对象
        Student2 s2 = new Student2();
        System.out.println(s2.toString());
    }
}
        执行结果为:
                姓名:null年龄:0

                Process finished with exit code 0

赋值一下

public class StudentTest2 {
    public static void main(String[] args) {
        //创建Student2对象
        Student2 s2 = new Student2();
        System.out.println(s2.toString());
		//赋值
        s2.setName("伟爷");
        s2.setAge(18);
        System.out.println(s2.toString());
    }
}
        执行结果为:
                姓名:null年龄:0
                姓名:伟爷年龄:18

                Process finished with exit code 0

5、类最终写法的诞生

通过上述案例,诞生了类的最终写法

类最终写法:4.0版本:

             成员变量:private
             构造方法:无参,有参
             成员方法:getXxx()和setXxx(),有特有方法就加上特有方法
		      toString():自动生成即可 快捷键	Alt+Insert回车

最终版本案例:

class Student2 {
    //定义成员变量
    private String name;
    private int age;
    //无参构造方法
    Student2(){

    }
    //带参构造方法
    Student2(String name,int age){
        this.name = name;
        this.age  = age;
    }
    //定义公共的setXxx()和getXxx()方法
    public void setName(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public int getAge() {
        return age;
    }
    
  //重写方法
//Alt+Insert回车,选择toString()方法,回车再回车
    @Override
    public String toString() {
        return "Student2{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

public class StudentTest2 {
    public static void main(String[] args) {
        //创建Student2对象
        Student2 s2 = new Student2();
        //赋值
        s2.setName("伟爷");
        s2.setAge(18);
        System.out.println(s2.toString());
    }
}
        执行结果为:
        Student2{name='伟爷', age=18}

        Process finished with exit code 0

toString方法总结

如果子类中(学生类)不重写toString,在测试类中,通过对象调用该方法,打印出的是地址值;
重写之后再调用toString,打印出的就是规范的成员变量值

6、学习Object类中的一个方法:equals

java robot 类 javarobot类介绍_成员变量_05

public boolean equals(Object obj)指示一些其他对象是否等于此
==:
   比较基本类型:比较的是值是否相同
   比较引用类型:比较的地址值是否相同
equals:
       比较的是引用数据类型

案例:

public class Student3 {
    //定义成员变量
    private String name;
    private int age;
    //无参构造方法
    Student3(){

    }
    //带参构造方法
    Student3(String name,int age){
        this.name = name;
        this.age  = age;
    }
    //定义公共的setXxx()和getXxx()方法
    public void setName(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public int getAge() {
        return age;
    }

    //重写toString()
    @Override
    public String toString() {
        return "Student3{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

public class StudentTest3{
    public static void main(String[] args) {
        Student3 s3 = new Student3("伟爷",18);
        Student3 s4 = new Student3("伟爷",18);
        System.out.println(s3==s4);//比较的是地址值是否相同:false

        Student3 s5 =s3;//将对象s3赋值给s5对象
        System.out.println(s5==s3);//true

        //用epuals比较引用数据类型
        System.out.println(s3.equals(s4));//比较的是地址值是否相同:false
        System.out.println(s3.equals(s5));//比较的是地址值是否相同:true
        System.out.println(s3.equals(s3));//比较的是地址值是否相同:true
    }
}

我们只知道equals是用来比较引用数据类型的,但是我们却不知道是内部是如何实现的;

如果想要弄明白一个类中的方法是如何实现的时候,API也没告诉我们怎么办呢?

看源码。将鼠标光标放在方法名上  ctrl+鼠标左键

以 System.out.println(s3.equals(s4));为例
ctrl+鼠标左键
会出现下面代码:
   public boolean equals(Object obj) {
        return (this == obj);
    }
分析可知:this指的s3,obj指的是s4

通过观察源码发现:Object类中的equals方法,底层的实现依旧是 ==

而 == 比较引用数据类型比较的是地址值,当地址值不一样的时候返回的是false

由上可知,比较的都是地址值

如果我们想要比较两个对象的成员变量值,该怎么做呢?

由public boolean equals(Object obj)可知,equals是被public修饰的

想要在测试类中比较对象的成员变量值,在学生类中需要重写equals方法

(不需要我们自己重写,快捷键 Alt+Insert回车 自动生成即可)

重写equals方法后,再回到测试类。再次运行,调用equals比较的就是成员变量值了

public class StudentTest3{
    public static void main(String[] args) {
        Student3 s3 = new Student3("伟爷",18);
        Student3 s4 = new Student3("伟爷",18);
        System.out.println(s3==s4);//比较的是地址值是否相同:false

        Student3 s5 =s3;//将对象s3赋值给s5对象
        System.out.println(s5==s3);//true

        //用epuals比较引用数据类型
        System.out.println(s3.equals(s4));//比较的是地址值是否相同:true
        System.out.println(s3.equals(s5));//比较的是地址值是否相同:true
        System.out.println(s3.equals(s3));//比较的是地址值是否相同:true
    }
}

equals方法总结:

如果子类中(学生类)不重写equals方法,默认调用的是Object类中的equals方法,默认比较的是地址值;
重写equals方法之后,比较的是对象成员变量值

7、学习Object类中的一个方法:clone

java robot 类 javarobot类介绍_java robot 类_06

protected Object clone()
            创建并返回此对象的副本

未重写clone方法之前,调用该方法的时候会直接报错,所以要先在子类(学生类)中重写克隆方法

重写该方法与重写其他方法有点区别,该方法需要通过子类super去调用,不能使用Alt+Inset快捷键

java robot 类 javarobot类介绍_System_07

//重写clone方法。否则无法调用
    //通过子类super去调用(重写该方法不能使用Alt+Inset快捷键)
    //输入c,然后根据提示选择protected Object clone() {...}
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

重写clone方法后,再次回到测试类来调用该方法

java robot 类 javarobot类介绍_java robot 类_08

由上可知,重写clone方法后,在测试类调用该方法后,打印输出的时候,还是会报错;

这说明并不是什么样的类都可以被克隆,类需要满足一个标记才能被克隆

类该怎么去标记?

在工具说明书中:
clone的方法Object执行特定的克隆操作。
首先,如果此对象的类不实现接口Cloneable ,则抛出CloneNotSupportedException
将想要调用克隆方法的类实现Cloneable接口
通过观察API发现,Cloneable接口中没有成员变量也没有成员方法
今后看到类似于Cloneable接口里面什么都没有的接口,我们称之为标记接口

标记接口,只需在类名后面加implements Cloneable即可,表示实现接口

Public class Student4 implements Cloneable{
    //定义成员变量
    private String name;
    private int age;
    //无参构造方法
    Student4(){

    }
    //带参构造方法
    Student4(String name,int age){
        this.name = name;
        this.age  = age;
    }
    //定义公共的setXxx()和getXxx()方法
    ...(为了方便观看,暂且省略)

添加指针后,回到测试类再次运行

java robot 类 javarobot类介绍_成员变量_09

由上可知,通过调用克隆方法,输出的结果会打印出一模一样的。

我们可以发现,通过再次创建对象,再次赋值,也可以打印出一模一样的结果,那么克隆的意义在哪?

答:当二次赋值的时候,再输出,结果与第一次是不一样的;

但是用克隆输出的时候,无论前面再怎么赋值,打印出的结果都是和第一次一样的

拷贝在IT行业中常见两种:
    浅拷贝
        拷贝的时候,重新创建一个对象,成员变量值和被拷贝的一样,但是后续修改与原先的没有关系
    深拷贝
        拷贝的时候,没有创建新的对象,只是改个名字,地址值都一样,修改拷贝后的连带影响到原先的

8、学习Object类中的一个方法:finalize

java robot 类 javarobot类介绍_System_10

protected void finalize()
throws Throwable当垃圾收集确定不再有对该对象的引用时,
垃圾收集器在对象上调用该对象。
一个子类覆盖了处理系统资源或执行其他清理的finalize方法。
这个方法简单理解为就是用来垃圾回收的,什么时候回收呢?不确定。

具体情况下什么时候回收呢?自行上网了解GC机制(面试会问道)