10.0_[Java 封装]-抽象/封装/构造/重载/ static 修饰符

本文深入探讨了面向对象编程的核心概念,包括类与对象的关系、使用面向对象的原因、this关键字的用途、类的成员、构造方法及命名规范。通过创建华为和小米手机类,并模拟购买流程,展示了如何通过对象实现功能。此外,还讨论了常量的使用、构造方法的重载以及静态修饰符的作用,强调了封装在类设计中的重要性。
摘要由CSDN通过智能技术生成

##################################################

目录

抽象编程

面向对象设计的过程

类和对象的关系

为什么使用面向对象

this 关键字

类的成员

构造方法及调用

命名规范

通过创建对象实现购买手机等功能

创建类和对象

创建华为类

创建小米类

创建顾客购买类

测试效果

访问其她类中的常量

需求以及升级

升级前版本

升级后版本

构造方法及其重载

初始化对象时赋值

什么是构造方法

如何构造一个无参方法

调试跟踪构造方法的执行过程

设置断点

开始调试

方法重载的判断依据

带参构造方法和构造方法的重载

添加带参构造方法

有参构造存在则必须存在无参构造

构造方法没有返回值类型

自动销毁创建的对象

static 修饰符

static 的作用

使用 static 修饰属性和代码块

静态常量

封装类

何谓封装

通过公开方法访问被封装的人类

通过构造方法访问被封装的类成员属性

this 关键字的其她用法

this 调用成员变量

this 调用成员方法

this 调用重载的构造方法


##################################################

抽象编程

——————————

面向对象设计的过程

        学习面向对象理解其中的概念只是前提 灵活应用才是目的:

从现实世界中抽象出程序开发中的类 实现从现实到虚拟的转化

然后对抽象出的类进行操作 实现对现实世界中行为的模拟

再对抽象出的类进行优化 通过封装隐藏类的内部信息以提高安全性

        过程就是:

发现类
发现类的属性
发现类的方法

        面向对象设计的过程就是抽象的过程 由现实世界中的对象抽象出软件开发中的对象

——————————

类和对象的关系

        类/Class 和 对象/Object 是面向对象的中的两个核心概念

        类是对某一类事物的描述 是抽象的、概念上的定义 而对象却是实际存在的、具体的事物个体

        类和对象就好比模具和铸件的关系或图纸和设计出来的实物的关系

        我们可以由一个类创建多个对象

——————————

为什么使用面向对象

        现实世界就是面向对象的 任何存在的事物都可以看作对象

        而事物都有自己的属性和行为 各个事物之间还会发生各种联系

        面向对象就是采用现实模拟的方法设计和开发程序 实现了虚拟世界和现实世界的一致性 符合人们的思维习惯 同时又代码重用性高、可靠性高等优点,大大提高了软件尤其是大型软件的设计和开发效率

面向过程和核心是函数 以功能为中心 实现了函数级别的代码重用

面向对象的核心是封装了属性和方法的类 以数据为中心 实现了类级别的代码重用

面向对象因为采用了类 所以具有继承和多态特性 可以进一步重用代码和简化编程
而面向过程中没有继承和多态特性

——————————

this 关键字

        this 关键字通常指当前对象的引用

指定调用的是当前对象的成员

        用法:

this.当前对象的属性
this.当前对象的方法

——————————

类的成员

        类的属性和行为又称为

属性        成员变量或者成员属性

行为        成员方法

        统称为类的成员 除此之外还包括构造方法、代码块等

——————————

构造方法及调用

        我们通过构造方法来创建对象 语法:

类名 对象名 = new 类名();

        此后我们通过该对象名来访问属性和方法:

    访问属性:
对象名.属性名

    访问方法:
对象名.方法名

——————————

命名规范

        类名由一个或几个单词组成 每个单词的第一个字母大写

        属性名和方法名由一个或几个单词组成 第一个单词首字母小写 其她单词首字母大写

        常量名由一个或几个单词组成 所有字母大写

##################################################

通过创建对象实现购买手机等功能

——————————

创建类和对象

