回到基础:封装集合

以前学面向对象时,了解到它有三种特性:

  • 封装
  • 继承
  • 多态

Java中封装的实现,是通过为私有成员提供访问器方法,即通常所知的getter和setter方法。这样封装是否合适仍属争议,也超出了本文的 讨论范围。但是,当成员变量为集合类型(java.util.Collection,java.util.Map以及它们的子类)时,这样实现封装是完全 错误的。

我经常能见到的代码像下面这样:


1

2

3

4

5

6

7

8

9

10

11

public class MyBean {

    private Collection collection;

    public Collection getCollection() {

        return collection;

    }

    public void setCollection(Collection collection) {

        this.collection = collection;

    }

}

就我所见,这样的代码很普遍,这是由于Hibernate等ORM框架使得这种设计变得流行。很多时候,当我提出我的观点,得到的建议就是使用一种不可变的设计:


1

2

3

4

5

6

7

8

9

10

11

public class MyBean {

    private Collection collection;

    public MyBean(Collection collection) {

        this.collection = collection;

    }

    public Collection getCollection() {

        return collection;

    }

}

不合适的封装

然而,在使用集合类型的情形下,由于Java中集合类型自身是可变的,这其实并没有任何改变。很明显,无论是通过构造函数传入一个集合实例的引用, 还是返回它的引用,这完全没有进行封装。只有当集合实例的引用没有(在外部)保留,也不会返回(到外部),真正的封装才有可能实现。


1

2

3

List list = new ArrayList();

MyBean mybean = new MyBean(list);

list.add(new Object()); // 我们在mybean外部改变了封装的集合

不能使用具体的子类

另外,MyBean类可能需要封装一种更具体的集合类,比如List或者Set。从下面的代码片段可以看出,传入一个Set实例是不可能的。


1

2

3

4

5

6

7

8

9

10

11

public class MyBean {

    private List collection;

    public List getCollection() {

        return collection;

    }

    public void setCollection(List collection) {

        this.collection = collection;

    }

}

不能选择具体的实现

由上一点很自然地想到,使用(外部)提供的引用的话,我们也无法使用(可能为了更高效)自己定义的类,比如Apache Commons的FastArrayList。

实现建议

下面的代码做到了真正封装的出发点。


1

2

3

4

5

6

7

8

9

10

11

public class MyBean {

    private List collection = new ArrayList();

    public MyBean(Collection collection) {

        this.collection.addAll(collection);

    }

    public Collection getCollection() {

        return Collections.unmodifiableList(collection);

    }

}

这种方式解决了前面提到的几个问题:

  1. 集合实例的引用没有从构造函数中传入,这样就不可能在实例外部改变实例。
  2. 由于完全隔离,可以自由地选择集合的实现,为修改留下余地。
  3. 不能通过getter访问器方法获得被封装的集合实例的引用。

注意:为了可读性,前面的代码片段没有使用泛型。请在实际使用中加上。

采集

#HUABAN_WIDGETS .HUABAN-red-normal-icon-button, .HUABAN-red-large-icon-button, .HUABAN-red-small-icon-button, .HUABAN-white-normal-icon-button, .HUABAN-white-large-icon-button, .HUABAN-white-small-icon-button { background-image: url({{imgBase}}/widget_icons_ie6.png)

时间: 2024-11-03 21:06:22

回到基础:封装集合的相关文章

黑马程序员——黑马基础——Map,集合框架工具类Conlections和Arrays

黑马程序员--黑马基础--Map,集合框架工具类Conlections和Arrays ------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- 一,Map集合 Map<K,V>集合是一个接口,和List集合及Set集合不同的是,它是双列集合,并且可以给对象加上名字,即键(Key). 特点: 1)该集合存储键值对,一对一对往里存 2)要保证键的唯一性. Map集合的子类 Map |--Hashtable:底层是哈希表数据结构,不可以存入null键nu

Java基础之 集合体系结构(Collection、List、ArrayList、LinkedList、Vector)

Java基础之 集合体系结构详细笔记(Collection.List.ArrayList.LinkedList.Vector) 集合是JavaSE的重要组成部分,其与数据结构的知识密切相联,集合体系就是对数据结构的封装 数组与集合的比较 数组:长度固定,可以存储基本数据类型,也能存储对象 集合:长度可变,只能存储对象类型(由于有包装类的存在,集合可以存储任何类型) 集合的体系结构 集合也叫容器,用于存储对象 我们根据不同的需求和不同的数据结构来对集合做了不同的抽象 Collection接口-公共

