Java:Effective java学习笔记之 使类和成员的可访问性最小化

Posted JMW1407

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java:Effective java学习笔记之 使类和成员的可访问性最小化相关的知识,希望对你有一定的参考价值。

使类和成员的可访问性最小化

1.信息隐藏

区分一个组件设计得好不好,唯一重要的因素在于,它对于外部的其他组件而言,是否隐藏了其内部数据和其他实现细节。设计良好的组件会隐藏所有的实现细节,把API与实现清晰地隔离开来。然后模块之间只通过它们的 API 进行通信,一个模块不需要知道其他模块的内部工作情况。这种概念被称为 信息隐藏 或者 封装,是软件设计地基本原则之一。

信息隐藏之所以非常重要有许多原因,其中大多是因为:它可以有效地解除组成系统地各组件之间地耦合关系,即解耦,使得这些组件可以独立地开发、测试、优化、使用、理解和修改。

2.为什么要使类和成员的可访问性最小化?

虽然信息隐藏本身无论是对内还是对外都不会带来更好地性能,但是可以有效地调节性能:一旦完成一个系统,并通过剖析确定了那些组件影响了系统地性能(详见第67条).

  • 那些组件就可以被进一步优化,而不会影响到其他组件地正确性。
  • 信息隐藏提高了软件地可重用性。因为组件之间并不紧密相连,除了开发这写模块所使用地环境之外,它们在其他地环境中往往也很有用。
  • 最后,信息隐藏也降低了构建大型系统地风险。因为即使整个系统不可用,这些独立地组件仍然有可能是可用的。

因此,可以有效的解除系统中各个模块的耦合度、实现每个模块的独立开发、使得系统更加的可维护,更加的健壮。

3.如何最小化类和接口的可访问性?

(1)能将类和接口做成包级私有就一定要做成包级私有的。

(2)如果一个类或者接口,只被另外的一个类应用,那么最好将这个类或者接口做成其内部的私有类或者接口。

4.对于成员(域、方法、嵌套类和嵌套接口)访问级别

对于成员(域、方法、嵌套类和嵌套接口),有四种可能的访问级别

  • 1、私有的(private):只有在声明该成员的顶层类内部才可以访问这个成员。
  • 2、包级私有(package-private):声明该成员的包内部的任何都可以访问这个成员。从技术上将,他被称为“缺省”(default)访问级别,如果没有为成员指定访问修饰符,就采用这个访问级别(当然,接口成员除外,它们默认的访问级别是公有的)。
  • 3、受保护的(protected):声明该成员的类的子类可以访问这个成员(但是有一些限制,并且声明该成员的包内部的任何类也可以访问这个成员)。
  • 4、共有的(public):在任何地方都可以访问该成员。

5. 如何最小化一个类中成员的可访问性?

(1)首先设计出该类需要暴露出来的api,然后将剩下的成员设计成private类型。然后再其他类需要访问某些private类型的成员时,在删掉private,使其变成包级私有。如果你发现你需要经常这样做,那么就请你重新设计一下这个类的api。

(2)对于protected类型的成员,作用域是整个系统,所以,能用包访问类型的成员的话就尽量不要使用保护行的成员。

(3)不能为了测试而将包中的类或者成员变为public类型的,最多只能设置成包级私有类型。

(4)实例域绝对不能是public类型的。静态域也一样。

(5)如果一个包级私有的顶层类只是在某一个类的内部被用到,就应该考虑使它成为唯一使用它的那个类的私有嵌套类

(6)接口中的方法必须是共有的,导致所有实现该接口的类方法都隐含着共有访问级别。公有类永远都不应该暴露可变的域。对于不可变的域可以提供get访问方法,对于可变的提供get&set方法。

(7)假设常量构成了类提供的整个抽象的一部分,可以通过公有的静态final域来暴露这些常量。按惯例,这种域的名称由大写字母组成,单词之间用下划线隔开(详见第68条)。很重要的一点是,这些域要么包含基本类型的值,要么包含指向不可变对象的引用(详见第17条)。

注意点

  • 包含共有可变域的类不是线程安全的。
  • 静态final域要不包含基本类型的值,要不包含指向不可变的引用,不然会导致灾难。
  • 长度为0的数组都是可变的,声明为final也没用。可以使用两种方法,一是私有数组域,公有unmodifiableList;二是私有数组域,公有clone方法。

1、demo1

// Potential security hole!
public static final Thing[] VALUES =  ... ;

//举例
public class Demo 

    public static final String[] VALUE="a","b";
    
    public static void main(String[] args) 
          String[] value = Demo.VALUE;
        value[0]="c";
        for (String s : value) 
            System.out.println(s);
        
        String[] value1 = Demo.VALUE;
        for (String s : value1) 
            System.out.println(s);
        
    


输出:

c
b
c
b

2、demo2

使共有数组变成私有的,并增加一个公有的不可变列表:
private static final Thing[] PRIVATE_VALUES =  ... ;
public static final List<Thing> VALUES = Collections.unmodifiableList(Arrays.asList(PRIVATE_VALUES));


public class Demo2 

    private static final String[] PRIVATE_VALUES = "a", "b";
    public static final List<String> VALUES = Collections.unmodifiableList(Arrays.asList(PRIVATE_VALUES));

    public static void main(String[] args) 
        List<String> values = Demo2.VALUES;
        System.out.println(values);
    


输出:

a
b

该集合是不可变的。

3、demo3

返回私有数组的一个拷贝
private static final Thing[] PRIVATE_VALUES =  ... ;
public static final Thing[] values() 
    return PRIVATE_VALUES.clone();



public class Demo3 

    private static final String[] PRIVATE_VALUES = "a", "b";
    public static final String[] values()
        return PRIVATE_VALUES.clone();
    

    public static void main(String[] args) 
        String[] values = Demo3.values();
        values[0]="c";
        for (String value : values) 
            System.out.println(value);
        
        String[] values1 = Demo3.values();
        for (String value : values1) 
            System.out.println(value);
        
    


输出:

c
b
a
b

可见我们修改的仅仅是备份文件,类中的数组并没有被修改。

  • 方法覆盖超类的一个方法,访问的级别不允许低于超类中的访问级别。这样可以确保任何可使用超类的实例的地方也都可以使用子类的实例(详见第10条)。

参考

1、《Effective Java》阅读笔记 13使类和成员的可访问性最小化

以上是关于Java:Effective java学习笔记之 使类和成员的可访问性最小化的主要内容,如果未能解决你的问题,请参考以下文章

Java:Effective java学习笔记之 避免使用终结方法

Java:Effective java学习笔记之 消除过期对象引用

Java:Effective java学习笔记之 列表优先于数组

Java:Effective java学习笔记之 用enum代替int常量

Java:Effective java学习笔记之 复合优先于继承

Java:Effective java学习笔记之 接口优于抽象类