java的类和对象详解

news2025/1/19 7:01:24

一、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来实例化类,创建了对象person1
        person1.name = "白线";//对类的属性进行访问赋值
        person1.age = 15;
        Person person2 = new Person();//通过new来实例化类,创建了对象person2
        person2.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,day
        year = 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,day
        year = 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,day
        this.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,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(){//定义一个构造函数,这个函数不用在主函数里面写明调用,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.coloradmin.cn/o/884474.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

BUUCTF [CISCN2019 华东南赛区]Web11

分析 上面可以看出这是Smarty模板引擎 看到这个ip我们应该想到使用X-Forwarded-For字段 X-Forwarded-For 是一个 HTTP 扩展头部,用来描述请求者的ip 如果后端认为这个是我们的真实ip并使用Smarty来回显那么就可能造成了SSTI 当我们设置了 X-Forwarded-For: {{11}}时…

【EI/SCOPUS检索】2023年第二届光学成像与测量国际会议 (ICOIM2023)

2023年第二届光学成像与量国际会议 (ICOIM2023) 2023 2nd International Conference on Optical Imaging and Measurement 光学成像与测量密切相关且具有广泛的应用,如显微镜、望远镜、传感器等。通常,成像是测量的基础&#xf…

Python - 多线程,多进程中的join和Event及没有使用join和event区别

一. 前言 在Python的多线程和多进程编程中,join() 和 Event 都是用来控制线程或进程之间的同步关系的工具,它们的作用类似,但还是有一些区别。 二. 概念 1. join() join() 方法是线程或进程实例的一个方法,用于阻塞当前调用线…

6. 自定义异常 全局异常处理 测试异常处理

目录 1. 自定义异常 2. 全局异常处理 3. 测试异常处理 1. 自定义异常 创建⼀个异常类,加入状态码与状态描述属性。 凡是业务代码中出现的可预期的异常,统一抛出 ApplicationException public class ApplicationException extends RuntimeException{//…

[Java优选系列第1弹]如何优化Java三层架构开发效率?三个实用技巧分享

💞优选系列制作漫长,每篇一经写出不再创作,均是呕心沥血制作,且看且珍惜💫 一直在等你,你终于来啦💖 绿色代表解释说明 黄色代表重点 红色代表精髓 Java三层架构…

qt 安 装

之后版本都是在线安装 下载地址 Index of /archive/online_installers 只用这三个即可,其他不用管默认

操作系统-笔记-第一章-操作系统的概念

目录 一、第一章——操作系统的概念 1、操作系统的概念、功能 (1)层次 (2)总结 2、操作系统的特征(4个) (1)并发与并行 (2)共享与互斥 (3…

【网络基础实战之路】基于MPLS-VPN技术实现两个私网间互通的实战详解

系列文章传送门: 【网络基础实战之路】设计网络划分的实战详解 【网络基础实战之路】一文弄懂TCP的三次握手与四次断开 【网络基础实战之路】基于MGRE多点协议的实战详解 【网络基础实战之路】基于OSPF协议建立两个MGRE网络的实验详解 【网络基础实战之路】基于…

主流的嵌入式微处理器

目前主流的嵌入式微处理器系列有: ARM系列 MIPS系列 PowerPC系列 Super H系列 一、MPC/PPC系列 PowerPC(简称PPC),其基本设计源自IBM的POWER.1991年,APPLE(苹果电脑)、IBM、Motorola(摩托罗拉)组成的AIM联盟发展出Power微处理器…

Windows Server 2019设置使用照片查看器查看图片的设置方法

1、使用winR快捷键快速打开运行,输入regedit打开注册表: 2、在注册表中找到:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Photo Viewer\Capabilities\FileAssociations 3、在右侧新建字符串项: 4、例如新建两项.jpg 和.png值…

eNSP:mpls综合实验

实验要求&#xff1a; 拓扑图 路由、IP配置 r1: <Huawei>sys [Huawei]sys r1 [r1]int lo0 [r1-LoopBack0]ip add 192.168.1.1 24 [r1-LoopBack0]int g 0/0/0 [r1-GigabitEthernet0/0/0]ip add 192.168.2.1 30[r1]ip route-static 192.168.3.0 30 192.168.2.2 [r1]ip rou…

生信豆芽菜-TIP预测免疫

网址&#xff1a;http://www.sxdyc.com/immuneTipScore 一、TIP预测免疫的介绍 TIP&#xff08;Tumor Immune Prediction&#xff09;是一种用于预测肿瘤免疫状态的计算方法。它通过分析基因表达数据来推断肿瘤样本中的免疫细胞浸润情况和免疫反应程度。 TIP的基本原理如下&…

HTML中的字符串转义

为什么要转义&#xff1f; 转义可以防止 xss 攻击。接下来&#xff0c;我们来看一下如何转义。 HTML Sanitizer API Sanitizer 是浏览器自带的转义方法&#xff0c;在2021年初被提出&#xff0c;兼容性问题很大。 列举几个常用的 API&#xff1a; const $div document.qu…

RTC实验

一、RTC简介 RTC(Real Time Clock)即实时时钟&#xff0c;它是一个可以为系统提供精确的时间基准的元器件&#xff0c;RTC一般采用精度较高的晶振作为时钟源&#xff0c;有些RTC为了在主电源掉电时还可以工作&#xff0c;需要外加电池供电BCD码&#xff0c;四位二进制表示一位…

Cesium--一些实验过程中的效果记录

1.一种反射效果&#xff1a; 片元着色器代码 fragmentShaderSource:in vec3 v_positionMC;in vec3 v_positionEC;in vec2 v_st;void main(){czm_materialInput materialInput;vec3 normalEC normalize(czm_normal3D * czm_geodeticSurfaceNormal(v_positionMC, vec3(0.0), ve…

从零开始,外贸邮件营销如何做?

邮件营销是外贸企业开发新用户和维系老客户非常有效的方法之一&#xff0c;因其操作方便快捷、成本低廉且精准投放的特性&#xff0c;已成为外贸行业的必备营销手段。但如何才能利用好邮件营销&#xff0c;让邮件营销的作用发挥到最大呢&#xff1f;今天U-Mail李工就跟大家分享…

Neo4j的使用场景_以及Windows版Neo4j Community Server安装_欺诈检测_推荐_知识图谱---Neo4j图数据库工作笔记0003

可以看到使用场景,比如欺诈检测, 要建立图谱,才能进行,欺诈人员检测 可以看到图谱的各种应用场景 然后推荐引擎也需要,可以看到 在金融,旅行,求职招聘,保健,服务,媒体娱乐,都可以进行推荐 然后还有知识图谱 身份访问管理,这里,可以进行安全管理,可以挖掘出潜在关系,分析, 某…

【Nacos2.24持久化到Postgres数据库适配——详细版】

Nacos2.24持久化到Postgres数据库适配 前言步骤拉取源码添加依赖修改源码编译打包修改配置测试运行 参考 前言 公司基于springboot实现了一套单体框架&#xff0c;目前我负责搭建SpringCloud微服务框架&#xff0c;需要用到nacos&#xff0c;但是由于公司特殊性&#xff0c;na…

IntelliJ IDEA 2023.1 windows找不到文件‘chrome’

异常效果图 1、【打开设置】 2、 搜索【web brow】 3、 在桌面上找到常用的浏览器 例如我的edge-【右击】-【打开文件位置】-【找到目标】-【双击】-【ctrla全选】-【ctrlc复制】 4、修改正确的路径如下&#xff1a; 5、再次尝试打开【main.jsp】 浏览器正常显示&#xff01;…