Java零基础入门笔记8-Java封装

1、封装

1.1、封装的概念及特点

  • 封装即将类的某些信息隐藏在类内部,不允许外部程序直接访问,并通过该类提供的方法来实现对隐藏信息的操作和访问。简单来说就是,隐藏对象信息,留出访问的接口。
  • 举个例子,比如ATM机,我们利用它可以完成存取款、转账、余额查询等等操作。而钞票便是ATM的重要信息,但是我们在外部是无法直接看到这些钞票的,更不可能随意地拿走它(嘿嘿,除非…),这便是ATM机对钞票这个重要信息的隐藏,但同时ATM机提供了相应的操作接口(插卡口、取钞口、操作屏等),用户可以通过简单的操作,便可以获取ATM中存储的钞票。作为用户,根本不会去关心ATM内部在什么位置以什么方式存放这些钞票的,用户只需提供正确的银行卡和密码,并经过简单的操作便可以拿到钞票了。
  • 封装的特点:
    1. 只能通过规定的方法访问数据
    2. 隐藏类的实例细节,方便修改和实现

1.2、封装的实现

  • 实现步骤:
    1. 修改属性的可见性,将其修饰符设为private(加上private则只能在当前类中访问该属性,即隐藏了信息);
    2. 创建对应属性的公有(修饰符设为public)的getter和setter方法(及提供了对外开放的可操作接口,其中get为取值,set为赋值);
    3. 在getter和setter方法中加入属性的控制语句(通常在这里我们可以对属性的合法性进行判断,比如年龄必须大于0等)
  • 1.修改Cat类代码如下。
    • 在编写getter和setter方法的时候可按下图进行操作
    • 若只选择getter方法,则该属性便为只读属性了,这样的话也可以控制读写。
    • 这里写图片描述
public class Cat {
    // 1、修改属性的可见性,加上修饰符private,限定只能在当前类内访问
    private String name;
    private int month;
    private double weight;
    private String species;

    // 创建公有的getter和setter方法
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getMonth() {
        return month;
    }

    public void setMonth(int month) {
        // 可以在赋值语句中添加限制,这样更符合实际
        if (month <= 0)
            System.out.println("宠物猫的年龄必须大于0,赋值有误!");
        else
            this.month = month;
    }

    public double getWeight() {
        return weight;
    }

    public void setWeight(double weight) {
        this.weight = weight;
    }

    public String getSpecies() {
        return species;
    }

    public void setSpecies(String species) {
        this.species = species;
    }

}
  • 2.修改CatTest类代码。
public class CatTest {
    public static void main(String[] args) {
        Cat cat = new Cat();

        cat.setName("旺旺");
        cat.setMonth(5);
        cat.setWeight(3.5);
        cat.setSpecies("中华田园");
        if (cat.getMonth()>0) {
            System.out.println("昵称:" + cat.getName() + ",年龄:" + cat.getMonth() + ",体重:" + cat.getWeight() + ",品种:"
                    + cat.getSpecies());
        }else {
            System.out.println("年龄有误!");
            return;
        }
    }
}
  • 3.运行结果如下所示。
    这里写图片描述

  • 4.补充:我们要编写一个带年龄参数的构造方法(若调用了无参构造,还应额外编写一下无参构造)

public Cat(int month) {
    //这里若还用this.month=month的话,那在setter方法中限制条件将无效,若用setter方法赋值,则会生效
    this.setMonth(month);
}
  • CatTest类中使用该构造方法。
Cat cat = new Cat(5);//此时我们可以将属性直接赋值

3、使用包进行类管理

  • 在计算机中,我们使用文件对信息进行存储,然后用文件夹进行文件管理,同一个文件夹可以存储多个不同的文件,同名的文件只能存储在不同的文件夹,那在Java中是如何进行不同类文件的管理呢?
  • 在Java中是用进行文件的管理的,用以解决同名文件的冲突问题。
  • 前面提到过包的命名规则,这里再重申一下,我们一般用域名的倒序+模块+功能的形式来命名(这里我们简单命名一下即可,格式为com.xxx.machanics)。
  • 1.新建一个包,功能命名为com.cxs.machanics,然后再新建一个Cat类。
package com.cxs.mechanics;//定义包

/**
 * 机器猫类
 * 
 * @author chaixingsi
 *
 */
public class Cat {
    public Cat() {
        System.out.println("我是机器猫!");
    }
}
  • 2.同理在com.cxs.animal 包下的Cat类下的无参构造方法中添加一句System.out.println("我是宠物猫猫!");
  • 3.再新建一个包,命名为com.cxs.test,然后新建一个Test类。
package com.cxs.test;//定义包,并且只能有一个Package语句,必须放于首行