%%%%%

创建华为类

        华为手机类 Huawei.java code:

public class Huawei {
/* 华为类 */

    /* 属性 */
    String xh = "num.1";    // 默认手机型号
    int dl = 100;    // 电量默认 100

    /* 行为 */
    public void print() {
    // 输出手机信息

        System.out.printf ( "华为手机型号 [%s]", this.xh );
        System.out.printf ( "华为手机电量 [%d]", this.dl );
    }
}

Huawei.java

        以上是华为类的代码

%%%%%

创建小米类

        小米手机类 Xiaomi.java code:

public class Xiaomi {
/* 小米类 */

    String co = "红米";    // 默认手机颜色
    int dl = 99;    // 电量默认 99

    public void print() {
    // 输出手机信息

        System.out.printf ( "小米手机颜色 [%s]", this.co );
        System.out.printf ( "小米手机电量 [%d]", this.dl );
    }
}

小米类

        以上是小米类的代码

%%%%%

创建顾客购买类

        现在已经有两个手机类了 那么如何购买呢?

        新建一个测试类来创建具体的手机对象并输出信息

        Test.java code:

import java.util.Scanner;

public class Test {
/* 测试类 */

    public static void main (String [] args) {

        Scanner in = new Scanner (System.in);

        System.out.println ( "欢迎您来到二手店!" );
        System.out.print ( "请输入手机价格\n\t1000.小米 2000.华为\n<<< " );
        switch ( in.nextInt() ) {

            case 1000:
            /* 如果千元机就是小米 */

                    String co = "红米";
                    System.out.print ( "请选择手机颜色\n\t1.红米\n\t2.紫米\n<<< " );
                    if ( in.nextInt() == 1 )
                        ;
                    else
                        co = "紫米";

                    /* 创建小米对象并赋值 */
                    Xiaomi xm = new Xiaomi();
                    xm.co = co;

                    /* 输出小米信息 */
                    xm.print ();
                break;

            case 2000:
            /* 如果是两千 则为华为 */

                    String xh = null;    // 初值为空
                    System.out.print ( "请选择手机型号\n\t1 为 num.1\n\t2 为 num.2\n<<< " );
                    if ( in.nextInt () == 1 )
                        xh = "num.1";
                    else
                        xh = "num.2";

                    Huawei hw = new Huawei();
                    hw.xh = xh;
                    hw.print();
                break;
        }
    }
}

测试类

        如果要实现需求只有类是不行的 还需要创建对应类的实例 即对象

        以上代码根据输入的数据创建了不同的手机对象并输出相应的信息

%%%%%

测试效果

        Demo:

欢迎您来到二手店!
请输入手机价格
	1000.小米 2000.华为
<<< 1000
请选择手机颜色
	1.红米
	2.紫米
<<< 1
小米手机颜色 [红米]小米手机电量 [99]
欢迎您来到二手店!
请输入手机价格
	1000.小米 2000.华为
<<< 1000
请选择手机颜色
	1.红米
	2.紫米
<<< 2
小米手机颜色 [紫米]小米手机电量 [99]
欢迎您来到二手店!
请输入手机价格
	1000.小米 2000.华为
<<< 2000
请选择手机型号
	1 为 num.1
	2 为 num.2
<<< 1
华为手机型号 [num.1]华为手机电量 [100]
欢迎您来到二手店!
请输入手机价格
	1000.小米 2000.华为
<<< 2000
请选择手机型号
	1 为 num.1
	2 为 num.2
<<< 2
华为手机型号 [num.2]华为手机电量 [100]

##################################################

访问其她类中的常量

——————————

需求以及升级

        如果以人类创建了很多人对象 她们的性别分别为 靓仔/靓妹

        但是后来需求变化 规定人的性别只能为 男或女

        那么此时已经创建的每个人对象的性别都需要做相应修改 修改代码量很大 而且代码可能分散在多个文件中 不易查找

        有没有更好的解决办法呢?

        我们可以使用常量存储

