类和对象(两万字超详解析)(二)

本文涉及的产品
云解析DNS,个人版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 类和对象(两万字超详解析)

5. 对象的构造及初始化


5.1 如何初始化对象


通过前面知识点的学习知道,在Java方法内部定义一个局部变量时,必须要初始化,否则会编译失败。


public static void main(String[] args) {
  int a;
  System.out.println(a);
} 
 // Error:(26, 28) java: 可能尚未初始化变量a


要让上述代码通过编译,非常简单,只需在正式使用a之前,给a设置一个初始值即可。

如果是对象:


public static void main(String[] args) {
  Date d = new Date();
  d.printDate();
  d.setDate(2021,6,9);
  d.printDate();
} 
  // 代码可以正常通过编译


输出:


f34fc21ccd174144943e26bc4320bd7b.png

需要调用之前写的SetDate方法才可以将具体的日期设置到对象中。

通过上述例子发现两个问题:


  1. 每次对象创建好后调用SetDate方法设置具体日期,比较麻烦,那对象该如何初始化?
  2. 局部变量必须要初始化才能使用,为什么字段声明之后没有给值依然可以使用?

这就要讲到构造方法了。


5.2 构造方法


5.2.1 概念


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


public class Date {
    public int year;
    public int month;
    public int day;
    // 构造方法:
// 名字与类名相同,没有返回值类型,设置为void也不行
// 一般情况下使用public修饰
// 在创建对象时由编译器自动调用,并且在对象的生命周期内只调用一次
    public Date(int year, int month, int day){
        this.year = year;
        this.month = month;
        this.day = day;
        System.out.println("Date(int,int,int)方法被调用了");
    }
    public void printDate(){
        System.out.println(year + "-" + month + "-" + day);
    }
    public static void main(String[] args) {
// 此处创建了一个Date类型的对象,并没有显示调用构造方法
        Date d = new Date(2021,6,9); // 输出Date(int,int,int)表明方法被调用了
        d.printDate(); // 输出结果:2021-6-9
    }
}


注意:构造方法的作用就是对对象中的成员进行初始化,并不负责给对象开辟空间。


5.2.2 特性


  1. 名字必须与类名相同
  2. 没有返回值类型,设置为void也不行
  3. 创建对象时由编译器自动调用,并且在对象的生命周期内只调用一次(相当于人的出生,每个人只能出生一次)
  4. 构造方法可以重载(用户根据自己的需求提供不同参数的构造方法)
public class Date {
    public int year;
    public int month;
    public int day;
    // 无参构造方法
    public Date(){
        this.year = 1900;
        this.month = 1;
        this.day = 1;
    }
    // 带有三个参数的构造方法    
    public Date(int year, int month, int day) {   
        this.year = year;
        this.month = month;
        this.day = day;
    }
    public void printDate(){
        System.out.println(year + "-" + month + "-" + day);
    }
    public static void main(String[] args) {
        Date d = new Date();
        d.printDate();
        Date b = new Date(2022,11,11);
        b.printDate();
    }
}


输出:


4242abc75aee4554b37e76a0b07f075c.png


上述两个构造方法:名字相同,参数列表不同,因此构成了方法重载。

5. 如果用户没有显式定义,编译器会生成一份默认的构造方法,生成的默认构造方法一定是无参的。


public class Date {
    public int year;
    public int month;
    public int day;
    public void printDate(){
        System.out.println(year + "-" + month + "-" + day);
    }
    public static void main(String[] args) {
        Date d = new Date();
        d.printDate();
    }
}


上述Date类中,没有定义任何构造方法,编译器会默认生成一个不带参数的构造方法。


注意:一旦用户定义,编译器则不再生成。


下面代码便是这种错误:


public class Date {
    public int year;
    public int month;
    public int day;
    public Date(int year, int month, int day) {
        this.year = year;
        this.month = month;
        this.day = day;
    }
    public void printDate(){
        System.out.println(year + "-" + month + "-" + day);
    }
    public static void main(String[] args) {
// 如果编译器会生成,则生成的构造方法一定是无参的
// 则此处创建对象是可以通过编译的
// 但实际情况是:编译期报错
        Date d = new Date();  //这里编译器会报错,因为用户定义了构造函数,所以编译器不会再生成无参构造函数
        d.printDate();
    }
}