//import com.cxs.animal.*;//第一种:导入com.cxs.animal这个包下的所有类
import com.cxs.animal.Cat;//第二种:导入特定的类,这种加载方式效率要更高一点
//import com.cxs.mechanics.Cat;//这样会导致同名类的冲突(IDE会不清楚到底导入哪个Cat类),可以通过*问题解决
import com.cxs.mechanics.*;//这样在创建机器猫对象的时候得加上包名,不然默认还是调用的宠物猫类
//import com.cxs.*;//这里的含义是加载cxs文件夹下的类(.是代表当前目录),所有会造成无法解析类的错误,

public class Test {
    public static void main(String[] args) {
        Cat cat = new Cat();

        // 第三种:在类名面前加上包名
        com.cxs.animal.CatTest test = new com.cxs.animal.CatTest();

        // 要想创建一个机器猫,必须按如下形式进行
        com.cxs.mechanics.Cat mechanicsCat = new com.cxs.mechanics.Cat();
    }
}

3、static关键字

  • static是静态的意思。
  • 1.在宠物猫Cat类当中加一个价格属性,并用public修饰,如public int price;
  • 2.然后在修改Test代码如下。
package com.cxs.test;

import com.cxs.animal.Cat;

public class Test {
    public static void main(String[] args) {
        Cat oneCat = new Cat();
        oneCat.setName("旺旺");
        oneCat.price = 200;
        System.out.println(oneCat.getName() + "的售价为" + oneCat.price);

        Cat twoCat = new Cat();
        twoCat.setName("哈哈");
        twoCat.price = 500;
        System.out.println(twoCat.getName() + "的售价为" + twoCat.price);
    }
}
  • 3.运行代码,结果显而易见。
    这里写图片描述
  • 4.然后在宠物猫Cat类属性价格前面加上static关键字(如public static int price;),会在Test类当中有提示(要以静态的方式Cat.price来访问该属性)。
    这里写图片描述
  • 5.再次运行代码,结果如下。
    这里写图片描述
  • 6.解释:用static修饰的成员叫做静态成员,也叫类成员,它具有这样的一个特征:无论这个类实例化出来多少对象,都会共用同一块静态空间。而在上面的例子中,在price前面加上static修饰后,上面的宠物猫的价格是共用同一块存储空间的,每只实例化出来的宠物猫对象都可以操作这块空间区域,也就是后者将价格做了修改,因此两者的价格也就一样了。
  • 7.总结:静态成员有两个特征:
    1. 静态成员是类对象共享的。
    2. 静态成员在类加载时产生,销毁时释放,生命周期长。
  • 8.下面我们继续修改代码(运行略)。静态属性(类属性)的访问方式有两种(推荐后者):对象名.属性或者类名.属性
public class Test {
    public static void main(String[] args) {
        Cat oneCat = new Cat();
        oneCat.setName("旺旺");
        oneCat.price=100;
        Cat.price = 200;

        System.out.println(oneCat.getName() + "的售价为" + oneCat.price);
    }
}
  • 9.静态方法同静态属性。
  • 10.那类前面能加static吗?在类前面加static会提示这个修饰符不合法,只有publicabstractfinal三者可以。
    这里写图片描述
  • 11.局部变量前也不允许添加static,只能添加final关键字。
  • 12.在成员方法中是可以直接访问类的静态成员的(包含属性和方法)。
  • 13.静态方法中不能直接访问同一个类中的非静态成员,只能直接调用同一个类中的静态成员,若非要访问,只能在静态方法中实例化出来一个对象,然后通过对象.成员的方法来访问。

4、代码块

  • 在Java的程序当中,代码一般使用大括号{}括起来的,那么在语句当中出现大括号{},这就是代码块。
  • 当代码块出现在普通方法中时,我们称它为普通代码块,并且普通代码块的执行顺序和一般语句的执行顺序是一样的,都是顺序执行的。
  • 当代码块直接在类当中定义时,它便成为构造代码块了。
  • 1.修改Cat类代码。
public class Cat {
    private String name;
    private int month;
    private double weight;
    private String species;

    public static int price;

    {
        System.out.println("我是构造代码块");
    }

    public Cat() {
        System.out.println("我是宠物猫");
    }

    public void run(String name) {
        {
            System.out.println("我是普通代码块1");
        }

        System.out.println(name + "快跑");

        {
            System.out.println("我是普通代码块2");
        }
    }
}
  • 2.修改Test代码。
public class Test {
    public static void main(String[] args) {
        Cat oneCat = new Cat();
        oneCat.run("旺旺");
    }
}
  • 3.运行代码结果如下,发现构造代码块是在创建对象的时候调用,会优先无参构造方法的执行(多个构造代码块之间也是顺序执行的)。
    这里写图片描述
  • 4.此时若在构造代码块前面加上static,就会变为静态代码块。我们再Cat类当中加上如下代码并运行。
static{
    System.out.println("我是静态代码块");
}