用常量来存储不变的数据

        常量在程序运行过程中不会发生变化 只能被引用 不能被重新赋值

        也就是只能在定义时修改其值

        Java 中使用 final 关键字修饰常量并且常量名一般都大写

        final 除了可以用来修饰属性之外还可以修饰方法和类

        如果以后需要修改代码时 只需要修改常量即可 不管创建了多少个对象 只需要修改定义的常量即可!非常方便

——————————

升级前版本

        人类 code:

package demo;

public class Ren {

	String name = "无名氏";	// 昵称
	int tizhong = 100;	// 体重

	/* 该两行是性别常量 */
	final String SEX_MALE = "靓仔";
	final String SEX_FEMALE = "靓妹";
	String sex = SEX_MALE;	// 性别默认为男性
	
	public void print () {
	
		System.out.printf ( "姓名 [%s], 体重 [%d], 性别 [%s]", name, tizhong, sex );
	}
}

        测试类 code:

package demo;

public class Test {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub

		Ren r = new Ren();
		System.out.printf ( "第一个人的性别为 >>> %s\n", r.sex );
		
		r = new Ren();
		r.sex = r.SEX_FEMALE;
		System.out.printf ( "第二个人的性别为 >>> %s\n", r.sex );

		r = new Ren();
		r.sex = r.SEX_MALE;
		System.out.printf ( "第三个人的性别为 >>> %s\n", r.sex );
	}
}

        测试结果 demo:

第一个人的性别为 >>> 靓仔
第二个人的性别为 >>> 靓妹
第三个人的性别为 >>> 靓仔

——————————

升级后版本

        如果要改变人类对象的性别取值 则只需要修改人类中的两个常量值即可

        修改后的人类 code:

package demo;

public class Ren {

	String name = "无名氏";
	int tizhong = 100;

	final String SEX_MALE = "男";
	final String SEX_FEMALE = "女";
	String sex = SEX_MALE;
	
	public void print () { System.out.printf ( "姓名 [%s], 体重 [%d], 性别 [%s]", name, tizhong, sex ); }
}

        除此之外不需要任何修改 demo:
 

第一个人的性别为 >>> 男
第二个人的性别为 >>> 女
第三个人的性别为 >>> 男

##################################################

构造方法及其重载

——————————

初始化对象时赋值

        我们是先创建对象再給对象的属性赋值的 通过多条语句实现:

类名 对象名 = new 类名();
类名.对象名  = 类的成员;

        那么可否在创建对象的时候就完成赋值呢?

        Java 可以像 C# 一样通过无参或带参数的构造方法 Constructor 完成赋值的初始化工作

构造方法用于创建类的对象

构造方法的主要作用就是在创建对象时执行一些初始化操作

可以通过构造方法重载来实现多种初始化行为

——————————

什么是构造方法

        构造方法的名称和类名相同 没有返回值类型

        构造方法的主要作用就是在创建对象时执行一些初始化操作 例如給成员属性赋初值

——————————

如何构造一个无参方法

        在 Ren 中创建一个同名的无参方法 如下:

package demo;

public class Ren {
/* 人类 测试无参构造方法 */

	String name = "无名氏";
	int tizhong = 100;

	final String SEX_MALE = "男";
	final String SEX_FEMALE = "女";
	String sex = SEX_MALE;
	
	public Ren() {
	/* 无参构造方法 */

		name = "崽崽";
		tizhong = 80;
		System.out.println ( "执行构造方法" );
	}
	
	public void print () {
		
		System.out.printf ( "姓名 [%s], 体重 [%d], 性别 [%s]", name, tizhong, sex );
	}
	
	public static void main(String[] args) {
	/* 测试无参构造方法 */
		
		Ren constructure = null;
		constructure = new Ren();
		constructure.print();
	}
}

        其中 Ren() 就是 Ren 类的构造方法 执行结果如下:

执行构造方法
姓名 [崽崽], 体重 [80], 性别 [男]

demo

        从运行结果可以看到当执行语句

