张小飞的Java之路——第八章

本文介绍了Java中的封装概念,通过实例讲解了私有化封装、构造方法、this关键字、静态成员等核心概念,强调了封装的重要性以及如何通过私有化和提供公共访问方式来隐藏实现细节。
摘要由CSDN通过智能技术生成

写在前面:

视频是什么东西,有看文档精彩吗?

视频是什么东西,有看文档速度快吗?

视频是什么东西,有看文档效率高吗?


清晨。

诸小亮:“师弟,今天开始学习面向对象的第一个特征——封装

张小飞:“放心吧,昨天已经预习了,原来生活中处处都是封装”

“哦?那就倒是说说,什么是封装?”诸小亮问道

封装:隐藏实现的细节,同时对外提供简便操作方式

“能说出这句话,看来你预习的效果不错,不过能否具体举几个例子?”

“嗯…,就拿电脑来说吧,主机箱把主板、硬盘、CPU等封装到一起,只是提供一个按钮,我们就能一键开机”

“不错,这个例子很形象,还有吗?”

“比如:汽车,就因为汽车里面把所有东西都封装好了,所以才能按一下按钮就能启动”

“嗯,很好,预习的效果还是不错的,以后要坚持”诸小亮夸赞道

“嗯嗯,我会的”

“咱们继续说正题:在 Java 中,如何解释封装?”

“这个,我理解的是:只要是在一对儿 { } 中的代码,都可以称之为封装

“哦?为什么这么说呢?”

Java 中方法,把主体代码都封装在 { } 中,外界只需要传参数就行,而不用关心方法中的具体细节

“那 class 呢,它里面的代码也是在 { } 中”

类也是封装,不过封装的是:属性 和 方法

“唉,早就说你聪明了”

“哈哈,我也这样觉得,我觉得都不用你讲了”张小飞嘚瑟的说道

“看你得瑟的,我看要不是你那两蛋坠着你,你丫都要上天了”

“。。。。。。”

1. 私有化封装

诸小亮:“既然你了解了封装,那么咱就聊点儿其他的——私有化封装

张小飞:“好的,您说”

诸小亮:“目前我们是这样设置属性值的:”

在这里插入图片描述

张小飞:“有什么问题吗?”

“没有,但是如果修改一下:”

在这里插入图片描述

“哦,我大概明白您的意思了,设置 50 明显是不符合实际情况的,人哪有50米高”

“没错,50米那是奥特曼。但是这样的代码,仍然可以运行,这是因为:”

  • 目前定义的属性都是可以直接访问的,没办法对他人设置的值进行验证

张小飞:“那应该怎么办呢?”

诸小亮:“很简单,在属性前加上 **private **关键字,把属性私有化,比如:”

在这里插入图片描述

张小飞:“是吗?我来试试”

张小飞:“这样不行啊,编译都失败”
image.png
“这是因为,private 修饰的成员不能直接使用:”

private:权限修饰符,修饰的成员,只能在其类中访问,外界不能访问

“这样的话,如何给对象的属性设置值?”

“只要在 People 类中提供对应的操作方式就行了,比如:(注意查看注释)”

class People{
	//1. private 权限修饰符,它修饰的成员,只能在People类中访问,外界不能访问
	private double height;
	private double weight;
	
	//public 也是权限修饰符,它修饰的成员,外界可以访问
	//2. 对外 set 提供方法,设置height
	public void setHeight(double h){
		if(h>3 || h<0.5){
			//如果身高不对,抛出一个异常,之后程序就不再继续运行(异常,还没学,先用着)
			throw new IllegalArgumentException("设置的身高不对:"+h);
		}
		height = h;
	}
	//3. 对外 get 提供方法,获取height
	public double getHeight(){
		return height;
	}

}

public class Demo{
	public static void main(String[] args){
		People p = new People();
        //4. 利用对象,调用 People 类中对外提供的方法
		p.setHeight(50);
		System.out.println(p.getHeight());
	}
}

张小飞:“代码中的 IllegalArgumentException 是什么东西?”

