java的类和对象详解

一、java是面向对象的编程语言

首先一般的编程语言有两种,一种是面向对象,一种是面向过程。前者更加关注代码中对象与对象之间关系与协作,而后者更加注重代码的执行过程。
举个例子
在这里插入图片描述传统的方式:注重的是洗衣服的过程,少了一个环节可能都不行。而且不同衣服洗的方式,时间长度,拧干方式都不同,处理起来就比较麻烦。如果将来要洗鞋子,那就是另一种放方式。
按照该种方式来写代码,将来扩展或者维护起来会比较麻烦。
而现代洗衣服大家都用洗衣机,我们将洗衣服的步骤交给了洗衣机,我们更关心的是我们与洗衣机之间的交互的过程。
在这里插入图片描述以面向对象方式来进行处理,就不关注洗衣服的过程,具体洗衣机是怎么来洗衣服,如何来甩干的,用户不用去关心,只需要将衣服放进洗衣机,倒入洗衣粉,启动开关即可,通过对象之间的交互来完成的。

面相对象程序设计关注的是对象,而对象是现实生活中的实体,比如:洗衣机。但是洗衣机计算机并不认识,需要开发人员告诉给计算机什么是洗衣机。
比如
在这里插入图片描述
上图就是对洗衣机简单的描述,该过程称为对洗衣机对象(实体)进行抽象(对一个复杂事物的重新认知),但是这些简化的抽象结果计算机也不能识别,开发人员可以采用某种面相对象的编程语言来进行描述,比如:Java语言。

二、类的定义

上述对于洗衣机对象的一些属性的描述就是在定义一个类
类是用来对一个实体(对象)来进行描述的,主要描述该实体(对象)具有哪些属性(外观尺寸等),哪些功能(用来干啥),描述完成后计算机就可以识别了。

java中定义类时需要用到class关键字,具体语法如下

//创建类
classClassName{ field;    //字段(属性)或者成员变量  method;    //行为或者成员方法
}

类中包含的内容称为类的成员。属性主要是用来描述类的,称之为类的成员属性或者类成员变量。方法主要说明类具有哪些功能,称为类的成员方法

比如说定义人这样一个类(在Person.java文件里)

public class person{public String name;//定义一个名字属性public int age;//定义一个年龄属性public void eat(){System.out.println("干饭!");}public void sleep(){//定义了一个睡觉行为(方法)System.out.println("睡觉");}
}

采用Java语言将洗衣机类在计算机中定义完成,经过javac编译之后形成.class文件,在JVM的基础上计算机就可以识别了。

注意:
一般来说一个java文件只写一个类(只能有一个public类)。
public修饰的类必须要和文件名相同。比如创建时的文件名是helloworld.java文件,那么这个文件的类在创建的时候就是public class helloworld{}
类的命名采用大驼峰定义的风格
成员前写法统一为public
不要轻易去修改public修饰的类的名称,如果要修改文件名,通过开发工具修改
在这里插入图片描述

2.1类的实例化

定义了一个类,就相当于在计算机中定义了一种新的类型,与int,double类似,只不过int和double是java语言自带的内置类型,而类是用户自定义了一个新的类型,比如上述的:Person类。有了这些自定义的类型之后,就可以使用这些类来定义实例(或者称为对象)。
类的实例化需要通关键字new,并且类实例化化后就是我们需要的对象了。
比如在helloworld.java 文件中