constructure = new Ren();

        时就会执行构造方法 Ren() 中的代码

        构造方法是一个特殊的方法

        没有构造方法时系统会提供一个空的构造方法

        例如 Ren 类中没有 Ren() 这个构造方法就会系统一个空的构造方法:

public Ren() {
/* 空的无参构造方法 */

	;;
}

        如下:

package demo;

public class Ren {
/* 人类 测试无参构造方法 */

	String name = "无名氏";
	int tizhong = 100;

	final String SEX_MALE = "男";
	final String SEX_FEMALE = "女";
	String sex = SEX_MALE;
	
	public void print () {
		
		System.out.printf ( "姓名 [%s], 体重 [%d], 性别 [%s]", name, tizhong, sex );
	}
	
	public static void main(String[] args) {
	/* 测试无参构造方法 */
		
		Ren constructure = null;
		constructure = new Ren();
		constructure.print();
	}
}

         等同于:

package demo;

public class Ren {
/* 人类 测试无参构造方法 */

	String name = "无名氏";
	int tizhong = 100;

	final String SEX_MALE = "男";
	final String SEX_FEMALE = "女";
	String sex = SEX_MALE;
	
	public Ren() {
	/* 空的无参构造方法 */

		;;
	}
	
	public void print () {
		
		System.out.printf ( "姓名 [%s], 体重 [%d], 性别 [%s]", name, tizhong, sex );
	}
	
	public static void main(String[] args) {
	/* 测试无参构造方法 */
		
		Ren constructure = null;
		constructure = new Ren();
		constructure.print();
	}
}

        结果:

姓名 [无名氏], 体重 [100], 性别 [男]

——————————

调试跟踪构造方法的执行过程

        通过断电调试可以追踪构造方法的执行过程 从而更清楚直观地理解该过程

        这边我用的 IDE 环境是 MyEclipse 10.0

%%%%%

设置断点

        首先在该代码处设置断点:

constructure = new Ren();
constructure = new Ren();

%%%%%

开始调试

        点击 F11 开始调试 选择是:

F11

        按下 F5 即调试的单步跳入 进入 ren 类:

F5

F5

F5

        连续 F5 单步执行或按 F6 单步跳过先执行 Ren 类中的属性定义语句依次給各属性赋初值:

F6

        赋值完毕后进入构造方法:

进入构造方法

        执行完构造方法代码后会跳回我们标记的断点处 表示创建对象成功 并把对象引用赋給变量 constructure 至此构造方法执行完毕!

        在右上角该界面切换视图:

切换视图

——————————

方法重载的判断依据

        如果同一个类中包含了两个或两个以上的方法

她们的方法名相同而方法参数个数或参数类型不同则该方法已经称为被重载了!

        这个过程被称为方法重载

        成员方法和构造方法都可以进行重载

        其实我们之前已经使用过方法重载了 例如:

System.out.println ( 5211314 );
System.out.println ( false );
System.out.println ( "沃达死你!" );

        又如在帮助文档中 java.lang.Math 类中的 max 方法就实现了重载:

    返回两个 double 值中较大的一个
返回类型为 static double
方法原型为 max (double a, double b)

    返回两个 float 值中较大的一个
返回类型为 static float
方法原型为 max (float a, float b)

    返回两个 int 值中较大的一个
返回类型为 static int
方法原型为 max (int a, int b)

    返回两个 long 值中较大的一个
返回类型为 static long
方法原型为 max (long a, long b)

        方法重载的判断依据如下:

必须在同一个类中

方法名相同

参数列表不同即方法参数的个数或参数类型不同

与方法返回值和方法修饰符没有任何关系

        在使用 this 调用自身的其她构造方法时 只能作为第一条语句

——————————

带参构造方法和构造方法的重载

        我们前面虽然通过构造方法完成了对象成员属性的赋值 但是属性值已经在构造方法中固定了

        能不能在创建对象时完成不同属性的动态赋值呢??

此时可以通过带参数的构造方法在创建对象时完成不同属性的动态赋值

涉及到构造方法的重载

%%%%%

添加带参构造方法

        为 Ren 类添加两个有参的构造方法:

package demo;