6.构造方法中,可以通过this调用其他构造方法来简化代码。

public class Date {
    public int year;
    public int month;
    public int day;
    // 无参构造方法--内部给各个成员赋值初始值,该部分功能与三个参数的构造方法重复
    // 此处可以在无参构造方法中通过this调用带有三个参数的构造方法
    // 但是this(1900,1,1);必须是构造方法中第一条语句
    public Date() {
        //System.out.println(year); 注释取消掉,编译会失败
        this(1900, 1, 1);  //必须是构造方法第一条语句
        //this.year = 1900;
        //this.month = 1;
        //this.day = 1;
    }
    // 带有三个参数的构造方法
    public Date(int year, int month, int day) {
        this.year = year;
        this.month = month;
        this.day = day;
    }
}


注意:


  1. this(…)必须是构造方法中第一条语句
  2. 不能形成环 (成环会导致一直循环)
public Date(){
  this(1900,1,1);  //这里调用有参构造方法
}
public Date(int year, int month, int day) {
  this();   //又去调用无参构造方法,然后又回来,一直循环
}


7.绝大多数情况下使用public来修饰,特殊场景下会被private修饰(后面会讲)


5.3 默认初始化


在上文中提出的第二个问题:为什么局部变量在使用时必须要初始化,而成员变量可以不用呢?


public class Date {
    public int year;
    public int month;
    public int day;
    public Date(int year, int month, int day) {
// 成员变量在定义时,并没有给初始值, 为什么就可以使用呢?
        System.out.println(this.year);
        System.out.println(this.month);
        System.out.println(this.day);
    }
    public static void main(String[] args) {
        //int a;
        //System.out.println(a);     //此处a没有初始化,编译时报错:
        Date d = new Date(2021,6,9);  
    }
}


输出:

a130f85ac5cf45ffb9cb3097e9e728dd.png


要搞清楚这个过程,就需要知道 new 关键字背后所发生的一些事情:


Date d = new Date(2021,6,9);


在程序层面只是简单的一条语句,在JVM层面需要做好多事情,下面简单介绍下:


  1. 检测对象对应的类是否加载了,如果没有加载则加载
  2. 为对象分配内存空间
  3. 处理并发现安全问题

比如:多个线程同时申请对象,JVM要保证给对象分配的空间不冲突

  1. 初始化所分配的空间(关键明白这一点)

即:对象空间被申请好之后,对象中包含的成员已经设置好了初始值,比如:


8ccbe6ff5de54bae98f77a769551575f.png


  1. 设置对象头信息(关于对象内存模型)
  2. 调用构造方法,给对象中各个成员赋值


5.4 就地初始化


在声明成员变量时,就直接给出了初始值。


public class Date {
    public int year = 1900;
    public int month = 1;
    public int day = 1;
    public Date(){
    }
    public Date(int year, int month, int day) {
    }
    public static void main(String[] args) {
    Date d1 = new Date(2021,6,9);
    Date d2 = new Date();
    }
}


注意:代码编译完成后,编译器会将所有给成员初始化的这些语句添加到各个构造函数中。


6. 封装


6.1 封装的概念


面向对象程序三大特性:封装、继承、多态。而类和对象阶段,主要研究的就是封装特性。何为封装呢?简单来说就是套壳屏蔽细节。

比如:对于电脑这样一个复杂的设备,提供给用户的就只是:开关机、通过键盘输入,显示器,USB插孔等,让用户来和计算机进行交互,完成日常事务。但实际上:电脑真正工作的却是CPU、显卡、内存等一些硬件元件。

对于计算机使用者而言,不用关心内部核心部件,比如主板上线路是如何布局的,CPU内部是如何设计的等,用户只需要知道,怎么开机、怎么通过键盘和鼠标与计算机进行交互即可。因此计算机厂商在出厂时,在外部套上壳

子,将内部实现细节隐藏起来,仅仅对外提供开关机、鼠标以及键盘插孔等,让用户可以与计算机进行交互即可。