public class helloworld {public static void main(String[] args) {Person person1 = new Person();//通过new来实例化类,创建了对象person1person1.name = "白线";//对类的属性进行访问赋值person1.age = 15;Person person2 = new Person();//通过new来实例化类,创建了对象person2person2.name = "黑线";//对类的属性进行访问赋值person2.age = 16;}
}

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

2.2类的存储

再来说明一下类创建后分别是存在哪一片内存区域的

首先类在创建后只是一些信息,存在JDK内存的方法区,然后在实例化时,执行Person person1 = new Person();,会在栈区创建一个局部变量person1(又叫对象名),这个变量的类型是Person类型(其实就是结构体类型)在堆区开辟一片存储空间,这片存储空间的大小就是这个类定义的时候的大小。然后person1里面存的就是堆中那片区域的地址。在java 中这叫做该引用指向这个对象。person1.name = "白线"; person1.age = 15;就是在堆区里面对name属性(成员)赋值白线,对age属性(成员)赋值15。后面person2也是一样。

实际是我们在创建一个字符串并给字符串赋值的时候,其实底层也是类的实例化

public class helloworld {public static void main(String[] args) {String str1 = "abcde";String str2 = new String("abcde");//这两个是一样的}
}

此外,还有一点要说明,在定义类的时候,成员变量是并没有赋值的,但是java并么有报错,这是因为编译器给了他们默认的值,如果是引用类型默认为null,如果是int float long等默认是0,boolean的默认值是false,char 的默认值是’\u0000’.

2.3this引用

SE.09.00.28.55
我们先来 看一个代码

public class Day_Date {public int year;public int month;public int day;//定义三个成员变量public  void set_Date(int y,int m,int d){year = y;month = m;day = d;}public void print(){System.out.println(year+"年"+month+"月"+day+"日");}public static void main(String[] args) {Day_Date date1  = new Day_Date();date1.set_Date(2022,4,22);date1.print();Day_Date date2  = new Day_Date();date2.set_Date(2022,4,22);date2.print();Day_Date date3  = new Day_Date();date3.set_Date(2022,4,22);date3.print();}
}

结果是
在这里插入图片描述
但是如果我现在将set_date中的形参改为year month day 这时会出现 什么情况呢?

public class Day_Date {public int year;public int month;public int day;//定义三个成员变量public  void set_Date(int year,int month,int day){//形参变量名变成year,month,dayyear = year;month = month;day = day;}public void print(){System.out.println(year+"年"+month+"月"+day+"日");}public static void main(String[] args) {Day_Date date1  = new Day_Date();date1.set_Date(2022,4,22);date1.print();Day_Date date2  = new Day_Date();date2.set_Date(2022,4,22);date2.print();Day_Date date3  = new Day_Date();date3.set_Date(2022,4,22);date3.print();}
}

在这里插入图片描述
此时会发现,打印出来全是0,这是因为

public  void set_Date(int year,int month,int day){//形参变量名变成year,month,dayyear = year;month = month;day = day;}

编译器没法分清year,month ,day到底是什么了,是形参还是成员变量。

同时我们要知道这个代码的执行顺序是现在方法区里创建好Day_Date类,然后在栈区创建第一个对象(引用)date1并指向堆区里面的存储空间,按里面有初始化过的成员变量。但是我们在调用成员方法set_Date的时候,我们没有传任何有关于第一个对象的引用或者是地址,编译器怎么知道第一个set_Date是里面传输的实参在第一个对象的堆区空间里。后面的对象调用成员方法也是这样。

这是因为编译器省略了一个东西就是this引用

this引用指向当前对象(成员方法运行时调用该成员方法的对象),在成员方法中所有成员变量的操作,都是通过该引用去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。

所以我们写代码时,遇到成员方法需要用到调用成员变量时,最好在成员变量前加上this.这个更好理解

public class Day_Date {public int year;public int month;public int day;//定义三个成员变量public  void set_Date(int year,int month,int day){//形参变量名变成year,month,daythis.year = year;this.month = month;this.day = day;}public void print(){System.out.println(this.year+"年"+this.month+"月"+this.day+"日");}public static void main(String[] args) {Day_Date date1  = new Day_Date();date1.set_Date(2022,4,22);date1.print();Day_Date date2  = new Day_Date();date2.set_Date(2022,4,22);date2.print();Day_Date date3  = new Day_Date();date3.set_Date(2022,4,22);date3.print();}
}

至此我们在梳理一下这个内存的过程,创建类的过程就不说了,在执行Day_Date date1 = new Day_Date();时,系统会在栈区创建一个局部变量(或者叫对象)命名为data1,在堆区开辟一块存储空间用于存放输入data1对象所有变量,data1是引用类型,他存的是一个地址,指向的就是这块堆区。然后开始执行 date1.set_Date(2022,4,22);调用方法区的方法,然后将2022,4,22以及data1所在的堆区地址(也就是this这个引用类型)作为实参传入set_Date方法中,执行ste_Date方法。进入这个方法后,编译器区分俩个year的方法是编译器知道等号左边的year的是被this这个引用所指向的,也就是data1这个成员的year,而等号右边的year是临时开辟的形参,用于接收2022的year。

下面这个图就很好的说明了这一点

publicstaticvoidmain(String[]args){Date d=newDate();d.setDay(2020,9,15);d.printDate();
}

在这里插入图片描述注意:

  1. this的类型:对应类类型引用,即哪个对象调用就是哪个对象的引用类
  2. this只能在"成员方法"中使用,同时不能用于静态的成员方法(这个后面会说)
  3. 在"成员方法"中,this只能引用当前对象,不能再引用其他对象
  4. this是“成员方法”第一个隐藏的参数,编译器会自动传递,在成员方法执行时,编译器会负责将调用成员方法类也是可以通过编译的
    在这里插入图片描述

2.4构造方法

构造方法是java中一类比较特殊的方法。
我们在上面的代码中初始化用的是一个set_Date的成员方法。但是要知道我要是每次生成一个对象都要调用一个成员方法,这多麻烦啊!所以有没有简单一点的的方法呢!答案是有的,就是构造方法

构造方法(也称为构造器)是一个特殊的成员方法,名字必须与类名相同,在创建对象时,由编译器自动调用,并且在整个对象的生命周期内只调用一次
具体来说
在执行Day_Date date1 = new Day_Date();时,也就是实例化对象时,就会调用data1对象的构造方法。

构造方法非常特殊,没有返回值,(不是返回值为void,单纯就是 没有返回值,定义的时候也不写)方法名也必须和类名一致,参数列表可有可没有。

public class Day_Date {public int year;public int month;public int day;//定义三个成员变量public  void set_Date(int year,int month,int day){//形参变量名变成year,month,daythis.year = year;this.month = month;this.day = day;}public void print(){System.out.println(this.year+"年"+this.month+"月"+this.day+"日");}public Day_Date(){//定义一个构造函数,这个函数不用在主函数里面写明调用,java也会调用,// 如果你不写构造函数,java也会直接提供一个不带任何参数和函数体的构造方法System.out.println("这是构造函数!");}public static void main(String[] args) {Day_Date date1  = new Day_Date();date1.set_Date(2022,4,22);date1.print();}
}

构造方法的特性

  1. 名字必须与类名相同
  2. 没有返回值类型,设置为void也不行
  3. 创建对象时由编译器自动调用,并且在对象的生命周期内只调用一次(相当于人的出生,每个人只能出生一次)
  4. 构造方法可以重载(用户根据自己的需求提供不同参数的构造方法)

所以我们初始化对象,完全可以从构造方法的角度,直接传参就像下面这个例子一样

public class Day_Date {public int year;public int month;public int day;//定义三个成员变量//    public  void set_Date(int year,int month,int day){//形参变量名变成year,month,day
//        this.year = year;
//        this.month = month;
//        this.day = day;
//    }public void print(){System.out.println(this.year+"年"+this.month+"月"+this.day+"日");}public Day_Date(int year,int month,int day){//定义一个构造函数,这个函数不用在主函数里面写明调用,java也会调用,// 如果你不写构造函数,java也会直接提供一个不带任何参数和函数体的构造方法this.year = year;this.month = month;this.day = day;System.out.println("这是构造函数!");}public static void main(String[] args) {Day_Date date1  = new Day_Date(2022,4,22);//构造方法定义了形参和函数体后,直接赋值初始化就可以。date1.print();}
}

一定要注意,只要我们自己写了构造方法,那么java就会执行我们写的构造方法,只有我们没有写任何的构造方法时,java才会执行一个没有任何参数、返回值、函数体的构造方法。

这里有个问题需要解释一下
我们在调用构造函数是使用里this这个引用类型,但是this这个引用类型指向的是这个对象,但是我调用构造函数正是为了生成这个对象啊!这好像变成了我为了生成这个对象而引用了这个对象?
实际上,构造方法的作用就是对对象中的成员进行初始化,并不负责给对象开辟空间。也就是说对象的生成分为两步,第一步是开辟内存空间,这个是new来完成的,内存空间一旦开辟了就可以引用了,而第二步才是调用构造方法进行初始化,实际就是对内存空间内的成员变量进行赋值。

构造方法中,可以通过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;}
}

这里背后的逻辑在主函数初始化对象先调用了无参的函数构造方法,然后执行this(1900, 1, 1);此时系统会自动调用另外一个重载函数:带有三个参数的构造方法
从而完成初始化。
但是需要注意的是
1.必须放到this(1900, 1, 1);第一行
2.只能在构造方法内部用
3.不能形成环

public Date(){
this(1900,1,1);
}
public Date(int year, int month, int day) {
this();
}
/*
无参构造器调用三个参数的构造器,而三个参数构造器有调用无参的构造器,形成构造器的递归调用
编译报错:Error:(19, 12) java: 递归构造器调用
*/

2.5 默认初始化

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) {
// 此处a没有初始化,编译时报错:
// Error:(24, 28) java: 可能尚未初始化变量a
// int a;
// System.out.println(a);
Date d = new Date(2021,6,9);
}
}

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

  1. 检测对象对应的类是否加载了,如果没有加载则加载

  2. 为对象分配内存空间

  3. 处理并发安全问题
    比如:多个线程同时申请对象,JVM要保证给对象分配的空间不冲突

  4. 初始化所分配的空间
    即:对象空间被申请好之后,对象中包含的成员已经设置好了初始值,比如:
    在这里插入图片描述

  5. 设置对象头信息(关于对象内存模型后面会介绍)

  6. 调用构造方法,给对象中各个成员赋值

