访问修饰符你用对了吗

  不知道大家在平时的开发过程中有没有注意到访问修饰符,哈哈哈,有没有懵,在java中有哪些访问修饰符,还记得清吗?今天想分享下访问修饰符的哪些小事。

一、访问修饰符有哪些

  在java中提到访问修饰符,大家可能都不陌生,但对于访问修饰符我还是想再重申下,这些看似很普通的概念,在多年后的某个瞬间总能激起我们某些想法。

  java中说白了就三种元素:类、方法、属性,由这三种元素组合成了我们平时使用的API,来标识这三种元素的访问权限的字符就是访问修饰符,通俗点理解就是我有一个方法我只想自己自己知道,我不想别人知道那么我给它一个标识private,代表是私有的,那么别人就无法访问了,如果我想让方圆5公里的人知道,我给它个标识protected,那么就只有方圆5公里的人知道。访问修饰符就是来控制类、方法、属性的访问范围的

  在java中有四种访问修饰符,分别是public、protected、default、private。上面说到java中有类、方法、属性,下面看下这几种访问修饰符怎么起作用的。

  先上一张图,让大家有个大体的印象,

1.1、public  

  public,公开的,公共的。可以修饰类、方法、属性。在修饰类的时候,一个.java文件中只能有一个类是公共的,且和.java文件同名;重点看下最后这句话,

  看到了吧,在idea中给的提示很明确,Teacher是公共的(public),应该声明到一个文件名为Teacher.java的文件中。其实也很容易理解,在一个.java文件中有多个公共的class,是无法区分哪个是主类的,所以在一个.java文件中只能有一个公共的类。遗留一个小问题,在一个public的类中可以有其他修饰符修饰的类吗?后面揭晓。

  public修饰方法和属性,想必不用我多说了,在平时使用的比较多,public修饰方法和属性不受包的限制,在任何包中均可访问

1.2、protected

  protected,受保护的。可以修饰内部类、方法、属性。这里有个概念是内部类,当然和内部类相对应的就是外部类,所谓内部类就是在一个外部类中的类,外部类就是平时我们写的类,其类名和文件名一样。一个例子如下,

package com.example.day04;
/**
Teacher是外部类
 */
public class Teacher {
    /**
     * Inner是内部类
     */
    protected class Inner{
        
    }
}

重点来看下protected修饰的方法和属性,

package com.example.day04;
/**
Teacher是外部类
 */
public class Teacher {
    protected String name;
    protected void method(){
        System.out.println(this.name);
    }
}

那么name和method()方法可以被哪些类访问呐?看下本包中的类,

package com.example.day04;

public class TeacherA {
    public static void main(String[] args) {
        Teacher teacher=new Teacher();
        teacher.name="tom";
        teacher.method();
    }
}

protected修饰的方法、属性可以被本包中的类访问,再来看下本包中的子类,

package com.example.day04;

public class TeacherB extends Teacher{
    public static void main(String[] args) {
        TeacherB teacherB=new TeacherB();
        teacherB.name="tom";
        teacherB.method();
    }
}

打印结果如下,

tom

Process finished with exit code 0

protected修饰的方法、属性可以被本包中的子类访问,再来看下不同包中的类,

protected修饰的方法、属性不可以被不同包中的类访问,那么不同包的子类呐?

package cn.example.day04;

import com.example.day04.Teacher;

public class TeacherD extends Teacher {
    public static void main(String[] args) {
        TeacherD teacherD=new TeacherD();
        teacherD.name="tome";
        teacherD.method();
    }
}

结果如下,

tome

Process finished with exit code 0

protected修饰的方法、属性可以被不同包中的子类访问。

总结:protected修饰的属性和方法可以被同包中的类、子类访问;可以被不同包的子类访问,不可以被不同包的类访问。

1.3、default

这里说default其实不是那么严格,在java中不写访问修饰符,就是default,称为default只为了好记,其实没有“default”这个访问修饰符

default,默认的访问修饰符。可以用来修饰类、属性、方法。

有default修饰的类、属性、方法,

package com.example.day04;

class Address {
    String name;
    void method(){
        System.out.println(name);
    }
}

在本包下的类,

package com.example.day04;

public class AddressA {
    public static void main(String[] args) {
        Address address=new Address();
        address.name="china";
        address.method();
    }
}

结果如下,

china

Process finished with exit code 0

默认情况下的访问修饰符,在本包下的类是可以访问的。看下在本包下的子类,

package com.example.day04;

public class AddressB extends Address{
    public static void main(String[] args) {
        Address address=new Address();
        address.name="china";
        address.method();
    }
}

