您的位置:首页 > 其它

CS 251 Assignment 1&2 知识点总结与注意

2015-11-08 20:25 447 查看

中级软件设计课程作业1、2:知识点总结与注意

首先为了参照起来方便并且能够把握整体,这里就不顾及文章长度的先把整个作业全部的代码贴上,可以直接略过,以后看到后面有不清楚的内容再返回来。



整个作业就是实现一下Java泛型数组的几个自带功能。大的Tip,注意或者知识点在全部代码后面总结,小的注意就在代码里用中文提及:

package vandy.cs251;

import java.lang.ArrayIndexOutOfBoundsException;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Spliterator;
import java.util.function.Consumer;

/**
* Provides a generic dynamically-(re)sized array abstraction.
*/
public class Array<T extends Comparable<T>>
implements Comparable<Array<T>>,
Iterable<T>,
Cloneable {
/**
* The underlying array of type T.
* The current size of the array.
* Default value for elements in the array.
*/
private T[] myArray;    //Initiative the generic array
private int currentSize = 0;    //Set up the current size
private T defaultValue;    //Set up the default value of every elements of arrays


自己定义的变量别忘了考虑前面的关键词是用public、protect、private还是省略。TA第一眼就强调了这里的问题,可以看出这对于科班出身的程序员来说很重要。一般情况下,最为保险的就是将无需全局的变量限定为private。




/**
* Constructs an array of the given size.
* @param size Non-negative integer size of the desired array.
* @throws NegativeArraySizeException if the specified size is
*         negative.
*/
@SuppressWarnings("unchecked")
public Array(int size) {
if (size < 0)
throw new NegativeArraySizeException();    //An array's length can't be negative
myArray = (T[]) new Comparable[size];    //Must write in this way
//myArray = (T[]) new Object[size];
currentSize = size;
}

/**
* Constructs an array of the given size, filled with the provided
* default value.
* @param size Non-negative integer size of the desired array.
* @param mDefaultvalue A default value for the array.
* @throws NegativeArraySizeException if the specified size is
*         negative.
*/
@SuppressWarnings("unchecked")
public Array(int size,
T defaultValue) {
this(size);    //Using the constructor Array(int size)
Arrays.fill(myArray, defaultValue);    //Fill all the elements of array with the default value
this.defaultValue = defaultValue;    //update defaultValue and currentSize
currentSize = size;
}

/**
* Copy constructor; creates a deep copy of the provided array.
* @param s The array to be copied.
*/
@SuppressWarnings("unchecked")
public Array(Array<T> s) {
//Copies the specified array,
// truncating or padding with nulls (if necessary)
// so the copy has the specified length.
myArray = Arrays.copyOf(s.myArray, s.currentSize);
this.currentSize = s.currentSize;    //Remember s is a object
this.defaultValue = s.defaultValue;
}

/**
* Creates a deep copy of this Array.  Implements the
* Prototype pattern.
*/
@Override
public Object clone() {
return new Array<T>(this);    //Don't forget to use constructor Array(Array<T> s)
}

/**
* @return The current size of the array.
*/
public int size() { return this.currentSize; }    //Good OOP programming habit

/**
* @return The current maximum capacity of the array withough
*/
public int capacity() { return this.myArray.length; }    //The field length return the real capacity of array

/**
* Resizes the array to the requested size.
*
* Changes the capacity of this array to hold the requested number of elements.
* Note the following optimizations/implementation details:
* <ul>
*   <li> If the requests size is smaller than the current maximum capacity, new memory
*   is not allocated.
*   <li> If the array was constructed with a default value, it is used to populate
*   uninitialized fields in the array.
* </ul>
* @param size Non-negative requested new size.
*/
public void resize(int size) {
if (size <= myArray.length) {    //Note that copyOf will truncate when size is smaller
Arrays.fill(myArray, size, myArray.length, defaultValue);
}
else {
myArray = Arrays.copyOf(myArray, size);
Arrays.fill(myArray, currentSize, size, defaultValue);
}
currentSize = size;
}

/**
* @return the element at the requested index.
* @param index Non-negative index of the requested element.
* @throws ArrayIndexOutOfBoundsException If the requested index is outside the
* current bounds of the array.
*/
public T get(int index) {
rangeCheck(index);
return this.myArray[index];
}

/**
* Sets the element at the requested index with a provided value.
* @param index Non-negative index of the requested element.
* @param value A provided value.
* @throws ArrayIndexOutOfBoundsException If the requested index is outside the
* current bounds of the array.
*/
public void set(int index, T value) {
rangeCheck(index);
myArray[index] = value;    //Set value
}

/**
* Removes the element at the specified position in this Array.
* Shifts any subsequent elements to the left (subtracts one from
* their indices).  Returns the element that was removed from the
* Array.
*
* @throws ArrayIndexOutOfBoundsException if the index is out of range.
* @param index the index of the element to remove
* @return element that was removed
*/
public T remove(int index) {
rangeCheck(index);
T removedOne = myArray[index];
System.arraycopy(myArray, index + 1, myArray, index, currentSize - 1 - index);//Same as for loop below
/*for (int i = index; i < currentSize - 1; i++)
myArray[i] = myArray[i + 1];*/
currentSize -= 1;
return removedOne;

}

/**
* Compares this array with another array.
* <p>
* This is a requirement of the Comparable interface.  It is used to provide
* an ordering for Array elements.
* @return a negative value if the provided array is "greater than" this array,
* zero if the arrays are identical, and a positive value if the
* provided array is "less than" this array.
*/
@Override
public int compareTo(Array<T> s) {
int difference;
for (int i = 0; i < Math.min(this.currentSize, s.currentSize); i++){
difference = this.myArray[i].compareTo(s.myArray[i]);    //Cuz comparable() has compareTo method
if (difference != 0)
return difference;
}
return this.currentSize - s.currentSize;
//return s.currentSize - this.currentSize < 0 ? 1 : -1    //If you want to only return -1, 0, 1
}

/**
* Throws an exception if the index is out of bound.
*/
private void rangeCheck(int index) {
if (index >= currentSize)
throw new ArrayIndexOutOfBoundsException();
}

public class ArrayIterator
implements java.util.Iterator<T> {
int currentPosition = 0;    // Current position in the Array (defaults to 0).
int lastReturnIndex = -1;    // Index of last element returned;
// -1 if no such element or need followed by next().

/**
* @return True if the iteration has more elements that
* haven't been iterated through yet, else false.
*/
@Override
public boolean hasNext() {
return currentPosition != currentSize;
}

/**
* @return The next element in the iteration.
*/
@Override
public T next() {
currentPosition += 1;    //Careful this order
lastReturnIndex = currentPosition - 1;
return myArray[currentPosition - 1];
}

/**
* Removes from the underlying collection the last element
* returned by this iterator. This method can be called only
* once per call to next().
* @throws IllegalStateException if no last element was
* returned by the iterator.
*/
@Override
public void remove() {
if (lastReturnIndex == -1)
throw new IllegalStateException();
Array.this.remove(currentPosition - 1);    //The method "remove" of an object of Array class
currentPosition -= 1;    //Note that after removed one, the current position should reduce one too
lastReturnIndex = -1;    //This method can be called only once per call to next()
}
}

public class ArraySpliterator
implements java.util.Spliterator<T> {
/**
* Current position of this interator.
* The end of this iterator's partition.
*/
private int origin;    //The beginning position
private int fence;    //The end of the partition

/**
* Constructs a Spliterator that covers the entire range of
* the Array from beginning to end.
*/
public ArraySpliterator() {
origin = 0;
fence = Array.this.currentSize;    //
}

/**
* Constructs a Spliterator that covers a given range.
*/
private ArraySpliterator(int pos, int end) {
origin = pos;
fence = end;
}

/** Provides the characteristics of this spliterator. */
@Override
//All these are constants
public int characteristics() {
return IMMUTABLE | NONNULL | ORDERED | SIZED | SUBSIZED;
}

/**
* Applies the provided action to the next element in the array,
* if any remain in the partition of this spliterator.
* @return true if an action was applied, false otherwise.
*/
@Override
public boolean tryAdvance(Consumer<? super T> action) {
if (origin < fence){
action.accept(myArray[origin]);    //The 'accept' method of Class Consumer
origin += 1;
return true;
}
return false;
}

/**
* Attempts to partition the range covered by this iterator.
* @return null if the range is not partitionable.
*/
@Override
public ArraySpliterator trySplit() {
int lo = origin;
int mid = origin + (fence - origin)/2;    //Careful must add origin
if (lo < mid){
origin = mid;
return new ArraySpliterator(lo, mid);
}
return null;
}

/**
* Estimates the size of the partition covered by this
* spliterator.
*/
@Override
public long estimateSize() {
return fence - origin;
}
}

/**
* Factory method that returns an Iterator.
*/
public Iterator<T> iterator() {
return new ArrayIterator();
}    //Using Factory method is a good habit

/**
* Factory method that returns a SplitIterator.
*/
public Spliterator<T> spliterator() {
return new ArraySpliterator();
}
}


