Java学习之旅第二季-12:访问控制修饰符

12.1 访问控制概述

访问控制(Access Control)修饰符用于控制代码访问其修饰目标的权限,之前我们见过最多的是 public。

Java中提供了4种访问控制范围(或成为访问级别),从大到小依次为:公开、受保护、默认(包内私有)、私有,下表是他们对应的关键字及控制范围简要描述(除了默认级别没有关键字,其它3个都有对应的关键字):

访问控制修饰符修饰目标控制范围
public顶层类型(类,接口等),属性,方法,内部类型(内部类、接口等)所有的代码都可以访问
protected属性,方法,内部类型(内部类、接口等)本包及其子类(继承)可访问
默认顶层类型(类,接口等),属性,方法,内部类型(内部类、接口等)本包的代码可访问
private属性,方法,内部类型(内部类、接口等)本类代码可访问

12.2 public

公开的访问控制使用public关键字,该关键字可以修饰顶层元素,如类,接口,枚举,记录,注解等,还可以修饰属性、方法或内部类/接口等。比如之前我们经常见到的写法:

public class PublicClass{
    public int num = 1;

    public void printNum(){
    	System.out.println(num);
    }
}

由于public修饰的元素是在项目中所有位置都能访问到,一般修饰最多的是类及方法。属性极少使用public修饰,这与封装有关。

12.3 protected

受保护的访问范围 ,修饰 的目标只能本包访问或子类访问,比如声明以下的类:

package com.laotan.article12;

public class ProtectedClass {
    protected int num = 1;

    protected void print() {
        System.out.println(num);
    }
}

上面的类中声明了两个受保护的成员,如果在其它包的类中访问是不允许的:

package com.laotan.article12.sub;

import com.laotan.article12.ProtectedClass;

public class ProtectedClassTest {
    static void main() {
        ProtectedClass protectedClass=new ProtectedClass();
        System.out.println(protectedClass.num);            // 报错
    }
}

在另一个包访问受保护的 num 会提示:

'num' has protected access in 'com.laotan.article12.ProtectedClass'

要注意的是,就算是不同包中的子类按照上述方式访问也是不成立的:

package com.laotan.article12.sub;

import com.laotan.article12.ProtectedClass;

public class ChildProtectedClass extends ProtectedClass {
    public void printNum() {
        ProtectedClass protectedClass = new ProtectedClass();
        System.out.println(protectedClass.num);           // 与上一个例子报一样的错误
    }
}

实际上对于子类中可访问受保护的成员,应该从继承的角度理解,即受保护的成员能被继承到子类,既然如此,子类直接访问即可:

package com.laotan.article12.sub;

import com.laotan.article12.ProtectedClass;

public class ChildProtectedClass extends ProtectedClass {
    public void printNum() {
        System.out.println(num);
    }
}

这样调用才是符合 Java 语法的。

12.4 default

默认访问控制范围也叫包基本的访问控制,这种访问级别并没有对应的关键字,比如:

package com.laotan.article12;

class DefaultDemo {
}

在class关键字前没有其他修饰符,这个类就只能在与之同包的代码中被使用到,如果在其他包中访问,比如:

package com.laotan.article12.sub;

import com.laotan.article12.DefaultDemo;

public class DefaultClassTest {
    static void main() {
        DefaultDemo defaultDemo = new DefaultDemo();    // 报错
    }
}

会出现以下错误信息:

'com.laotan.article12.DefaultDemo' is not public in 'com.laotan.article12'. Cannot be accessed from outside package

虽然两个类所在的包似乎有父子关系,在在Java中这种所谓的“父子包”并没有语法上的支持,它们实际上毫无关系。这也导致两个类是在不同的包中,那么出错就是因为违反了默认访问控制的约束。如果DefaultClassTest类和DefaultDemo在同一个包中就没问题了。

如果类是public的,其中的成员是默认访问级别的,在包外也是不能访问到的:

package com.laotan.article12;

public class DefaultDemo {
	int num = 1;             // 默认访问级别的变量
	
    void print() {
        System.out.println(num);
    }
}

在子包中访问:

package com.laotan.article12.sub;

import com.laotan.article12.DefaultDemo;

public class DefaultClassTest {
    static void main() {
        DefaultDemo defaultDemo = new DefaultDemo();
        System.out.println(defaultDemo.num);          // 报错
        defaultDemo.print();                          // 报错
    }
}

同样出现类似的出错信息:

'num' is not public in 'com.laotan.article12.DefaultDemo'. Cannot be accessed from outside package

12.5 private

私有访问控制对应的关键字private可以修饰属性,方法及内部类,其被访问到的范围最小,被修饰的成员只能在本类中被访问,通常用于修饰属性达到封装之目的。

public class Dog {
    private int age;        // 年龄
    private float weight;   // 体重
    private String breed;   // 品种
    private String color;   // 毛色
    
    private void print() {
        System.out.println("age:" + age);
    }
}

上面的类声明中,4个属性及1个方法都是private修饰的,意味着在其它类中不能访问到它们。

12.6 访问控制应用-POJO

POJO (Plain Old Java Object)是指简单的 Java 对象,它通常没有实现特定的接口或继承特定的类。POJO 的设计原则是简单、普通、纯粹的 Java 对象,不依赖于特定的框架或技术。POJO 通常用于封装数据,可以包含一些私有字段(属性)和公共的 getter 和 setter 方法,用于对属性进行读写操作。主要用途包括:数据传输,数据存储,数据交换,单元测试等。

它的实现要求:

  • 类必须是具体的和公共的
  • 具有无参数的构造方法
  • 属性被private修饰
  • 为每一个属性提供一对public的getter与setter方法
  • 只读属性只提供getter方法,只写属性只提供setter方法

方法命名规则:

  • 非布尔类型属性,如 String name,使用这样的方法命名:setName、getName
  • 布尔类型属性,如 boolean exist,使用:setExist,isExist

典型示例如下:

public class Dog {
    private int age;        // 年龄
    private float weight;   // 体重
    private String breed;   // 品种
    private String color;   // 毛色

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public float getWeight() {
        return weight;
    }

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

    public String getBreed() {
        return breed;
    }

    public void setBreed(String breed) {
        this.breed = breed;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }
}

声明的 getter 与 setter 方法可以使用IDEA产生,也可以借助于Lombok开源包,减少getter与setter这样的模板代码

使用时,调用setter方法为实例的属性赋值,使用getter方法获取实例的属性值:

Dog erHa1 = new Dog();
erHa1.setAge(3);
erHa1.setWeight(2.4F);
erHa1.setBreed("西伯利亚哈士奇");
erHa1.setColor("灰色");

System.out.println(erHa1.getAge());
System.out.println(erHa1.getWeight());
System.out.println(erHa1.getBreed());
System.out.println(erHa1.getColor());

12.7 小结

本小节介绍了Java中的访问控制修饰符,Java中提供了4种访问控制范围:public、protected、默认(无修饰符)、private。public常用于修饰类和方法、protected适用于子类继承场景、默认访问控制用于包内共享、private主要用于封装属性。还介绍了访问控制的典型应用-POJO。访问控制是Java封装特性的重要实现方式,合理使用可以提高代码的安全性和可维护性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值