public class Ren {
/* 人类 测试无参构造方法 */

	String name = "无名氏";
	int tizhong = 100;
	double shengao = 2.00;	// 身高默认两米!

	final String SEX_MALE = "男";
	final String SEX_FEMALE = "女";
	String sex = SEX_MALE;
	
	public Ren() {
	/* 无参构造方法 */

		name = "崽崽";
		tizhong = 80;
		
		System.out.println ( "执行无参构造方法 >>>" );
	}
	
	public Ren(String name, double shengao) {
	/* 两个参数的构造方法 */
		
		this.name = name;	/* this 强制表示类的成员属性 右边的 name 没有 this 关键字就是表示本方法参数中声明的 name 变量 */
		this.shengao = shengao;
		
		System.out.println ( "\n\n执行二参构造方法 >>>" );
	}
	
	public Ren(String name, double shengao, int tizhong, String sex) {
	/* 四个参数的构造方法 */
		
		this.name = name;
		this.shengao = shengao;
		this.tizhong = tizhong;
		this.sex = sex;
		
		System.out.println ( "\n\n执行四参构造方法 >>>" );
	}
	
	public void print () {
		
		System.out.printf ( "姓名 [%s], 身高 [%.2f],体重 [%d], 性别 [%s]", name, shengao, tizhong, sex );
	}
	
	public static void main(String[] args) {
	/* 测试无参构造方法 */
		
		Ren constructure = null;
		
		/* 无参构造方法测试 */
		constructure = new Ren();
		constructure.print();
		
		/* 二参构造方法测试 */
		constructure = new Ren( "仔仔", 1.64 );
		constructure.print();
		
		/* 四参构造方法测试 */
		constructure = new Ren( "崽崽", 1.52, 52, constructure.SEX_FEMALE );
		constructure.print();
	}
}

        测试结果:

执行无参构造方法 >>>
姓名 [崽崽], 身高 [2.00],体重 [80], 性别 [男]

执行二参构造方法 >>>
姓名 [仔仔], 身高 [1.64],体重 [100], 性别 [男]

执行四参构造方法 >>>
姓名 [崽崽], 身高 [1.52],体重 [52], 性别 [女]

        上面一共有 3 个构造方法

        方法名相同 但是参数列表不同 这称为构造方法的重载

        可以通过构造方法的重载来实现多种初始化行为

        在创建对象时可以根据需要选择合适的构造方法

——————————

有参构造存在则必须存在无参构造

        在没有給类提供任何构造方法时 系统会提供一个无参的方法体为空的默认构造方法

        一旦提供了自定义构造方法 系统将不再提供这个默认的构造方法

        此时需要手动添加

        例如现在去掉无参构造:

	public Ren() {
	/* 无参构造方法 */

		name = "崽崽";
		tizhong = 80;
		
		System.out.println ( "执行无参构造方法 >>>" );
	}

        去掉后报错:

package demo;

public class Ren {
/* 人类 测试无参构造方法 */

	String name = "无名氏";
	int tizhong = 100;
	double shengao = 2.00;	// 身高默认两米!

	final String SEX_MALE = "男";
	final String SEX_FEMALE = "女";
	String sex = SEX_MALE;
	
	public Ren(String name, double shengao) {
	/* 两个参数的构造方法 */
		
		this.name = name;	/* this 强制表示类的成员属性 右边的 name 没有 this 关键字就是表示本方法参数中声明的 name 变量 */
		this.shengao = shengao;
		
		System.out.println ( "\n\n执行二参构造方法 >>>" );
	}
	
	public Ren(String name, double shengao, int tizhong, String sex) {
	/* 四个参数的构造方法 */
		
		this.name = name;
		this.shengao = shengao;
		this.tizhong = tizhong;
		this.sex = sex;
		
		System.out.println ( "\n\n执行四参构造方法 >>>" );
	}
	
	public void print () {
		
		System.out.printf ( "姓名 [%s], 身高 [%.2f],体重 [%d], 性别 [%s]", name, shengao, tizhong, sex );
	}
	
