从零开始学习 Java:简单易懂的入门指南之Runtime、Object(十三)

简介: 从零开始学习 Java:简单易懂的入门指南之Runtime、Object(十三)

Runtime,Object类

1 Runtime

1.1 概述

1.2 常见方法

2 Object类

2.1 概述

2.2 常见方法


1 Runtime

1.1 概述

Runtime表示Java中运行时对象,可以获取到程序运行时设计到的一些信息


1.2 常见方法

常见方法介绍


我们要学习的Object类中的常见方法如下所示:

public static Runtime getRuntime()    //当前系统的运行环境对象
public void exit(int status)      //停止虚拟机
public int availableProcessors()    //获得CPU的线程数
public long maxMemory()           //JVM能从系统中获取总内存大小(单位byte)
public long totalMemory()       //JVM已经从系统中获取总内存大小(单位byte)
public long freeMemory()        //JVM剩余内存大小(单位byte)
public Process exec(String command)   //运行cmd命令

代码示例:

public class RunTimeDemo1 {
    public static void main(String[] args) throws IOException {
        /*
            public static Runtime getRuntime() 当前系统的运行环境对象
            public void exit(int status) 停止虚拟机
            public int availableProcessors() 获得CPU的线程数
            public long maxMemory() JVM能从系统中获取总内存大小(单位byte)
            public long totalMemory() JVM已经从系统中获取总内存大小(单位byte)
            public long freeMemory() JVM剩余内存大小(单位byte)
            public Process exec(string command) 运行cmd命令
        */
        //1.获取Runtime的对象
        //Runtime r1 =Runtime.getRuntime();
        //2.exit 停止虚拟机
        //Runtime.getRuntime().exit(0);
        //System.out.println("看看我执行了吗?");
        //3.获得CPU的线程数
        System.out.println(Runtime.getRuntime().availableProcessors());//8
        //4.总内存大小,单位byte字节
        System.out.println(Runtime.getRuntime().maxMemory() / 1024 / 1024);//4064
        //5.已经获取的总内存大小,单位byte字节
        System.out.println(Runtime.getRuntime().totalMemory() / 1024 / 1024);//254
        //6.剩余内存大小
        System.out.println(Runtime.getRuntime().freeMemory() / 1024 / 1024);//251
        //7.运行cmd命令
        //shutdown :关机
        //加上参数才能执行
        //-s :默认在1分钟之后关机
        //-s -t 指定时间 : 指定关机时间
        //-a :取消关机操作
        //-r: 关机并重启
        Runtime.getRuntime().exec("shutdown -s -t 3600");
    }
}

2 Object类

2.1 概述

tips:重点内容

查看API文档,我们可以看到API文档中关于Object类的定义如下:



Object类所在包是java.lang包。Object 是类层次结构的根,每个类都可以将 Object 作为超类。所有类都直接或者间接的继承自该类;换句话说,该类所具备的方法,其他所有类都继承了。


查看API文档我们可以看到,在Object类中提供了一个无参构造方法,如下所示:



但是一般情况下我们很少去主动的创建Object类的对象,调用其对应的方法。更多的是创建Object类的某个子类对象,然后通过子类对象调用Object类中的方法。

2.2 常见方法

tips:重点内容

常见方法介绍

我们要学习的Object类中的常见方法如下所示:


public String toString()        //返回该对象的字符串表示形式(可以看做是对象的内存地址值)
public boolean equals(Object obj)   //比较两个对象地址值是否相等;true表示相同,false表示不相同
protected Object clone()          //对象克隆

案例演示


接下来我们就来通过一些案例演示一下这些方法的特点。


案例1:演示toString方法


实现步骤:


创建一个学生类,提供两个成员变量(name , age);并且提供对应的无参构造方法和有参构造方法以及get/set方法

创建一个测试类(ObjectDemo01),在测试类的main方法中去创建学生对象,然后调用该对象的toString方法获取该对象的字符串表现形式,并将结果进行输出

如下所示:


Student类

public class Student {
    private String name ;       // 姓名
    private String age ;        // 年龄
    // 无参构造方法和有参构造方法以及get和set方法略
    ...
}

ObjectDemo01测试类

public class ObjectDemo01 {
    public static void main(String[] args) {
        // 创建学生对象
        Student s1 = new Student("itheima" , "14") ;
        // 调用toString方法获取s1对象的字符串表现形式
        String result1 = s1.toString();
        // 输出结果
        System.out.println("s1对象的字符串表现形式为:" + result1);
    }
}