诸小亮:“是一种异常,不过还没学,先用着”

张小飞“噢,不过我运行了一下代码,提示:”

image.png
诸小亮:“这表示 setHeight 中的异常生效了,提示:设置的值不对”

诸小亮:“另外:在一个class中,属性和方法都可以私有化”

张小飞:“什么意思?”

“。。。,就是说,类中的属性和方法都可以用 private 修饰”

“哦~,这样啊,明白了”

2. 构造方法

张小飞:“什么是构造方法?”

诸小亮:“使用 new 创建对象时,它后面的 People() 就是构造方法”

构造方法:也称为 构造器、构造函数
目的:创建对象 及 初始化成员属性
格式:方法名必需跟类名一致(大小写也要一致)
注意:每个类中都至少有一个构造函数

张小飞:“可是,People 中没有 people() 这个方法啊”

诸小亮:“这就是我们要说的——默认构造方法”

1. 默认构造方法

诸小亮:“目前, People 类中并没有 People() 方法,但仍然可以使用,这是因为:”

  • javac 编译时,如果发现某个类没有构造方法,那么会自动加上一个无参数构造方法

张小飞:“无参数…,构造方法也可以设置参数吗?”

“当然了,否则如何给成员属性初始化呢?我们可以自己写一个有参数的构造方法,比如:”
image.png

张小飞:“师兄,不行啊,编译还失败:”
image.png

诸小亮:“这是因为:我们自己写了一个构造方法,这样默认的无参数构造方法就不能用了
image.png

2. 重载

张小飞:“构造函数也可以重载?”

诸小亮:“可以的,只要参数类型和参数个数不同,任何方法都可以重载,比如:”
image.png

3. 私有构造函数

诸小亮:“构造函数使用 private 修饰符,那么它就是私有构造函数,只能在本类中使用,比如:”
image.png
张小飞:“这个 this 是???”

诸小亮:“this 是一个关键字,this(h) 表示调用 People(double h) 这个方法,另外:”

this(参数),这句代码必须放到第一行

注意:构造函数不能被一般方法调用,上面的eat,run,setHeight 等,都是一般方法

张小飞:“但是,这个 this 具体是什么含义呢?”

诸小亮:“这就是我们接下来要说的内容了”

3. this关键字

诸小亮:“从现在开始我们就使用 idea 了”

张小飞:“太好了, 早就不想用记事本啦”

1. 当前对象

诸小亮:“this:当前对象,也就是说哪个对象调用这个方法,方法中的 this 就是谁,比如:”

class People{
    private double height;
    private double weight;

    private People(double h){
        height = h;
    }
    public People(double h, double w){
        this(h);
        weight = w;
        //1. 构造方法中输出 this 的值
        System.out.println("构造方法中的this对象:"+this);
    }
    public double getHeight(){
        //2. 一般方法中输出 this 的值
        System.out.println("getHeight中的this对象:"+this);
        return height;
    }
}

public class Demo{
    public static void main(String[] args){
        People p = new People(1.8, 200);
        p.getHeight();
        //3. 最后输出 p 的值
        System.out.println(p);
    }
}

诸小亮:“你把上面的代码运行一下,看看上面结果”

张小飞:“结果显示,三个输出都是同一个对象”
image.png
诸小亮:“现在明白为什么 this 是当前对象了吧”

张小飞:“明白,明白”

2. 构造函数中的this

张小飞:“师兄,this(h);这句代码中的 this 也是当前对象吗?”

诸小亮:“是的,this(参数…),表示调用其他的构造函数,不过这只是第一种用法”

“还有第二种用法?”

“是的,不过我们先看个现象,目前构造函数中的参数是这样的:”
image.png
“这样的代码阅读性很差,一般来说,方法的参数名称应该是更有意义,比如:”
image.png

张小飞:“但是这样就跟类中的成员变量重复了, 上面的代码无法给成员变量赋值,我试过”
image.png
结果:
image.png

诸小亮:“你说的不错,这时候就可以用 this,比如:”
image.png
张小飞:“原来如此,我也试试”

