• 【JavaSE】类和对象——上


    1. 类的定义


    1.1 什么是类

    类是用来对一个实体(对象)来进行描述的,主要描述该实体(对象)具有哪些属性,哪些功能(用来干啥)。同时类是用户自定义的数据类型,包括属性和行为。在类里方法外定义的属性和方法分别称为成员变量和成员方法


    1.2 如何定义类

    在这里插入图片描述
    当然 class 前也可以加修饰访问限定符,并且一个 java 文件中只能有一个被 public 修饰的类我们这里先不用管。

    class Dog {
    	 //狗的属性
        public String name;
        public int age;
        public String variety;
        //狗的行为
        public void bark() {
            System.out.println("汪汪汪");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在上面的狗类中,狗有名字、年龄、品种等属性,也会执行叫等行为。

    注意:

    1. 一个 java 文件中最好只定义一个类,但为了方便讲解本章节我们写在一起。
    2. 先不用管 public 是什么意思照着写先,后面会讲解。

    2. 类的实例化


    1. 定义了一个类,就相当于在计算机中定义了一种新的类型,与int,double类似,只不过int和double是java语言自带的内置类型,而类是用户自定义了一个新的类型。
    2. 用类类型创建对象的过程,称为类实例化,在 java 中通过 new 关键字来实例化对象
    3. 类就相当于一个模板,通过这个模板可以实例化出多个对象。如我们定义了一个狗类我们就可以通过这个狗类实例化出多个狗对象,如二哈、中华田园犬、金毛等等。

    在这里插入图片描述

    实例化方法:
    在这里插入图片描述
    这里的类名是一个自定义数据类型,也可看成 类类型 变量 = new 类类型()

    如我们对上面的狗类进行实例化,一个 java 文件最好只定义一个类,但为了方便讲解我们写在一起。

    class Dog {
        public String name;
        public int age;
        public String variety;
    
        public void bark() {
            System.out.println("汪汪汪");
        }
        //打印
        public void print() {
            System.out.println("姓名:" + name + ",年龄:" + age + ",种类:" + variety);
        }
    
    }
    public class TestDemo1 {
        public static void main(String[] args) {
            Dog dog1 = new Dog();//实例化对象,存放地址的变量叫引用
            dog1.name = "小毛"; //通过 引用.属性 访问进行赋值
            dog1.age = 4;
            dog1.variety = "哈士奇";
            dog1.print();
            dog1.bark(); //通过 引用.方法 进行访问
    
            Dog dog2 = new Dog();
            dog2.name = "土狗";
            dog2.age = 5;
            dog2.variety = "中华田园犬";
            dog2.print();
            dog2.bark();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    在这里插入图片描述通过上面我们可以看出,一个类可以实例化出多个对象,它们的品种、姓名等不一样。

    • new 关键字用于创建一个对象的实例.
    • 使用 . 来访问对象中的属性和方法.
    • 同一个类可以创建多个实例.

    当实例化一个对象时,会在堆中先开辟一块内存空间,我们画出上面的两个对象内存的分布。
    在这里插入图片描述
    dog1 和 dog2 引用存放的是对象的地址

    以下语句中 dog5 = dog1; 代表什么:

    class Dog {
        public String name;
        public int age;
        public String variety;
    
        public void bark() {
            System.out.println("汪汪汪");
        }
        //打印
        public void print() {
            System.out.println("姓名:" + name + ",年龄:" + age + ",种类:" + variety);
        }
    
    }
    public class TestDemo1 {
        public static void main(String[] args) {
            Dog dog1 = new Dog();//实例化对象,存放地址的变量叫引用
            dog1.name = "小毛"; //通过 引用.属性 访问进行赋值
            dog1.age = 4;
            dog1.variety = "哈士奇";
            Dog dog5 = new Dog();
            dog5 = dog1; //dog5这个引用 指向/引用了 dog1 引用所指向/引用的对象
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    就是 dog5 存放了 dog1 引用 所引用对象的地址,即 dog5 和 dog1 存放一样的地址。

    当我们没有赋值时,打印成员变量时,打印的是其类型对应的 0 值。引用类型是 null, boolean类型是false

    class Dog {
        public String name;
        public int age;
        public String variety;
    
        public void bark() {
            System.out.println("汪汪汪");
        }
        public void print() {
            System.out.println("姓名:" + name + ",年龄:" + age + ",种类:" + variety);
        }
    }
    public class TestDemo1 {
        public static void main(String[] args) {
    		Dog dog3 = new Dog();
            dog3.print();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    在这里插入图片描述


    3. this关键字


    3.1 this访问成员变量和成员方法

    当我们想要实现一个日期类时。

    class MyDate {
        public int year;
        public int month;
        public int day;
        //通过setMyDate()方法赋值
        public void setMyDate(int myYear, int myMonth, int myDay) {
            year = myYear;
            month = myMonth;
            day = myDay;
        }
        public void print() {
            System.out.println(year + "年" + month + "月" + day + "日");
        }
    }
    public class TestDemo2 {
        public static void main(String[] args) {
            MyDate date = new MyDate();
            date.setMyDate(2022, 11, 5);
            date.print(); //通过print方法打印
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    在这里插入图片描述

    那当我们把 setMyDate() 方法改成以下后。

        //通过setMyDate()方法赋值
        public void setMyDate(int year, int month, int day) {
            year = year;//形参等于形参
            month = month;
            day = day;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    这个方法中,year = year 的意思是形参等于形参,并没有对该对象的属性进行赋值。

    在这里插入图片描述

    当我们使用 this 引用访问时可以避免此问题。

    class MyDate {
        public int year;
        public int month;
        public int day;
        //通过setMyDate()方法赋值
        public void setMyDate(int year, int month, int day) {
            this.year = year; //访问成员变量
            this.month = month;
            this.day = day;
            this.print(); //访问成员方法,打印
        }
        public void print() {
            System.out.println(year + "年" + month + "月" + day + "日");
        }
    }
    public class TestDemo2 {
        public static void main(String[] args) {
            MyDate date = new MyDate();
            date.setMyDate(2022, 11, 5);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    在这里插入图片描述



    1. this代表当前对象的引用。即谁调用就是谁的对象属性。
    如: 在这里插入图片描述当前 this.year 即为 date.year

    如果再加以下语句

    MyDate date2 = new MyDate();
    date2.seMyDate(2014, 11, 11);
    
    • 1
    • 2

    此时的 this.year 相当于 date2.year。


    2. this.成员变量/方法,只能在方法中使用,但不能在静态方法中使用

    3. 在类的方法中,属于该类的属性最好在前面加 this ,用来防止形参和成员变量冲突时,没有赋值上。

    package testdemo1;
    
    class MyDate {
        public int year;
        public int month;
        public int day;
        //通过setMyDate()方法赋值
        public void setMyDate(int year, int month, int day) {
            this.year = year;
            this.month = month;
            this.day = day;
            this.print();
        }
        public void print() {
            System.out.println(this.year + "年" + this.month + "月" + this.day + "日");
        }
    
    }
    public class TestDemo2 {
        public static void main(String[] args) {
            MyDate date = new MyDate();
            date.setMyDate(2022, 11, 5);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    4. this 实际上是一个隐式的参数。
    我们进行调试
    在这里插入图片描述实际上是长这个样子的:
    在这里插入图片描述

    在这里插入图片描述

    java编译器给每个“成员方法“增加了一个隐藏的引用类型参数,该引用参数指向当前对象(成员方法运行时调用该成员方法的对象),在成员方法中所有成员变量的操作,都是通过该引用去访问 。只不过所有的操作对用户是透明 的,即用户不需要来传递,编译器自动完成

    总结:

    1. this的类型:对应类类型引用,即哪个对象调用就是哪个对象的引用类型。
    2. this只能在"成员方法"中使用,不能在静态方法中使用。
    3. 在"成员方法"中,this只能引用当前对象,不能再引用其他对象。
    4. this是“成员方法”第一个隐藏的参数,编译器会自动传递,在成员方法执行时,编译器会负责将调用成员方法 对象的引用传递给该成员方法,this负责来接收。


    3.2 构造方法及this()

    我们给类初始化的方法有:

    3.2.1 就地初始化

    class Student {
        public String name = "张三";
        public int age = 20;
        public String sex = "男";
        public int score = 99;
        public void doClass() {
            System.out.println(this.name + "正在上课");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    这样的初始化方式不好。

    3.2.2 使用 set 方法赋值

    在讲 this.访问成员变量和成员方法时说过,可以往回看。


    3.2.3 使用构造方法

    构造方法(也称为构造器)是一个特殊的成员方法,名字必须与类名相同,在创建对象时,由编译器自动调用,并且在整个对象的生命周期内只调用一次。

    1. 构造方法使用方法:
    在这里插入图片描述

    当我们实例化一个对象时需要:(必须有这两步,但不一定只有这两步)

    1. 为对象分配内存
    2. 调用合适的构造方法 (说明一个类中可以多个构造方法)

    在这里插入图片描述

    那么问题来了,之前我们没有调用构造方法为什么没报错呢?
    那是因为当我们不写构造方法时,编译器会默认帮我们生成一个不带参数的构造方法。
    当我们写构造方法后,编译器就不会帮我们提供不带参数的构造方法

    在这里插入图片描述
    2. 当类中有多个构造方法时。

    package testdemo1;
    
    class Student {
        public String name;
        public int age;
        public String sex;
        public int score;
    
        public Student() {
            System.out.println("不带参数的构造方法");
        }
    
        public Student(String name, int age) {
            this.name = name;
            this.age = age;
            System.out.println("带2个参数的构造方法");
        }
    
        public Student(String name, int age, String sex, int score) {
            this.name = name;
            this.age = age;
            this.sex = sex;
            this.score = score;
            System.out.println("带4个参数的构造方法");
        }
    
        public void doClass() {
            System.out.println(this.name + "正在上课");
        }
    }
    public class TestDemo3 {
        public static void main(String[] args) {
            Student student1 = new Student();//调用不带参数的构造方法
            
            Student student2 = new Student("张三", 22, "男", 99);//调用带四个参数的构造方法
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    我们可以看到当有多个构造方法时,调用合适的构造方法

    在这里插入图片描述

    3. 使用 this() 调用本类中的其他构造方法

    class Student {
        public String name;
        public int age;
        public String sex;
        public int score;
    
        public Student() {
            this("张三", 19); //调用带两个参数的构造方法
            System.out.println("不带参数的构造方法");
        }
    
        public Student(String name, int age) {
            this.name = name;
            this.age = age;
            System.out.println("带2个参数的构造方法");
        }
    }
    public class TestDemo3 {
        public static void main(String[] args) {
            Student student1 = new Student();//调用不带参数的构造方法
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    在这里插入图片描述在这里插入图片描述

    4. 使用 this() 不能形成环

    在这里插入图片描述

    总结:

    1. 构造方法是没有返回值的方法,方法名和类名是一样的。
    2. 构造方法不止一个,可以有多个,多个构造方法之间,构成了重载。
    3. 当我们写了一个类之后,没有写构造方法的时候,编译器会帮我们默认生成一个不带参数的构造方法。
    4. 当我们写了任何一个构造方法之后,编译器不再为我们,提供不带参数的构造方法。
    5. 一个类至少会有1个构造方法就算你没有写。
    6. 构造方法本质就是来实例化对象的时候调用。1、分配内存2、调用合适的构造方法。
    7. this可以用来调用本类中其他的构造方法【构造方法当中使用】。必须放到第一行!!!所以,只能在当前构造方法当中,调用一个。

    4. 如何便捷的打印对象中属性

    当我们实例化对象后,想要打印该对象的属性时,可以这么写:

    package testdemo1;
    
    class Student {
        public String name;
        public int age;
        public String sex;
        public int score;
        public Student(String name, int age, String sex, int score) {
            this.name = name;
            this.age = age;
            this.sex = sex;
            this.score = score;
            System.out.println("带4个参数的构造方法");
        }
        public void doClass() {
            System.out.println(this.name + "正在上课");
        }
        public void print() {
            System.out.println("[姓名:" + this.name
                                + ",年龄:" + this.age
                                + ",性别:" + this.sex
                                + ",成绩:" + this.score
                                + "]");
        }
    }
    public class TestDemo3 {
        public static void main(String[] args) {
            Student student2 = new Student("张三", 22, "男", 99);
            student.print();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    在这里插入图片描述
    当然也可以在主方法利用 引用.成员变量 进行打印,这里就不写出了。

    当我们直接使用 System.out.println(); 打印一个对象时:

    class Student {
        public String name;
        public int age;
        public String sex;
        public int score;
        
        public Student(String name, int age, String sex, int score) {
            this.name = name;
            this.age = age;
            this.sex = sex;
            this.score = score;
        }
        public void doClass() {
            System.out.println(this.name + "正在上课");
        }
    }
    public class Test1 {
        public static void main(String[] args) {
            Student student1 = new Student("张三", 22, "男", 99);
            System.out.println(student1);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    在这里插入图片描述

    打印的是一个地址。我们跳转到 println 的源码看看

    System.out.println(student1);
    打印不同的东西 println() 采用不同的写法

    在这里插入图片描述

    • 所以当我们想要打印成员属性时,通过对象的引用变量进行打印(System.out.println(student1);),我们可以自己在 Student 类中写一个 toString() 方法,编译器会调用类中的 toString() 方法,因为当打印 student1对象时,如果student1 不为 null ,编译器会在该对象中看看有没有 toString() 方法,有则调用,没有则默认调用上面说到的toString() 方法。

    写法如下

    
    class Student {
        public String name;
        public int age;
        public String sex;
        public int score;
        public Student(String name, int age, String sex, int score) {
            this.name = name;
            this.age = age;
            this.sex = sex;
            this.score = score;
        }
        public void doClass() {
            System.out.println(this.name + "正在上课");
        }
        //toString()方法
        @Override
        public String toString() {
            return "Student{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    ", sex='" + sex + '\'' +
                    ", score=" + score +
                    '}';
        }
    }
    public class Test1 {
        public static void main(String[] args) {
            Student student1 = new Student("张三", 22, "男", 99);
            System.out.println(student1);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    在这里插入图片描述

    idea可使用快捷键直接写出

    在这里插入图片描述

    那么当 Student student1 = null 时呢

    在这里插入图片描述

    在这里插入图片描述
    打印的是 null。

    好的,到这里本章节就结束了,如发现有错误,请各位大佬及时指出。

  • 相关阅读:
    抖音矩阵系统,抖音矩阵系统源码。
    leetcode 第 364 场周赛
    LeetCode50天刷题计划第二季(Day 31 — 两数之和 II - 输入有序数组(11.10-11.20)分数到小数(11.30-12.30)
    无代码开发卡片视图入门教程
    北斗导航 | 基于奇异值分解的接收机自主完好性监测算法
    C++多态收尾
    数据库Redis(一):基础知识
    分享一个卡片轮播
    单卡显存不足时如何进行多卡推理?
    Cesium+Shader:两种动态墙效果
  • 原文地址:https://blog.csdn.net/Autonmy_/article/details/127702484