JAVA中的对象容器

容器的用途

如果对象的数量与生命周期都是固定的,自然我们也就不需要很复杂的数据结构。

我们可以通过创建引用来持有对象,如

Class clazz;

也可以通过数组来持有多个对象,如

Class[] clazs = new Class[10];

然而,一般情况下,我们并不知道要创建多少对象,或者以何种方式创建对象。数组显然只能创建固定长度的对象,为了使程序变得更加灵活与高效,Java类库提供了一套完整的容器类,具备完善的方法来解决上述问题。

注意:当数组的元素的类型是类的时候,数组的每一个元素其实只是对象的管理者而不是对象本身。因此,仅仅创建数组并没有创建其中的每一个对象!

容器的分类

观察上图,我们可以得出容器主要分为两种类型,两个接口Collection与Map定义了两类不同的对象存储方式。

Collection用以保存单一的元素,Map保存关联键值对。通过泛型来指定容器存放的数据类型。 Iterator 设计的目的是在未知容器具体的类型的情况下,用来遍历容器元素。剩下的容器类型都是继承了这两个接口。

下面介绍几个适合初学者的简单容器

1.ArrayList

类型:范型容器

ArrayList<String> notes=new ArrayList<String>();  容器类有两个类型:容器的类型、元素的类型

ArrayList有顺序的,下标索引从0开始。

它的优点在于随机访问元素快,但是在中间插入和移除比较慢

那么现在我们就一起来看看为什么ArrayList随机访问快,而插入移除比较慢。先说关于ArrayList的初始化。

ArrayList有三种方式进行初始化如下:

private transient Object[] elementData;
public ArrayList() {
        this(10);
    }
  public ArrayList(int initialCapacity) {
        super();
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        this.elementData = new Object[initialCapacity];
    }
 public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        size = elementData.length;
        // c.toArray might (incorrectly) not return Object[] (see 6260652)
        if (elementData.getClass() != Object[].class)
            elementData = Arrays.copyOf(elementData, size, Object[].class);
    }

我们可以看出ArrayList其实就是采用的是数组(默认是长度为10的数组)。所有ArrayList在读取的时候是具有和数组一样的效率,它的时间复杂度为1。

插入尾部就是elementData[size++] = e;当然中间会进行扩容。现在主要说插入中间为什么相对来说比较慢源码如下:

public void add(int index, E element) {
        rangeCheckForAdd(index);//验证(可以不考虑)

        ensureCapacityInternal(size + 1);  // Increments modCount!!(超过当前数组长度进行扩容)
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);(核心代码)
        elementData[index] = element;
        size++;
    }

下面以一个简单的记事本程序来展示ArrayList的操作:

public class NoteBook {
 
	private ArrayList<String> notes=new ArrayList<String>();
 
	public void add(String s) {
		//ArrayList的add方法
		notes.add(s);		
	}
	public void add(String s,int location) {
		notes.add(location, s);
	}
	public int  getSize() {
		return notes.size();		
	}
	public String getNote(int index) {
		return notes.get(index);
		
	}
	public void removeNote(int index) {
		notes.remove(index);
		
	}
	public String[] list() {
		String[] a=new String[notes.size()];
		/*for (int i = 0; i < notes.size(); i++) {
			a[i]=notes.get(i);
		}*/
		notes.toArray(a);
		return a;
	}
	public static void main(String[] args) {
		 String[] aStrings=new String[2];
		 aStrings[0]="first";
		 aStrings[1]="second";
         NoteBook noteBook=new NoteBook();         
         noteBook.add("first");
         noteBook.add("second");
         noteBook.add("third",1);
         System.out.println(noteBook.getSize());
         System.out.println(noteBook.getNote(0));
         System.out.println(noteBook.getNote(1));
         noteBook.removeNote(1);
         String[] a=noteBook.list();
         for (int i = 0; i < a.length; i++) {
			System.out.println(a[i]);
		}	}
}

2.Set

Set是一个集合,它的特点是不可以有重复的对象,也就是数学中集合的概念,所以Set最常用的就是测试归属性,很容易的询问出某个对象是否存在Set中。并且Set是具有和Collection完全一样的接口,没有额外的功能,只是表现的行为不同。下面介绍Set容器中的HashSet.

HashSet

HashSet的特点是查询速度比较快,但是存储的元素是随机的并没有排序。我们可以用下面这段代码测试一下Set中元素的唯一性和无序性。

public static void main(String[] args){
        /**
         * 没有顺序可循,这是因为hashset采用的是散列(处于速度考虑)
         */
        Random random=new Random(47);   //47为种子,想要获取一个范围内的随机数(例如26,随机数可能是0-25),首先需要一个种子(其实就是一个数值)。 
        Set<Integer> intset=new HashSet<Integer>();
        for (int i=0;i<10000;i++){  
            intset.add(random.nextInt(30)); //随机生成一个30以内的数
        }
        System.out.print(intset);
    }

输出结果:

从这个结果可以看到,即使我们循环了10000次产生一个随机数,intset中还是只有30个数而且是无序的。

下面是用HashSet做的一个输出硬币名称的简单程序

public class Coin {	
	private HashMap<Integer, String> coinnames=new HashMap<Integer,String>();
	public Coin() {
		// TODO Auto-generated constructor stub
		coinnames.put(1, "penny");
		coinnames.put(10, "dime");
		coinnames.put(25, "quarter");
		coinnames.put(50, "half-dolar");
		coinnames.put(50,"五毛");
		System.out.println(coinnames.keySet().size());		
		System.out.println(coinnames);
}
	public String  getName(int amount) {
		if (coinnames.containsKey(amount)) {
			return coinnames.get(amount);
		}else {
			return "NOT FOUND";
		}		
			}
	public static void main(String[] args) {
        java.util.Scanner in=new java.util.Scanner(System.in);
        int amount=in.nextInt();
        Coin coin=new Coin();
        String name =coin.getName(amount);
        System.out.println(name);
	}
}

运行看看结果

从这个结果我们可以知道,  hash表中的每一个key值只能对应一个结果,如果对一个key值多次赋值,这个key只会对应最后一次的结果。同时hash不能放入foreach循环中,遍历没有特别简单的方法,则需遍历key的集合。

for (Integer k : coinnames.keySet()) {
			String string=coinnames.get(k);
			System.out.println(string);
		}

参考资料:

https://blog.csdn.net/weixin_41228894/article/details/80388418

https://www.cnblogs.com/ACFLOOD/p/5555555.html

https://www.cnblogs.com/LipeiNet/p/5888513.html

猜你喜欢

转载自blog.csdn.net/Gamer_Lee/article/details/82754701
今日推荐