【Java SE】类和对象(下)

简介: 从本期开始,欢迎各位正式开始面向对象编程,Java 一门纯面向对象编程的语言,在它的世界里,一切皆为对象,面向对象和面向过程其实都是一种解决问题的思路,而面向对象主要是各个对象之间互相交互去完成一件事情。

4、this 引用的认识

4.1 为什么需要 this 引用

假设这里我们要对前面的 Student 类进行修改,如果跟上面一样一个个初始化姓名年龄分数等太麻了,能不能在类中写一个方法可以用来一次性初始化里面的成员变量呢?当然是可以的:

public class Student {
    //成员变量【属性】
    public String name; //姓名
    public int age; //年龄
    public float score; //分数
    public String subject; //课程
    //成员方法【行为】
    public void studySubject() {
        System.out.println(name + "正在学习" + subject);
    }
    public void setStudentData(String n, int a, float c, String s) {
        n = name;
        a = age;
        c = score;
        s = subject;
    }
    public static void main(String[] args) {
        Student student1 = new Student();
        student1.setStudentData("张三", 20, 59.9f, "Linux");
        Student student2 = new Student();
        student2.setStudentData("李四", 22, 89.8f, "Java");
        student1.studySubject();
        student2.studySubject();
    }
}

但是这里细心的小伙伴可能就发现了,你这个成员方法里面的形参名取得很随意啊,就不能跟成员变量名一样吗?如果我的形参名跟成员变量名一样了,那方法体中,是谁给谁赋值呢?成员变量给成员变量,还是形参给形参?但是在实际中,如果形参和成员变量名一样,则会是局部变量优先,所以也就是形参给自己赋值!

第二个问题,我们 new 了两个对象,student1和student2分别引用了他们,这两个对象都在调用studySubject方法,这两个方法又是如何知道打印的是哪个对象的数据呢?

如果想弄清楚这几个问题,请往后看:

4.2 什么是 this 引用?

this 引用是指向当前对象的!也就是在方法运行的时候调用该成员方法的对象,我们在成员方法中所有对成员变量的操作,本质是通过 this 引用去访问的!不过这些操作编译器帮我们做了,对于我们来说是透明的,也就是用户不需要传递,编译器自己搞定

所以我们上面的 studySubject() 这个成员方法实际上是这样的:

public void studySubject(Student this) {
        System.out.println(this.name + "正在学习" + this.subject);
    }

这个地方,this 引用的是什么呢?其实就是哪个对象调用了这个成员方法,它引用的就是谁!this 代表了当前对象的引用

如果是 student1.studySubject(),那么 this 接收的就是 student1,也就是说 this 在这里是成员方法第一个隐藏参数,编译器会自动传递,在成员方法执行的时候,编译器会负责将调用成员方法对象的引用传递给该成员方法,this 负责来接收,所以这就是为什么在成员方法内部我们能使用 this.成员变量 的操作了!

现在使用 this 来解决我们上面成员方法命名的问题:

public void setStudentData(String name, int age, float score, String subject) {
        this.name = name;
        this.age = age;
        this.score = score;
        this.subject = subject;
    }

那我们在以后写代码在成员方法内部访问成员变量要不要加上 this 呢,虽然编译器会自动加上,但我们最好加上,不仅语义更明确,也可以避免形参与成员变量重名的情况

所以目前我们知道了 this 引用的三个用法:

  • this 访问当前成员变量 this.
  • this 访问成员方法(在成员方法中,嵌套其他成员方法) this.
  • this 访问构造方法 this();

5、对象的构造和初始化

5.1 如何初始化对象

这个相信大家都在前面见到过了,可以使用 引用.成员变量  进行初始化,同时呢也可以像我们上面一样写一个成员方法来初始化,但是像以上两种做法还是比较麻烦的,因为每次都要实例化对象之后才能进行初始化,能不能做到在创建对象的同时给成员变量初始化呢?

我们还知道一个点,变量不初始化是不能使用的,但是如果是对象的话,不初始化里面的成员变量是会有默认值的!这是为什么呢?

5.2 构造方法

构造方法是一种特殊的成员方法,也被称作为构造器,它特殊在哪呢?

首先它的方法名必须与类名相同!没有返回类型!设置成void也不行,一般用public修饰,并且在创建对象的时候,自动调用,而且在整个对象的生命周期中只能调用一次!

那么我们现在就在我们原有的 Student 类中添加一个构造方法:

public class Student {
    //成员变量【属性】
    public String name; //姓名
    public int age; //年龄
    public float score; //分数
    public String subject; //课程
    //构造方法
    public Student(String name, int age, float score, String subject) {
        this.name = name;
        this.age = age;
        this.score = score;
        this.subject = subject;
    }
    //成员方法【行为】
    public void studySubject() {
        System.out.println(this.name + "正在学习" + this.subject);
    }
    public static void main(String[] args) {
        Student student1 = new Student("李四", 22, 89.8f, "Java");
        student1.studySubject();
    }
}

这里我们通过增加了一个带有参数的构造方法,可以看到,在创建对象的时候,就可以调用构造方法初始化了, 看到这,有的小伙伴大吃一惊,原来我们之前创建方法的时候不都是在调用一个无参的构造方法吗?是的!但是我们之气明明没有写构造方法啊,这是怎么回事?

当我们没有任何构造方法的时候,编译器会给我们提供一个不带参数的构造方法!

那我们现在写了一个构造方法,那如果下次再创建对象的时候,不传参呢?不行!因为只有在没有任何构造方法的时候,编译器才会提供,如果有了,我们在创建的时候不需要参数还得自己写一个无参的构造方法!而且构造方法的作用主要是给对象中成员进行初始化的!不负责给成员开辟空间!

上面这么一解释,我们既然可以有多个构造方法,但是构造方法的方法名必须与类名一样,那是不是说明构造方法支持重载!是的!构造方法支持重载!

构造方法中,可以用 this 调用其他的构造方法,但是必须是第一条语句,而且不能成环调用,也就 this 调用的方法里不能还有 this 调用:

public Student(String name, int age, float score, String subject) {
        this(name);
        this.name = name;
        this.age = age;
        this.score = score;
        this.subject = subject;
    }
    public Student(String name) {
        System.out.println(name + "构造成功!");
    }

所以到现在我们就明白了一个点:当构造方法调用完成之后,对象才正真产生了!

5.3 默认初始化

前面说过,没初始化对象中的成员变量是有默认值的,为啥呢?简单说一下,在JVM层面上,我们new一个对象,首先要检查类是否被加载,然后为对象分配空间,接着处理并发问题,为了保证分配的空间不冲突,再就是初始化所分配的空间,也就是初始化成默认值,再然后就是设置对象头信息这个后期讲,接着才是调用构造方法。

那么他们的默认值是什么呢?这个参考我上期文章,里面有一个表格,写的很清楚。引用类型的默认值是 null。

5.4 就地初始化

就地初始化是什么意思呢?就是在我们定义类里面成员变量的时候就直接给初始值了,比如:

public class Student {
    //成员变量【属性】
    public String name = "张三"; //姓名
    public int age = 20; //年龄
    public float score = 60.0f; //分数
    public String subject = "Linux"; //课程
}

这种会在编译完成后,编译器会将所有的成员初始化的这些语句添加到各个构造函数中,每个构造函数中默认会添加这些语句!

相关文章
|
13天前
|
Java
java代码优化:判断内聚到实体对象中和构造上下文对象传递参数
通过两个常见的java后端实例场景探讨代码优化,代码不是优化出来的,而是设计出来的,我们永远不可能有专门的时间去做代码优化,优化和设计在平时
29 15
|
2月前
|
Java 开发者
在 Java 中,一个类可以实现多个接口吗?
这是 Java 面向对象编程的一个重要特性,它提供了极大的灵活性和扩展性。
175 57
|
28天前
|
JSON Java Apache
Java基础-常用API-Object类
继承是面向对象编程的重要特性,允许从已有类派生新类。Java采用单继承机制,默认所有类继承自Object类。Object类提供了多个常用方法,如`clone()`用于复制对象,`equals()`判断对象是否相等,`hashCode()`计算哈希码,`toString()`返回对象的字符串表示,`wait()`、`notify()`和`notifyAll()`用于线程同步,`finalize()`在对象被垃圾回收时调用。掌握这些方法有助于更好地理解和使用Java中的对象行为。
|
2月前
|
存储 缓存 安全
java 中操作字符串都有哪些类,它们之间有什么区别
Java中操作字符串的类主要有String、StringBuilder和StringBuffer。String是不可变的,每次操作都会生成新对象;StringBuilder和StringBuffer都是可变的,但StringBuilder是非线程安全的,而StringBuffer是线程安全的,因此性能略低。
79 8
|
2月前
|
安全 Java
Java多线程集合类
本文介绍了Java中线程安全的问题及解决方案。通过示例代码展示了使用`CopyOnWriteArrayList`、`CopyOnWriteArraySet`和`ConcurrentHashMap`来解决多线程环境下集合操作的线程安全问题。这些类通过不同的机制确保了线程安全,提高了并发性能。
|
2月前
|
存储 Java 程序员
Java基础的灵魂——Object类方法详解(社招面试不踩坑)
本文介绍了Java中`Object`类的几个重要方法,包括`toString`、`equals`、`hashCode`、`finalize`、`clone`、`getClass`、`notify`和`wait`。这些方法是面试中的常考点,掌握它们有助于理解Java对象的行为和实现多线程编程。作者通过具体示例和应用场景,详细解析了每个方法的作用和重写技巧,帮助读者更好地应对面试和技术开发。
149 4
|
2月前
|
Java Android开发
Eclipse 创建 Java 类
Eclipse 创建 Java 类
36 0
|
5月前
|
Java 开发者
奇迹时刻!探索 Java 多线程的奇幻之旅:Thread 类和 Runnable 接口的惊人对决
【8月更文挑战第13天】Java的多线程特性能显著提升程序性能与响应性。本文通过示例代码详细解析了两种核心实现方式:Thread类与Runnable接口。Thread类适用于简单场景,直接定义线程行为;Runnable接口则更适合复杂的项目结构,尤其在需要继承其他类时,能保持代码的清晰与模块化。理解两者差异有助于开发者在实际应用中做出合理选择,构建高效稳定的多线程程序。
70 7
|
3月前
|
Java 开发者
在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口
【10月更文挑战第20天】在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口。本文揭示了这两种方式的微妙差异和潜在陷阱,帮助你更好地理解和选择适合项目需求的线程创建方式。
52 3
|
3月前
|
Java
Java中多线程编程的基本概念和创建线程的两种主要方式:继承Thread类和实现Runnable接口
【10月更文挑战第20天】《JAVA多线程深度解析:线程的创建之路》介绍了Java中多线程编程的基本概念和创建线程的两种主要方式:继承Thread类和实现Runnable接口。文章详细讲解了每种方式的实现方法、优缺点及适用场景,帮助读者更好地理解和掌握多线程编程技术,为复杂任务的高效处理奠定基础。
55 2