看代码正常编译未出错,肯定是可以的。

默认情况下的访问修饰符,在本包下的子类是可以访问的。不同包下的类和子类,这里不再一一列出例子了,直接给出下面的结论,

默认情况下的访问修饰符,在不同包下的类、子类都是不可以访问的默认修饰符修饰的类、属性、方法。

总结,默认情况下的访问修饰符,在本包下的类、子类是可以访问的;在不同包下的类、子类都是不可以访问

1.4、private

private,私有的。可以修饰类、属性、方法。

在private修饰类时,不可以修饰外部类,可以修饰内部类。重点看下修饰的属性、方法,这个是我们在平时开发中用的最多的。

这里有一个使用private修饰的属性、方法,

package com.example.day04;

public class Person {

    private String name;
    private void method(){
        System.out.println(name);
    }
    private class A{
        
    }
}

看下图,在本包中,

private修饰的属性、方法在本包中的类中是无法访问的。看下在本包的子类呐?

private修饰的属性、方法在本包的子类中是无法访问的。

总结,private修饰的属性、方法在本包中的类、子类是无法访问的,在不同包的类、子类是无法访问的。

二、一些小趣事

上面说了很多乏味的基础知识,在日常的开发中你可能都意识不到天天在用。下面看一下几个有意思的小问题。

2.1、一个public修饰的类中可以有其他类吗

我们知道一个public修饰的类的类名和.java文件名是一样的,那么在这个类中还可以有其他类吗?

从上图中可以看到,一个public修饰的类中仅可以有默认修饰符修饰的类,protected、private修饰的均不可以,public修饰的也不可以哦。

2.2、protected方法存在的意义

  protected修饰的方法可以在本包类、子类、不同包的子类访问。这种方法存在的意义是什么呐?在继承中,子类可以访问父类的protected方法,既然是继承了,那么没继承的类便不可访问,protected很好的诠释了继承的意义。平时开发中使用protected方法是在抽象类中的抽象方法。

package com.example.day04;

/**
 * 抽象的Car工厂
 */
public abstract class AbstractCarFactory {
    protected abstract void generateCar();
}

那么子类需要去覆盖该抽象方法,非子类不需要覆盖该方法,所以这个方法是protected访问修饰符修饰的。有人会说是public修饰的可以吗?当然可以,但是权限肯定是越小越好啊,

package com.example.day04;

public class BiyadiCarFactroy extends AbstractCarFactory{
    @Override
    public void generateCar() {
        System.out.println("generate biyadi car");
    }
}

在子类中还可以改变覆盖方法的访问修饰符。

2.3、有了private为什么还要public

在开发中写的最多的可能就是类似下面的实体类,

package com.example.day04;

public class Address {
    private String name;
    private String code;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getCode() {
        return code;
    }
    public void setCode(String code) {
        this.code = code;
    }
}

  Address类中属性是private,而getXXX和setXXX方法是public,这是为了保护属性,方式使用实例.属性的方式进行设置/获取值,而是通过其提供的setXXX/getXXX方法来设置/获取值。通过方法的方式,可以在设置值的过程中对值进行校验、判断等操作,而直接通过实例.属性的方式则无法完成上面的操作,只不过在日常的开发中,都是直接赋值,没有进行校验、判断等其他操作而已。例下方,

  public void setName(String name) {
        System.out.println("设置name的值为:"+name);
        if(name.equals("china")){
            this.name = name;
        }
        System.out.println("设置完成");
    }

2.4、子类无法访问父类的私有属性吗

上面我们知道在子类中是无法访问父类的私有属性的,因为属性是私有的即使子类也是无法访问的。但我依然可以访问到,

我们直接无法访问到name属性,但是我们可以通过其暴露的getXXX方法啊。

三、总结

  本文分享了在平时开发中很容易忽略的一个点,就是访问修饰符,我们平时用的最多的要属public、private,但是为什么要使用,这样使用的好处是什么。有人说一个项目中都是自己项目内的人,没必要考虑访问修饰符,我直接都用public不是更好,这样也没错,但是这样带来的后果是没有任何的访问限制,类比生活中人人都是想怎么干就怎么干,想去什么地方就去什么地方,这样岂不是没了规则,这个社会是不是无法正常运转了。到了程序中虽然没有那么严重,但是遵循一定的原则,对代码的整体设计后续的扩展性也是好的。本文只是想做个引子,提醒小伙伴们日常的开发中多思考,多尝试。

posted @ 2022-05-21 17:43  良工说技术  阅读(940)  评论(0编辑  收藏  举报