	public static void main(String[] args) {
	/* 测试无参构造方法 */
		
		Ren constructure = null;
		
		/* 无参构造方法测试 */
		constructure = new Ren();
		constructure.print();
		
		/* 二参构造方法测试 */
		constructure = new Ren( "仔仔", 1.64 );
		constructure.print();
		
		/* 四参构造方法测试 */
		constructure = new Ren( "崽崽", 1.52, 52, constructure.SEX_FEMALE );
		constructure.print();
	}
}

未定义

        如果没有汉化提示的应该是

The constructor Ren() is undefined

        构造函数 Ren() 未定义
 

——————————

构造方法没有返回值类型

        构造方法没有返回值类型

        如果有则不是构造方法而是和构造方法同名的成员方法!!

——————————

自动销毁创建的对象

        学会了创建对象 如何销毁对象呢?在 Java 中对象的销毁不需要程序员来做

        而是通过 Java 虚拟机的垃圾回收器在后台自动实现的

##################################################

static 修饰符

——————————

static 的作用

        static 可以用来修饰属性、方法和代码块

        static 修饰的变量属于这个类所有 即由这个类创建的所有对象共同用一个 static 变量

        通常把 staic 修饰的属性和方法称为 类属性/类变量、类方法

        不使用 static 修饰的属性和方法属于单个对象 通常称为 实例属性/实例变量、实例方法

        使用 static 修饰方法最常见的例子是我们熟悉的 main() 方法

        在方法中不能定义 static 变量 类变量不能为局部变量

——————————

使用 static 修饰属性和代码块

        示例使用 static 修饰属性和代码块时是如何分配内存空间的

在加载类的过程中 完成静态变量的内存分配 再执行静态块 两者是在创建对象之前进行的

类属性、类方法可以通过类名和对象名访问 实例属性、实例方法只能通过对象名访问

类方法只能访问类属性和其她类方法

静态方法中不能使用 this 和 super 关键字

        code:

package demo;

public class Test {

	static int i;
	static int m = 30;
	
	int j, k = 25;
	
	static {
		
		i = 10;
		System.out.println ( "i 的初始值为 " + i );
	}
	
	public Test() {
		
		j = 20;
		System.out.println ( "j 的初始值为 " + j );
	}
	
	public static void getNum() {
		
		System.out.println ( "得到 i 的值为 " + i );
	}
	
	public static void main(String[] args) {

		Test ts = new Test();
		
		System.out.println ( "i 的值为 " + ts.i );
		
		ts.getNum ();
		System.out.println ( "m 的值为 " + ts.m );
		System.out.println ( "k 的值为 " + ts.k );
	}

}

        demo:

i 的初始值为 10
j 的初始值为 20
i 的值为 10
得到 i 的值为 10
m 的值为 30
k 的值为 25

——————————

静态常量

        在使用常量时为了方便调用可以使用 static 来修饰 这种方式非常推荐使用

        例如:

static final String SEX_MALE = "男";

        在使用时可以直接通过

类名.SEX_MALE

        调用以访问

        这时称这个常量为静态常量

##################################################

封装类

——————————

何谓封装

        封装是面向对象的三大特性之一

就是将各类的状态信息隐藏在类内部
不允许外部程序直接访问
而通过类提供的方法来实现对隐藏信息的操作和访问

        封装的好处是掩藏类的细节实现 让使用者只能通过程序规定的方法来访问数据 可以方便地加入存取控制语句 限制不合理操作

        通过 private、protected、public 和默认权限的控制符来实现权限的控制

        我们一般将属性均设置为 private 权限 这样属性只在类内可见

        再用 public 提供的公开权限属性和方法和外界进行交互操作

        如何封装呢?修改属性的可见性来限制对属性的访问

        然后为每个属性创建一对 赋值/setter 方法和 取值/getter 方法

        用于对这些属性的存取 在赋值方法中加入对属性的存取控制语句

    封装时会用到多个权限控制符来修饰成员变量和方法

    类权限:
private 具有类可见性
成员变量和方法只能在其定义的类中被访问

    包权限:
protected 具有包间可见性
可以被同一个包中的类访问
还可以被同一个项目中不同包中的子类访问

    公开权限:
public 具有项目可见性
可以被同一个项目中的所有类访问
这是最大的访问权限

——————————

通过公开方法访问被封装的人类

        封装的 Ren 类:

package demo;

class Ren {
/* 人类 */
	
	private String name = "无名氏";	// 人名
	private int health = 100;	// 健康码
	private double shengao = 1.70;	// 身高
	
	private final char NAN = '男';    // 这两行其实这个程序没用 但是示例还可以这样声明私密常量
	private final char NV = '女';
	private char sex = '男';	// 性别
	
	public String getName() {
	/* 获取人名 */
		
		return name;
	}
	
	public void setName (String name) {
	/* 设置人名 */
		
		this.name = name;
	}
	
	public int getHealth() {
	/* 获取健康码 */
		
		return health;
	}
	
	public void setHealth (int health) {
	/* 设置健康码 */
		
		if (health > 100 || health < 0) {

			this.health = 50;
			System.out.println ( "健康码应该在 0 和 100 之间 默认值为 50 表示需要注射疫苗!" );
		} else
			this.health = health;
	}
	
	public double getShengao() {
	/* 获取身高 */
		
		return shengao;
	}
	
	public void setShengao (double shengao) {
	/* 设置身高 */
		
		this.shengao = shengao;
	}
	
	public char getSex() {
	/* 获取性别 */
		
		return sex;
	}
	
	public void setSex (char sex) {
	/* 设置性别 */
		
		this.sex = sex;
	}
	
	public void print () {
	/* 输出该人信息 */
		
		System.out.printf ( "姓名 >>> [%s]\n", this.name );
		System.out.printf ( "健康码 >>> [%d]\n", this.health );
		System.out.printf ( "身高 >>> [%f]\n", this.shengao );
		System.out.printf ( "性别 >>> [%c]\n", this.sex );
	}
}

        此时不可以直接访问 因为 Ren 类中的属性都是私密的 外类不可见:

外类不可见

         必须通过我们设置的公开方法来跟外界交互:

package demo;

class Main {
/* 主要类 */
	
	public static void main (String[] args) {
		
		Ren r = new Ren();
		
		r.setName ( "崽子" );	// 设置该人对象的名字
		r.setHealth ( 1000 );	// 设置该人对象的健康码
		System.out.printf ( "赋值介绍——————————\n" );
		System.out.printf ( "昵称 >>> [%s]\n", r.getName() );
		System.out.printf ( "昵称 >>> [%s]\n", r.getHealth() );
		
		System.out.printf ( "\n调用自带方法介绍——————————\n" );
		r.print ();
	}
}

        运行结果:

健康码应该在 0 和 100 之间 默认值为 50 表示需要注射疫苗!
赋值介绍——————————
昵称 >>> [崽子]
昵称 >>> [50]

调用自带方法介绍——————————
姓名 >>> [崽子]
健康码 >>> [50]
身高 >>> [1.700000]
性别 >>> [男]

        我们可以看到采用了 private 修饰符的变量不能再类外部访问 而通过 public 修饰的 setter 和 getter 方法访问

        我们通过在 setter 方法中编写相应存取语句可以避免出现不符合实际需求的赋值!

——————————

通过构造方法访问被封装的类成员属性

        现在我们需要去掉所有的 setter 方法 保留所有的 getter 方法

        去掉赋值方法 保留读取方法 而采用构造方法实现对类成员属性的赋值

        修改后的人类如下:

package demo;

class Ren {
/* 人类 */
	
	private String name = "无名氏";
	private int health = 100, happy = 90;	// 新增 happy 心情程度
	private double shengao = 1.70;
	private char sex = '男';
	

/* —————————— 读操作 —————————— */
	
	public String getName() {
		
		return name;
	}
	
	public int getHealth() {
		
		return health;
	}
	
	public double getShengao() {
		
		return shengao;
	}
	
	public char getSex() {
		
		return sex;
	}
	