封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互。


6.2 访问限定符


Java中主要通过类和访问权限来实现封装:类可以将数据以及封装数据的方法结合在一起,更符合人类对事物的认知,而访问权限用来控制方法或者字段能否直接在类外使用。Java中提供了四种访问限定符:

ae7f081501ee421b9b5a499c071bbe78.png


注:默认就是default不加修饰限定符的意思,可就是可以访问。


理解:

public:可以理解为一个人的外貌特征,谁都可以看得到

default: 对于自己家族中(同一个包中)不是什么秘密,对于其他人来说就是隐私了

private:只有自己知道,其他人都不知道


【说明】

protected主要是用在继承中,继承部分详细介绍

default权限指:什么都不写时的默认权限

访问权限除了可以限定类中成员的可见性,也可以控制类的可见性


例:


class Computer {
    private String cpu; // cpu
    private String memory; // 内存
    public String screen; // 屏幕
    String brand; // 品牌---->default属性
    public Computer(String brand, String cpu, String memory, String screen) {
        this.brand = brand;
        this.cpu = cpu;
        this.memory = memory;
        this.screen = screen;
    }
    public void Boot(){
        System.out.println("开机~~~");
    }
    public void PowerOff(){
        System.out.println("关机~~~");
    }
    public void SurfInternet(){
        System.out.println("上网~~~");
    }
}
public class Date{
    public static void main(String[] args) {
        Computer p = new Computer("HW", "i7", "8G", "13*14");
        System.out.println(p.brand); // default属性:只能被本包中类访问
        System.out.println(p.screen); // public属性: 可以任何其他类访问
        // System.out.println(p.cpu); // private属性:只能在Computer类中访问,不能被其他类访问
    }
}


注意:一般情况下成员变量设置为private,成员方法设置为public。


相关文章
|
2天前
|
缓存 开发者 索引
深入解析 `org.elasticsearch.action.search.SearchRequest` 类
深入解析 `org.elasticsearch.action.search.SearchRequest` 类
8 0
|
17天前
|
存储 安全 Java
滚雪球学Java(60):深入解析Java中的Vector集合类!
【6月更文挑战第14天】🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
151 59
滚雪球学Java(60):深入解析Java中的Vector集合类!
|
21天前
|
SQL 缓存 算法
【源码解析】Pandas PandasObject类详解的学习与实践
【源码解析】Pandas PandasObject类详解的学习与实践
|
13天前
|
JavaScript 前端开发 Java
【JavaScript】ECMAS6(ES6)新特性概览(二):解构赋值、扩展与收集、class类全面解析
【JavaScript】ECMAS6(ES6)新特性概览(二):解构赋值、扩展与收集、class类全面解析
16 2
|
13天前
|
存储 JavaScript 前端开发
【JavaScript】JavaScript 中的 Class 类:全面解析
【JavaScript】JavaScript 中的 Class 类:全面解析
17 1
|
13天前
|
消息中间件 监控 安全
深入解析Linux命令ipcmk:IPC对象管理新视角
`ipcmk`非标准Linux命令,假设的IPC对象创建工具,用于演示如何管理消息队列、信号量和共享内存。虽无此命令,但理解其概念有助于掌握IPC管理。例如,创建命名消息队列`my_mq`,最大1000消息,可模拟使用`ipcmk -t mq -n my_mq -q 1000`。实际操作中,应根据需求选择合适IPC机制,设置安全权限,监控使用并及时清理。
|
13天前
|
Java
【Java】Object类简单解析
【Java】Object类简单解析
15 1
|
21天前
|
存储 SQL 算法
【源码解析】深入解析 pandas的Block 类中算术运算和重排实现
【源码解析】深入解析 pandas的Block 类中算术运算和重排实现
|
3天前
|
存储 缓存 Java
Java对象内存布局深度解析
Java对象内存布局深度解析
8 0
|
4天前
|
缓存 算法 Java
提升编程效率的利器: 解析Google Guava库之常用工具类-40个示例(七)
提升编程效率的利器: 解析Google Guava库之常用工具类-40个示例(七)

推荐镜像

更多