运行程序进行测试,控制台输出结果如下所示:


s1对象的字符串表现形式为:com.itheima.api.system.demo04.Student@3f3afe78

1

为什么控制台输出的结果为:com.itheima.api.system.demo04.Student@3f3afe78; 此时我们可以查看一下Object类中toString方法的源码,如下所示:


public String toString() {    // Object类中toString方法的源码定义
  return getClass().getName() + "@" + Integer.toHexString(hashCode());
}

其中getClass().getName()对应的结果就是:com.itheima.api.system.demo04.Student;Integer.toHexString(hashCode())对应的结果就是3f3afe78。


我们常常将"com.itheima.api.system.demo04.Student@3f3afe78"这一部分称之为对象的内存地址值。但是一般情况下获取对象的内存地址值没有太大的意义。获取对象的成员变量的字符串拼接形式才


算有意义,怎么实现呢?此时我们就需要在Student类中重写Object的toString方法。我们可以通过idea开发工具进行实现,具体步骤如下所示:


  1. 1.在空白处使用快捷键:alt + insert。此时会弹出如下的对话框


2,选择toString,此时会弹出如下的对话框



同时选择name和age属性,点击OK。此时就会完成toString方法的重写,代码如下所示:

@Override
public String toString() {
    return "Student{" +
        "name='" + name + '\'' +
        ", age='" + age + '\'' +
        '}';
}

这段代码就是把Student类中的成员变量进行了字符串的拼接。重写完毕以后,再次运行程序,控制台输出结果如下所示:

s1对象的字符串表现形式为:Student{name='itheima', age='14'}

此时我们就可以清楚的查看Student的成员变量值,因此重写toString方法的意义就是以良好的格式,更方便的展示对象中的属性值

我们再来查看一下如下代码的输出:

// 创建学生对象
Student s1 = new Student("itheima" , "14") ;
// 直接输出对象s1
System.out.println(s1);

运行程序进行测试,控制台输出结果如下所示:

Student{name='itheima', age='14'}

我们可以看到和刚才的输出结果是一致的。那么此时也就证明直接输出一个对象,那么会默认调用对象的toString方法,因此如上代码的等同于如下代码:

// 创建学生对象
Student s1 = new Student("itheima" , "14") ;
// 调用s1的toString方法,把结果进行输出
System.out.println(s1.toString());

因此后期为了方便进行测试,我们常常是通过输出语句直接输出一个对象的名称。


小结:


在通过输出语句输出一个对象时,默认调用的就是toString()方法

输出地址值一般没有意义,我们可以通过重写toString方法去输出对应的成员变量信息(快捷键:atl + insert , 空白处 右键 -> Generate -> 选择toString)

toString方法的作用:以良好的格式,更方便的展示对象中的属性值

一般情况下Jdk所提供的类都会重写Object类中的toString方法

案例2:演示equals方法


实现步骤:


1.在测试类(ObjectDemo02)的main方法中,创建两个学生对象,然后比较两个对象是否相同

代码如下所示:

public class ObjectDemo02 {
    public static void main(String[] args) {
        // 创建两个学生对象
        Student s1 = new Student("itheima" , "14") ;
        Student s2 = new Student("itheima" , "14") ;
        // 比较两个对象是否相等
        System.out.println(s1 == s2);
    }
}

运行程序进行测试,控制台的输出结果如下所示:

false

因为"=="号比较的是对象的地址值,而我们通过new关键字创建了两个对象,它们的地址值是不相同的。因此比较结果就是false。

我们尝试调用Object类中的equals方法进行比较,代码如下所示:

// 调用equals方法比较两个对象是否相等
boolean result = s1.equals(s2);
// 输出结果
System.out.println(result);

运行程序进行测试,控制台的输出结果为:

false

为什么结果还是false呢?我们可以查看一下Object类中equals方法的源码,如下所示:

public boolean equals(Object obj) {   // Object类中的equals方法的源码
    return (this == obj);
}

通过源码我们可以发现默认情况下equals方法比较的也是对象的地址值。比较内存地址值一般情况下是没有意义的,我们希望比较的是对象的属性,如果两个对象的属性相同,我们认为就是同一个对象;


那么要比较对象的属性,我们就需要在Student类中重写Object类中的equals方法。equals方法的重写,我们也可以使用idea开发工具完成,具体的操作如下所示:


1.在空白处使用快捷键:alt + insert。此时会弹出如下的对话框



  1. 2.选择equals() and hashCode()方法,此时会弹出如下的对话框


点击next,会弹出如下对话框:



选择neme和age属性点击next,此时就会弹出如下对话框:



取消name和age属性(因为此时选择的是在生成hashCode方法时所涉及到的属性,关于hashCode方法后期再做重点介绍),点击Finish完成生成操作。生成的equals方法和hashCode方法如下:

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    Student student = (Student) o;
    return Objects.equals(name, student.name) && Objects.equals(age, student.age);  // 比较的是对象的name属性值和age属性值
}
@Override
public int hashCode() {
    return 0;
}

hashCode方法我们暂时使用不到,可以将hashCode方法删除。重写完毕以后运行程序进行测试,控制台输出结果如下所示:

true

此时equals方法比较的是对象的成员变量值,而s1和s2两个对象的成员变量值都是相同的。因此比较完毕以后的结果就是true。


小结:


默认情况下equals方法比较的是对象的地址值

比较对象的地址值是没有意义的,因此一般情况下我们都会重写Object类中的equals方法

案例2:对象克隆


把A对象的属性值完全拷贝给B对象,也叫对象拷贝,对象复制


对象克隆的分类:


深克隆和浅克隆


浅克隆:


不管对象内部的属性是基本数据类型还是引用数据类型,都完全拷贝过来


基本数据类型拷贝过来的是具体的数据,引用数据类型拷贝过来的是地址值。


Object类默认的是浅克隆



深克隆:

基本数据类型拷贝过来,字符串复用,引用数据类型会重新创建新的



package com.itheima.a04objectdemo;
public class ObjectDemo4 {
    public static void main(String[] args) throws CloneNotSupportedException {
        // protected object clone(int a) 对象克隆 
        //1.先创建一个对象
        int[] data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0};
        User u1 = new User(1, "zhangsan", "1234qwer", "girl11", data);
        //2.克隆对象
        //细节:
        //方法在底层会帮我们创建一个对象,并把原对象中的数据拷贝过去。
        //书写细节:
        //1.重写Object中的clone方法
        //2.让javabean类实现Cloneable接口
        //3.创建原对象并调用clone就可以了
        //User u2 =(User)u1.clone();
        //验证一件事情:Object中的克隆是浅克隆
        //想要进行深克隆,就需要重写clone方法并修改里面的方法体
        //int[] arr = u1.getData();
        //arr[0] = 100;
        //System.out.println(u1);
        //System.out.println(u2);
        //以后一般会用第三方工具进行克隆
        //1.第三方写的代码导入到项目中
        //2.编写代码
        //Gson gson =new Gson();
        //把对象变成一个字符串
        //String s=gson.toJson(u1);
        //再把字符串变回对象就可以了
        //User user =gson.fromJson(s, User.class);
        //int[] arr=u1.getData();
        //arr[0] = 100;
        //打印对象
        //System.out.println(user);
    }
}
package com.itheima.a04objectdemo;
import java.util.StringJoiner;
//Cloneable
//如果一个接口里面没有抽象方法
//表示当前的接口是一个标记性接口
//现在Cloneable表示一旦实现了,那么当前类的对象就可以被克降
//如果没有实现,当前类的对象就不能克隆
public class User implements Cloneable {
    private int id;
    private String username;
    private String password;
    private String path;
    private int[] data;
    public User() {
    }
    public User(int id, String username, String password, String path, int[] data) {
        this.id = id;
        this.username = username;
        this.password = password;
        this.path = path;
        this.data = data;
    }
    /**
     * 获取
     *
     * @return id
     */
    public int getId() {
        return id;
    }
    /**
     * 设置
     *
     * @param id
     */
    public void setId(int id) {
        this.id = id;
    }
    /**
     * 获取
     *
     * @return username
     */
    public String getUsername() {
        return username;
    }
    /**
     * 设置
     *
     * @param username
     */
    public void setUsername(String username) {
        this.username = username;
    }
    /**
     * 获取
     *
     * @return password
     */
    public String getPassword() {
        return password;
    }
    /**
     * 设置
     *
     * @param password
     */
    public void setPassword(String password) {
        this.password = password;
    }
    /**
     * 获取
     *
     * @return path
     */
    public String getPath() {
        return path;
    }
    /**
     * 设置
     *
     * @param path
     */
    public void setPath(String path) {
        this.path = path;
    }
    /**
     * 获取
     *
     * @return data
     */
    public int[] getData() {
        return data;
    }
    /**
     * 设置
     *
     * @param data
     */
    public void setData(int[] data) {
        this.data = data;
    }
    public String toString() {
        return "角色编号为:" + id + ",用户名为:" + username + "密码为:" + password + ", 游戏图片为:" + path + ", 进度:" + arrToString();
    }
    public String arrToString() {
        StringJoiner sj = new StringJoiner(", ", "[", "]");
        for (int i = 0; i < data.length; i++) {
            sj.add(data[i] + "");
        }
        return sj.toString();
    }
    @Override
    protected Object clone() throws CloneNotSupportedException {
        //调用父类中的clone方法
        //相当于让Java帮我们克隆一个对象,并把克隆之后的对象返回出去。
        //先把被克隆对象中的数组获取出来
        int[] data = this.data;
        //创建新的数组
        int[] newData =new int[data.length];
        //拷贝数组中的数据
        for (int i = 0; i < data.length; i++) {
            newData[i] = data[i];
        }
        //调用父类中的方法克隆对象
            User u=(User)super.clone();
        //因为父类中的克隆方法是浅克隆,替换克隆出来对象中的数组地址值
        u.data =newData;
        return u;
    }
}


