Java 访问修饰符

我们先来说说消费者(客户端程序员)和生产者(类库开发人员)之间的关系,从消费者的角度出发,他们希望你的代码代码保持不变,哪怕是出现了新版本,这样就不耽搁他们的调用;但是从生产者的角度出发,他们必须对代码进行修改,以确保功能的更新,但同时又要兼顾这些改动不会对消费者造成影响。

所以情况已经很明显了,一边要改,一边不让改,为了解决这个问题,Java 提供了访问修饰符,供类库开发人员向客户端程序员指明那些是可用的,哪些不可用。访问权限的控制等级为:publicprotecteddefault(该关键字可省略)和 private

public

使用了 public 关键字,就意味着 public 之后紧跟着的类、接口、成员变量、方法都是对所有类可见,哪怕这些类不在同一个包下。我们先在 com.access 包下定义一个类 Ball:

package com.access;

public class Ball {

    /**
     * public 修饰无参构造器
     */
    public Ball() {
        System.out.println("Ball constructor!");
    }

    /**
     * 没有修饰符,即为 default
     */
    void play(){
        System.out.println("play ball!");
    }
}

然后在 com.model 包下新建一个 Student 类:

package com.model;

import com.access.Ball;

public class Student {

    public static void main(String[] args) {
        Ball ball = new Ball();
        //play 方法不可调用,不信你试试
        //ball.play();
    }
}

这时候就发现调用 Ball 的 public 构造器毫无压力,但是调用 default 的方法就不行了,这是因为 default 修饰的方法只对当前包下面的类提供访问权限,其它包下的类禁止访问。

protected

关键字 protected 关键字修饰的访问权限,叫做继承访问权限。顾名思义,protected 处理的是继承的概念,我们通常会用一个子类通过关键字 extends 去继承一个父类,从而去获取父类的属性并改变父类现有成员的行为。那么问题来了,父类可能并不想让所有的类都能访问它的成员,而只想将权限赋予它的子类,那么就需要 protected 来完成这个任务了。

我们先在 com.access 包下定义一个 Fruit 类:

package com.access;

public class Fruit {

    //用 protected 来修饰
    protected double weight = 1.22;

    //default 修饰
    double size = 1.22;

}

然后在 com.model 包下定义一个 Banana 类:

package com.model;

import com.access.Fruit;

public class Banana extends Fruit{

    void bite(){
        //可以获取父类 weight 属性,但是不能获取 size
        System.out.println(weight);
    }
}

我们可以看到,子类和父类并不在一个包下,但是子类仍然可以访问父类 Fruit 的 weight 属性,同时也能看到父类中 default 修饰的 size 属性,子类是无法访问的。这就是 protected 关键字的功劳了,如果父类只想让子类(无论是否在同一个包)来访问它的某些属性,那么用 protected 修饰即可。

default

如果在一个成员、类、方法,接口前没有加任何关键字,那么就默认为 default,即包访问权限。这就意味着当前包中的所有其他类都对其有访问权限,但对于这个包之外的所有类,对其不可访问。

我们在 com.access 包下新建一个类 Food :

package com.access;

public class Food {

    /**
     * 没有关键字,即 default
     */
    void eat() {
        System.out.println("eat method");
    }
}

/**
 * 没有关键字修饰的类
 */
class Rice {
    /**
     * 没有关键字,即 default
     */
    double weight = 1.22;
}

在 com.access 下再新建一个类 Dinner:

package com.access;

public class Dinner {

    public static void main(String[] args) {
        Food food = new Food();
        //同包,可直接访问
        food.eat();
        //同包的类
        Rice rice = new Rice();
        System.out.println(rice.weight);
    }
}

我们可以看到,随意访问同包下的没有加关键字(视为 default)的成员是没有压力的,这也就是设计目的了。包访问权限允许将包内所有的类组合起来,以使它们彼此之间可以轻松的相互作用。当把类组织起来放在一个包内,那么也就给他们的包访问权限的成员赋予了相互访问的权限。

private

关键字 private 的意思就是,除了当前类之外,任何其它类都无法访问这个成员。就相当于这个成员被隔离了,可以随意改变,而不用担心影响到其它的类。比如,以下这个单例:

public class SingletonTest {

    /**
     * 静态内部类
     */
    private static class SingletonHandle {
        private static SingletonTest singletonTest = new SingletonTest();
    }

    /**
     * 私有构造器
     */
    private SingletonTest() {
    }

    /**
     * 通过静态内部类实现单例模式
     * @return
     */
    public static SingletonTest getSingletonTest() {
        return SingletonHandle.singletonTest;
    }
}

使用 private 关键字来修饰构造器,这样外部的类就无法通过 new 关键字访问构造器来获取该类的对象,而只能通过调用 getSinletonTest() 方法来获取类对象,这样就可以用过 private 关键字来控制消费者行为。同时,在一个类中,只要确定某个方法是“助手”方法,那么也可以定义为 private,以确保其它类的方法不会误用到它。

最后补充一点:类既不可以是 private 也不可以是 protected 的,对于类的访问权限,仅有两个选择:default 和 public。

欢迎关注公众号 一盐难进

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值