Java基础——封装、继承、多态

Java基础--封装.继承.多态 --小实例快速成长 抽象: 1.目的:将复杂的东西简单化,将繁乱的内容有序化. 2.过程:对相同.相似的东西合而为一,对不同的内容进行归门别类. 3.结果:类.接口. 封装: 1.目的:化零为整,将零散的内容进行归属,进行权限控制. 2.过程:将某对象的属性.方法(功能)统一到其名下,并分别设置.适当的权限进行控制管理. 3.结果:对象,接口. 继承: 1.求大同存小异:在一个系列内,大部分都有的内容,就划归父类:子类将父类的内容继承过来,可以有自身的一些发展和

J2SE基础:10集合2

2:列表(List) 特点: (1):有序的(插入的顺序有序),元素有索引值. (2):允许重复. set/get/listIterator/subList ArrayList 特点:(1):底层数组方式实现. (2):元素是有序的.(是指添加进去的元素有序,不是指对象之间的顺序) (3):不是线程同步的. (4):由于是用数组实现,查找比较快. 循环: 迭代器 For循环 双向迭代器 LinkedList 特点:(1):底层机制链表方式实现. (2):元素是有序的.(是指添加进去的元素有序,不

重构第一天:封装集合

在一些情况下,在一个类中选择不去暴露整个集合给调用者是非常有必要的.比如当我们给一个集合添加/删除item时,我们需要添加一些额外的逻辑.因为这个原因,一个非常好的办法就是让暴露出来的collecction只能被迭代而不能被修改.让我们看下面的例子. public class Order { private List<OrderLine> _orderLines; public IEnumerable<OrderLine> OrderLines { get { return _or

java基础之集合Set

1.集合 当向集合Set中增加对象时,首先集合计算要增加对象的hashcode,根据该值得到一个位置用来存放当前的对象,当在该位置没有一个对象存在的时候,集合set认为该对象在集合中不存在,直接增加进去.如果在该位置有一个对象存在,接着将准备增加到集合中的的对象与该位置上的对象进行equals比较,若返回false,在进行一次散列,将该对象放到散列后计算出的新地址.若返回true,不会再将该对象增加到集合中 2.当重写equals方法时,必须要重写hashcode方法 如果一个类的两个对象,使用

java基础之集合List-ArrayList、LinkedList、Vector的区别

PS:本篇博客主要参考jdk的底层源码,而非自己动手写代码. 请问ArrayList.LinkedList.Vector的区别 ①ArrayList底层实际上是采用数组实现的(并且该数组的类型的Object类型的) ②如果jdk6,采用Array.copyOf()方法来生成一个新的数组,如果是jdk5,采用的是System.arraycopy()方法(当添加的数据量大于数组的长度时候) ③List list = newArrayList()时,底层会生成一个长度为10的数组来存放对象 ④Arra

黑马程序员——java基础 ArrayList集合基本方法演示

java基础 ArrayList集合基本方法演示 import java.util.ArrayList; import java.util.Iterator; public class ArrayListDemos { public static void main(String[] args) { // 创建一个新的容器 ArrayList al = new ArrayList(); al.add("abc1"); al.add("abc2"); al.add(&

【Java重构系列】重构31式之封装集合

2009年,Sean Chambers在其博客中发表了31 Days of Refactoring: Useful refactoring techniques you have to know系列文章,每天发布一篇,介绍一种重构手段,连续发文31篇,故得名“重构三十一天:你应该掌握的重构手段”.此外,Sean Chambers还将这31篇文章[即31种重构手段]整理成一本电子书, 以下是博客原文链接和电子书下载地址: 博客原文:http://lostechies.com/seanchamber

基础篇——集合与泛型

一.集合 TreeSet:以有序状态保持并可防止重复,其元素必须是Comparable HashMap:可用成对的key/value来存取 LinkedList:针对经常插入或者删除中间元素所设计的高效率集合 HashSet:防止重复的集合,可快速地找出相符的元素 LinkedHashMap:类似HashMap,但可以记住元素插入的顺序,也可以设定成依照元素上次存取的先后来排序 ArrayList:可以避免重复的元素,动态的操作 二.排序 对于基础主数据类型,可以用Collection.sort