后记
👉👉💕💕美好的一天,到此结束,下次继续努力!欲知后续,请看下回分解,写作不易,感谢大家的支持!! 🌹🌹🌹

相关文章
|
5天前
|
设计模式 消息中间件 算法
【实习总结】Java学习最佳实践!
【实习总结】Java学习最佳实践!
23 3
|
5天前
|
数据采集 安全 Java
Java并发编程学习12-任务取消(上)
【5月更文挑战第6天】本篇介绍了取消策略、线程中断、中断策略 和 响应中断的内容
30 4
Java并发编程学习12-任务取消(上)
|
3天前
|
算法 Java C++
刷题两个月,从入门到字节跳动offer丨GitHub标星16k+,美团Java面试题
刷题两个月,从入门到字节跳动offer丨GitHub标星16k+,美团Java面试题
|
4天前
|
NoSQL 算法 Java
【redis源码学习】持久化机制,java程序员面试算法宝典pdf
【redis源码学习】持久化机制,java程序员面试算法宝典pdf
|
4天前
|
算法 Java Python
保姆级Java入门练习教程,附代码讲解,小白零基础入门必备
保姆级Java入门练习教程,附代码讲解,小白零基础入门必备
|
5天前
|
SQL Java 关系型数据库
零基础轻松入门Java数据库连接(JDBC)
零基础轻松入门Java数据库连接(JDBC)
13 0
|
5天前
|
存储 安全 算法
Java一分钟之-Java集合框架入门:List接口与ArrayList
【5月更文挑战第10天】本文介绍了Java集合框架中的`List`接口和`ArrayList`实现类。`List`是有序集合,支持元素重复并能按索引访问。核心方法包括添加、删除、获取和设置元素。`ArrayList`基于动态数组,提供高效随机访问和自动扩容,但非线程安全。文章讨论了三个常见问题:索引越界、遍历时修改集合和并发修改,并给出避免策略。通过示例代码展示了基本操作和安全遍历删除。理解并正确使用`List`和`ArrayList`能提升程序效率和稳定性。
11 0
|
5天前
|
缓存 Java 数据库
Java并发编程学习11-任务执行演示
【5月更文挑战第4天】本篇将结合任务执行和 Executor 框架的基础知识,演示一些不同版本的任务执行Demo,并且每个版本都实现了不同程度的并发性。
34 4
Java并发编程学习11-任务执行演示
|
3天前
|
Java 测试技术
Java多线程的一些基本例子
【5月更文挑战第17天】Java多线程允许并发执行任务。示例1展示创建并启动两个`MyThread`对象,各自独立打印&quot;Hello World&quot;。示例2的`CounterExample`中,两个线程(IncrementThread和DecrementThread)同步地增加和减少共享计数器,确保最终计数为零。这些例子展示了Java线程的基本用法,包括线程同步,还有如Executor框架和线程池等更复杂的用例。
10 0
|
1天前
|
Java
Java一分钟之-并发编程:线程间通信(Phaser, CyclicBarrier, Semaphore)
【5月更文挑战第19天】Java并发编程中,Phaser、CyclicBarrier和Semaphore是三种强大的同步工具。Phaser用于阶段性任务协调,支持动态注册;CyclicBarrier允许线程同步执行,适合循环任务;Semaphore控制资源访问线程数,常用于限流和资源池管理。了解其使用场景、常见问题及避免策略,结合代码示例,能有效提升并发程序效率。注意异常处理和资源管理,以防止并发问题。
23 2