在说完构造方法后,我们来说一说面向对象程序的三大特性


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/99465.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

引领行业高质量发展|云畅科技参编《低代码开发平台创新发展路线图(2023)》

8月8日-9日,中国电子技术标准化研究院于北京顺利召开《低代码开发平台创新发展路线图(2023)》封闭编制会。云畅科技、浪潮、百度、广域铭岛等来自低代码开发平台解决方案供应商、用户方、科研院所等近30家相关单位的40余位专家参与了现场编制…

CentOS 8.5修改安装包镜像源

1 备份原配置 cd /etc/yum.repos.d mkdir backup mv *.repo backup/2 下载镜像源 2.1 使用wget下载 wget http://mirrors.aliyun.com/repo/Centos-8.repo2.2 使用curl下载 我是安装的最小版本的系统,默认只有curl curl使用方法:https://www.ruanyife…

【分布式共识】Multi-Paxos 算法思想

上一篇文章主要聊了Basic Paxos算法,而Multi-Paxos并不是一种算法,是一种算法思想。具体就是Basic Paxos解决的是对一个值达成共识。而后者是通过执行多次的Basic Paxos算法就多个值达成一致。具体的落地实现有Raft。 Muti-Paxos的问题 在Basic Paxos中…

14、缓存预热+缓存雪崩+缓存击穿+缓存穿透

