油管上的CS61B的视频
学习代码
205.75 被储存到32位中 前16位是小数点前 后16位是小数点后
声明 和 new 的创建对象
-
size方法迭代可视化
在 iterativeSize中 p 可以直接通过l的指针this来得到 我好久没遇见这种写法了
-get的递归写法内存图解
public class MySLList { // 在外界不需要关注并且需要保护的情况下 需要将其设置成私有 // 在外界不需要操作 嵌套类的时候 可以将其设置成 静态 static // 将static 看成 never looks outwards private static class MyIntNode { public int item; public MyIntNode next; public MyIntNode(int i, MyIntNode n) { item = i; next = n; } } private MyIntNode first; public MySLList(int x) { first = new MyIntNode(x, null); } /** * 返回列表中的第一项 */ public int getFirst(){ return first.item; } /** * 添加一个int 到list的最前面 */ public void addFirst(int x){ first = new MyIntNode(x, first); } public static void main(String[] args) { MySLList L = new MySLList(10); L.addFirst(15); } }
/** * @description: * @program: CS61B * @author: paleatta * @date: 2021-05-18 09:38 * @version: jdk1.8 **/ public class MySLList { // 在外界不需要关注并且需要保护的情况下 需要将其设置成私有 // 在外界不需要操作 嵌套类的时候 可以将其设置成 静态 static // 将static 看成 never looks outwards private static class MyIntNode { public int item; public MyIntNode next; public MyIntNode(int i, MyIntNode n) { item = i; next = n; } } private MyIntNode first; private int size; public MySLList() { first = null; size = 0; } public MySLList(int x) { first = new MyIntNode(x, null); size = 0; } /** * 添加一个int到list的最前面 */ public void addFirst(int x) { first = new MyIntNode(x, first); size++; } /** * 迭代 * 添加一个int到list的最后面 */ public void addLast(int x) { if (first == null){ first = new MyIntNode(x, null); return ; } MyIntNode p = first; while (p.next != null) { p = p.next; } p.next = new MyIntNode(x, null); size++; } /** * 通过缓存来减小时间上的消耗 */ public int cacheSize() { return size; } public static void main(String[] args) { MySLList L1 = new MySLList(); L1.addFirst(10); L1.addFirst(5); L1.addFirst(20); int size = L1.cacheSize(); System.out.println(size); } }
/** * @description: * @program: CS61B * @author: paleatta * @date: 2021-05-18 09:38 * @version: jdk1.8 **/ public class MySLList { // 在外界不需要关注并且需要保护的情况下 需要将其设置成私有 // 在外界不需要操作 嵌套类的时候 可以将其设置成 静态 static // 将static 看成 never looks outwards private static class MyIntNode { public int item; public MyIntNode next; public MyIntNode(int i, MyIntNode n) { item = i; next = n; } } private MyIntNode sentinel; private int size; public MySLList() { //这里的-1 是随意的 可以随便取 因为用不到 sentinel = new MyIntNode(-1, null); size = 0; } public MySLList(int x) { sentinel = new MyIntNode(x, null); size = 1; } /** * 返回列表中的第一项 */ public int getFirst() { return sentinel.next.item; } /** * 添加一个int到list的最前面 */ public void addFirst(int x) { sentinel.next = new MyIntNode(x, sentinel.next); size++; } /** * 迭代 * 添加一个int到list的最后面 */ public void addLast(int x) { MyIntNode p = sentinel.next; while (p.next != null) { p = p.next; } p.next = new MyIntNode(x, null); size++; } /** * 通过缓存来减小时间上的消耗 */ public int cacheSize() { return size; } /** * 老师的版本 * 主要是由与SLList本身不是MyIntNode类 * 无法进入递归 因此由多写了一个私有的对外部不开放的函数 * 用其参数的来进行递归 */ public int size() { return size(sentinel.next); } private static int size(MyIntNode p) { if (p.next == null) return 1; return size(p.next) + 1; } /** * 递归 * 返回SLList的长度 */ public int MySize() { int size = 0; MyIntNode p = sentinel.next; while (p != null) { size++; p = p.next; } return size; } public static void main(String[] args) { // MySLList L = new MySLList(15); // L.addFirst(10); // L.addFirst(5); // L.addFirst(20); MySLList L1 = new MySLList(); L1.addFirst(10); L1.addFirst(5); L1.addFirst(20); int size = L1.size(); System.out.println(size); } }
- 在原来SLList中是使用first作为链表的第一个节点,但是在这里的第一个节点不是sentinal,而是sentinal.next,哨兵节点本身不作为链表中的一员,仅仅作为开头,放置出现null而产生了,其item也毫无作用
- 只要生成以一个SLList 其sentinel的地址是不会改变的,因此可以将其设置为final
private final MyIntNode sentinel; private MyIntNode last; private int size;
- 和前面的哨兵节点一样,在链表的最后添加一个哨兵节点。
- 将最后的哨兵节点的next和sentinel.next相连接,变成循环链表。
public class MySLList<Generic> { // 在外界不需要关注并且需要保护的情况下 需要将其设置成私有 // 在外界不需要操作 嵌套类的时候 可以将其设置成 静态 static // 将static 看成 never looks outwards private class MyGenericNode { public Generic item; public MyGenericNode next; public MyGenericNode(Generic i, MyGenericNode n) { item = i; next = n; } } private final MyGenericNode sentinel; private MyGenericNode last; private int size; }
二维数组的内存显示
- 对于array来讲 其只是一段连续的存储空间,其寻找存储内容需要序号
- 对于class来讲 在不使用反射的条件下 其是一段强编码后进行存储 其只能对于属性进行操作 无法对于索引进行操作
他们都作为引用类型 其在栈中的存储类型都是32位的引用地址。
- 与其他语言的数组相比,Java数组:
对于“slicing”没有特殊的语法(例如在Python中)。
无法缩小或扩展(例如在Ruby中)。
没有成员方法(例如Javascript)。
必须仅包含相同类型的值(与Python不同)。
public class MyAList { private int[] items; private int size; public MyAList() { items = new int[100]; size = 0; } //添加到末尾 扩容时默认扩容100 public void addLast(int item) { items[size] = item; size++; } public int getLast() { return items[size - 1]; } public int get(int index) { return items[index]; } public int size() { return size; } }
/** * removeLast() */ public int removeLast() { int x = items[size]; //items[size - 1] = 0; size--; return x; }
/** * 默认扩容100 */ private void resize() { resize(size + 100); } /** * 调整容量到目标容量 * @param capacity */ private void resize(int capacity) { int[] temp = new int[capacity]; System.arraycopy(items, 0, temp, 0, size); items = temp; } //添加到末尾 扩容时默认扩容100 public void addLast(int item) { if (size >= items.length) resize(); items[size] = item; size++; } //添加数组 public void addLast(int[] is) { if (size + is.length >= items.length) resize(size + is.length); // items[size] = item; System.arraycopy(is, 0, items, size, is.length); size += is.length; }
每次达到数组大小限制时,便开始调整数组大小。这非常慢,因为将数组复制到新数组意味着我们必须对每个项目执行复制操作。最糟糕是,由于我们仅调整了一个额外的框的大小,因此,如果我们选择添加另一项,则每次添加到数组时都必须再次执行此操作。
相较于LinkedList来说 AList每次都需要扩容和复制,花费的时间更多,而LinkedList来说,更多的时间是操作指针,其复杂度不高,花费的时间也就更少。
提高调整大小性能而不是添加一个额外的框,我们可以创建一个包含size * FACTOR项的新数组,其中FACTOR可以是任何数字,例如2。我们将在本课程的稍后部分讨论为什么这样做很快。
原来的扩容是+size 是线性的 现在用* 是几何增长 大大减小了时间
private void resize(int capacity) { int[] temp = new int[capacity]; System.arraycopy(items, 0, temp, 0, size); items = temp; }
主要注意以下几点
- java不允许创建泛型数组对象 因此只能创建object[] 并将其类型强制转化成Generic[]
- removeLast() 在只有int类型是我们认为可以不对超出的size的那一位进行操作,但是在Generic中,将超出的那一位置为null可以让GC回收其引用对象在堆中的垃圾,节约空间
public class MyAList<Generic> { private Generic[] items; private int size; public MyAList() { items = (Generic[]) new Object[100]; size = 0; } /** * 默认扩容100 */ private void resize() { resize(size * 2); } /** * 调整容量到目标容量 * * @param capacity */ private void resize(int capacity) { Generic[] temp = (Generic[]) new Object[capacity]; System.arraycopy(items, 0, temp, 0, size); items = temp; } //添加到末尾 扩容时默认扩容100 public void addLast(Generic item) { if (size >= items.length) resize(); items[size] = item; size++; } //添加数组 public void add(Generic[] is) { if (size + is.length >= items.length) resize(size + is.length); // items[size] = item; System.arraycopy(is, 0, items, size, is.length); size += is.length; } public Generic getLast() { return items[size - 1]; } public Generic get(int index) { return items[index]; } public int size() { return size; } /** * removeLast() */ public Generic removeLast() { Generic returnItem = items[size]; items[size] = null; size--; return returnItem; } }
import static org.junit.Assert.*; //对两个数组进行断言判定 //如果两个数组相同 那么通过 //不相同则返回异常 assertArrayEquals(expected, input);
public class MySort { /** * 实现选择排序一共由三个步骤 * 1 寻找最小的项 * 2 把它移动到最前面 * 3 重复进行1和2步骤 (使用递归?) * @param x */ //对外排序的接口 其实际是调用 sort重载方法来实现的 public static void sort(String[] x ){ sort(x,0); } private static void sort(String[] x ,int start) { if (start == x.length) return; /*1. 寻找最小的项目*/ int smallest = findSmallest(x , start); /*2. 把它移动到最前面*/ swap(x,start,smallest); /*3. 递归排序剩下的部分*/ sort(x,start+1); } /*1. 寻找最小的项目,从start开始*/ private static int findSmallest(String[] x , int start) { int smallestIndex = start; for (int i = start; i < x.length; i++) { int flag = x[smallestIndex].compareTo(x[i]); if (flag > 0) smallestIndex = i; } return smallestIndex; } /*2. 交换指定的两个item*/ private static void swap(String[] x, int a, int b) { String temp = x[a]; x[a] = x[b]; x[b] = temp; } }
//声明中虽然使用的是List 是父类 ,但是实际上是调用了子类的对象,因此用父类的声明,但是走的是子类的方法。 // 这里可以结合java堆栈的知识相关先联想一下,就比较容易理解。 List<String> someSLList = new SLList<>(); List<String> someAList = new AList<>();
public interface List<Item> { default public void print(){ for (int i = 0; i < size(); i++) { System.out.print(get(i)); } System.out.println(); } } public static void main(String[] args) { List<String> someSLList = new SLList<>(); someSLList.addFirst("elk1"); someSLList.addLast("dwell"); someSLList.addLast("on"); someSLList.addLast("existential"); someSLList.addLast("crises"); someSLList.print(); List<String> someAList = new AList<>(); someAList.addFirst("elk2"); someAList.addLast("dwell2"); someAList.addLast("on"); someAList.addLast("existential"); someAList.addLast("crises"); someAList.print(); }
@Override public void print() { System.out.println("THIS IS THE OVERRIDDEN VERSION."); Node p = sentinel.next; while (p != null) { System.out.print(p.item + " "); p = p.next; } }
public static void main(String[] args) { List<String> someSLList = new SLList<>(); someSLList.addFirst("elk1"); someSLList.addLast("dwell"); someSLList.addLast("on"); someSLList.addLast("existential"); someSLList.addLast("crises"); someSLList.print(); List<String> someAList = new AList<>(); someAList.addFirst("elk2"); someAList.addLast("dwell"); someAList.addLast("on"); someAList.addLast("existential"); someAList.addLast("crises"); someAList.print(); }
- greet只在父类中存在。sniff在父类中有,但是由于子类也有sniff且签名相同,因此在Dog类中将其重写了。在flatter方法中,因为其签名不相同,因此没有将其重写,可以当作重载函数处理,父类的入参是Animal类型,Dog的入参是Dog类型。
//构造函数也可以这么写 private final SLList<Item> lostItems = new SLList<>(); //========================================= //可以不写super 在编译的时候会自动使用父类的无参构造,写不写super();都一样。 public VengefulSLList() { // super(); lostItems = new SLList<>(); }
Java中的方法传递通常使用调用对象方法去进行获得。
通过实现接口的方式,对子类进行方法的调用,以及对象方法的调用。也就是我们常说的多态性。
Compiler allows the memory box to hold any subtype.
Compiler allows calls based on static type.
Overriden non-static methods are selected at runtime based on dynamic type.
For overloaded methods, the method is selected at compile time.
- 超类和子类有相同的变量名。
- 超类和子类有相同的静态方法,且其前名相同。这是override是不生效的,因为override只对成员函数生效。
public class MyDog implements Comparable<MyDog> { public String name; private int size; public MyDog(String name, int size) { this.name = name; this.size = size; } // @Override public int MyCompare(Object item) { MyDog dog = (MyDog) item; return size - dog.size; } @Override public int compareTo(MyDog dog) { return size - dog.size; } private static class NameComparator implements Comparator<MyDog> { @Override public int compare(MyDog o1, MyDog o2) { // 这里的compareTo不是上面的方法 // 是实现了Comparator以后的自带的方法 return o1.name.compareTo(o2.name); } } public static Comparator<MyDog> getNameComparator(){ return new NameComparator(); } }
public class MyMaximizer { public static Comparable max(Comparable[] items){ int maxDex = 0; for (int i = 0; i < items.length; i += 1) { int cmp = items[i].compareTo(items[maxDex]); if (cmp > 0) { maxDex = i; } } return items[maxDex]; } }
public class MyDogLauncher { public static void main(String[] args) { MyDog d1 = new MyDog("Elyse", 3); MyDog d2 = new MyDog("Sture", 9); MyDog d3 = new MyDog("Benjamin", 15); MyDog[] myDogs = new MyDog[]{d1, d2, d3}; MyDog d = (MyDog) MyMaximizer.max(myDogs); System.out.println(d.name); Comparator<MyDog> nc = MyDog.getNameComparator(); int flag = nc.compare(d1, d2); System.out.println(flag); if (flag > 0) { System.out.println(d1.name); return; } System.out.println(d2.name); } }
- 该类实现了Itreable,并重写其相关方法,返回迭代器。
- 迭代器中重写了next方法和hasnext方法,并使其有作用
MyArraySet<Integer> aset = new MyArraySet<>(); ………………………………………………………… Iterator<Integer> iterator = aset.iterator(); while (iterator.hasNext()) System.out.println(iterator.next());
MyArraySet<Integer> aset = new MyArraySet<>(); ………………………………………………………… //iteration for (int i : aset) { System.out.println(i); }
for (int i : aset) { //首先调用public Iterator<T> iterator() {} 获得迭代器 //调用hasNext()方法 查看是否为true //如果为true调用iterator.next(),索引移动到i+1 返回第i个item //为false则跳出循环 System.out.println(i); }
- 私自获得比较器或迭代器 , 通过实现able的方法 来进行和自身相关的操作。尤其是在书写代码方面,有很高的相似度。
- String 内存浪费内存严重
- StringBuffer 内存不浪费 线程安全 效率低
- StringBuilder 内存不浪费 线程不安全 效率高
- 通常情况下建议使用StringBuilder 要求线程安全的情况下使用StringBuffer 减少直接使用String 尽量从Stringbuilder 或者StringBuffer转换过去。
public boolean equals(Object obj) { return (this == obj); }
//equals的代码 @Override public boolean equals(Object other) { if (other == this) return true; if (other == null) return false; if (other.getClass() != this.getClass()) return false; MyArraySet<T> o = (MyArraySet<T>) other; if (o.size != this.size) return false; //注意这里T和this的类型并不相同,为什么还可以成功 for (T item : this) { if (!o.contains(item)) return false; } return true; }
@Override public String toString() { List<String> stringItems = new ArrayList<>(); for (T x : this) { stringItems.add(x.toString()); } return "{"+String.join(",", stringItems)+"}"; }