Java基础:封装

2. 封装

2.1 什么是Java中的封装


将类的某些信息隐藏在类的内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问。

使用封装的好处有哪些?

  • 只能通过规定的方法访问数据
  • 隐藏类的实例细节,方便修改和实现。

封装的实现步骤是什么?

  • 第一步:修改属性的可见性,即:设为private修饰符
  • 第二步:创建get/set方法,用于属性的读写
  • 第三步:在get/set方法中加入属性控制语句,用于对属性值的合法性判断

我们发现之前在写Telephone.java这个类的属性的时候,属性前面并没有加任何的修饰符,所以在其他文件(比如main()方法中)是可以直接访问和操作属性值的,从而来修改属性的原始值。我们说,这种方式其实是不好的,应该用封装的方式将属性信息隐藏起来,给用户一个特定方法让他去访问我们的属性值。此时,我们需要进行以下操作:

首先,在Telephone.java类中定义成员变量,并加上private修饰符,接着定义属性的get和set方法,如下:

package com.example;

public class Telephone {
   // 1. 定义类的成员变量,并加上private修饰符
   private float screen;
   private float cpu;
   private float mem;

   // 2. 定义成员变量的get和set方法
   public float getScreen(){
       return screen;
   }
   public void setScreen(float newScreen){
       screen = newScreen;
   }

   // 自定义的无参构造方法
   public Telephone(){
       System.out.println("执行了无参构造方法!");
   }

   // 有参的构造方法,目的是给成员变量复制
   public Telephone(float newScreen, float newCpu, float newMem){
       if(newScreen < 3.5f) {
           System.out.println("您输入屏幕尺寸参数有问题,自动为你赋值3.5");
           screen = 3.5f;
       }else{
           screen = newScreen;
       }
       cpu = newCpu;
       mem = newMem;
       System.out.println("执行了有参构造方法!");
   }
}

然后,main()方法中修改如下:

package com.example;
 
public class Main {
 
    public static void main(String[] args) {
    // write your code here
        // 通过无参的构造方法可以创建对象
        // Telephone phone = new Telephone();
        // 通过有参的构造方法也可以创建对象,并给对象中的实例变量赋初值
        Telephone phone2 = new Telephone(1.5f, 4.0f, 64.0f);
        // 3. 给属性赋值,然后得到属性值
        phone2.setScreen(6.7f);
        System.out.println("phone2的screen:" + phone2.getScreen());
    }
}

我们来看下执行结果,如下:

您输入屏幕尺寸参数有问题,自动为你赋值3.5
执行了有参构造方法!
phone2的screen:6.7

2.2 使用包管理Java中的类

我们在封装的时候,经常会遇到一个问题:封装的信息中,类的名字很可能会出现冲突,那怎么来解决这个问题呢?这个时候Java中的包就派上用场了。

1、包的作用

  • 管理Java文件
  • 解决同名文件冲突

2、包的定义:package 包名

  • 必须放在Java源程序的第一行
  • 包名间可以使用“.”号隔开. 如:com.nwd.example.

3、系统中的包
格式:
如:

  • java.lang.(类) //包含Java语言基础的类
  • java.util.(类) //包含Java语言中各种工具类
  • java.io.(类) //包含输入、输出相关功能的类

4、包的使用
(1)可以通过import关键字,在某个文件使用其他文件中的类

如: import com.nwd.music.example

(2)Java中,包的命名规范是全小写字母拼写
(3)使用的时候不但可以加载某个包下的文件,也可以加载某个具体包下的文件

如:com.nwd.*
如:com.nwd.music.*

2.3 Java中的this关键字

1、this关键字代表当前对象

  • this.属性:表示操作当前对象的属性
  • this.方法:表示调用当前对象的方法

2、封装对象的属性的时候,经常会用到this关键字
get/set方法中,如下:

2.4 Java中的内部类

问题:什么是内部类呢?
答:内部类( Inner Class )就是定义在另外一个类里面的类。与之对应,包含内部类的类被称为外部类。

问题:那为什么要将一个类定义在另一个类里面呢?独立的一个类不好吗?
答:内部类的主要作用如下:

  1. 内部类提供了更好的封装,可以把内部类隐藏在外部类之内,不允许同一个包中的其他类访问该类
  2. 内部类的方法可以直接访问外部类的所有数据,包括私有的数据
  3. 内部类所实现的功能使用外部类同样可以实现,只是有时使用内部类更方便

下面我们通过一个简单的例子来了解一下内部类,首先创建一个类HelloWorld.java,然后在这个类的内部也创建一个叫做Inner的内,如下:

package com.example;
 
public class HelloWorld {
 
    private String name = "啪啪啪";
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    //在HelloWorld类中定义一个内部类 Inner
    public class Inner{
        //定义 内部类的方法
        public void show() {
            System.out.println("执行了HelloWorld类的内部类Inner!");
            System.out.println("外部类的 姓名 默认值是:" + name);
            setName("你好,Hello");
            System.out.println("内部类调用外部方法后,外部类的 姓名 属性值是:" + getName());
        }
    }
}

然后,在main方法中实例化这两个类的对象,并调用Inner类对象的方法,如下:

package com.example;
 
public class Main {
 
    public static void main(String[] args) {
    // write your code here
        //1.创建外部类的对象
        HelloWorld hello = new HelloWorld();
        //2.创建内部类的对象
        HelloWorld.Inner inn = hello.new Inner();
        //3.调用内部类的方法
        inn.show();
    }
}

接着,我们来执行一下main方法,结果如下:

执行了HelloWorld类的内部类Inner!
外部类的 姓名 默认值是:啪啪啪
内部类调用外部方法后,外部类的 姓名 属性值是:你好,Hello

2.5 Java中的成员内部类

内部类中最常见的就是成员内部类,也称为普通内部类。我们来看如下代码:

首先创建了一个内Oute.java,其中有一个私有变量a,默认初值为99,并在这个Outer类中还创建了一个Inner类,如下:

package com.example;
 
public class Outer {
    private int a = 99; //外部类的私有属性
 
    public class Inner {
        int b = 2;
 
        public void test() {
            System.out.println("访问外部类中的a:" + a);
            System.out.println("访问内部类中的b:" + b);
        }
    }
}

接着,在main方法中,先实例化一个外部类Outer的对象,然后用这个外部类对象去创建一个内部类Inner的对象,最后用这个内部类对象去调用内部类的方法,如下:

package com.example;
 
public class Main {
 
    public static void main(String[] args) {
    // write your code here
        Outer o = new Outer();   //创建一个外部类对象 o
        Outer.Inner i = o.new Inner(); //使用外部类对象创建一个内部类对象 i
        i.test(); //内部类对象调用外部类对象的方法
    }
}

接着,我们来执行一下main方法,结果如下:

访问外部类中的a:99
访问内部类中的b:2

从上面的代码中我们可以看到,成员内部类的使用方法:
1、 Inner 类定义在 Outer 类的内部,相当于 Outer 类的一个成员变量的位置,Inner 类可以使用任意访问控制符,如 public 、 protected 、 private 等;
2、 Inner 类中定义的 test() 方法可以直接访问 Outer 类中的数据,而不受访问控制符的影响,如直接访问 Outer 类中的私有属性a;
3、 定义了成员内部类后,必须使用外部类对象来创建内部类对象,而不能直接去 new 一个内部类对象,即:内部类 对象名 = 外部类对象.new 内部类( );
4、 编译上面的程序后,会发现产生了两个 .class 文件(存在于包中),如下:



其中,第二个是外部类的 .class 文件,第一个是内部类的 .class 文件,即成员内部类的 .class 文件总是这样:外部类名$内部类名.class

  • 如果内部类和外部类具有相同的成员变量或方法,内部类默认访问自己的成员变量或方法。而如果要访问外部类的成员变量或方法,可以使用“this”关键字。比如:



    main方法不变,还是如下:



    运行结果如下:

访问外部类中的a:99
访问内部类中的a:100

从结果看,使用了this关键字后,的确能够访问外部类的成员变量。

  • 外部类不能直接使用内部类的成员或方法


2.6 Java中的静态内部类

静态内部类是 static 修饰的内部类,这种内部类的特点是:

1、 静态内部类不能直接访问外部类的非静态成员,但可以通过 new 外部类().成员 的方式访问
2、 如果外部类的静态成员与内部类的成员名称相同,可通过“外部类名.静态成员”访问外部类的静态成员;如果外部类的静态成员与内部类的成员名称不相同,则可通过“成员名”直接调用外部类的静态成员
3、 创建静态内部类的对象时,不需要外部类的对象,可以直接创建,即: 内部类 对象名= new 内部类()

基于上面3点,我们来实践一下。首先创建一个SOuter.java的外部类,同时在其内部创建一个内部类SInner,如下:

package com.example;
 
public class SOuter {
    private int a = 99;  // 外部类的私有成员变量
    static int b = 10;   // 外部类的静态成员变量
 
    // 定义一个静态内部类
    public static class SInner{
        int b = 20; // (静态)内部类的成员变量
        public void test() {
            System.out.println("访问外部类中的b:" + SOuter.b);
            System.out.println("访问内部类中的b:" + b);
        }
    }
}

main方法如下:

package com.example;
 
public class Main {
 
    public static void main(String[] args) {
    // write your code here
        SOuter.SInner si = new SOuter.SInner();  // 直接创建静态内部类的对象
        si.test(); // 调用test方法
    }
}

程序运行结果如下:

访问外部类中的b:10
访问内部类中的b:20

2.7 Java中的方法内部类

方法内部类就是内部类定义在外部类的方法中,方法内部类只在该方法的内部可见,即只在该方法内可以使用。我们也来实践一下。

首先创建一个MOuter.java的外部类,这个外部类中有一个show()方法,然后我们在这个show方法中创建一个内部类MInner,如下:

package com.example;
 
public class MOuter {
    // 外部类中的方法
    public void show() {
        final int a = 25; //定义一个外部类的常量
        int b = 30;
 
        //定义一个方法中的内部类
        class MInner{
            int c = 10; // 内部类中的变量
            //内部类中的方法
            public void print() {
                System.out.println("访问外部类方法中的常量a:" + a);
                System.out.println("访问内部类中的变量c:" + c);
            }
        }
        MInner mi = new MInner(); // 创建方法内部类的对象
        mi.print(); // 调用内部类的方法     
    }
}

main方法如下:

package com.example;
 
public class Main {
 
    public static void main(String[] args) {
    // write your code here
        MOuter mo = new MOuter(); //创建外部类的对象
        mo.show(); // 调用外部类方法
    }
}

我们来看看运行结果,如下:

访问外部类方法中的常量a:25
访问内部类中的变量c:10

由于方法内部类不能在外部类的方法以外的地方使用,因此方法内部类不能使用访问控制符和 static 修饰符。

你可能感兴趣的:(Java基础:封装)