这里写图片描述

  • 5.其实,静态代码块是在类加载时调用的,优先构造代码的执行(当然多个静态代码块之间也是顺序执行的)。
  • 6.继续修改Test类,我们再实例化一个对象。那么这些代码块会执行几次呢?
public class Test {
    public static void main(String[] args) {
        Cat oneCat = new Cat();
        Cat twoCat = new Cat();
    }
}
  • 7.下面结果表明,不管实例化多少对象,静态代码块在类加载时只执行一次(可以将执行一次的代码放在静态代码块当中类提高程序效率),而构造代码块执行的次数与实例化对象的数量是一致的。
    这里写图片描述
  • 8.另外,我们可以在构造代码块中为当前类当中的成员属性和静态属性赋值,但是在静态代码块中只能给静态属性赋值,不能给成员属性赋值(除非先实例化出来对象,然后通过对象.成员的方法来访问)。
  • 9.我们再来看一下run(String name)方法。每个代码块是一个独立的作用空间,在run方法中有三个代码块(总共三对{}),因此有三个作用空间。修改run()方法及Test类的代码如下。
public void run(String name) {
    {
        int temp = 12;
        System.out.println("我是普通代码块1,temp=" + temp);
    }

    System.out.println(name + "快跑");

    {
        int temp = 13;
        System.out.println("我是普通代码块2,temp=" + temp);
    }
}
public class Test {
    public static void main(String[] args) {
        Cat oneCat = new Cat();
        oneCat.run("旺旺");
    }
}
  • 10.运行代码,结果如下。
    这里写图片描述
  • 11.若在方法体中也输出temp值会怎么样呢?这时会出错,提示无法解析。这是因为代码块当中的temp的生命周期仅限于代码块的范围
    这里写图片描述
  • 12.那么我们在方法体中再定义一个temp呢?这时代码块2中的temp会提示重复定义,这是因为该方法体中temp生命周期是在它定义的地方开始直到方法的结束。若将方法体的temp移到方法体最上面,则两个代码块中的temp便都重复定义了。
    这里写图片描述

5、Java命名规范

下面我们来总结一下Java的命名规范:

5.1、包

  • 所有字母都小写
  • 包命名的路径要符合所开发的系统模块的定义,以便看了包名就明白是哪个模块,从而直接到对应包里找相应的实现。
  • 由于Java面向对象的特性,每名开发人员都可以编写属于自己的包,为了保证每个包名的唯一性,在最新的Java编程规范中,要求开发人员在自己定义的包名前面加上唯一的前缀。由于互联网上的域名称是不会重复的,所有多数开发人员采用自己公司的名称.项目名.模块名.*.*.*,因此在互联网上域名,可以称作自己程序包的唯一前缀。
  • 个人项目包的命名:
    1. indi:个体项目,指个人发起,但非自己独自完成的项目,可公开或私有的项目,版权主要属于发起者。例如:包名为indi.发起者名.项目名.模块名.*.*.*
    2. pers:个人项目,指个人发起,独自完成,可分享的项目,版权主要属于个人。例如:包名为pers.个人名.项目名.模块名.*.*.*
    3. priv:私有项目,指个人发起,独自完成,非公开的私人使用项目,版权属于个人,例如:包名为priv.个人名.项目名.模块名.*.*.*
  • 团队项目包的命名:
    1. team:团队项目指由团队发起,并由该团队开发的项目,版权属于该团队所有。例如:包名为team.团队名.项目名.模块名.*.*.*
    2. com:公司项目,由项目发起的公司所有。例如:包名为com.公司名.项目名.模块名.*.*.*

5.2、类名

  • 类的命名,所有单词的首字母大写。
  • 根据约定,Java类名通常以大写字母开头。
    • 如果类名称由多个单词组成,则每个单词的首字母均应为大写,例如:TestPage;
    • 如果类名中包含单词缩写,则这个缩写的词的首字母均应为大写,例如:XMLExample;
    • 还有一点命名技巧就是由于类是设计是用来代表对象的,所有命名类时应尽量选择名词。

5.3、方法名

  • 首字母小写,如果是由多个单词组成的话,第一个单词首字母小写,其余单词的首字母应大写。

5.4、变量名

  • 主要命名规范有以下三种:
    1. Camel标记法:首字母是小写的,接下来的单词都以大写字母开头。
    2. Pascal标记法:首字母是大写的,接下来的单词都以大写字母开头。
    3. 匈牙利标记法:在以Pascal标记法的变量前面附加小写序列说明该变量的类型。
  • 在Java中,我们一般使用匈牙利标记法,格式:[Prefix]-BaseTag-Name,其中 [Prefix]是可选的,BaseTag是数据类型的缩写,Name是变量名字,说明变量的作用,具体用法详见百科:匈牙利标记法

猜你喜欢

转载自blog.csdn.net/chaixingsi/article/details/81944987