缓存预热缓存雪崩缓存击穿缓存穿透 ● 缓存预热、雪崩、穿透、击穿分别是什么?你遇到过那几个情况? ● 缓存预热你是怎么做到的? ● 如何避免或者减少缓存雪崩? ● 穿透和击穿有什么区别?它两一个意思还是截然不同&am…

CW4-6A-S、CW4-10A-S、CW4-20A-S、CW4-30A-S螺栓式滤波器

CW3L2-3A-S、CW3L2-6A-S、CW3L2-10A-S、CW3L2-20A-S CW3-3A-S、CW3-6A-S、CW3-10A-S、CW3-20A-S、CW3-30A-S CW4EL2-3A-S、CW4EL2-6A-S、CW4EL2-10A-SCW4EL2-20A-S、CW4EL2-30A-S CW4E-3A-S、CW4E-6A-S、CW4E-10A-S、CW4E-20A-S、CW4E-30A-S CW4E-40A-S(001)、CW4E-50A-S(0…

论文导读 | Operation ResearchManagement Science近期文章精选

推文作者:周梓渊 编者按 如何准确估计和预测债券风险溢价?债券保险是否为市政债券的发行人提供价值?我们如何界定社会福利政策对小部分群体的负面影响?垄断零售商的线上线下定价有何诀窍?顶刊中的行为理论真的对应现实…

排名前 6 位的数学编程语言

0 说明 任何对数学感兴趣或计划学习数学的人,都应该至少对编程语言有一定的流利程度。您不仅会更有就业能力,还可以更深入地理解和探索数学。那么你应该学习什么语言呢? 1.python 对于任何正在学习数学的人来说,Python都是一门很棒…

win10系统docker创建ubuntu容器解决开发环境问题

一、win10系统使用docker的原因 最近啊,在学习人工智能-深度学习,用的win10系统进行开发,老是出现一些莫名其妙的问题,无法解决,每天都在为环境问题搞得伤透了脑筋。 说到底还是要使用Linux系统进行开发比较合适。 …

跟随角色镜头时,解决地图黑线/白线缝隙的三种方案

下面一共三个解决方案,这里我推荐第二个方案解决,因为够快速和简单。 现象: 解决方案一: 参考【Unity2D】去除地图中的黑线_unity选中后有线_香菇CST的博客-CSDN博客,博主解释是因为抗锯齿采样导致的问题。 具体到这…

【后端】Core框架版本和发布时间以及.net 6.0启动文件的结构

2023年,第35周,第1篇文章。给自己一个目标,然后坚持总会有收货,不信你试试! .NET Core 是一个跨平台的开源框架,用于构建现代化的应用程序。它在不同版本中有一些重要的区别和发布时间 目录 一、Core版本和…

【OpenVINOSharp】在英特尔® 开发者套件爱克斯开发板使用OpenVinoSharp部署Yolov8模型

在英特尔 开发者套件爱克斯开发板使用OpenVinoSharp部署Yolov8模型 一、英特尔开发套件 AIxBoard 介绍1. 产品定位2. 产品参数3. AI推理单元 二、配置 .NET 环境1. 添加 Microsoft 包存储库2. 安装 SDK3. 测试安装4. 测试控制台项目 三、安装 OpenVINO Runtime1. 下载 OpenVINO…

Linux的热拔插UDEV机制

文章目录 UDEV简介守护进程基本特点 守护进程和后台进程的区别开发守护进程结束 UDEV简介 udev是一个设备管理工具,udev以守护进程的形式运行,通过侦听内核发出来的uevent来管理/dev目录下的设备文件。 udev在用户空间运行,而不在内核空间 …

css 文字排版-平铺

序: 1、表格的宽度要有!!!!! 2、容器不能是display:inline 3、扩展---》node全栈框架 代码 text-align-last: justify; width: 70px; display: inline-block; 主要是用于表单左侧文字排序!

resource doesn‘t have a corresponding Go package.

resource doesnt have a corresponding Go package. GO这个鬼东西不能直接放src下。 ************ Building Go project: ProjectGoTest ************with GOPATH: D:\Go;D:\eclipse-jee-oxygen-2-win32-x86_64\workspace\ProjectGoTest >> Running: D:\Go\bin\go.exe …

探索人工智能 | 模型训练 使用算法和数据对机器学习模型进行参数调整和优化

前言 模型训练是指使用算法和数据对机器学习模型进行参数调整和优化的过程。模型训练一般包含以下步骤:数据收集、数据预处理、模型选择、模型训练、模型评估、超参数调优、模型部署、持续优化。 文章目录 前言数据收集数据预处理模型选择模型训练模型评估超参数调…

PSP - 基于扩散生成模型预测蛋白质结构 EigenFold 算法与环境配置

欢迎关注我的CSDN:https://spike.blog.csdn.net/ 本文地址:https://spike.blog.csdn.net/article/details/132357976 Paper: EigenFold: Generative Protein Structure Prediction with Diffusion Models EigenFold 是用于蛋白质结构预测的扩散生成模型…

卷积神经网络——上篇【深度学习】【PyTorch】

文章目录 5、卷积神经网络5.1、卷积5.1.1、理论部分5.1.2、代码实现5.1.3、边缘检测 5.2、填充和步幅5.2.1、理论部分5.2.2、代码实现 5.3、多输入多输出通道5.3.1、理论部分5.3.2、代码实现 5.4、池化层 | 汇聚层5.4.1、理论部分5.4.2、代码实现 5、卷积神经网络 5.1、卷积 …

文件同步工具rsync

文章目录 作用特性安装命令服务端启动增加安全认证及免密登录 实时推送源服务器配置结合inotify实现实时推送 参数详解 学些过程中遇到的问题 作用 rsync是linux系统下的数据镜像备份工具。使用快速增量备份工具Remote Sync可以远程同步,支持本地复制,或…

基于Spring Boot的餐厅订餐网站的设计与实现(Java+spring boot+MySQL)

获取源码或者论文请私信博主 演示视频: 基于Spring Boot的餐厅订餐网站的设计与实现(Javaspring bootMySQL) 使用技术: 前端:html css javascript jQuery ajax thymeleaf 微信小程序 后端:Java springbo…

opencv进阶02-在图像上绘制多种几何图形

OpenCV 提供了方便的绘图功能,使用其中的绘图函数可以绘制直线、矩形、圆、椭圆等多种几何图形,还能在图像中的指定位置添加文字说明。 OpenCV 提供了绘制直线的函数 cv2.line()、绘制矩形的函数 cv2.rectangle()、绘制圆的函数cv2.circle()、绘制椭圆的…