	public int getHappy() {
	/* 获取心情程度 */
		
		return happy;
	}
	
	public void print () {
		
		System.out.printf ( "姓名 >>> [%s]\n", this.name );
		System.out.printf ( "健康码 >>> [%d]\n", this.health );
		System.out.printf ( "身高 >>> [%.2f]\n", this.shengao );
		System.out.printf ( "性别 >>> [%c]\n", this.sex );
		System.out.printf ( "心情 >>> [%d]\n", this.happy );
		System.out.println ();	// 为了美观
	}

/* —————————— 写操作 —————————— */

	public Ren (String name, double shengao, char sex ) {
	/* 通过构造方法来实现命名和身高及性别 */
	
		this.name = name;
		this.shengao = shengao;
		this.sex = sex;
	}
	
	public void yi() {
	/* 通过打疫苗维持健康码 */
		
		if ( health >= 100 )
			
			System.out.println ( "快滚去打疫苗!" );
		else {

			health += 5;
			happy += 30;	// 开心程度增加 30 点
			System.out.println ( "一针增加了 5 点健康程度.." );
		}
	}
	
	public void jie() {
	/* 通过逛街减少健康码 */
		
		if ( health < 60 )
			
			System.out.println ( "很抱歉您被感染了。" );
		else {
			
			System.out.println ( "正在陪 cp 逛街.." );
			health -= 10;
			happy -= 50;	// 开心程度减少 50 点
		}
	}
}

        修改后的测试类:

package demo;

class Main {
/* 主要类 */
	
	public static void main (String[] args) {
		
		/* 初始后 */
		Ren r = new Ren( "崽崽", 2.50, '女' );
		r.print ();
		
		/* 逛街后 */
		r.jie();
		r.print();
		
		/* 打针后 */
		r.yi();
		r.print();
	}
}

        运行结果如下:

姓名 >>> [崽崽]
健康码 >>> [100]
身高 >>> [2.50]
性别 >>> [女]
心情 >>> [90]

正在陪 cp 逛街..
姓名 >>> [崽崽]
健康码 >>> [90]
身高 >>> [2.50]
性别 >>> [女]
心情 >>> [40]

一针增加了 5 点健康程度..
姓名 >>> [崽崽]
健康码 >>> [95]
身高 >>> [2.50]
性别 >>> [女]
心情 >>> [70]

——————————

this 关键字的其她用法

        this 关键字是对一个对象的默认引用

        在每个实例方法内部都有一个 this 引用变量指向调用这个方法的对象

因为 this 是在对象内部指代自身的引用所以只能调用实例变量、实例方法和构造方法

this 关键字不能调用类变量和类方法、也不能调用局部变量

%%%%%

this 调用成员变量

        可以解决成员变量和局部变量的同名冲突:

    当成员变量和局部变量名同名必须使用 this 以区分:
public void ooxx(int name) {

    this.name = name;    /* 成员变量 = 局部变量 */
}

    成员变量和局部变量不同命则 this 关键字可以省略
public void ooxx(int a) {

    name = b;    /* 等同于 this.name = a */
}

%%%%%

this 调用成员方法

        例如直接调用成员方法 print() 可以省略 this 关键字:

public void jie() {
		
	if ( health < 60 )
			
		System.out.println ( "很抱歉您被感染了。" );
	else {
			
		System.out.println ( "正在陪 cp 逛街.." );
		health -= 10;
		happy -= 50;
	}

	this.print ();    // 调用成员方法 this 关键字可以省略!
}

%%%%%

this 调用重载的构造方法

        如果要使用 this 关键字调用重载的构造方法只能在构造方法内使用而且必须是构造方法的第一条语句!

public Ren (String name, char sex) {

    this.name = name;
    this.sex = sex;
}

public Ren (String name, int health, int happy, double shengao, char sex) {

    this (name, sex);    /* 调用重载的构造方法 */
    this.health = health;
    this.happy = happy;
    this.shengao = shengao;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

燃吹

呜呜呜没钱钱吃饭了……

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值