3. 一般方法中的 this

诸小亮:“在一般方法也可以使用 this,比如:”
image.png
张小飞:“但是不用 this 也可以正常执行啊”

诸小亮:“所以这种意义不大,工作中为了方便,都会省略this”

4. 静态成员

张小飞:“师兄,‘静态成员’是什么意思?”
诸小亮:“一个类中,有些成员是可以被所有对象共享的,这些成员就被成为静态成员

一个成员变量或者方法,使用 static 修饰符,那么它就是静态成员

1. 静态变量

诸小亮:“静态变量,又称为:类变量,需要 static 修饰符,比如:”
image.png
张小飞:“这个 String…,还没学吧”

“嗯,是还没学,不过很简单,先用着”

“那么这个静态变量跟 heigh、weight 这样的一般变量有什么区别呢?”

“heigh、weight 是对象私有,也就是说每个对象都有这两个属性,而且值各不相同,但是 blood 属于所有对象都共享的一个属性,比如:”

public static void main(String[] args){
    People p1 = new People(1.8, 200);
    People p2 = new People(2.0, 200);
    //1. 分别输出 p1 p2 的 height 属性
    System.out.println(p1.getHeight());
    System.out.println(p2.getHeight());
    //结果:各不相同,因为 height 是对象私有属性

    System.out.println("-----------分割线-----------");

    //2. 利用 p1 对象修改 blood 这个静态变量
    p1.blood = "蓝色";
    System.out.println(p1.blood);
    System.out.println(p2.blood);
    //结果:输出一样,因为 blood 所有对象共有
}

结果:
image.png
张小飞:“原来如此,不过静态属性不需要写 get 和 set 方法吗?”

诸小亮:“一般来说,静态属性不用 get 和 set 方法,直接通过:类名.静态属性
image.png
“这是为什么?”

因为静态变量描述的是整个类,是整个类的属性

2. 静态方法

张小飞:“这个静态方法,也是用 static 修饰符吗?”

诸小亮:“没错,静态方法,又称为:类方法,也需要 static 修饰符,比如:”

//静态方法,使用方式:类名.方法名
public static void test(){
    System.out.println("test是一个静态方法");
}

张小飞:“师兄,我这里报红了?”

image.png

诸小亮:“idea中,报红都是语法问题,表示编译失败,鼠标放上去会有提示信息”

image.png
上图表示:静态方法中,不能直接使用一般的成员变量

张小飞:“原来如此,不过好像可以使用静态变量”

image.png
诸小亮:“是的,所有有句话:静态只能访问静态(静态方法只能放回静态属性和其他静态方法)

3. 内存分布(了解)

诸小亮:“来,我们接着聊一聊内存分布”

张小飞:“是静态方法和静态变量的内存占用吗?”

诸小亮:“没错,不过这个不重要,了解一下就行”

“jvm 在执行代码前,会把class文件加载到内存之中,所以静态成员也会加载到内存中”

“JDK 1.7之前,方法区中存放着 .class对象 和 静态区(存放静态成员),比如:”
image.png
注意:JDK 1.7之前叫方法区,又称:永久代

JDK 1.7时,静态区转移到堆内存
image.png

从 JDK 8 开始,没有方法区了,class放在元数据空间中
image.png

4. 静态代码块

诸小亮:“在一个类中,由 static 开头的代码块,就是静态代码块

张小飞:“是这样吗?”
image.png
诸小亮:“没错,上图红框的就是:静态代码块”

“不过,它有什么用呢?”张小飞问

“作用:**给类进行初始化(比如:静态变量设置值,调用某个静态方法等),**重要的是:”

  • 只要加载类,就会执行对应的 static 代码

示例:
image.png
结果:
image.png

张小飞:“但是我这里就执行了一次,您看看:”
image.png
结果:
image.png
诸小亮:“静态代码块随着类的加载而执行,因为类只是加载一次,所以就执行一次”

张小飞:“原来是这样”

5. 构造代码块(了解)

