最近一直被琐事耽误,学习java虽然没停,但是每天学的比较少,继续加油吧!
容器,用来装其他对象的对象。数组也是个容器,它作为容器的优势是简单,效率高,缺点是不灵活,容量不可变。
这里用一张图显示一下容易的结构吧。我学习也是按照这个来的。
基础阶段,不仅要学习使用,还要多练习,所以我还自己实现了这些容器,虽然没有很完美,但是作为练习,还是可以的。
学习容器之前,要知道泛型,可以帮助我们建立类型安全的集合,可以理解为容器的标签。本质是数据类型的参数化。理解为数据类型的占位符,常用T E V三者字母表示。
class MyCollection <E>{
Object []objs=new Object[5];
public void set(E e,int index) {
objs[index]=e;
}
// public Object get(int index) {
// return objs[index];
// }
public E get(int index) {
return (E) objs[index];
}
}
定义一个类,使用表示一种数据类型。
MyCollection<String> mc=new MyCollection<>();//这里写String,返回的就是String
mc.set("小明", 0);
//mc.set(1234, 1);
//Integer a=(Integer)mc.get(1);
String b=mc.get(0);//无泛型,需要每次都强制类型转换
String c=mc.get(0);//加泛型,无需强制转换,因为已经用String站位了
System.out.println(c);
接下来测试Collection接口中的方法。
ArrayList实现类
Collection<String> c=new ArrayList<>();
System.out.println(c.size());//返回容器中元素数量
System.out.println(c.isEmpty());//看容器是否是空的
c.add("小明");//泛型是String,所以这里也是字符串
System.out.println(c.contains("小明"));//测试是否包含元素
c.add("小红");
System.out.println(c);
System.out.println(c.size());//返回容器中元素数量
c.remove("小红");//移除,不是删除,容器只是存放了地址,移除的只是地址,但是那个对象还在
System.out.println(c);
c.clear();//移除所有元素
System.out.println(c.size());
Object []objs=c.toArray();//转出来一个数组
System.out.println(objs);
其他的实现类的方法与ArrayList的方法基本类似,因为他们都是继承自Collection接口。
自己实现一个List
public class LMList5 <E>{
private Object[] elemantData;
private int size;
private static final int DEFALT_CAPACITY=10;//默认长度
public LMList5() {
elemantData=new Object[DEFALT_CAPACITY];//默认长度为10
}
public LMList5(int capacity) {//也可以设置长度
if (capacity<0) {
throw new RuntimeException("长度不能为负数");
}
else if (capacity==0) {
elemantData=new Object[DEFALT_CAPACITY];//默认长度为10
}
else {
elemantData=new Object[capacity];
}
}
public void add(E element) {
//什么时候扩容
if (size==elemantData.length) {
//怎么扩容?
Object []newArray=new Object[elemantData.length+(elemantData.length>>1)]; //扩容一半的空间
System.arraycopy(elemantData, 0, newArray, 0, elemantData.length);
elemantData=newArray;
}
elemantData[size++]=element;
}
public E get(int index) {
//检查索引合法性[0,size)
cheakRange(index);
return (E)elemantData[index];
}
public void set(int index,E element) {
//检查索引合法性[0,size)
cheakRange(index);
elemantData[index]=element;
}
//检查索引合法性函数
public void cheakRange(int index) {
//检查索引合法性[0,size)
if (index<0||index>size-1) {
throw new RuntimeException("索引不合法:"+index);
}
}
public void remove(int index) {
cheakRange(index);
int numMoved=elemantData.length-index-1;
if (numMoved>0) {
System.arraycopy(elemantData, index+1, elemantData, index,numMoved);
}
elemantData[--size]=null;
}
//移除元素
public void remove(E element) {
//element将他挨个和所有元素比较,获得第一个比较为true的返回
for(int i=0;i<size;i++) {
if (element.equals(get(i))) {//容器中所有的比较操作都是用的equals
remove(i);
}
}
}
public int size() {
return size;
}
public boolean isEmpty() {
if (size==0) {
return true;
}
else {
return false;
}
}
@Override
public String toString() {
StringBuilder sb=new StringBuilder();
sb.append("[");
for(int i=0;i<size;i++) {
sb.append(elemantData[i]+",");
}
sb.setCharAt(sb.length()-1, ']');
return sb.toString();
}
public static void main(String[] args) {
LMList5<String> lm1=new LMList5<>();
for (int i = 0; i <40; i++) {
lm1.add("小"+i);
}
lm1.add("aa");
lm1.add("bb");
lm1.add("cc");
System.out.println(lm1);
System.out.println(lm1.get(40));
//lm1.set(-50,"kk");
lm1.remove(40);
lm1.remove("bb");
System.out.println(lm1);
System.out.println(lm1.get(40));
System.out.println(lm1.size());
System.out.println(lm1.isEmpty());
}
}
这些东西还是练一下的比较好,并不是重复造车轮,而是练习。
然后还有自己练习的LinkList。LinkList实际上是用了节点连接所有的数据。所以首先定义一个节点类,这个类需要有上一个元素,本元素,下一个元素。
public class Node2<E> {
Node2 <E>previous;
E element;
Node2 <E>next;
}
接下来是实现LinkList,这个代码是自己练习写的,不是跟着老师上课写的,注释好像没怎么写,不过比较简单。
public class TestLinkedList2 <E>{
int size=0;
Node2<E> lastNode=new Node2<>();
Node2<E> fristNode=new Node2<>();
public void put(E element) {
if (lastNode.element==null) {
lastNode.previous=null;
lastNode.element=element;
lastNode.next=null;
fristNode=lastNode;
}
else {
Node2 temp=new Node2();
temp.previous=lastNode;
temp.element=element;
temp.next=null;
lastNode.next=temp;
lastNode=temp;
}
size++;
}
public E get(int index) {
Node2 <E>temp=new Node2<>();
temp=fristNode;
for (int i = 0; i < index; i++) {
temp= temp.next;
}
return (E)temp.element;
}
public void put(int index,E element) {
Node2 <E>temp=new Node2<E>();
temp=fristNode;
for(int i=0;i<index;i++) {
temp=temp.next;
}
Node2 <E>up=new Node2<E>();
Node2 <E>newNode=new Node2<E>();
up=temp.previous;
up.next=newNode;
newNode.previous=up;
newNode.element=element;
newNode.next=temp;
temp.previous=newNode;
}
public void remove(int index) {
Node2 <E>temp=new Node2<E>();
temp=fristNode;
for(int i=0;i<index;i++) {
temp=temp.next;
}
Node2 <E>up=new Node2<E>();
Node2 <E>down=new Node2<E>();
up=temp.previous;
down=temp.next;
up.next=down;
down.previous=up;
}
@Override
public String toString() {
StringBuilder sb=new StringBuilder("[");
Node2<E> temp=new Node2<E>();
temp=fristNode;
while (temp.next!=null) {
sb.append(temp.element+",");
temp=temp.next;
}
sb.append(temp.element+"]");
return sb.toString();
}
public static void main(String[] args) {
TestLinkedList2<String> t=new TestLinkedList2<>();
t.put("aa");
t.put("bb");
t.put("cc");
System.out.println(t);
System.out.println(t.get(1));
t.put(2,"dd");
System.out.println(t);
t.remove(2);
System.out.println(t);
}
}
这里实现了一下基本的函数,为了显示,把ToString()重写了一下。
写的时候,我会出一些错误,但是最近学习了调试程序,通过看每个值的逻辑变化,都把错误改过来了。
再来个map吧。其实这些东西没什么可以写的,知道怎么用,知道原理就行了,剩下的就是敲敲敲敲。。。
Map ,有一个键值对,<K,V>,不可重复,若重复,则替换,意思就是一个K对应一个V,如果给K不同的值,就会替代。
然后Hash表,就是一个数组,存放map的数组。然后节点有四个属性,hash值,Key,Value,Next。通过Key 的值获得Hash的值,方法是K&(length-1),length是数组的长度,使用这种方法,数组长度必须是2的整数次方。
public class Node2<K,V> {
int hash;
K key;
V value;
Node2 next;
}
public class TestMap4 <K,V>{
Node2 []table;//位桶
int size;//存放建值对
public TestMap4() {
table=new Node2[16];//必须是2的整数次方
}
public void put(K key,V value) {
//定义新节点对象
Node2 newNode2=new Node2();
newNode2.hash=myHash(key.hashCode(), table.length);
newNode2.key=key;
newNode2.value=value;
newNode2.next=null;
Node2 temp=table[newNode2.hash];
Node2 ItLast=null;
boolean keyRepeat=false;
if (temp==null) {//如果此处的节点为空,直接放进去
table[newNode2.hash]=newNode2;
size++;
}
else {
while(temp!=null) {
if(temp.key.equals(newNode2.key)) {
temp.value=newNode2.value;
keyRepeat=true;
break;
}
else {
ItLast=temp;
temp=temp.next;
}
}
if (!keyRepeat) {
ItLast.next=newNode2;
size++;
}
}
}
public V get(K key) {
int hash=myHash(key.hashCode(), table.length);
Object value=null;
if (table[hash]!=null) {
Node2 temp=table[hash];
while (temp!=null) {
if (temp.key.equals(key)) {
value=temp.value;
break;
}
else {
temp=temp.next;
}
}
}
return (V)value;
}
public static int myHash(int v,int length) {
return v&(length-1);
}
@Override
public String toString() {
StringBuilder sb=new StringBuilder("{");
for (int i = 0; i < table.length; i++) {//遍历数组
Node2 temp=table[i];
//遍历链表
while (temp!=null) {
sb.append(temp.key+":"+temp.value+",");
temp=temp.next;
}
}
sb.setCharAt(sb.length()-1, '}');
return sb.toString();
}
public static void main(String[] args) {
TestMap4<Integer,String> m1=new TestMap4<>();
System.out.println();
m1.put(10, "aa");
m1.put(20, "bb");
m1.put(30, "cc");
m1.put(18, "cc");
m1.put(34, "sss");
m1.put(50, "cc");
m1.put(33, "4564");
System.out.println(m1);
System.out.println(m1.get(50));
}
内容有点多,下一篇继续,我会把前几天的补上的。