作用域

简介: 作用域

在Java中,我们经常看到public、protected、private这些修饰符。在Java中,这些修饰符可以用来限定访问作用域。


public

定义为public的class、interface可以被其他任何类访问:


package abc;

public class Hello {
    public void hi() {
    }
}


上面的Hello是public,因此,可以被其他包的类访问:


package xyz;

class Main {
    void foo() {
        // Main可以访问Hello
        Hello h = new Hello();
    }
}


定义为public的field、method可以被其他类访问,前提是首先有访问class的权限:


package abc;

public class Hello {
    public void hi() {
    }
}


上面的hi()方法是public,可以被其他类调用,前提是首先要能访问Hello类:


package xyz;

class Main {
    void foo() {
        Hello h = new Hello();
        h.hi();
    }
}


private


定义为private的field、method无法被其他类访问:


package abc;

public class Hello {
    // 不能被其他类调用:
    private void hi() {
    }
    
    public void hello() {
        this.hi();
    }
}


实际上,确切地说,private访问权限被限定在class的内部,而且与方法声明顺序无关。推荐把private方法放到后面,因为public方法定义了类对外提供的功能,阅读代码的时候,应该先关注public方法:


package abc;

public class Hello {
    public void hello() {
        this.hi();
    }
    
    private void hi() {
    }
}



由于Java支持嵌套类,如果一个类内部还定义了嵌套类,那么,嵌套类拥有访问private的权限:


// private


Run


定义在一个class内部的class称为嵌套类(nested class),Java支持好几种嵌套类。


protected


protected作用于继承关系。定义为protected的字段和方法可以被子类访问,以及子类的子类:


package abc;

public class Hello {
    // protected方法:
    protected void hi() {
    }
}

上面的protected方法可以被继承的类访问:


package xyz;

class Main extends Hello {
    void foo() {
        // 可以访问protected方法:
        hi();
    }
}


package

最后,包作用域是指一个类允许访问同一个package的没有public、private修饰的class,以及没有public、protected、private修饰的字段和方法。


package abc;
// package权限的类:
class Hello {
    // package权限的方法:
    void hi() {
    }
}


只要在同一个包,就可以访问package权限的class、field和method:


package abc;

class Main {
    void foo() {
        // 可以访问package权限的类:
        Hello h = new Hello();
        // 可以调用package权限的方法:
        h.hi();
    }
}


注意,包名必须完全一致,包没有父子关系,com.apache和com.apache.abc是不同的包。


局部变量


在方法内部定义的变量称为局部变量,局部变量作用域从变量声明处开始到对应的块结束。方法参数也是局部变量。


package abc;

public class Hello {
    void hi(String name) { // ①
        String s = name.toLowerCase(); // ②
        int len = s.length(); // ③
        if (len < 10) { // ④
            int p = 10 - len; // ⑤
            for (int i=0; i<10; i++) { // ⑥
                System.out.println(); // ⑦
            } // ⑧
        } // ⑨
    } // ⑩
}


我们观察上面的hi()方法代码:


方法参数name是局部变量,它的作用域是整个方法,即①~⑩;

变量s的作用域是定义处到方法结束,即②~⑩;

变量len的作用域是定义处到方法结束,即③~⑩;

变量p的作用域是定义处到if块结束,即⑤~⑨;

变量i的作用域是for循环,即⑥~⑧。



使用局部变量时,应该尽可能把局部变量的作用域缩小,尽可能延后声明局部变量。


final

Java还提供了一个final修饰符。final与访问权限不冲突,它有很多作用。


用final修饰class可以阻止被继承:


package abc;

// 无法被继承:
public final class Hello {
    private int n = 0;
    protected void hi(int t) {
        long i = t;
    }
}


用final修饰method可以阻止被子类覆写:


package abc;

public class Hello {
    // 无法被覆写:
    protected final void hi() {
    }
}


用final修饰field可以阻止被重新赋值:


package abc;

public class Hello {
    private final int n = 0;
    protected void hi() {
        this.n = 1; // error!
    }
}


用final修饰局部变量可以阻止被重新赋值:


package abc;

public class Hello {
    protected void hi(final int t) {
        t = 1; // error!
    }
}


最佳实践


如果不确定是否需要public,就不声明为public,即尽可能少地暴露对外的字段和方法。


把方法定义为package权限有助于测试,因为测试类和被测试类只要位于同一个package,测试代码就可以访问被测试类的package权限方法。


一个.java文件只能包含一个public类,但可以包含多个非public类。如果有public类,文件名必须和public类的名字相同。


相关文章
|
9天前
|
存储 缓存 JavaScript
哪些情况适合使用块级作用域,哪些情况适合使用函数作用域?
【10月更文挑战第29天】块级作用域和函数作用域在不同的场景下各有优势,合理地选择和运用这两种作用域可以使JavaScript代码更加清晰、高效和易于维护。在实际开发中,需要根据具体的业务需求、代码结构和编程模式来决定使用哪种作用域,或者在适当的情况下结合使用两者,以达到最佳的编程效果。
|
1月前
|
JavaScript 前端开发
作用域和作用域链及预解析
作用域和作用域链及预解析
20 4
|
2月前
C 作用域详解
在 C 语言中,作用域决定了变量和函数的可见性和生命周期,包括块作用域、函数作用域、文件作用域和全局作用域。块作用域内的变量仅在块内有效,函数作用域内的变量在整个函数内有效,文件作用域内的全局变量和函数在整个文件内有效,而全局作用域内的变量和函数在整个程序运行期间有效。作用域的优先级遵循局部变量优先的原则,局部变量会遮蔽同名的全局变量。变量的生命周期分为局部变量(函数调用时创建和销毁)、全局变量(程序开始时创建和结束时销毁)以及静态变量(整个程序期间有效)。理解作用域有助于避免命名冲突和错误,提高代码的可读性和可维护性。
|
6月前
|
JavaScript 前端开发 Python
函数与作用域
编程中的函数与作用域概念。函数是可重用的代码块,能提高代码的可读性、可维护性和复用性。基础用法包括定义、调用和返回值。高级用法涉及函数嵌套、匿名函数(lambda函数)和装饰器。装饰器能在不修改原函数代码的情况下添加功能。 作用域决定了变量的可见范围,从内到外是局部、嵌套、全局和内置作用域。闭包是能访问外部函数变量的内部函数,即使外部函数执行完毕,闭包仍能保留其状态。闭包常用于实现特殊功能,如记忆化和延迟执行。 立即执行函数表达式(IIFE)是JavaScript中的模式,用于创建私有作用域和防止变量污染全局。IIFE常用于封装变量、避免命名冲突以及实现模块化和函数作为参数传递。
|
Linux 网络架构
暂时性死区以及函数作用域
暂时性死区以及函数作用域
171 0
|
设计模式 自然语言处理 JavaScript
一篇文章帮你真正理解javascsript作用域闭包
一篇文章帮你真正理解javascsript作用域闭包
85 0
|
自然语言处理 JavaScript 前端开发
作用域是什么
作用域是什么
121 0
|
存储 缓存 JavaScript
深入理解作用域和闭包(下)
深入理解作用域和闭包(下)
深入理解作用域和闭包(下)
|
存储 JavaScript 前端开发
深入理解作用域和闭包(上)
深入理解作用域和闭包(上)
深入理解作用域和闭包(上)
|
自然语言处理 前端开发 JavaScript
作用域闭包
作用域闭包
88 0