诸小亮:“来,我们再看——构造代码块,也是放在类作用,不需要任何修饰符,比如:”
image.png
张小飞:“它的作用是什么?”

诸小亮:“用来给所有对象初始化,一般用不上,所以只是了解,比如:”
image.png
结果:
image.png
张小飞:“原来如此,每次创建对象的时候,都会执行构造代码块”

6. 对象的初始化流程

诸小亮:“师弟,看了这么多,下面我们要总结一下:对象的初始化流程”

张小飞:“不就是在构造方法里面初始化对象中的属性么,还有什么流程”

“哪儿那么简单,这么快就忘了?创建对象时,构造代码块先执行啊”

“额…,那它的流程是?”

“稍等一下,咱们有没有说过:显式初始化?”

“这又是啥?”

1. 显示初始化

诸小亮:“我们就先看看——显示初始化:在类中直接给成员变量设置值,比如:”
image.png
张小飞:“就这么简单啊”

诸小亮:“没错,就这么简单,然后修改一下代码,在构造代码块输出 weight 属性”
image.png
结果:
image.png
张小飞:“您是想说:**显示初始化,在构造代码块之前运行 **吗?”

诸小亮:“没错,知道了这个,我们就来看对象的初始化流程”

2. 初始化流程

诸小亮:“先修改代码:”

class People{
    private double height;
    private double weight = 7;//显示初始化
    //构造代码块
    {
        System.out.println("这里是构造代码块,设置weight属性之前。。。。。" + weight);
        this.weight = 100;
        System.out.println("这里是构造代码块,设置weight属性。。。。。" + weight);
    }

    People(double weight){
        System.out.println("这里是构造方法,设置weight属性之前。。。。。" + this.weight);
        this.weight = weight;
        System.out.println("这里是构造方法,设置weight属性之后。。。。。" + this.weight);
    }
}

public class Demo{
    public static void main(String[] args){
        //创建一个对象,看看它的初始化流程
        new People(8);
    }
}

结果:

image.png

“完整的流程是这样的:”

  1. 加载class文件到内存
  2. 通过 new 关键字,在堆内存中开辟空间
  3. 进行默认初始化(double类型默认值是0.0)
  4. 执行构造函数,但在执行函数中的代码前,隐式的干了 3 件事
    1. 执行super():调用父类的构造方法(还没学)
    2. 属性进行显示初始化
    3. 执行构造代码块
  5. 执行构造函数

7. 知识点太多

诸小亮:“你在发什么愣?”

张小飞:“额…,我在想,什么时候能中500万就不用学习了”

“天下没有免费的午餐,有付出才会有汇报,能白白的接到天上掉下来的馅饼只有两种可能”

“哪两种可能?”

“一,脸跟地球一样大。二,馅饼和地球一样大”

“…”


诸小亮:“好了,关于封装就这么多了,你有什么问题吗?”

张小飞:“暂时没有,不过感觉知识点东西很零碎,看都能看懂,就是记不住”

这个没有什么好的方法,只有一个字——练

“怎么练?”

这个简单,我待会儿会给你找一些练习题,做的多了,你就会了

“好的,好的”

“那么,你再回顾一下,一会儿我们稍微总结一下”

半个小时候。

诸小亮:“你能用自己话描述一下什么是封装吗?”

张小飞:“封装:隐藏实现的细节,同时对外提供简便操作方式

  • Java:就是把 方法和属性 放到类中,外界通过 对象.方法 或 类名.方法 的方式调用

“说的不错,那么这有什么好处呢?”

“好处,有这么几个:”

  • 需要调用某个方法,只需要创建对象就行了,不用自己单独实现这个方法
  • 另外,可以对成员变量进行更精确的控制

诸小亮:“一个类主要可以分为几部分?”

张小飞:“主要还是两类:成员变量、成员方法”

  • 成员变量:一般变量、静态变量
  • 成员方法:“构造方法,一般方法,静态方法”

诸小亮:“什么是静态成员?”

张小飞:“由 static 修饰的都属于静态成员,包括:静态方法、静态变量、静态代码块等”

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值