面向对象——访问器、修改器、构造函数、对象的创建流程
在之前的代码讲解中,我们将一类事物封装成一个类,再去创建一个相应的对象去调用方法完成相应的操作这是非常方便的,但是在之前的代码我们发现,对象不仅仅能调用类中的方法,还可以访问到该类中的成员变量并进行赋值,在点坐标中只要是int类型的值我们都取值,这是因为坐标的涵盖数值是非常广的,那么如果一个类的成员变量是其他含义,那么对值的随意改变就是不合理的了,比如如果一个成员变量是为年龄(age),那么年龄的取值范围是从0岁到100岁的(假设最大为100),那么我们如果将age的成员变量的修饰权限还定义为public的话此时是不符合常理的,这样会在后续的代码在运行的过程中 会偏离预期结果 甚至会出错,而且后期也会很难维护。有人可能会说在赋值的时候加上一个判断,这样就可以避免了,这是一个好的想法,但是如果在主函数中加上判断,这样的面向对象是没有任何意义的,因为我们面向对象的思想是调用方便,尽量减少在主函数中的操作,那么我么应该在哪儿加呢?
访问器、修改器
这里应该将成员变量进行私有化修饰,这样外界就不会访问到了,避免了对数据域的直接修改,那称 为数据域封装,么如何可以进行合理的修改呢?为了能够访问私有数据域,可以提供一个 get 方法返回数据域的值。为了能够更新一个数据域,可以提供一个 set 方法给数据域设置新值。get 方法也被称 为访问器(accessor), 而 set 方法称为修改器(mutator),这样在修改器中加上判断条件是很合理的,那么具体怎么实现呢?声明如下:
public 返回值类型 get+成员变量名首字母大写(){ //访问器一定有返回值
return this.+该成员变量;
}
public void set+成员变量名首字母大写(该成员变量数据类型 该成员变量名){ //修改器一定有参数的传递
(在赋值之前可以加判断,判断修改的值是否合理)
this.+该成员变量 = 传进来的成员变量;
}
既然修改成员变量的值是通过对象来调用的,那么对象是如何创建的呢?
构造函数
我们知道在定义一个实体类之后,在主类或者其他的类中,当然在当前类中都是可以创建该类的对象的,而且我们知道使用new关键字就可以创建一个对象出来,其实在程序中,对象的创建是和构造函数相关的,如下面的代码
public class Animal{ //实体动物类private int age;private String name;public void setAge(int age){ //成员变量年龄的修改器if(age<0){age=0;}else{this.age = age;}public int getAge(){ //成员变量年龄的访问器return this.age;}public void setName(String name){ //成员变量名字的修改器this.age = age;}public String getName(){ //成员变量名字的访问器return this.name;}public void sleep(){System.out.println(age+"岁的"+name+"正安静的闭眼睡觉");}
}public class Demo01{ //主类public static void main(String[] args){Animal dog = new Animal(); //创建一个对象dog.age = 8; //给年龄赋值dog.name = "欢欢"; //给姓名赋值dog.sleep();}
}
我们发现实体类中,除了两个成员变量之外就只有一个普通的sleep方法,刚说创建对象是和实体类的构造函数有关,但是我们并没有看到构造函数,那么对象是怎么被创建出来的呢?
如果类中没有定义任何构造函数的话 会有一个隐藏的无参构造函数,
那么什么是构造函数呢?构造方法是一种特殊的方法。它们有以下三个特殊性:
1.构造方法必须具备和所在类相同的名字。 (如上面代码的构造函数为:Animal(){ })
2.构造方法没有返回值类型,甚至连 void 也没有。
3.构造方法是在创建一个对象使用 new 操作符时调用的。构造方法的作用是初始化对象。
由此可以得出,没有声明任何构造函数时,他会有一个默认的不带参数的构造函数,那么如果声明一个其他的构造函数并且是带参数的,那么默认的不带参数的函数就不存在了,所以我们在创建对象时进行的初始化其实调用的是相应的构造函数,并在这些构造函数是要明确写出来的,并不会默认构造,如上代码我们可以优化:
public class Animal{ //实体动物类private int age;private String name;Animal(){ } //无参构造函数Animal(int age){ //带有年龄参数初始化的构造函数this.age = age;}Animal(String name){ //带有名字参数初始化的构造函数this.name = name;}Animal(int age,String name){ //带有年龄和名字参数初始化的构造函数this.age = age;this.name = name;}public void setAge(int age){ //成员变量年龄的修改器if(age<0){age=0;}else{this.age = age;}public int getAge(){ //成员变量年龄的访问器return this.age;}public void setName(String name){ //成员变量名字的修改器this.age = age;}public String getName(){ //成员变量名字的访问器return this.name;}public void sleep(){System.out.println(age+"岁的"+name+"正安静的闭眼睡觉");}
}public class Demo01{ //主类public static void main(String[] args){Animal dog1 = new Animal(); //创建一个内容为null的对象dog1.age = 8;dog1.name = "欢欢";dog1.sleep();Animal dog2 = new Animal(7,"旺旺"); //创建一个对象,并将其姓名和名字进行初始化dog2.sleep();}
}
在上面的代码中我们创建了不同的构造函数,用于不同状态的对象的初始化,但是上面的代码还是不够简化,很多都是this.+成员变量在进行赋值的时初始化,这里我么可以再将代码进行简化。我们知道this关键字指代的是当前的对象或是成员变量,用于区分与传进来的参数。这里我们可以借助this关键字来进行构造函数的调用:
public class Animal{ //实体动物类private int age;private String name;Animal(){ //无参构造函数初始化为空,调用有两个参数的构造函数进行空初始化this(0,null);}Animal(int age){ //调用有两个参数的构造函数进行年龄初始化,名字初始化为空this(age,null);}Animal(String name){ //调用有两个参数的构造函数进行名字初始化,年龄初始化为空this(0,name); }Animal(int age,String name){this.age = age;this.name = name;}public void setAge(int age){ //成员变量年龄的修改器if(age<0){age=0;}else{this.age = age;}public int getAge(){ //成员变量年龄的访问器return this.age;}public void setName(String name){ //成员变量名字的修改器this.age = age;}public String getName(){ //成员变量名字的访问器return this.name;}public void sleep(){System.out.println(age+"岁的"+name+"正安静的闭眼睡觉");}
}public class Demo01{ //主类public static void main(String[] args){Animal dog1 = new Animal();dog1.age = 8;dog1.name = "欢欢";dog1.sleep();Animal dog2 = new Animal(7,"旺旺");dog2.sleep();}
}
构造函数调用构造函数是可以,但是不能产生回调 只能一条线走到底
因此我们可以总结一下构造函数与成员函数的区别:
构造函数没有返回值,成员函数可有可无
构造函数只有在创建对象时调用 ,成员函数在对象创建之后由对象调用
构造函数可以调用构造函数,无非是构造函数中某段代码的封装 不应该作为对象的特有行为 需要priva
构造函数可以调用成员函数,但成员函数不能调用构造函数
对象创建流程
那么有了构造函数之后,来说一下对象的创建流程:
1.javac 编译源代码 生成若干个字节码
2.java 将相关的字节码文件加载进JVM中的方法区
3.JVM在方法区中找main主函数 加载进栈内存中运行
4.主函数进栈
5.创建对象的流程
5.1 在堆内存中开辟空间并分配地址
5.2 对成员变量进行【默认初始化】
5.3 相应的构造函数进栈
5.4 先对成员变量进行【显式初始化】
5.5 再执行构造函数的代码【针对性初始化】
5.6 构造函数出栈 对象创建完毕 返回地址
重载
在上面的代码我们看到,我们声明了很多的构造函数,它们的函数名都和类名相同只是参数的不同,但是在创建对象时,它们却是无歧义的,我们称这样的函数叫重载函数(这里又见面啦,在介绍函数时就已经提到过了),所以不仅成员函数有重载,构造函数也一样有重载。
Animal(){ } //无参构造函数
Animal(int age){ //带有年龄参数初始化的构造函数
this.age = age;
}
Animal(String name){ //带有名字参数初始化的构造函数
this.name = name;
}
Animal(int age,String name){ //带有年龄和名字参数初始化的构造函数
this.age = age;
this.name = name;
}
面向对象——访问器、修改器、构造函数、对象的创建流程相关推荐
- Java-Day12 面向对象的三大特征之封装、继承,单例模式(饿汉式、懒汉式)、方法重写 (覆盖)、注解 (annotation)、super关键字、对象的创建流程超详细
目录 1. 面向对象的三大特征之封装 1.1 封装的含义 1.2 封装的目的 1.3 封装的优点 1.4 封装的实现过程 1.5 拓展知识:JavaBean 2. 面向对象的三大特征之继承 2.1 继 ...
- TObject简要说明-对象的创建流程
Delphi:TObject简要说明-对象的创建流程2009-08-14 08:57TObject = class //创建 constructor Create; //释放 procedure Fr ...
- php页面修改器,读取器/修改器
名字 命名 get(Price)Attr($price,$data) Index文件<?php namespace app\index\controller; use \app\index\mo ...
- java对象的访问定位_2、JVM-Java对象的创建、对象结构、对象访问定位-Go语言中文社区...
目录 记录下来方便个人学习复习 注:根据new的参数在常量池中定位一个类的符号引用 --这句话的意思是:常量池相当于c语言中的指针地址集合,所以就是在常量池中保存new对象的地址,通过地址定位对象在堆 ...
- Java 虚拟机学习笔记 | 类加载过程和对象的创建流程
前言 创建对象是 Java 语言绕不开的话题,那么对象是如何创建出来的呢?我们今天就来聊一聊.对象创建第一步就是检查类是否加载,而类的加载又牵扯到类的加载过程.如果单说对象的创建而绕开类的加载过程,感 ...
- 二十一、PHP框架Laravel学习笔记——模型的访问器和修改器
一.访问器 访问器:就是在获取数据列表时,拦截属性并对属性进行修改的过程: 比如,我们在输出性别时,在性别左右加上括号,或给邮件转换为大写: //访问器,前固定 get,后固定 Attribute,G ...
- laravel获取器和修改器
laravel获取器和修改器 获取器 修改器 获取器 Eloquent 提供了一种便利的方法,可以在获取或设定属性时进行转换.要定义获取器,只要在模型里加入类似 getXxxxAttribute 的方 ...
- Blender基础:阵列修改器、倒角修改器、镜像修改器
1.修改器 修改器Modifier,对模型进行修改 相当于一个函数,类似于y=f(x) 演示: 1.选中一个mesh类型的物体 2.修改器属性,添加修改器|倒角修改器 3.点 实时.打开/关闭修改 ...
- MongoDB 之 $关键字 及 $修改器 $set $inc $push $pull $pop MongoDB - 4
MongoDB中类似这样的关键字有很多, $lt $gt $lte $gte 等等,这么多我们也不方便记,这里我们说说几个比较常见的 一.查询中常见的 等于 大于 小于 大于等于 小于等于 等于 : ...
最新文章
- 【阿里巴巴】CBU技术部招聘
- 今天收拾了个电脑抽屉,发现原来我是个有钱人
- redis value多大会影响性能_事务对MySQL性能有什么影响?有无索引查找对其影响有多大?...
- 最实用的logback讲解(2)—appender
- python newspaper_第74天:Python newspaper 框架
- 【C++】Visual Studio教程(二) - 代码编辑器
- 文件读取ini文件另一种读取办法
- java 画多边形_javascript绘制一个多边形
- c# mysql存储过程 输出参数值_MySQL 存储过程参数用法 in, out, inout
- java获取大乐透开奖_java生成大乐透中奖号码
- 文件在IDEA中已进行Git的Commit操作,使其从暂存区提交到本地仓库,但是未Push到远程仓库,此时进行Pull操作出现代码冲突
- Nginx+Keepalived主备配置
- leetcode—26.求前k大值与前k小值
- 祝贺自己的博客又一个关键字排名上去了
- 第6 章 面向对象的程序设计
- 3dmm计算特征向量,c++读写txt和二进制记录
- php 银联支付-app
- Obsidian关系图谱如何让节点可以手动拖动
- Java项目:博客系统西瓜社区(springboot+mybatis-plus+thymeleaf)
- android前台服务也被杀,android如何让后台服务service不被杀死(设置前台服务)
热门文章
- Altium.Designer.v6.9破解说明
- CVE-2020-1938 幽灵猫( GhostCat ) Tomcat-Ajp协议 任意文件读取/JSP文件包含漏洞分析
- SWT高仿360软件管家一
- 2-1.2.2 Simulink数据类型
- 杭州前端阿里线下聚会(下)
- Opencv Mat矩阵操作
- 基于ssh的高校学生就业系统
- Unity通过Addressable + ILRuntime 实现代码和资产的热更新(案例+图文详情+源码)
- python输入坐标求面积_利用python中的坐标计算多边形面积
- Linux c 停车场管理系统