程序规范上的注意:

private T[] myArray;    //Initiative the generic arrayprivate int currentSize = 0;    //Set up the current size
private T defaultValue;    //Set up the default value of every elements of arrays

自己定义的变量最好在前面加上my或者m,比如这里myArray,并且应该是mCurrentSize和mDefaultValue才更好。
在代码注释上,Java好像推荐如下在代码上面另起一行注释的风格:
//All these are constants
public int characteristics() {
return IMMUTABLE | NONNULL | ORDERED | SIZED | SUBSIZED;
}

但个人认为这样原本完整的代码将总要被每一句上面可能的该句注释隔断,代码看起来不是一气呵成,看着费劲;并且在peer review时看了其他人如此注释风格的代码,整体的代码整洁、美观度也不及自己原本的紧跟每句空四格注释风格。因此,之后还是按照自己原来的注释风格,如果注释后该行的长度太长,那么可以考虑改行改变注释位置或者其他。当然注释风格问题并不really count,整体清楚、整洁、美观就好~

Java对于数组的自行赋值:
Java跟C的一处不同在于,对于声明了但是没有进行赋值的数组或者某数组中未赋值的部分元素,Java会根据数组创建的类型自动进行赋值。如Assignment 1里对char[]数组中不需要赋值的元素就根本不用管,不用纠结到底应该赋\0还是\u000(null),Java会自动处理好的。
Java数组length关键词含义:
Java中public final length关键词是针对的数组,下图很清楚的说明了length的含义:

也即,数组的length指的是该数组的capacity而不是该数组的current size。是该数组一共开辟的存储空间而不是该数组目前已经有填充了的空间。下面对Java中与length相关的几个方法进行简单区别:
length关键词仅针对array使用,eg: myarray.length
length()方法是针对string的,eg: myString.length()
size()方法通常针对泛型集合说的,eg: myArrayList.size()
capacity()方法可以用在StringBuffer上,eg: MyStringBuffer.capacity()
当然这几个词代表的含义仍然有细微差别,否则全都用length作名字不就完了,具体的区别详见链接:
http://www.wellho.net/mouth/2649_length-size-or-capacity-in-java-.html
this关键词的重要性和妙用!
这里推荐三个链接:
http://www.javatpoint.com/this-keyword (全面给出了this关键词的6个主要用途)
/article/7355089.html (对比解释了this和super关键词)
http://javarevisited.blogspot.com/2012/01/this-keyword-java-example-tutorial.html(给了几个使用this的注意事项)
在Java中,this关键词没有C++中那么必须和重要,但很多情况下使用this仍然是很方便的。this通常指当前对象。主要的应用有:当想要引用当前对象的某种东西,比如当前对象的某个方法,或当前对象的某个成员,就可以利用this来实现;this的另一个用途是调用当前对象的另一个构造函数。这两个主要的用途都在本此作业中出现:
this.currentSize = s.currentSize;    //Remember s is a object
这是最常见的用途了,用this指当前class中变量(注意必须是instance variable)。
this(size);    //Using the constructor Array(int size)
第二个常见的用法this(),调用当前class的构造函数。Array.this.remove(currentPosition - 1); //The method "remove" of an object of Array class
第三个例子有助于对this关键词的理解,这里专门拿出来说明。这句完成的操作是:在Array class里的ArrayIterator inner class中的remove方法里直接调用Array class里的remove方法。这里这种写法说明了此时的this并不指的是当前处于的ArrayIterator class,而是定位在了Array class,这种对this的使用很常用,要理解。

factory method的使用:
在本此作业最后使用ArrayIterator和ArraySpliterator接口时,定义了两个factory method如下:
/**
* Factory method that returns an Iterator.
*/
public Iterator<T> iterator() {
return new ArrayIterator();
}    //Using Factory method is a good habit

/**
* Factory method that returns a SplitIterator.
*/
public Spliterator<T> spliterator() {
return new ArraySpliterator();
}
两个方法完成的内容很简单,但体现出一种良好的面向对象编程习惯!算是一种design pattern。这样当接口名字变动后,就只用改factory method里这一处就好了。而如果没有使用factory method,那么所有程序中用到new接口的地方名字全都要改,当代码量很大时,这无疑是十分不便的。
对于接口使用这里等等还有疑问!?

interface的使用:
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: